package build import ( "encoding/json" "sort" "strings" "testing" "time" occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" ) const fp2 = "src2:2222222222222222222222222222222222222222222222222222222222222222" func stateOf(vals map[string][]byte) StateRead { return StateRead{ Keys: func() ([]string, error) { var ks []string for k := range vals { ks = append(ks, k) } sort.Strings(ks) return ks, nil }, Get: func(k string) (json.RawMessage, time.Time, error) { return vals[k], time.Time{}, nil }} } // Design 47 G §589: builder_build by module answers its keys newest first with whole fingerprints, event-builds and the open // ask, and names the watched branches whose newest entry names a key's fingerprint; a module none of whose keys the newest // entry names says so; with a fingerprint, that key alone. func TestBuilderBuildAnswersAModulesKeysWhole(t *testing.T) { failed, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildFailed, EventBuilds: 3, Manifest: mdigest('a'), Error: "transport fault: connection, node-build-go ace, dial tcp: connection refused"}) done, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildDone, Manifest: mdigest('a'), Artifacts: []builds.BuiltArtifact{{Name: "x", Kind: "file", Digest: "sha256:" + strings.Repeat("a", 64)}}}) k1, _ := builds.BuilderBuildKey("m", fp1) k2, _ := builds.BuilderBuildKey("m", fp2) other, _ := builds.BuilderBuildKey("other", fp1) vals := map[string][]byte{k1: failed, k2: done, other: done} ask := occ.Kept{Ask: oc.Ask{ID: "retake-1", About: k1, Expires: occ.FormatTime(time.Now().Add(time.Hour))}, Asked: time.Now()} askRaw, _ := json.Marshal(ask) r := &BuildReader{Builds: stateOf(vals), Asked: stateOf(map[string][]byte{"ask.retake-1": askRaw}), Newest: func(string) (map[string]string, error) { return map[string]string{"main": fp1, "feature": fp2}, nil }} a, err := r.Build("m", "") if err != nil || len(a.Builds) != 2 { t.Fatalf("builds = %+v, %v, want the module's two keys", a, err) } var row BuildRow for _, b := range a.Builds { if b.Fingerprint == fp1 { row = b } } if row.Fingerprint != fp1 || len(row.Fingerprint) != len("src2:")+64 || row.State != builds.BuildFailed || row.EventBuilds != 3 || row.Node != "ace" || !strings.HasPrefix(row.Error, "transport fault: connection, node-build-go ace, dial tcp") || row.Ask == nil || row.Ask.ID != "retake-1" || len(row.Newest) != 1 || row.Newest[0] != "main" { t.Errorf("the failed key = %+v, want its fingerprint whole, its error whole, event-builds 3, the open ask and newest main", row) } if one, err := r.Build("m", fp2); err != nil || len(one.Builds) != 1 || one.Builds[0].Fingerprint != fp2 || one.Builds[0].Newest[0] != "feature" { t.Errorf("one key = %+v, %v", one, err) } r.Newest = func(string) (map[string]string, error) { return map[string]string{"main": "src2:" + strings.Repeat("c", 64)}, nil } if n, err := r.Build("m", ""); err != nil || !strings.Contains(n.Note, "no build key of m is the newest entry's") || !strings.Contains(n.Note, "main names src2:"+strings.Repeat("c", 64)) { t.Errorf("a module none of whose keys the newest entry names: %+v, %v", n, err) } } // Design 47 G §589: builder_stuck answers each key's fingerprint whole, as the build-input fingerprint the catalog graph entry carries it. func TestBuilderStuckAnswersTheFingerprintWhole(t *testing.T) { building, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildBuilding, Step: "asked", Manifest: mdigest('a')}) k, _ := builds.BuilderBuildKey("m", fp1) out, err := StuckReader{Builds: stateOf(map[string][]byte{k: building})}.Stuck("m") if err != nil { t.Fatal(err) } rows := out["stuck"].([]Stuck) if len(rows) != 1 || rows[0].FP != fp1 { t.Fatalf("stuck = %+v, want the fingerprint %s whole", rows, fp1) } }