package check import ( "strings" "testing" "unicode/utf8" "git.novox.be/novox/mesh-sdk/go/delivery" ) func lineCase(t testing.TB, pulls ...delivery.CandidatePull) (*Case, Pull) { cs := caseOf(t, pulls...) return cs, cs.Pulls[0] } func passVerdict() delivery.Verdict { return delivery.Verdict{State: delivery.VerdictPass, Levels: map[string]delivery.LevelResult{delivery.LevelUnit: {Run: 12, Kept: 301}, delivery.LevelIntegration: {Run: 3, Kept: 40}}, Took: delivery.Took{Queue: 800, Clone: 4100, Unit: 400, IntegrationSetup: 3200, IntegrationRun: 12000}, Composition: &delivery.Composition{State: delivery.CompositionNotRun}} } func TestAPassOpensWithTheVerdictAndSaysTheCommitsTheCountsTheTimesAndThatTheCompositionWasNotRun(t *testing.T) { // 1300/AC1 cs, p := lineCase(t, pullOf(repoA, 7, head1)) full := Report(passVerdict(), cs, p, nil, nil, nil) for _, want := range []string{"pass 111111111111 on aaaaaaaaaaaa", "unit 12 run, 301 kept", "integration 3 run, 40 kept", "queue 800ms", "clone 4.1s", "unit 400ms", "int setup 3.2s", "int run 12s", "composition not yet run"} { if !strings.Contains(full, want) { t.Errorf("the report %q lacks %q", full, want) } } if !strings.HasPrefix(full, "pass ") || strings.Contains(full, "composition passed") { t.Errorf("report = %q", full) } line := Line(passVerdict(), cs, p, nil, nil, nil) if n := utf8.RuneCountInString(line); n > MaxLine { t.Errorf("the line is %d characters, want at most %d: %q", n, MaxLine, line) } if !strings.HasPrefix(line, "pass 111111111111 on aaaaaaaaaaaa") || !strings.Contains(line, "composition not yet run") || !strings.Contains(line, "unit 12 run 301 kept") || !strings.Contains(line, "clone 4.1s") || !strings.Contains(line, "int 3.2s+12s") { t.Errorf("line = %q", line) } } func TestAFailureNamesTheTestTheConflictOrTheRefusedStepFirst(t *testing.T) { // 1300/AC2 cs, p := lineCase(t, pullOf(repoA, 7, head1)) for name, c := range map[string]struct { v delivery.Verdict want string }{ "test": {delivery.Verdict{State: delivery.VerdictFail, Failed: delivery.FailedFirst{Test: "unit: m/a.TestX", Words: "want 4"}}, "failed: unit: m/a.TestX: want 4"}, "conflict": {delivery.Verdict{State: delivery.VerdictFail, Failed: delivery.FailedFirst{Machine: "shanks", Words: "novox/mesh-delivery#7 does not merge into the trunk: files in conflict: go.mod"}}, "failed: shanks: novox/mesh-delivery#7 does not merge into the trunk: files in conflict: go.mod"}, "refused": {delivery.Verdict{State: delivery.VerdictFail, Failed: delivery.FailedFirst{Machine: "mesh-build-go", Words: "no go build node qualifies: builders disagree"}}, "failed: mesh-build-go: no go build node qualifies"}, } { line := Line(c.v, cs, p, nil, nil, nil) if !strings.HasPrefix(line, c.want) || !strings.Contains(line, "111111111111 on aaaaaaaaaaaa") { t.Errorf("%s: line = %q, want it to open with %q and name the commits", name, line, c.want) } } } func TestALevelOverItsBoundIsNamedWithItsSlowestTestsAndTheVerdictIsNotChanged(t *testing.T) { // 1300/AC3 cs, p := lineCase(t, pullOf(repoA, 7, head1)) v := passVerdict() v.OverBound = []string{"unit"} line := Line(v, cs, p, nil, []string{"unit pkg.TestSlow 7.0s"}, nil) if !strings.HasPrefix(line, "pass ") || !strings.Contains(Report(v, cs, p, nil, []string{"unit pkg.TestSlow 7.0s"}, nil), "over bound: unit (slowest unit pkg.TestSlow 7.0s)") { t.Errorf("line = %q", line) } } func TestSkippedTestsAreSaidAndNeverAFlatPass(t *testing.T) { // 1300/AC6 cs, p := lineCase(t, pullOf(repoA, 7, head1)) v := passVerdict() v.Levels[delivery.LevelUnit] = delivery.LevelResult{Run: 12, Kept: 301, Skipped: 2} if line := Line(v, cs, p, nil, nil, nil); !strings.Contains(line, "unit 12 run, 301 kept, 2 skipped") { t.Errorf("line = %q", line) } } func TestAGroupsMembersEachCarryTheSameVerdict(t *testing.T) { // 1300/AC4 cs := caseOf(t, pullOf(repoA, 7, head1), pullOf(repoSDK, 12, head2)) a := Line(passVerdict(), cs, cs.Pulls[0], nil, nil, nil) b := Line(passVerdict(), cs, cs.Pulls[1], nil, nil, nil) if !strings.HasPrefix(a, "pass ") || !strings.HasPrefix(b, "pass ") || !strings.Contains(Report(passVerdict(), cs, cs.Pulls[0], nil, nil, nil), "group feat/x of 2 pull requests") { t.Errorf("lines %q and %q", a, b) } if !strings.Contains(a, "111111111111") || !strings.Contains(b, "222222222222") { t.Errorf("each member's line names its own head: %q and %q", a, b) } } func TestTheBuildsOfTheTouchedModulesAreSaidAndDroppedFirstWhenTheLineIsTooLong(t *testing.T) { // ADR 0484 clause 7 cs, p := lineCase(t, pullOf(repoA, 7, head1)) builds := []BuildNote{{"avahi", "built"}, {"mesh-tools", "waiting"}} if r := Report(passVerdict(), cs, p, builds, nil, nil); !strings.Contains(r, "builds: avahi built, mesh-tools waiting") { t.Errorf("report = %q", r) } line := Line(passVerdict(), cs, p, builds, nil, nil) if utf8.RuneCountInString(line) > MaxLine { t.Errorf("line %q is too long", line) } short := passVerdict() short.Took = delivery.Took{} if l := Line(short, cs, p, builds[:1], nil, nil); !strings.Contains(l, "builds: avahi built") { t.Errorf("a short line keeps its builds: %q", l) } } func TestALineIsNeverLongerThanTheLimit(t *testing.T) { // 1300/AC1 cs, p := lineCase(t, pullOf(repoA, 7, head1)) v := delivery.Verdict{State: delivery.VerdictFail, Failed: delivery.FailedFirst{Test: "integration: " + strings.Repeat("pkg/", 50) + ".TestSomething", Words: strings.Repeat("because ", 40)}} if line := Line(v, cs, p, nil, nil, nil); utf8.RuneCountInString(line) > MaxLine || !strings.HasPrefix(line, "failed: integration: ") { t.Errorf("line = %q (%d)", line, utf8.RuneCountInString(line)) } } func TestARunningCheckIsPending(t *testing.T) { cs, p := lineCase(t, pullOf(repoA, 7, head1)) if line := Line(delivery.Verdict{State: delivery.VerdictRunning}, cs, p, nil, nil, nil); line != "checking 111111111111 on aaaaaaaaaaaa" { t.Errorf("line = %q", line) } } func TestThePassedCompositionIsSaidOnlyWhenItWasRun(t *testing.T) { // ADR 0484 clause 6 cs, p := lineCase(t, pullOf(repoA, 7, head1)) v := passVerdict() v.Composition = &delivery.Composition{State: delivery.CompositionPass, SDK: "afbe371003a570f088be4a394d83aa7a9458f7ab"} if r := Report(v, cs, p, nil, nil, nil); !strings.Contains(r, "composition passed with afbe371003a5") { t.Errorf("report = %q", r) } v.Composition = nil if r := Report(v, cs, p, nil, nil, nil); !strings.Contains(r, "composition not yet run") || strings.Contains(r, "composition passed") { t.Errorf("a verdict with no composition: %q", r) } } func TestTheCompositionsTimeAndMachinesAreSaidOnceTheAssignerReportsThem(t *testing.T) { // 1300 (C10), the assigner's verdict (issue 1297) cs, p := lineCase(t, pullOf(repoA, 7, head1)) v := passVerdict() v.Took.Composition = 2400 v.Composition = &delivery.Composition{State: delivery.CompositionPass, SDK: "afbe371003a570f088be4a394d83aa7a9458f7ab", Machines: []string{"g14", "ace", "novox", "shanks"}} r := Report(v, cs, p, nil, nil, nil) for _, want := range []string{"composition passed in 2.4s with afbe371003a5 on 4 machines: ace, g14, novox, shanks"} { if !strings.Contains(r, want) { t.Errorf("report %q lacks %q", r, want) } } if l := Line(v, cs, p, nil, nil, nil); !strings.Contains(l, "composition passed in 2.4s") || !strings.Contains(l, "on 4 machines") || utf8.RuneCountInString(l) > MaxLine { t.Errorf("line = %q", l) } v.State, v.Failed = delivery.VerdictFail, delivery.FailedFirst{Machine: "novox", Words: "composition refused"} v.Composition = &delivery.Composition{State: delivery.CompositionFail, Words: "novox: two seats claim dns", Machines: []string{"novox"}} if r := Report(v, cs, p, nil, nil, nil); !strings.Contains(r, "composition failed in 2.4s on novox: novox: two seats claim dns") { t.Errorf("failed composition report = %q", r) } } // 1887/D7-go, review round 2 item 5: the line says the unit level's gofmt and go vet time beside its tests'. func TestTheLineSaysTheLintTime(t *testing.T) { b := newBench(t) test := b.test b.test = func(c stepCall) (any, error) { r, err := test(c) if res, ok := r.(Tested); ok && res.Level == delivery.LevelUnit { res.Lint = 1.5 return res, err } return r, err } out := b.judge(t, caseOf(t, pullOf(repoA, 7, head1))) if out.Verdict.Took.Lint != 1500 { t.Fatalf("took = %+v, want the lint's 1.5 s", out.Verdict.Took) } cs := caseOf(t, pullOf(repoA, 7, head1)) pc := parts(out.Verdict, cs, cs.Pulls[0], out.Builds, out.Slowest, out.Judged) if !strings.Contains(pc.times, "lint 1.5s") || !strings.Contains(pc.shortTimes, "lint 1.5s") { t.Errorf("times = %q, short %q, want the lint's time in both forms of the line", pc.times, pc.shortTimes) } }