package link import ( "encoding/json" "testing" "time" ) // The builds a walk may take are read from the build seat's own outcomes of its checks (novox/hq ADR 0350 ยง2): only // checks of the walk's pull requests, only builds made, newest first. func TestNatsTheBuildsAWalkMayTakeAreTheChecksOutcomesOfItsPullRequests(t *testing.T) { js := aBus(t) since := time.Now().Add(-time.Minute) say := func(r BuildResult) { body, _ := json.Marshal(r) if _, err := js.Context().Publish(BuildOutcomeOf(TheBuildMachine), body); err != nil { t.Fatal(err) } } mine := &CheckRequest{Owner: "novox", Repo: "shop", Number: 7} built := CheckBuilt{Module: "app", Key: "r1:1", Made: []MadeArtifact{{Name: "server", Reference: "s/app/server@sha256:a"}}} say(BuildResult{ID: "build-1", Checked: mine, Check: &CheckOutcome{Verdict: "pass", Built: []CheckBuilt{built, {Module: "web", NotBuilt: "it has no reuse key"}}}}) say(BuildResult{ID: "build-2", Checked: &CheckRequest{Owner: "novox", Repo: "shop", Number: 8}, Check: &CheckOutcome{Verdict: "pass", Built: []CheckBuilt{built}}}) say(BuildResult{ID: "build-3", Repository: "novox/shop", Commit: "c0ffee"}) // a build, not a check newer := built newer.Key = "r1:2" say(BuildResult{ID: "build-4", Checked: mine, Check: &CheckOutcome{Verdict: "pass", Built: []CheckBuilt{newer}}}) got, err := ReadCheckBuilds(t.Context(), js, TheBuildMachine, []PullRef{{Owner: "novox", Repo: "shop", Number: 7}}, since) if err != nil { t.Fatal(err) } if len(got) != 2 || got[0].Check != "build-4" || got[0].Built.Key != "r1:2" || got[1].Check != "build-1" || got[1].Pull.Number != 7 { t.Fatalf("read %+v", got) } } // A build is read with the head its check judged, and a kept build is named as the check's that built it (novox/hq // issue 703). func TestNatsAKeptBuildIsTheBuildersCheckAndEveryBuildSaysItsHead(t *testing.T) { js := aBus(t) since := time.Now().Add(-time.Minute) say := func(r BuildResult) { body, _ := json.Marshal(r) if _, err := js.Context().Publish(BuildOutcomeOf(TheBuildMachine), body); err != nil { t.Fatal(err) } } mine := &CheckRequest{Owner: "novox", Repo: "shop", Number: 7} app := CheckBuilt{Module: "app", Key: "r1:1", Made: []MadeArtifact{{Name: "server", Reference: "s/app/server@sha256:a"}}} say(BuildResult{ID: "build-1", Checked: mine, Check: &CheckOutcome{Verdict: "pass", Head: "aaaaaaaaaaaa", Built: []CheckBuilt{app}}}) kept := app kept.Kept = "build-1" say(BuildResult{ID: "build-2", Checked: mine, Check: &CheckOutcome{Verdict: "pass", Head: "aaaaaaaaaaaa", Built: []CheckBuilt{kept}}}) got, err := ReadCheckBuilds(t.Context(), js, TheBuildMachine, []PullRef{{Owner: "novox", Repo: "shop", Number: 7}}, since) if err != nil { t.Fatal(err) } if len(got) != 2 || got[0].Check != "build-1" || got[0].Built.Kept != "build-1" || got[0].Head != "aaaaaaaaaaaa" || got[1].Check != "build-1" || got[1].Head != "aaaaaaaaaaaa" { t.Fatalf("read %+v", got) } } // Two spellings of a head are the same head only when both say at least twelve characters of it. func TestSameHeadNeedsTwelveCharactersOfBoth(t *testing.T) { for _, c := range []struct { a, b string same bool }{ {"aaaaaaaaaaaa", "aaaaaaaaaaaabbbb", true}, {"aaaaaaaaaaaabbbb", "aaaaaaaaaaaa", true}, {"aaaaaaaaaaaa", "aaaaaaaaaaab", false}, {"", "", false}, {"aaaa", "aaaaaaaaaaaa", false}, } { if SameHead(c.a, c.b) != c.same { t.Errorf("SameHead(%q, %q) is %v", c.a, c.b, !c.same) } } }