blob: 66a26ace91bdcac9d33b2bdd672b77afd745ad9b [file] [log] [blame]
package skip_tasks
import (
"context"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/deepequal/assertdeep"
ftestutils "go.skia.org/infra/go/firestore/testutils"
"go.skia.org/infra/go/git"
"go.skia.org/infra/go/git/repograph"
"go.skia.org/infra/go/git/testutils/mem_git"
"go.skia.org/infra/go/gitstore"
"go.skia.org/infra/go/gitstore/mem_gitstore"
)
func setup(t *testing.T) (*DB, func()) {
c, cleanup := ftestutils.NewClientForTesting(context.Background(), t)
b, err := New(context.Background(), c)
require.NoError(t, err)
return b, cleanup
}
func TestAddRemove(t *testing.T) {
b1, cleanup1 := setup(t)
defer cleanup1()
// Test.
r1 := &Rule{
AddedBy: "test@google.com",
TaskSpecPatterns: []string{".*"},
Name: "My Rule",
}
ctx := context.Background()
require.NoError(t, b1.addRule(ctx, r1))
// The Firestore emulator doesn't seem to allow different clients to see each
// other's data, so we use the same client as b1.
b2, err := New(ctx, b1.client)
require.NoError(t, err)
assertRulesAreEqual := func() {
require.Eventually(t, func() bool {
require.NoError(t, b2.Update(ctx))
if len(b1.rules) == len(b2.rules) {
assertdeep.Equal(t, b1.rules, b2.rules)
return true
}
return false
}, 30*time.Second, 100*time.Millisecond)
}
assertRulesAreEqual()
require.NoError(t, b1.RemoveRule(ctx, r1.Name))
assertRulesAreEqual()
}
func TestRuleCopy(t *testing.T) {
r := &Rule{
AddedBy: "me@google.com",
TaskSpecPatterns: []string{"a", "b"},
Commits: []string{"abc123", "def456"},
Description: "this is a rule",
Name: "example",
}
assertdeep.Copy(t, r, r.Copy())
}
func TestRules(t *testing.T) {
type testCase struct {
taskSpec string
commit string
expectMatch bool
msg string
}
tests := []struct {
rule Rule
cases []testCase
}{
{
rule: Rule{
AddedBy: "test@google.com",
Name: "Match all taskSpecs",
TaskSpecPatterns: []string{
".*",
},
},
cases: []testCase{
{
taskSpec: "My-TaskSpec",
commit: "abc123",
expectMatch: true,
msg: "'.*' should match all taskSpecs.",
},
},
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "Match some taskSpecs",
TaskSpecPatterns: []string{
"My.*kSpec",
},
},
cases: []testCase{
{
taskSpec: "My-TaskSpec",
commit: "abc123",
expectMatch: true,
msg: "Should match",
},
{
taskSpec: "Your-TaskSpec",
commit: "abc123",
expectMatch: false,
msg: "Should not match",
},
},
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "Match one commit",
TaskSpecPatterns: []string{
".*",
},
Commits: []string{
"abc123",
},
},
cases: []testCase{
{
taskSpec: "My-TaskSpec",
commit: "abc123",
expectMatch: true,
msg: "Single commit match",
},
{
taskSpec: "My-TaskSpec",
commit: "def456",
expectMatch: false,
msg: "Single commit does not match",
},
},
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "Commit range",
TaskSpecPatterns: []string{},
Commits: []string{
"abc123",
"bbadbeef",
},
},
cases: []testCase{
{
taskSpec: "My-TaskSpec",
commit: "abc123",
expectMatch: true,
msg: "Inside commit range (1)",
},
{
taskSpec: "My-TaskSpec",
commit: "bbadbeef",
expectMatch: true,
msg: "Inside commit range (2)",
},
{
taskSpec: "My-TaskSpec",
commit: "def456",
expectMatch: false,
msg: "Outside commit range",
},
},
},
}
for _, test := range tests {
for _, c := range test.cases {
require.Equal(t, c.expectMatch, test.rule.Match(c.taskSpec, c.commit), c.msg)
}
}
}
func setupTestRepo(t *testing.T) (context.Context, repograph.Map, []string) {
ctx := context.Background()
gs := mem_gitstore.New()
mg := mem_git.New(t, gs)
ri, err := gitstore.NewGitStoreRepoImpl(ctx, gs)
require.NoError(t, err)
repo, err := repograph.NewWithRepoImpl(ctx, ri)
require.NoError(t, err)
mg.AddUpdater(repo)
commits := []string{}
/*
* commit 8
|
* commit 7
|\ Merge: 4 6
| |
| | Merge branch 'mybranch'
| |
| * commit 6
| |
| * commit 5
| |
* | commit 4
| |
* | commit 3
| |
* | commit 2
|/
* commit 1
|
* commit 0
*/
// 0
commits = append(commits, mg.Commit("0"))
// 1
commits = append(commits, mg.Commit("1"))
// 2
commits = append(commits, mg.Commit("2"))
// 3
commits = append(commits, mg.Commit("3"))
// 4
commits = append(commits, mg.Commit("4"))
// 5
mg.NewBranch("mybranch", commits[1])
commits = append(commits, mg.Commit("5"))
// 6
commits = append(commits, mg.Commit("6"))
// 7
mg.CheckoutBranch(git.MainBranch)
commits = append(commits, mg.Merge("mybranch"))
// 8
commits = append(commits, mg.Commit("8"))
repos := repograph.Map{
"fake.git": repo,
}
return ctx, repos, commits
}
func TestValidation(t *testing.T) {
// Setup.
_, repos, commits := setupTestRepo(t)
// Test.
tests := []struct {
rule Rule
expect error
msg string
}{
{
rule: Rule{
AddedBy: "",
Name: "My rule",
TaskSpecPatterns: []string{".*"},
Commits: []string{},
},
expect: fmt.Errorf("Rules must have an AddedBy user."),
msg: "No AddedBy",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "",
TaskSpecPatterns: []string{".*"},
Commits: []string{},
},
expect: fmt.Errorf("Rules must have a name."),
msg: "No Name",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "01234567890123456789012345678901234567890123456789",
TaskSpecPatterns: []string{".*"},
Commits: []string{},
},
expect: nil,
msg: "Long Name",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "012345678901234567890123456789012345678901234567890",
TaskSpecPatterns: []string{".*"},
Commits: []string{},
},
expect: fmt.Errorf("Rule names must be shorter than 50 characters. Use the Description field for detailed information."),
msg: "Too Long Name",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "My rule",
TaskSpecPatterns: []string{},
Commits: []string{},
},
expect: fmt.Errorf("Rules must include a taskSpec pattern and/or a commit/range."),
msg: "No taskSpecs or commits",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "My rule",
TaskSpecPatterns: []string{".*"},
Commits: []string{},
},
expect: nil,
msg: "One taskSpec pattern, no commits",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "My rule",
TaskSpecPatterns: []string{
"A.*B",
"[C|D]{42}",
"[Your|My]-TaskSpec",
"Test.*",
"Some-TaskSpec",
},
Commits: []string{},
},
expect: nil,
msg: "Five taskSpec patterns, no commits",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "My rule",
TaskSpecPatterns: []string{},
Commits: commits[8:9],
},
expect: nil,
msg: "One commit",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "My rule",
TaskSpecPatterns: []string{},
Commits: []string{
commits[8][:38],
},
},
expect: fmt.Errorf("Unable to find commit %s in any repo.", commits[8][:38]),
msg: "Invalid commit",
},
{
rule: Rule{
AddedBy: "test@google.com",
Name: "My rule",
TaskSpecPatterns: []string{},
Commits: commits[0:5],
},
expect: nil,
msg: "Five commits",
},
}
for _, test := range tests {
require.Equal(t, test.expect, ValidateRule(&test.rule, repos), test.msg)
}
}
func TestCommitRange(t *testing.T) {
// Setup.
ctx, repos, commits := setupTestRepo(t)
b, cleanup := setup(t)
defer cleanup()
// Test.
// Create a commit range rule.
startCommit := commits[0]
endCommit := commits[6]
rule, err := NewCommitRangeRule(ctx, "commit range", "test@google.com", "...", []string{}, startCommit, endCommit, repos)
require.NoError(t, err)
err = b.AddRule(ctx, rule, repos)
require.NoError(t, err)
// Ensure that we got the expected list of commits.
require.Equal(t, []string{
commits[5],
commits[1],
commits[0],
}, b.rules[rule.Name].Commits)
// Test a few commits.
tc := []struct {
commit string
expect bool
msg string
}{
{
commit: "",
expect: false,
msg: "empty commit does not match",
},
{
commit: startCommit,
expect: true,
msg: "startCommit matches",
},
{
commit: endCommit,
expect: false,
msg: "endCommit does not match",
},
{
commit: commits[1],
expect: true,
msg: "middle of range matches",
},
{
commit: commits[8],
expect: false,
msg: "out of range does not match",
},
}
for _, c := range tc {
require.Equal(t, c.expect, b.Match("", c.commit))
}
}