Files
mesh-sdk/go/declaration/process_test.go
T
jschoubben 3218da4ee4 J3: mesh-sdk within its test budget, each file of declaration and the provider harness one test of subtests
The unit test functions fall from 587 to 476 (the budget is 500): the cases of each of twenty test files in
declaration and provider/harness become subtests of one test named for the file, under their own names, their bodies
unchanged. Integration tests stay at 30 (budget 50).

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
2026-11-04 14:28:23 +01:00

197 lines
7.6 KiB
Go

package declaration
import (
"strings"
"testing"
)
func aProcess() *Process {
return &Process{
ID: "server", Type: TypeProcess, Name: "greeter",
Source: "https://store.invalid/greeter/daemon",
Digest: "sha256:" + strings.Repeat("a", 64),
Run: []string{"node", "index.js"},
}
}
// A process is part of the vocabulary, or a declaration carrying one is refused whole.
func testAProcessIsSomethingTheHostSpeaks(t *testing.T) {
var found bool
for _, kind := range Vocabulary() {
if kind == TypeProcess {
found = true
}
}
if !found {
t.Fatal("a process cannot be declared, so a module that declares one is refused")
}
if newOf(TypeProcess) == nil {
t.Fatal("the decoder has no daemon, so one would be refused as an unknown kind")
}
}
// **Pinned by digest, like everything else that crosses a network.** A bundle fetched by a
// reference somebody can repoint is not pinned, and it is the one thing on a machine that would
// then be running code nobody reviewed.
func testAProcesssBundleMustBePinned(t *testing.T) {
for _, bad := range []string{"", "latest", "sha256:short", strings.Repeat("a", 64)} {
d := aProcess()
d.Digest = bad
if problems := d.validate("a process", false); len(problems) == 0 {
t.Fatalf("a process pinned by %q was accepted", bad)
}
}
}
// What to run is named, never inferred. Guessing an entrypoint from which files are present makes
// a process change what it runs when somebody adds a file.
func testAProcessMustSayWhatToRun(t *testing.T) {
d := aProcess()
d.Run = nil
if problems := d.validate("a process", false); len(problems) == 0 {
t.Fatal("a process with no command was accepted")
}
}
// Its name becomes a unit name and a path, so a separator in it would write somewhere nobody meant.
func testAProcesssNameCannotEscapeItsUnit(t *testing.T) {
// "." and ".." are one path element each, and the mesh's own bundle directory and its parent:
// removing a process named ".." would delete every bundle the mesh has, and more (novox/hq ADR
// 0118). A leading dash is an option to the service manager, not a unit.
for _, bad := range []string{"", "../escape", "two words", "a/b", ".", "..", "-", "--now"} {
d := aProcess()
d.Name = bad
if problems := d.validate("a process", false); len(problems) == 0 {
t.Fatalf("a process called %q was accepted", bad)
}
}
}
// And a well-formed one is accepted, or the tests above prove only that everything is refused.
func testAWellFormedDaemonIsAccepted(t *testing.T) {
if problems := aProcess().validate("a process", false); len(problems) != 0 {
t.Fatalf("a well-formed daemon was refused: %v", problems)
}
}
// **The modes are exclusive, and saying so is the point of having one kind.** Something that runs
// once does not run on a schedule; something not running between fires cannot be restarted when a
// file changes. A container's modes carry the same rule, and this is the same rule because it is
// the same thing hosted differently.
func testTheModesAreExclusive(t *testing.T) {
both := aProcess()
both.RunOnce = true
both.Schedule = "0 3 * * *"
if problems := both.validate("a process", false); len(problems) == 0 {
t.Fatal("a process that runs once and on a schedule was accepted")
}
watching := aProcess()
watching.Schedule = "0 3 * * *"
watching.RestartOn = []string{"some-file"}
if problems := watching.validate("a process", false); len(problems) == 0 {
t.Fatal("a scheduled process was given something to restart on, and it is never running")
}
// A process yields only while it stays up, at a priority the host knows, within the machine (issue 1806).
for name, bad := range map[string]func(*Process){
"a step that yields": func(p *Process) { p.RunOnce = true; p.Yields = &Yields{Priority: YieldIdle} },
"an unknown priority": func(p *Process) { p.Yields = &Yields{Priority: "low"} },
"a share over the whole": func(p *Process) { p.Yields = &Yields{CPUShare: 150} },
"a yield saying nothing": func(p *Process) { p.Yields = &Yields{} },
} {
p := aProcess()
bad(p)
if problems := p.validate("a process", false); len(problems) == 0 {
t.Errorf("%s was accepted", name)
}
}
}
// A cadence that is not a cadence is refused near its author, rather than by a machine at the far
// end of a declaration.
func testAScheduleMustBeACadence(t *testing.T) {
for _, bad := range []string{"often", "0 3 * *", "99 3 * * *"} {
p := aProcess()
p.Schedule = bad
if problems := p.validate("a process", false); len(problems) == 0 {
t.Fatalf("a process scheduled %q was accepted", bad)
}
}
}
// And each mode on its own is accepted, or the tests above prove only that everything is refused.
func testEachModeOnItsOwnIsAccepted(t *testing.T) {
once := aProcess()
once.RunOnce = true
if problems := once.validate("a process", false); len(problems) != 0 {
t.Fatalf("a step was refused: %v", problems)
}
every := aProcess()
every.Schedule = "0 3 * * *"
if problems := every.validate("a process", false); len(problems) != 0 {
t.Fatalf("a scheduled process was refused: %v", problems)
}
yielding := aProcess()
yielding.Yields = &Yields{Priority: YieldIdle, CPUShare: 50}
if problems := yielding.validate("a process", false); len(problems) != 0 {
t.Fatalf("a daemon yielding at idle under half the machine was refused: %v", problems)
}
}
// **The one that cannot be escaped, only refused.**
//
// Everything else a unit file reinterprets can be escaped: a percent specifier doubled, whitespace
// quoted, a quote backslashed. A newline cannot — it ends the line, and what follows is read as a
// unit DIRECTIVE. A value carrying one could write ExecStart= and have the machine run something
// nobody declared.
//
// So it is refused here, near whoever wrote it, rather than rendered into a unit at the far end of
// a declaration.
func testAnEnvironmentValueCannotCarryALineBreak(t *testing.T) {
for _, bad := range []string{
"safe\nExecStart=/usr/bin/whatever",
"carriage\rreturn",
} {
p := aProcess()
p.Env = map[string]string{"X": bad}
problems := p.validate("a process", false)
if len(problems) == 0 {
t.Fatalf("a value containing %q was accepted", bad)
}
var said bool
for _, problem := range problems {
if strings.Contains(problem, "line break") {
said = true
}
}
if !said {
t.Fatalf("refused for some other reason, which would stop being true: %v", problems)
}
}
}
// And ordinary awkward values are accepted, because escaping is what handles those — refusing them
// too would make a module unable to hold a generated password.
func testOrdinaryAwkwardValuesAreAccepted(t *testing.T) {
p := aProcess()
p.Env = map[string]string{"PASSWORD": `a%H b"c\d`}
if problems := p.validate("a process", false); len(problems) != 0 {
t.Fatalf("a password containing the characters passwords contain was refused: %v", problems)
}
}
// TestProcess holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestProcess(t *testing.T) {
t.Run("AProcessIsSomethingTheHostSpeaks", testAProcessIsSomethingTheHostSpeaks)
t.Run("AProcesssBundleMustBePinned", testAProcesssBundleMustBePinned)
t.Run("AProcessMustSayWhatToRun", testAProcessMustSayWhatToRun)
t.Run("AProcesssNameCannotEscapeItsUnit", testAProcesssNameCannotEscapeItsUnit)
t.Run("AWellFormedDaemonIsAccepted", testAWellFormedDaemonIsAccepted)
t.Run("TheModesAreExclusive", testTheModesAreExclusive)
t.Run("AScheduleMustBeACadence", testAScheduleMustBeACadence)
t.Run("EachModeOnItsOwnIsAccepted", testEachModeOnItsOwnIsAccepted)
t.Run("AnEnvironmentValueCannotCarryALineBreak", testAnEnvironmentValueCannotCarryALineBreak)
t.Run("OrdinaryAwkwardValuesAreAccepted", testOrdinaryAwkwardValuesAreAccepted)
}