Builds: design 47 G §262, §245, §440, §447 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
71 lines
3.1 KiB
Go
71 lines
3.1 KiB
Go
package processbuilds
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/declaration"
|
|
)
|
|
|
|
// Design 47, *The fingerprint handover*: the build of a daemon is read from its running process's environment and of a
|
|
// container from its configuration, narrowed by module; one started without the value, one not running and one the
|
|
// runtime cannot read each say why their build is unknown, never a guessed fingerprint.
|
|
func TestProcessBuildsAreReadFromTheRunningProcesses(t *testing.T) {
|
|
fp := "src2:" + strings.Repeat("a", 64)
|
|
d := &declaration.Declaration{Resources: []declaration.Resource{
|
|
&declaration.Process{ID: "web.d", Type: declaration.TypeProcess, Module: "web", Name: "web-d"},
|
|
&declaration.Process{ID: "old.d", Type: declaration.TypeProcess, Module: "old", Name: "old-d"},
|
|
&declaration.Process{ID: "down.d", Type: declaration.TypeProcess, Module: "down", Name: "down-d"},
|
|
&declaration.Container{ID: "db.c", Type: declaration.TypeContainer, Module: "db", Name: "db-c"},
|
|
&declaration.Container{ID: "gone.c", Type: declaration.TypeContainer, Module: "gone", Name: "gone-c"},
|
|
&declaration.Directory{ID: "web.dir", Type: declaration.TypeDirectory, Module: "web"},
|
|
}}
|
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
|
switch {
|
|
case name == "systemctl" && args[len(args)-1] == "web-d.service":
|
|
return "MainPID=11\nActiveEnterTimestamp=Mon 2026-11-09 10:00:00 UTC\n", nil
|
|
case name == "systemctl" && args[len(args)-1] == "old-d.service":
|
|
return "MainPID=12\nActiveEnterTimestamp=\n", nil
|
|
case name == "systemctl":
|
|
return "MainPID=0\nActiveEnterTimestamp=\n", nil
|
|
case name == "docker" && args[len(args)-1] == "db-c":
|
|
return `["A=1","MESH_FINGERPRINT=` + fp + `"]` + "\t2026-11-09T10:00:00.5Z\n", nil
|
|
}
|
|
return "", errors.New("no such container")
|
|
}
|
|
environ := func(pid int) ([]byte, error) {
|
|
if pid == 11 {
|
|
return []byte("A=1\x00MESH_FINGERPRINT=" + fp + "\x00"), nil
|
|
}
|
|
return []byte("A=1\x00"), nil
|
|
}
|
|
r := Reader{Node: "n1", Run: run, Environ: environ}
|
|
got := r.Read(context.Background(), d, "")
|
|
by := map[string]string{}
|
|
for _, p := range got.Processes {
|
|
by[p.Module] = p.Fingerprint + "|" + p.Unknown
|
|
}
|
|
want := map[string]string{"web": fp + "|", "db": fp + "|",
|
|
"old": "|started before the node-engine handed MESH_FINGERPRINT, or without it",
|
|
"down": "|the unit runs no process now", "gone": "|the container cannot be read: no such container"}
|
|
if len(by) != len(want) || got.Node != "n1" {
|
|
t.Fatalf("read %v, want %v", by, want)
|
|
}
|
|
for m, w := range want {
|
|
if by[m] != w {
|
|
t.Errorf("%s: %q, want %q", m, by[m], w)
|
|
}
|
|
}
|
|
if got.Processes[0].Module != "db" || got.Processes[len(got.Processes)-1].Module != "web" || got.Processes[len(got.Processes)-1].Started == nil {
|
|
t.Errorf("order or start time wrong: %+v", got.Processes)
|
|
}
|
|
if one := r.Read(context.Background(), d, "web"); len(one.Processes) != 1 || one.Processes[0].Process != "web-d.service" {
|
|
t.Errorf("narrowed by module: %+v", one.Processes)
|
|
}
|
|
if none := r.Read(context.Background(), nil, ""); none.Error == "" || none.Processes == nil {
|
|
t.Errorf("no declaration: %+v", none)
|
|
}
|
|
}
|