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) } }