package view import ( "bytes" "net/http" "net/http/httptest" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/delivery" ) const ( hA = "0123456789abcdef0123456789abcdef01234567" hB = "89abcdef0123456789abcdef0123456789abcdef" fF = "src1:1111111111111111111111111111111111111111111111111111111111111111" fG = "src1:2222222222222222222222222222222222222222222222222222222222222222" ) func candidate(t *testing.T, group string, pulls ...delivery.CandidatePull) Entry { t.Helper() heads := make([]delivery.Head, len(pulls)) for i, p := range pulls { heads[i] = p.Head } hash, err := delivery.HeadsHash(heads) if err != nil { t.Fatal(err) } b, err := delivery.EncodeCandidate(delivery.Candidate{Group: group, HeadsHash: hash, Pulls: pulls}) if err != nil { t.Fatal(err) } return Entry{Bucket: delivery.CandidatesBucket, Key: group, Value: b, At: t0} } func pullOf(repo string, n int, head string, modules ...string) delivery.CandidatePull { if modules == nil { modules = []string{} } return delivery.CandidatePull{Head: delivery.Head{Repository: repo, Number: n, Head: head}, Modules: modules} } func modEntry(t *testing.T, name string, m delivery.Module) Entry { t.Helper() b, err := delivery.EncodeModule(m) if err != nil { t.Fatal(err) } return Entry{Bucket: delivery.ModulesBucket, Key: name, Value: b, At: t0} } func fpRow(t *testing.T, s Snapshot, module string) FingerprintRow { t.Helper() for _, f := range s.Fingerprints { if f.Module == module { return f } } t.Fatalf("no fingerprint row for %s in %+v", module, s.Fingerprints) return FingerprintRow{} } func TestSnapshotListsTheCandidateGroups(t *testing.T) { // 1241/AC1 m := New() fill(m, candidate(t, "feat/x", pullOf("novox/mesh-delivery", 12, hA, "a", "b"), pullOf("novox/mesh-catalog", 300, hB, "c")), candidate(t, "feat/y", pullOf("novox/mesh-delivery", 13, hB))) g := m.Snapshot().Groups if len(g) != 2 || g[0].Group != "feat/x" || g[1].Group != "feat/y" { t.Fatalf("groups = %+v", g) } // sorted by repository: mesh-catalog before mesh-delivery if len(g[0].Pulls) != 2 || g[0].Pulls[0].Repository != "novox/mesh-catalog" || g[0].Pulls[0].Number != 300 { t.Fatalf("pulls = %+v", g[0].Pulls) } p := g[0].Pulls[1] if p.Repository != "novox/mesh-delivery" || p.Number != 12 || p.Head != hA[:12] || strings.Join(p.Modules, ",") != "a,b" { t.Errorf("pull = %+v, want #12 with head %s and modules a,b", p, hA[:12]) } if len(g[1].Pulls) != 1 || len(g[1].Pulls[0].Modules) != 0 { t.Errorf("feat/y = %+v", g[1]) } m.Apply(Entry{Bucket: delivery.CandidatesBucket, Key: "feat/x", Deleted: true}) if g := m.Snapshot().Groups; len(g) != 1 || g[0].Group != "feat/y" { t.Errorf("after the delete: %+v", g) } } // 1955/L7 (ADR 0571 ยง1): the view reads no build record of the controller's: a module with no fingerprint of the new // form is said so, never compared with the controller's builds. func TestAModuleOfTheOldFormIsComparedWithNoBuild(t *testing.T) { m := New() fill(m, modEntry(t, "a", delivery.Module{FP: fF, Repository: "novox/mesh-delivery", Commit: hA}), modEntry(t, "b", delivery.Module{None: "an artifact compiles a Go program from a build source that git trees do not pin: no fingerprint before release 4", Repository: "novox/mesh-delivery", Commit: hA})) s := m.Snapshot() for _, name := range []string{"a", "b"} { if r := fpRow(t, s, name); r.State != FPNone || !(strings.Contains(r.Reason, "new form") || strings.Contains(r.Reason, "release 4")) || r.Build != "" { t.Errorf("%s = %+v, want none: no build of the builder's is compared", name, r) } } } func shown(t *testing.T) *Model { m := New() fill(m, candidate(t, "feat/x", pullOf("novox/mesh-delivery", 12, hA, "a"), pullOf("novox/mesh-catalog", 300, hB, "c")), modEntry(t, "a", delivery.Module{FP2: fp2A, Repository: "novox/mesh-delivery", Commit: hA}), builderKey(t, "a", fp2A, delivery.BuilderBuild{State: delivery.BuildFailed, Error: "the compile failed"}), modEntry(t, "b", delivery.Module{None: "no tree", Repository: "novox/mesh-delivery", Commit: hA})) return m } func TestTableAndPagePrintTheGroupsAndTheComparison(t *testing.T) { // 1241/AC6 m := shown(t) var out bytes.Buffer Table(&out, m.Snapshot()) for _, want := range []string{"CANDIDATES", "feat/x", "novox/mesh-delivery#12", hA[:12], "novox/mesh-catalog#300", "FINGERPRINT", "the compile failed", fp2A, "no tree"} { if !strings.Contains(out.String(), want) { t.Errorf("the table lacks %q:\n%s", want, out.String()) } } rec := httptest.NewRecorder() Web(m).ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil)) for _, want := range []string{"CANDIDATES", "feat/x", "novox/mesh-delivery#12", hA[:12], "FINGERPRINTS", "the compile failed", fp2A, "no tree"} { if !strings.Contains(rec.Body.String(), want) { t.Errorf("the page lacks %q:\n%s", want, rec.Body.String()) } } } func TestUnreadableIndexerValuesAreNamed(t *testing.T) { // never dropped silently m := New() fill(m, Entry{Bucket: delivery.CandidatesBucket, Key: "feat/x", Value: []byte("{"), At: t0}, Entry{Bucket: delivery.ModulesBucket, Key: "a", Value: []byte("{"), At: t0}) s := m.Snapshot() if len(s.Unreadable) != 2 || len(s.Groups) != 0 || len(s.Fingerprints) != 0 { t.Errorf("snapshot = %+v", s) } }