LogEnded copied the outcome, manifest, bases, artifacts and imports of the build's key but not its error or step, and the log entry had no field for them: a failed build read back as only "failed". Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
69 lines
3.1 KiB
Go
69 lines
3.1 KiB
Go
package builds
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTheBuildersLogKeepsAStartAndAnEndAndTheirDuration(t *testing.T) {
|
|
// ADR 0571 clause 1: the builder's log, a start and an end, and the duration between them.
|
|
at := time.Date(2026, 10, 29, 22, 0, 0, 0, time.UTC)
|
|
start := BuildLogEntry{Event: BuildStartedEvent, Module: "letta", FP: "src2:a", Source: "abc", Repository: "novox/mesh-catalog",
|
|
Directory: "modules/letta", Commit: "abc123", Node: "ace", At: at}
|
|
end := start
|
|
end.Event, end.At, end.Outcome, end.Manifest, end.Against = BuildEndedEvent, at.Add(3*time.Minute), "done", "sha256:m", []string{"artifact-store://base/image@sha256:b"}
|
|
end.Made = []BuiltArtifact{{Name: "image", Kind: "image", Digest: "sha256:1", Reference: "artifact-store://letta/image@sha256:1"}}
|
|
failed := end
|
|
failed.Outcome, failed.Made, failed.Error, failed.Step = BuildFailed, nil, "go test: TestX failed", "test"
|
|
for _, e := range []BuildLogEntry{start, end, failed} {
|
|
raw, err := EncodeBuildLogEntry(e)
|
|
back, derr := DecodeBuildLogEntry(raw)
|
|
if err != nil || derr != nil || back.Event != e.Event || back.Outcome != e.Outcome || back.Directory != "modules/letta" ||
|
|
back.Repository != "novox/mesh-catalog" || back.Commit != "abc123" || back.Error != e.Error || back.Step != e.Step {
|
|
t.Errorf("%s read back as %+v, %v %v", e.Event, back, err, derr)
|
|
}
|
|
}
|
|
if d, ok := BuildDuration(start, end); !ok || d != 3*time.Minute {
|
|
t.Errorf("the build took %s, %v", d, ok)
|
|
}
|
|
older := end
|
|
older.At, older.FP = at.Add(-time.Hour), "src2:b"
|
|
other := end
|
|
other.Module = "mesh-catalog"
|
|
if n := NewestPerModule([]BuildLogEntry{older, end, other}); n["letta"].FP != "src2:a" || len(n) != 2 {
|
|
t.Errorf("each module's newest is %v", n)
|
|
}
|
|
if e := EndedSince([]BuildLogEntry{end, start, older}, at.Add(-2*time.Hour)); len(e) != 2 || e[0].FP != "src2:b" {
|
|
t.Errorf("the ended builds since are %v", e)
|
|
}
|
|
if k, err := BuildLogKey("letta"); k != "letta" || err != nil || BuildLogRead != "mesh-delivery-builder.build-log" {
|
|
t.Errorf("the key is %q, %v", k, err)
|
|
}
|
|
if _, err := BuildLogKey("a.b"); err == nil {
|
|
t.Error("a module with a dot was taken as a key")
|
|
}
|
|
for _, edit := range []func(*BuildLogEntry){func(e *BuildLogEntry) { e.Outcome = "" }, func(e *BuildLogEntry) { e.Commit = "" },
|
|
func(e *BuildLogEntry) { e.Event, e.Outcome, e.Against = BuildStartedEvent, "", nil },
|
|
func(e *BuildLogEntry) {
|
|
e.Event, e.Outcome, e.Against, e.Made, e.Manifest, e.Error = BuildStartedEvent, "", nil, nil, "", "x"
|
|
},
|
|
func(e *BuildLogEntry) {
|
|
e.Event, e.Outcome, e.Against, e.Made, e.Manifest, e.Node, e.Line, e.Step = BuildSaidEvent, "", nil, nil, "", "", "asked", "test"
|
|
}} {
|
|
bad := end
|
|
edit(&bad)
|
|
if _, err := EncodeBuildLogEntry(bad); err == nil {
|
|
t.Errorf("%+v was encoded", bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOnlyABuildsStartOrEndIsABuildEntry(t *testing.T) {
|
|
for entry, want := range map[string]bool{`{"event":"build.started"}`: true, `{"event":"build.ended"}`: true, `{"event":"build.said"}`: false,
|
|
`not json`: true, `{}`: true} {
|
|
if got := IsBuildEntry([]byte(entry)); got != want {
|
|
t.Errorf("IsBuildEntry(%s) = %v", entry, got)
|
|
}
|
|
}
|
|
}
|