Merge pull request 'Give the build record's layout to readers outside the controller (issue 1223)' (#38) from fix/1223-build-record-layout into main
This commit was merged in pull request #38.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package delivery
|
||||
|
||||
import "time"
|
||||
|
||||
// BuildRecord is the layout mesh-controller internal/chain/records.go Build writes (line 91), the fields a reader outside
|
||||
// the controller reads (novox/hq ADR 0437 §4 §5, issue 1223). The controller's record carries more; a decode ignores
|
||||
// what is not here. SourceInputs has no json keys of its own: it is written under its Go field names, as the controller
|
||||
// writes it.
|
||||
type BuildRecord struct {
|
||||
ID string `json:"id"`
|
||||
State string `json:"state,omitempty"`
|
||||
Repository string `json:"repository"`
|
||||
Ref string `json:"ref,omitempty"`
|
||||
Module string `json:"module,omitempty"`
|
||||
Commit string `json:"commit,omitempty"`
|
||||
At time.Time `json:"at,omitzero"`
|
||||
SourceFingerprint string `json:"source-fingerprint,omitempty"`
|
||||
SourceInputs *SourceInputs `json:"source-inputs,omitempty"`
|
||||
}
|
||||
|
||||
// BuildsBucket is the bucket the builds are kept in: mesh-controller internal/broker/controller_buckets.go:101,
|
||||
// BucketName(ControllerSeat, ChainBuilds), with ControllerSeat "mesh-controller" (internal/broker/streams.go:359) and
|
||||
// ChainBuilds "builds" (controller_buckets.go:113).
|
||||
const BuildsBucket = "mesh-controller_builds"
|
||||
|
||||
// BuildKey is a build's record under its module, a build that knew none under the request's key: copied from
|
||||
// mesh-controller internal/chain/keys.go:35-40 (BuildKey, with RequestKey at line 42).
|
||||
func BuildKey(module, id string) string {
|
||||
if module == "" {
|
||||
return "req." + id
|
||||
}
|
||||
return module + ".build." + id
|
||||
}
|
||||
|
||||
// NewestKey is the key of a module's newest build, of any state: copied from mesh-controller internal/chain/keys.go:44.
|
||||
// The key holds no record: its value is the newest build's id as raw bytes (internal/inventory/chain_builds.go:210 and
|
||||
// :546), and the record lives at BuildKey(module, id). The pointer is a hint, checked against that record.
|
||||
func NewestKey(module string) string { return module + ".newest" }
|
||||
@@ -0,0 +1,86 @@
|
||||
package delivery
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The fixture is a record the controller's own encoder wrote (json.Marshal of a chain.Build, mesh-controller
|
||||
// internal/chain, a throwaway test run once and deleted) with build-agent's build-1792395447088936520 values, plus a
|
||||
// manifest-digest and one made artifact, which a BuildRecord does not carry.
|
||||
func loadBuildFixture(t *testing.T) []byte {
|
||||
t.Helper()
|
||||
raw, err := os.ReadFile("testdata/build-record-build-agent.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
func TestBuildRecordDecodes(t *testing.T) { // 1223/AC1
|
||||
var r BuildRecord
|
||||
if err := json.Unmarshal(loadBuildFixture(t), &r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, c := range []struct{ name, got, want string }{
|
||||
{"id", r.ID, "build-1792395447088936520"},
|
||||
{"module", r.Module, "build-agent"},
|
||||
{"repository", r.Repository, "novox/mesh-controller"},
|
||||
{"ref", r.Ref, "main"},
|
||||
{"commit", r.Commit, "7a74cee83f88e6585a5511c3cc53bdf0f5303d20"},
|
||||
{"state", r.State, "built"},
|
||||
{"source-fingerprint", r.SourceFingerprint, "src1:e846efe73716b78e80860baaac96153de2cb76551325753838ca245d2160a3d7"},
|
||||
} {
|
||||
if c.got != c.want {
|
||||
t.Errorf("%s = %q, want %q", c.name, c.got, c.want)
|
||||
}
|
||||
}
|
||||
if want := time.Date(2026, 10, 19, 9, 38, 0, 0, time.UTC); !r.At.Equal(want) {
|
||||
t.Errorf("at = %v, want %v", r.At, want)
|
||||
}
|
||||
if r.SourceInputs == nil {
|
||||
t.Fatal("source-inputs missing")
|
||||
}
|
||||
fp, none := SourceFingerprint(*r.SourceInputs)
|
||||
if none != "" || fp != r.SourceFingerprint {
|
||||
t.Errorf("SourceFingerprint of the decoded inputs = %q (none %q), the record says %q", fp, none, r.SourceFingerprint)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildRecordWithoutInputs(t *testing.T) { // 1223/AC2
|
||||
var m map[string]json.RawMessage
|
||||
if err := json.Unmarshal(loadBuildFixture(t), &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
delete(m, "source-inputs")
|
||||
raw, _ := json.Marshal(m)
|
||||
var r BuildRecord
|
||||
if err := json.Unmarshal(raw, &r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if r.SourceInputs != nil {
|
||||
t.Errorf("source-inputs = %+v, want nil", r.SourceInputs)
|
||||
}
|
||||
if r.Module != "build-agent" {
|
||||
t.Errorf("module = %q, want build-agent", r.Module)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildKeys(t *testing.T) { // 1223/AC3
|
||||
// Literal values of mesh-controller internal/broker/controller_buckets.go:101 (BucketName(ControllerSeat, ChainBuilds)
|
||||
// is "mesh-controller_builds") and internal/chain/keys.go:35-44.
|
||||
if BuildsBucket != "mesh-controller_builds" {
|
||||
t.Errorf("BuildsBucket = %q", BuildsBucket)
|
||||
}
|
||||
if got := BuildKey("build-agent", "build-1"); got != "build-agent.build.build-1" {
|
||||
t.Errorf("BuildKey = %q", got)
|
||||
}
|
||||
if got := BuildKey("", "build-1"); got != "req.build-1" {
|
||||
t.Errorf("BuildKey without a module = %q", got)
|
||||
}
|
||||
if got := NewestKey("build-agent"); got != "build-agent.newest" {
|
||||
t.Errorf("NewestKey = %q", got)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"build-1792395447088936520","state":"built","repository":"novox/mesh-controller","ref":"main","module":"build-agent","commit":"7a74cee83f88e6585a5511c3cc53bdf0f5303d20","manifest-digest":"sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef","source-fingerprint":"src1:e846efe73716b78e80860baaac96153de2cb76551325753838ca245d2160a3d7","source-inputs":{"Module":"build-agent","Tree":"11c0b4f90cae0d6e4ef9cc48cbfdf9f6dbe52bca","Bases":["sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc","sha256:8ac98ca534ac3f51e1f420a1dd2c15e74c75cfa0f23f3ad27eb5d7236c349a0c"],"Contexts":{"server":"narrow:d51ca744fd11af59d616c858f76c27b3e58e16e11fbdc0c720eb9d7d19d55fac"},"Toolchains":null,"Unpinned":""},"made":[{"name":"server","kind":"image","reference":"registry.example/build-agent@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc"}],"at":"2026-10-19T09:38:00Z"}
|
||||
Reference in New Issue
Block a user