package builderkeys import ( "errors" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/delivery" ) const fp = "src2:" + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" func moduleValue(t *testing.T, commit, fp2 string) []byte { t.Helper() raw, err := delivery.EncodeModule(delivery.Module{FP: "src1:" + strings.Repeat("a", 64), FP2: fp2, Manifest: strings.Repeat("b", 64), Repository: "novox/mesh-catalog", Commit: commit}) if err != nil { t.Fatal(err) } return raw } // A plan's module is the indexer's value written for the merge the plan carries, not a later merge's (ADR 0501 §2). func TestPickAtIsTheNewestValueOfTheCommit(t *testing.T) { other := "src2:" + strings.Repeat("c", 64) values := [][]byte{ moduleValue(t, "1111111111", other), moduleValue(t, "2222222222", other), moduleValue(t, "2222222222", fp), // the same merge, computed again when a toolchain appeared moduleValue(t, "3333333333", other), } m, err := pickAt("x", "2222222222", values) if err != nil { t.Fatal(err) } if m.FP2 != fp { t.Fatalf("FP2 at 2222222222 is %s, want the newest of that commit %s", m.FP2, fp) } // An abbreviated commit names the same one. if m, err := pickAt("x", "2222222", values); err != nil || m.FP2 != fp { t.Fatalf("an abbreviated commit: %v %v", m.FP2, err) } // No commit is the newest value. if m, err := pickAt("x", "", values); err != nil || m.Commit != "3333333333" { t.Fatalf("the newest: %v %v", m.Commit, err) } } func TestPickAtSaysNoValueOfACommitNotWritten(t *testing.T) { _, err := pickAt("x", "4444444444", [][]byte{moduleValue(t, "1111111111", fp), []byte("{not json")}) if !errors.Is(err, ErrNoValue) { t.Fatalf("want ErrNoValue, got %v", err) } if !strings.Contains(err.Error(), "x at 4444444444") || !strings.Contains(err.Error(), "not read") { t.Fatalf("the words name neither the module and commit nor the unread value: %v", err) } } // A done key with references is delivered from; a done key with an artifact without one is waited for, said // (ADR 0498 §8); a failed key says the builder's own words. func TestAKeySaysWhatItIs(t *testing.T) { missing := Key{Module: "x", Fingerprint: fp} if missing.Done() || missing.Failed() || !strings.Contains(missing.Says(), "no build of x") { t.Fatalf("a missing key: %q", missing.Says()) } done := Key{Module: "x", Fingerprint: fp, Found: true, Build: delivery.BuilderBuild{State: delivery.BuildDone, Artifacts: []delivery.BuiltArtifact{ {Name: "a", Digest: "sha256:1", Reference: "artifact-store://x/a/blobs/sha256:1"}, {Name: "img", Kind: "image", Digest: "sha256:2"}, }}} if !done.Done() || len(done.Unreferenced()) != 1 || done.Unreferenced()[0] != "img" { t.Fatalf("unreferenced: %v", done.Unreferenced()) } if !strings.Contains(done.Says(), "waits for the reference of img") { t.Fatalf("a done key without a reference: %q", done.Says()) } failed := Key{Module: "x", Fingerprint: fp, Found: true, Build: delivery.BuilderBuild{State: delivery.BuildFailed, Error: "digests differ: ace sha256:1, g14 sha256:2\nmore"}} if !failed.Failed() || !strings.HasSuffix(failed.Says(), "failed: digests differ: ace sha256:1, g14 sha256:2") { t.Fatalf("a failed key: %q", failed.Says()) } building := Key{Module: "x", Fingerprint: fp, Found: true, Build: delivery.BuilderBuild{State: delivery.BuildBuilding, By: "ace"}} if building.Done() || !strings.Contains(building.Says(), "building on ace") { t.Fatalf("a building key: %q", building.Says()) } }