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
This commit is contained in:
2026-11-04 14:28:23 +01:00
parent 635aed57fd
commit 3218da4ee4
20 changed files with 342 additions and 131 deletions
+24 -10
View File
@@ -16,7 +16,7 @@ const adoptedResources = `"resources":[
const sixtyFour = "0000000000000000000000000000000000000000000000000000000000000000"
func TestAnAdoptionIsReadWithTheDeclaration(t *testing.T) {
func testAnAdoptionIsReadWithTheDeclaration(t *testing.T) {
d, err := Parse([]byte(`{"adoption":{"taken":["postgres"],"untaken":{"hello-web":["hello-web.page","hello-web.server"]}},
"declaration":1,` + adoptedResources + `}`))
if err != nil {
@@ -36,7 +36,7 @@ func TestAnAdoptionIsReadWithTheDeclaration(t *testing.T) {
}
}
func TestADeclarationWithNoAdoptionIsConverged(t *testing.T) {
func testADeclarationWithNoAdoptionIsConverged(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,` + adoptedResources + `}`))
if err != nil {
t.Fatal(err)
@@ -49,7 +49,7 @@ func TestADeclarationWithNoAdoptionIsConverged(t *testing.T) {
}
}
func TestAnAdoptionNamingAnUnknownIDIsRefused(t *testing.T) {
func testAnAdoptionNamingAnUnknownIDIsRefused(t *testing.T) {
refusal := refusalFor(t, `{"adoption":{"taken":[],"untaken":{"hello-web":["hello-web.missing"]}},
"declaration":1,`+adoptedResources+`}`)
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "hello-web.missing") {
@@ -57,7 +57,7 @@ func TestAnAdoptionNamingAnUnknownIDIsRefused(t *testing.T) {
}
}
func TestAnAdoptionMayNameAResourceOfAnyKind(t *testing.T) {
func testAnAdoptionMayNameAResourceOfAnyKind(t *testing.T) {
// A directory, a service or an action can reach what was found as surely as a file can, so
// the controller lists every resource of an untaken module (novox/hq ADR 0103).
d, err := Parse([]byte(`{"adoption":{"taken":[],"untaken":{"hello-web":["hello-web.data"]}},
@@ -70,7 +70,7 @@ func TestAnAdoptionMayNameAResourceOfAnyKind(t *testing.T) {
}
}
func TestAnIDUnderTwoModulesIsRefused(t *testing.T) {
func testAnIDUnderTwoModulesIsRefused(t *testing.T) {
refusal := refusalFor(t, `{"adoption":{"taken":[],"untaken":{"a":["hello-web.page"],"b":["hello-web.page"]}},
"declaration":1,`+adoptedResources+`}`)
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "both") {
@@ -78,7 +78,7 @@ func TestAnIDUnderTwoModulesIsRefused(t *testing.T) {
}
}
func TestAModuleBothTakenAndUntakenIsRefused(t *testing.T) {
func testAModuleBothTakenAndUntakenIsRefused(t *testing.T) {
refusal := refusalFor(t, `{"adoption":{"taken":["hello-web"],"untaken":{"hello-web":["hello-web.page"]}},
"declaration":1,`+adoptedResources+`}`)
if !strings.Contains(strings.Join(refusal.Problems, "\n"), "both taken and untaken") {
@@ -86,7 +86,7 @@ func TestAModuleBothTakenAndUntakenIsRefused(t *testing.T) {
}
}
func TestTheMeshsOwnResourcesAreNeverUntaken(t *testing.T) {
func testTheMeshsOwnResourcesAreNeverUntaken(t *testing.T) {
refusal := refusalFor(t, `{"adoption":{"taken":[],"untaken":{"x":["adoption.guard"]}},
"declaration":1,"resources":[
{"id":"adoption.guard","type":"file","path":"/etc/mesh/guard.nft","content":"x"}]}`)
@@ -95,11 +95,11 @@ func TestTheMeshsOwnResourcesAreNeverUntaken(t *testing.T) {
}
}
func TestAnAdoptionWithAnUnknownFieldIsRefused(t *testing.T) {
func testAnAdoptionWithAnUnknownFieldIsRefused(t *testing.T) {
refusalFor(t, `{"adoption":{"taken":[],"held":["x"]},"declaration":1,`+adoptedResources+`}`)
}
func TestACarriedBundleCannotSayTheNodeIsAdopted(t *testing.T) {
func testACarriedBundleCannotSayTheNodeIsAdopted(t *testing.T) {
_, err := ParseTrusted([]byte(`{"adoption":{"taken":[]},"declaration":1,` + adoptedResources + `}`))
if err == nil || !strings.Contains(err.Error(), "only the mesh can say") {
t.Fatalf("a bundle claiming adoption was not refused: %v", err)
@@ -107,7 +107,7 @@ func TestACarriedBundleCannotSayTheNodeIsAdopted(t *testing.T) {
}
// novox/hq ADR 0105: a service may take over a found tunnel, said whole and on an adopted node.
func TestTakingOverATunnelIsSaidWholeAndForARunningService(t *testing.T) {
func testTakingOverATunnelIsSaidWholeAndForARunningService(t *testing.T) {
adoptedWith := func(service string) error {
_, err := Parse([]byte(`{"declaration":1,"adoption":{"taken":[]},"resources":[` + service + `]}`))
return err
@@ -130,3 +130,17 @@ func TestTakingOverATunnelIsSaidWholeAndForARunningService(t *testing.T) {
}
}
}
// TestAdoption holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestAdoption(t *testing.T) {
t.Run("AnAdoptionIsReadWithTheDeclaration", testAnAdoptionIsReadWithTheDeclaration)
t.Run("ADeclarationWithNoAdoptionIsConverged", testADeclarationWithNoAdoptionIsConverged)
t.Run("AnAdoptionNamingAnUnknownIDIsRefused", testAnAdoptionNamingAnUnknownIDIsRefused)
t.Run("AnAdoptionMayNameAResourceOfAnyKind", testAnAdoptionMayNameAResourceOfAnyKind)
t.Run("AnIDUnderTwoModulesIsRefused", testAnIDUnderTwoModulesIsRefused)
t.Run("AModuleBothTakenAndUntakenIsRefused", testAModuleBothTakenAndUntakenIsRefused)
t.Run("TheMeshsOwnResourcesAreNeverUntaken", testTheMeshsOwnResourcesAreNeverUntaken)
t.Run("AnAdoptionWithAnUnknownFieldIsRefused", testAnAdoptionWithAnUnknownFieldIsRefused)
t.Run("ACarriedBundleCannotSayTheNodeIsAdopted", testACarriedBundleCannotSayTheNodeIsAdopted)
t.Run("TakingOverATunnelIsSaidWholeAndForARunningService", testTakingOverATunnelIsSaidWholeAndForARunningService)
}
+8 -2
View File
@@ -8,7 +8,7 @@ import (
// Defends novox/hq issue 128: a file written into a block carries only its lines, in content,
// never a line the host keeps as its own marker, and says where a new region goes only as a block.
func TestAFileWrittenIntoABlockIsRefusedUnlessItIsOnlyItsLines(t *testing.T) {
func testAFileWrittenIntoABlockIsRefusedUnlessItIsOnlyItsLines(t *testing.T) {
for name, c := range map[string]struct{ resource, refusal string }{
"a begin marker in content": {`{"id":"f","type":"file","path":"/etc/hosts","into":"block","content":"a\n# BEGIN mesh f\nb\n"}`, "# BEGIN mesh f"},
"an end marker in content": {`{"id":"f","type":"file","path":"/etc/hosts","into":"block","content":"a\n# END mesh other\n"}`, "# END mesh other"},
@@ -30,7 +30,7 @@ func TestAFileWrittenIntoABlockIsRefusedUnlessItIsOnlyItsLines(t *testing.T) {
}
}
func TestAFileWrittenIntoABlockIsRead(t *testing.T) {
func testAFileWrittenIntoABlockIsRead(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"mesh-wireguard.fact-node-names","type":"file","path":"/etc/hosts","into":"block","content":"10.42.0.1 ace\n# BEGIN devtool x\n"},
{"id":"dhcpcd.options","type":"file","path":"/etc/dhcpcd.conf","into":"block","content":"nohook resolv.conf\n","at":"start"},
@@ -50,3 +50,9 @@ func TestAFileWrittenIntoABlockIsRead(t *testing.T) {
t.Errorf("the markers are %q and %q", begin, end)
}
}
// TestBlock holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestBlock(t *testing.T) {
t.Run("AFileWrittenIntoABlockIsRefusedUnlessItIsOnlyItsLines", testAFileWrittenIntoABlockIsRefusedUnlessItIsOnlyItsLines)
t.Run("AFileWrittenIntoABlockIsRead", testAFileWrittenIntoABlockIsRead)
}
+12 -4
View File
@@ -9,7 +9,7 @@ import (
// arrival and computes the next due minute the scheduler fires on (novox/hq ADR 0053). These test
// the parsing and the evaluation; the firing is tested against the scheduler.
func TestParseCronRefusesMalformed(t *testing.T) {
func testParseCronRefusesMalformed(t *testing.T) {
for _, expr := range []string{
"", // nothing
"* * * *", // four fields
@@ -31,7 +31,7 @@ func TestParseCronRefusesMalformed(t *testing.T) {
}
}
func TestParseCronAcceptsTheOrdinaryForms(t *testing.T) {
func testParseCronAcceptsTheOrdinaryForms(t *testing.T) {
for _, expr := range []string{
"* * * * *", // every minute
"0 3 * * *", // 03:00 daily
@@ -47,7 +47,7 @@ func TestParseCronAcceptsTheOrdinaryForms(t *testing.T) {
}
}
func TestCronNextIsTheNextMatchingMinute(t *testing.T) {
func testCronNextIsTheNextMatchingMinute(t *testing.T) {
// A Monday at 12:00:30, so "next" must round up to a whole minute and land on the first match
// strictly after now — never re-firing the minute we are already in.
now := time.Date(2026, 9, 7, 12, 0, 30, 0, time.UTC) // 2026-09-07 is a Monday
@@ -77,7 +77,7 @@ func TestCronNextIsTheNextMatchingMinute(t *testing.T) {
}
}
func TestCronDayFieldsAreOredWhenBothRestricted(t *testing.T) {
func testCronDayFieldsAreOredWhenBothRestricted(t *testing.T) {
// The standard cron surprise: when day-of-month and day-of-week are both set, a day matches if
// EITHER does. "1 * 13 * 5" is due on the 13th OR on any Friday. 2026-09-07 is a Monday the 7th
// — neither — and 2026-09-11 is a Friday, and 2026-11-13 is the 13th.
@@ -98,3 +98,11 @@ func TestCronDayFieldsAreOredWhenBothRestricted(t *testing.T) {
t.Error("a Monday the 7th matched a cron restricted to the 13th OR Friday")
}
}
// TestCron holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestCron(t *testing.T) {
t.Run("ParseCronRefusesMalformed", testParseCronRefusesMalformed)
t.Run("ParseCronAcceptsTheOrdinaryForms", testParseCronAcceptsTheOrdinaryForms)
t.Run("CronNextIsTheNextMatchingMinute", testCronNextIsTheNextMatchingMinute)
t.Run("CronDayFieldsAreOredWhenBothRestricted", testCronDayFieldsAreOredWhenBothRestricted)
}
+62 -29
View File
@@ -30,7 +30,7 @@ func refusalFor(t *testing.T, raw string) *RefusalError {
return refusal
}
func TestAValidDeclarationParsesInOrder(t *testing.T) {
func testAValidDeclarationParsesInOrder(t *testing.T) {
d, err := Parse([]byte(valid()))
if err != nil {
t.Fatalf("unexpected refusal: %v", err)
@@ -45,7 +45,7 @@ func TestAValidDeclarationParsesInOrder(t *testing.T) {
}
}
func TestAnUnknownTypeRefusesTheWholeDeclaration(t *testing.T) {
func testAnUnknownTypeRefusesTheWholeDeclaration(t *testing.T) {
// The property everything else rests on. A host that skipped what it did not understand
// would apply most of a declaration and report success — a node that looks configured and
// is not, which is 04-ISSUES/003 with the declaration on the other side of the wire.
@@ -64,7 +64,7 @@ func TestAnUnknownTypeRefusesTheWholeDeclaration(t *testing.T) {
}
}
func TestAnUnknownFieldIsRefused(t *testing.T) {
func testAnUnknownFieldIsRefused(t *testing.T) {
// A field the host does not know is a thing the control plane believes it asked for.
refusal := refusalFor(t, `{"declaration":1,"resources":[
{"id":"conf","type":"file","path":"/etc/x","content":"a","immutable":true}
@@ -74,7 +74,7 @@ func TestAnUnknownFieldIsRefused(t *testing.T) {
}
}
func TestAFieldTheTypeDoesNotUseIsRefusedNotIgnored(t *testing.T) {
func testAFieldTheTypeDoesNotUseIsRefusedNotIgnored(t *testing.T) {
// The same fault in miniature: set and ignored means the control plane believes it asked
// for something the host will never do.
refusal := refusalFor(t, `{"declaration":1,"resources":[
@@ -86,7 +86,7 @@ func TestAFieldTheTypeDoesNotUseIsRefusedNotIgnored(t *testing.T) {
}
}
func TestAnUnknownVersionIsRefusedWhole(t *testing.T) {
func testAnUnknownVersionIsRefusedWhole(t *testing.T) {
// An older host handed a newer vocabulary must not quietly do half of it.
refusal := refusalFor(t, `{"declaration":99,"resources":[
{"id":"a","type":"directory","path":"/etc/mesh"}
@@ -102,7 +102,7 @@ func TestAnUnknownVersionIsRefusedWhole(t *testing.T) {
}
}
func TestEveryProblemIsReportedAtOnce(t *testing.T) {
func testEveryProblemIsReportedAtOnce(t *testing.T) {
// A declaration is generated, so a person reading a refusal is debugging the generator.
// Fixing one problem at a time and re-running to find the next wastes their afternoon.
refusal := refusalFor(t, `{"declaration":1,"resources":[
@@ -115,7 +115,7 @@ func TestEveryProblemIsReportedAtOnce(t *testing.T) {
}
}
func TestIdentityIsRequiredAndUnique(t *testing.T) {
func testIdentityIsRequiredAndUnique(t *testing.T) {
// Identity is what lets the store know this is the same resource it applied last time,
// which is what makes removal possible at all.
refusal := refusalFor(t, `{"declaration":1,"resources":[
@@ -127,7 +127,7 @@ func TestIdentityIsRequiredAndUnique(t *testing.T) {
}
}
func TestModeIsRefusedUnlessItMeansWhatItLooksLike(t *testing.T) {
func testModeIsRefusedUnlessItMeansWhatItLooksLike(t *testing.T) {
// "644" and "0644" differ, and the one that looks right in a manifest is the four-digit
// form. Accepting both would make a mode mean two things.
for _, mode := range []string{"644", "0999", "rwxr-xr-x", "07777777"} {
@@ -145,7 +145,7 @@ func TestModeIsRefusedUnlessItMeansWhatItLooksLike(t *testing.T) {
}
}
func TestARefusalSaysNothingWasApplied(t *testing.T) {
func testARefusalSaysNothingWasApplied(t *testing.T) {
// The reader's first question is whether the machine was left half-changed.
refusal := refusalFor(t, `{"declaration":1,"resources":[{"id":"x","type":"nope"}]}`)
if !strings.Contains(refusal.Error(), "none of it was applied") {
@@ -153,13 +153,13 @@ func TestARefusalSaysNothingWasApplied(t *testing.T) {
}
}
func TestAnEmptyDeclarationIsAMistake(t *testing.T) {
func testAnEmptyDeclarationIsAMistake(t *testing.T) {
refusalFor(t, `{"declaration":1,"resources":[]}`)
}
// --- the vocabulary the foundation bootstrap needs (novox/hq 07-the-foundation.md) ---
func TestAnActionOverTheLinkIsRefused(t *testing.T) {
func testAnActionOverTheLinkIsRefused(t *testing.T) {
// novox/hq ADR 0005. The link may push declarations of known shape and never a command to
// run. This is the boundary the whole security argument rests on, so it is asserted
// directly rather than inferred from the type list.
@@ -179,7 +179,7 @@ func TestAnActionOverTheLinkIsRefused(t *testing.T) {
}
}
func TestAnActionWithoutVerifyIsRefused(t *testing.T) {
func testAnActionWithoutVerifyIsRefused(t *testing.T) {
// An action that runs and reports success without reading anything back is the fault this
// host exists to prevent. Verify is also the idempotency check, so an action without one
// cannot be applied twice safely either.
@@ -194,7 +194,7 @@ func TestAnActionWithoutVerifyIsRefused(t *testing.T) {
}
}
func TestAnImageMustBePinnedByDigest(t *testing.T) {
func testAnImageMustBePinnedByDigest(t *testing.T) {
// novox/hq ADR 0006: reproducibility comes from pinning the identity of a thing. A bundle
// naming a tag pins nothing — it names whatever that tag points at on the day it runs.
for _, image := range []string{
@@ -226,7 +226,7 @@ func TestAnImageMustBePinnedByDigest(t *testing.T) {
// can start. The mesh's own control plane is built from source and lives in no public registry; a
// machine that built it, or was handed it, names it by what it is — a content address, not a name,
// and immutable in exactly the way the rule asks for.
func TestAnImageTheMachineHoldsIsNamedByItsOwnDigest(t *testing.T) {
func testAnImageTheMachineHoldsIsNamedByItsOwnDigest(t *testing.T) {
held := "sha256:" + strings.Repeat("b", 64)
if _, err := ParseTrusted([]byte(`{"declaration":1,"resources":[
{"id":"control","type":"container","name":"mesh-controller","image":"` + held + `"}
@@ -245,7 +245,7 @@ func TestAnImageTheMachineHoldsIsNamedByItsOwnDigest(t *testing.T) {
}
}
func TestAFieldTheNewTypesDoNotUseIsRefused(t *testing.T) {
func testAFieldTheNewTypesDoNotUseIsRefused(t *testing.T) {
// The field-set check must cover the types added last, not only the three it was written
// for. A package that carries a `content` is a control plane believing it asked for
// something that will never happen.
@@ -266,7 +266,7 @@ func TestAFieldTheNewTypesDoNotUseIsRefused(t *testing.T) {
}
}
func TestTheVocabularyIsTheTwelveShapesTheMeshNeeds(t *testing.T) {
func testTheVocabularyIsTheTwelveShapesTheMeshNeeds(t *testing.T) {
// Six of them the bootstrap uses (novox/hq 07-the-foundation.md), and removing one is a
// failing test rather than a discovery during a first-node install.
//
@@ -320,7 +320,7 @@ func TestTheVocabularyIsTheTwelveShapesTheMeshNeeds(t *testing.T) {
}
}
func TestADeclarationFromDiskMayBeAnnotated(t *testing.T) {
func testADeclarationFromDiskMayBeAnnotated(t *testing.T) {
// The bundle in this repository is mostly explanation of why each digest is what it is, and
// it could be built into a binary and not applied from disk — two readers for one file. The
// failure was `invalid character '/'`, which names the symptom and not the cause.
@@ -346,7 +346,7 @@ func TestADeclarationFromDiskMayBeAnnotated(t *testing.T) {
}
}
func TestSomethingInsideAValueIsNotAComment(t *testing.T) {
func testSomethingInsideAValueIsNotAComment(t *testing.T) {
// Every image reference has a `//` in it somewhere near. Only whole lines are dropped.
d, err := ParseFileTrusted([]byte(`{"declaration":1,"resources":[
{"id":"f","type":"file","path":"/etc/x","content":"see https://example.invalid/ for why"}]}`))
@@ -370,7 +370,7 @@ func TestSomethingInsideAValueIsNotAComment(t *testing.T) {
//
// Not hypothetical: a test harness appended a line to the foundation bundle by accident, every
// apply kept working, and nothing said so for the entire time it was wrong.
func TestSomethingAfterTheDeclarationIsRefused(t *testing.T) {
func testSomethingAfterTheDeclarationIsRefused(t *testing.T) {
good := `{"declaration":1,"resources":[{"id":"a","type":"file","path":"/tmp/a",` +
`"content":"x","mode":"0644"}]}`
if _, err := ParseFileTrusted([]byte(good)); err != nil {
@@ -394,7 +394,7 @@ func TestSomethingAfterTheDeclarationIsRefused(t *testing.T) {
}
// A name that would read as a reference to something else is refused before it reaches a runtime.
func TestANetworkNameIsRefusedIfItIsNotOne(t *testing.T) {
func testANetworkNameIsRefusedIfItIsNotOne(t *testing.T) {
for _, name := range []string{"", "mail/private", "host:mail", "a b"} {
refusal := refusalFor(t, `{"declaration":1,"resources":[
{"id":"private","type":"network","name":"`+name+`"}
@@ -409,7 +409,7 @@ func TestANetworkNameIsRefusedIfItIsNotOne(t *testing.T) {
//
// The alternative is a configuration file containing the literal `${secret:x}`, which the program
// reads as a value and fails on somewhere with no connection to this.
func TestAFileAskingForASecretItWasNotGivenIsRefused(t *testing.T) {
func testAFileAskingForASecretItWasNotGivenIsRefused(t *testing.T) {
refusal := refusalFor(t, `{"declaration":1,"resources":[
{"id":"c","type":"file","path":"/tmp/x","content":"token=${secret:absent}"}
]}`)
@@ -419,7 +419,7 @@ func TestAFileAskingForASecretItWasNotGivenIsRefused(t *testing.T) {
}
// And a secret nobody asked for, because somebody believes it is in a file where it is not.
func TestASecretTheContentNeverUsesIsRefused(t *testing.T) {
func testASecretTheContentNeverUsesIsRefused(t *testing.T) {
refusal := refusalFor(t, `{"declaration":1,"resources":[
{"id":"c","type":"file","path":"/tmp/x","content":"nothing here","secrets":{"spare":"S"}}
]}`)
@@ -431,7 +431,7 @@ func TestASecretTheContentNeverUsesIsRefused(t *testing.T) {
// The runtime's resolver and address flags take only addresses; a name would be refused at
// create, after the old container was already gone. Refused on arrival instead — and an address
// without a user-defined network is refused for the same reason.
func TestAContainersResolverAndAddressAreAddressesOrRefused(t *testing.T) {
func testAContainersResolverAndAddressAreAddressesOrRefused(t *testing.T) {
refused := func(body string) []string {
_, err := Parse([]byte(`{"declaration":1,"resources":[` + body + `]}`))
if err == nil {
@@ -452,7 +452,7 @@ func TestAContainersResolverAndAddressAreAddressesOrRefused(t *testing.T) {
}
}
func TestAnExplicitlyEmptyDeclarationIsAccepted(t *testing.T) {
func testAnExplicitlyEmptyDeclarationIsAccepted(t *testing.T) {
// A deliberately-empty declaration (novox/hq issue 127) says owns_nothing, and is applied so
// the node drops what it last held — distinct from an accidental empty body, which is refused.
if _, err := Parse([]byte(`{"declaration":1,"owns_nothing":true,"resources":[]}`)); err != nil {
@@ -467,7 +467,7 @@ func TestAnExplicitlyEmptyDeclarationIsAccepted(t *testing.T) {
// A container's kept networks are names, not its own network, and not for a step (novox/hq ADR
// 0163, rule 4); and the mesh may say which modules it left out, which a carried bundle may not.
func TestKeptNetworksAndLeftOutModulesAreReadStrictly(t *testing.T) {
func testKeptNetworksAndLeftOutModulesAreReadStrictly(t *testing.T) {
pinnedImage := "postgres@sha256:" + strings.Repeat("a", 64)
d, err := Parse([]byte(`{"declaration":1,"left_out":["web"],"resources":[
{"id":"app","type":"container","name":"app","image":"` + pinnedImage + `","networks":["predecessor_default"]}
@@ -506,7 +506,7 @@ func TestKeptNetworksAndLeftOutModulesAreReadStrictly(t *testing.T) {
}
// A container may ask for a capability by name, and nothing else (novox/hq ADR 0170).
func TestACapabilityIsNamedOrRefused(t *testing.T) {
func testACapabilityIsNamedOrRefused(t *testing.T) {
image := "postgres@sha256:" + strings.Repeat("a", 64)
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"fw","type":"container","name":"fw","image":"` + image + `","network":"host","capabilities":["NET_ADMIN","CAP_NET_RAW"]}
@@ -527,7 +527,7 @@ func TestACapabilityIsNamedOrRefused(t *testing.T) {
// A container may send its output to the machine's journal, and nowhere else but the runtime's own
// file (novox/hq ADR 0179): what reads the machine's logs then reads the container's too.
func TestAContainerMayLogToTheJournalAndNowhereElse(t *testing.T) {
func testAContainerMayLogToTheJournalAndNowhereElse(t *testing.T) {
image := "postgres@sha256:" + strings.Repeat("a", 64)
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"front","type":"container","name":"front","image":"` + image + `","logging":"journald"}
@@ -548,7 +548,7 @@ func TestAContainerMayLogToTheJournalAndNowhereElse(t *testing.T) {
// Issue 1024, ADR 0422: a directory or archive says how it treats files it did not write.
func TestADirectoryAndAnArchiveSayWhatTheyDoWithUnknownFiles(t *testing.T) {
func testADirectoryAndAnArchiveSayWhatTheyDoWithUnknownFiles(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"d","type":"directory","path":"/home/a/x","unknown":"move-out","knows":["keep","sub/"]},
{"id":"r","type":"archive","source":"https://x/y","digest":"sha256:` + strings.Repeat("a", 64) + `","path":"/home/a/y","unknown":"module"}
@@ -570,7 +570,7 @@ func TestADirectoryAndAnArchiveSayWhatTheyDoWithUnknownFiles(t *testing.T) {
}
}
func TestBadUnknownAndKnowsFormsAreRefusedNamingTheResource(t *testing.T) {
func testBadUnknownAndKnowsFormsAreRefusedNamingTheResource(t *testing.T) {
digest := `"digest":"sha256:` + strings.Repeat("a", 64) + `"`
cases := map[string]string{
"bad value": `{"id":"d","type":"directory","path":"/x","unknown":"delete"}`,
@@ -593,3 +593,36 @@ func TestBadUnknownAndKnowsFormsAreRefusedNamingTheResource(t *testing.T) {
})
}
}
// TestDeclaration holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestDeclaration(t *testing.T) {
t.Run("AValidDeclarationParsesInOrder", testAValidDeclarationParsesInOrder)
t.Run("AnUnknownTypeRefusesTheWholeDeclaration", testAnUnknownTypeRefusesTheWholeDeclaration)
t.Run("AnUnknownFieldIsRefused", testAnUnknownFieldIsRefused)
t.Run("AFieldTheTypeDoesNotUseIsRefusedNotIgnored", testAFieldTheTypeDoesNotUseIsRefusedNotIgnored)
t.Run("AnUnknownVersionIsRefusedWhole", testAnUnknownVersionIsRefusedWhole)
t.Run("EveryProblemIsReportedAtOnce", testEveryProblemIsReportedAtOnce)
t.Run("IdentityIsRequiredAndUnique", testIdentityIsRequiredAndUnique)
t.Run("ModeIsRefusedUnlessItMeansWhatItLooksLike", testModeIsRefusedUnlessItMeansWhatItLooksLike)
t.Run("ARefusalSaysNothingWasApplied", testARefusalSaysNothingWasApplied)
t.Run("AnEmptyDeclarationIsAMistake", testAnEmptyDeclarationIsAMistake)
t.Run("AnActionOverTheLinkIsRefused", testAnActionOverTheLinkIsRefused)
t.Run("AnActionWithoutVerifyIsRefused", testAnActionWithoutVerifyIsRefused)
t.Run("AnImageMustBePinnedByDigest", testAnImageMustBePinnedByDigest)
t.Run("AnImageTheMachineHoldsIsNamedByItsOwnDigest", testAnImageTheMachineHoldsIsNamedByItsOwnDigest)
t.Run("AFieldTheNewTypesDoNotUseIsRefused", testAFieldTheNewTypesDoNotUseIsRefused)
t.Run("TheVocabularyIsTheTwelveShapesTheMeshNeeds", testTheVocabularyIsTheTwelveShapesTheMeshNeeds)
t.Run("ADeclarationFromDiskMayBeAnnotated", testADeclarationFromDiskMayBeAnnotated)
t.Run("SomethingInsideAValueIsNotAComment", testSomethingInsideAValueIsNotAComment)
t.Run("SomethingAfterTheDeclarationIsRefused", testSomethingAfterTheDeclarationIsRefused)
t.Run("ANetworkNameIsRefusedIfItIsNotOne", testANetworkNameIsRefusedIfItIsNotOne)
t.Run("AFileAskingForASecretItWasNotGivenIsRefused", testAFileAskingForASecretItWasNotGivenIsRefused)
t.Run("ASecretTheContentNeverUsesIsRefused", testASecretTheContentNeverUsesIsRefused)
t.Run("AContainersResolverAndAddressAreAddressesOrRefused", testAContainersResolverAndAddressAreAddressesOrRefused)
t.Run("AnExplicitlyEmptyDeclarationIsAccepted", testAnExplicitlyEmptyDeclarationIsAccepted)
t.Run("KeptNetworksAndLeftOutModulesAreReadStrictly", testKeptNetworksAndLeftOutModulesAreReadStrictly)
t.Run("ACapabilityIsNamedOrRefused", testACapabilityIsNamedOrRefused)
t.Run("AContainerMayLogToTheJournalAndNowhereElse", testAContainerMayLogToTheJournalAndNowhereElse)
t.Run("ADirectoryAndAnArchiveSayWhatTheyDoWithUnknownFiles", testADirectoryAndAnArchiveSayWhatTheyDoWithUnknownFiles)
t.Run("BadUnknownAndKnowsFormsAreRefusedNamingTheResource", testBadUnknownAndKnowsFormsAreRefusedNamingTheResource)
}
+16 -6
View File
@@ -15,7 +15,7 @@ func refFile(extra string) string {
}
// 1694/AC1: a reference round trips, and an invalid one is refused naming the field.
func TestAFileReferenceRoundTripsAndABadOneNamesItsField(t *testing.T) {
func testAFileReferenceRoundTripsAndABadOneNamesItsField(t *testing.T) {
d, err := Parse([]byte(refFile("")))
if err != nil {
t.Fatal(err)
@@ -49,7 +49,7 @@ func TestAFileReferenceRoundTripsAndABadOneNamesItsField(t *testing.T) {
}
// 1694/AC2: a declaration as today's SDK writes it reads unchanged and its bytes carry no new key.
func TestAnInlineFileIsReadAndWrittenAsBefore(t *testing.T) {
func testAnInlineFileIsReadAndWrittenAsBefore(t *testing.T) {
const in = `{"id":"m.f","type":"file","path":"/e","content":"hello"}`
d, err := Parse([]byte(`{"declaration":1,"resources":[` + in + `]}`))
if err != nil {
@@ -65,7 +65,7 @@ func TestAnInlineFileIsReadAndWrittenAsBefore(t *testing.T) {
}
// 1694/AC3: the controller's helper makes a reference of a big file and the engine's check refuses a changed byte.
func TestABigFileBecomesAReferenceAndAChangedByteFailsTheCheck(t *testing.T) {
func testABigFileBecomesAReferenceAndAChangedByteFailsTheCheck(t *testing.T) {
big := strings.Repeat("x", FileReferenceThreshold+1)
f := &File{ID: "m.f", Type: TypeFile, Path: "/e", Content: big}
if !f.TravelsByDigest() {
@@ -95,7 +95,7 @@ func TestABigFileBecomesAReferenceAndAChangedByteFailsTheCheck(t *testing.T) {
}
// 1694/AC4: what stays inline, and bytes files travel decoded.
func TestWhichFilesTravelByDigest(t *testing.T) {
func testWhichFilesTravelByDigest(t *testing.T) {
small := strings.Repeat("x", FileReferenceThreshold)
big := strings.Repeat("x", FileReferenceThreshold+1)
for name, f := range map[string]File{
@@ -126,7 +126,7 @@ func TestWhichFilesTravelByDigest(t *testing.T) {
}
}
func TestTheSharedNames(t *testing.T) {
func testTheSharedNames(t *testing.T) {
if FileBucketPrefix != "declaration-files-" || FileReferencesCapability != "file-references" || FileReferenceThreshold != 65536 {
t.Fatal("a name changed")
}
@@ -136,7 +136,7 @@ func TestTheSharedNames(t *testing.T) {
}
// 1694/AC6: each node has a bucket of its own, so a grant names it and never needs a `*` (ADR 0486 §2).
func TestEachNodeHasABucketOfItsOwn(t *testing.T) {
func testEachNodeHasABucketOfItsOwn(t *testing.T) {
for _, n := range []string{"ace", "g14", "novox", "shanks"} {
b, err := FileBucketFor(n)
if err != nil || b != "declaration-files-"+n {
@@ -156,3 +156,13 @@ func TestEachNodeHasABucketOfItsOwn(t *testing.T) {
}
}
}
// TestFilereference holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestFilereference(t *testing.T) {
t.Run("AFileReferenceRoundTripsAndABadOneNamesItsField", testAFileReferenceRoundTripsAndABadOneNamesItsField)
t.Run("AnInlineFileIsReadAndWrittenAsBefore", testAnInlineFileIsReadAndWrittenAsBefore)
t.Run("ABigFileBecomesAReferenceAndAChangedByteFailsTheCheck", testABigFileBecomesAReferenceAndAChangedByteFailsTheCheck)
t.Run("WhichFilesTravelByDigest", testWhichFilesTravelByDigest)
t.Run("TheSharedNames", testTheSharedNames)
t.Run("EachNodeHasABucketOfItsOwn", testEachNodeHasABucketOfItsOwn)
}
+8 -2
View File
@@ -9,7 +9,7 @@ import (
// A container may be given supplementary groups (novox/hq ADR 0480 clause 7, issue 1636): numbers, each above zero.
// 1636/AC1: a declaration with groups decodes, is written back with them, and a declaration without them has none.
func TestAContainerWithGroupsDecodesAndIsWrittenBack(t *testing.T) {
func testAContainerWithGroupsDecodesAndIsWrittenBack(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"n8n.server","type":"container","name":"n8n","image":"` + anImage + `","groups":[2000,2001]},
{"id":"n8n.plain","type":"container","name":"plain","image":"` + anImage + `"}]}`))
@@ -34,7 +34,7 @@ func TestAContainerWithGroupsDecodesAndIsWrittenBack(t *testing.T) {
}
// 1636/AC2: zero, a number below it, one the kernel keeps for "no group" and a number twice are refused, naming why.
func TestAContainersGroupsAreWholeNumbersAboveZeroAndNotRepeated(t *testing.T) {
func testAContainersGroupsAreWholeNumbersAboveZeroAndNotRepeated(t *testing.T) {
for want, groups := range map[string]string{
"never root": `[0]`,
"below zero": `[-5]`,
@@ -53,3 +53,9 @@ func TestAContainersGroupsAreWholeNumbersAboveZeroAndNotRepeated(t *testing.T) {
t.Error("a group named by text was accepted")
}
}
// TestGroups holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestGroups(t *testing.T) {
t.Run("AContainerWithGroupsDecodesAndIsWrittenBack", testAContainerWithGroupsDecodesAndIsWrittenBack)
t.Run("AContainersGroupsAreWholeNumbersAboveZeroAndNotRepeated", testAContainersGroupsAreWholeNumbersAboveZeroAndNotRepeated)
}
+8 -2
View File
@@ -8,7 +8,7 @@ import (
const anImage = "docker.io/library/x@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
// The fields ADR 0325 adds, read as the controller sends them (novox/hq ADR 0325 §2, §3, §5, issue 567).
func TestIdentitiesUsersAndARunAsAreReadAsSent(t *testing.T) {
func testIdentitiesUsersAndARunAsAreReadAsSent(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,
"identities":[{"module":"radarr","name":"mesh-radarr","uid":61001,"gid":61001}],
"resources":[
@@ -35,7 +35,7 @@ func TestIdentitiesUsersAndARunAsAreReadAsSent(t *testing.T) {
// What the engine refuses on arrival: a root number, an identity not named for its module, a field it does not
// know, a user that writes a read access, a variable set twice.
func TestWhatADeclarationMayNotSayOfAnIdentity(t *testing.T) {
func testWhatADeclarationMayNotSayOfAnIdentity(t *testing.T) {
for want, raw := range map[string]string{
"never root": `"identities":[{"module":"m","name":"mesh-m","uid":0,"gid":61001}],"resources":[]`,
"named mesh-<module>": `"identities":[{"module":"m","name":"m","uid":61001,"gid":61001}],` +
@@ -59,3 +59,9 @@ func TestWhatADeclarationMayNotSayOfAnIdentity(t *testing.T) {
}
}
}
// TestIdentity holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestIdentity(t *testing.T) {
t.Run("IdentitiesUsersAndARunAsAreReadAsSent", testIdentitiesUsersAndARunAsAreReadAsSent)
t.Run("WhatADeclarationMayNotSayOfAnIdentity", testWhatADeclarationMayNotSayOfAnIdentity)
}
+10 -3
View File
@@ -4,7 +4,7 @@ import "testing"
// 1132/AC1: a resource says its module, and the declaration says each module's build; a resource that does
// not say gets today's guess, so an older controller still works.
func TestAResourceSaysItsModuleAndTheDeclarationItsBuilds(t *testing.T) {
func testAResourceSaysItsModuleAndTheDeclarationItsBuilds(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,
"builds":{"novox.be":"b-9","web":"b-4"},
"resources":[
@@ -30,7 +30,7 @@ func TestAResourceSaysItsModuleAndTheDeclarationItsBuilds(t *testing.T) {
}
// 1132/AC1: the module the declaration gives wins over the guess, even when the id would guess another.
func TestTheDeclaredModuleWinsOverTheGuess(t *testing.T) {
func testTheDeclaredModuleWinsOverTheGuess(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"a.b.c","type":"directory","path":"/srv/a","module":"a.b"},
{"id":"x.y","type":"directory","path":"/srv/x","module":"other"}]}`))
@@ -43,7 +43,7 @@ func TestTheDeclaredModuleWinsOverTheGuess(t *testing.T) {
}
// 1132/AC1: every kind accepts the field.
func TestEveryKindAcceptsAModule(t *testing.T) {
func testEveryKindAcceptsAModule(t *testing.T) {
for _, typ := range []Type{TypeDirectory, TypeFile, TypeUser, TypeNetwork, TypeAccess, TypeArchive, TypeProcess,
TypeService, TypeOpening, TypePackage, TypeContainer, TypeAction} {
r := newOf(typ)
@@ -58,3 +58,10 @@ func TestEveryKindAcceptsAModule(t *testing.T) {
}
}
}
// TestModule holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestModule(t *testing.T) {
t.Run("AResourceSaysItsModuleAndTheDeclarationItsBuilds", testAResourceSaysItsModuleAndTheDeclarationItsBuilds)
t.Run("TheDeclaredModuleWinsOverTheGuess", testTheDeclaredModuleWinsOverTheGuess)
t.Run("EveryKindAcceptsAModule", testEveryKindAcceptsAModule)
}
+10 -3
View File
@@ -12,7 +12,7 @@ func withOrder(order string) string {
return `{"declaration":1,` + order + `"resources":[{"id":"etc","type":"directory","path":"/etc/mesh","mode":"0755"}]}`
}
func TestADeclarationCarriesItsEpochAndSequence(t *testing.T) {
func testADeclarationCarriesItsEpochAndSequence(t *testing.T) {
d, err := Parse([]byte(withOrder(`"epoch":57,"sequence":3,`)))
if err != nil {
t.Fatalf("a declaration carrying its order was refused: %v", err)
@@ -27,7 +27,7 @@ func TestADeclarationCarriesItsEpochAndSequence(t *testing.T) {
}
}
func TestAnOrderBelowZeroIsRefused(t *testing.T) {
func testAnOrderBelowZeroIsRefused(t *testing.T) {
for _, order := range []string{`"epoch":-1,`, `"sequence":-4,`} {
refusal := refusalFor(t, withOrder(order))
if !strings.Contains(refusal.Error(), "below zero") {
@@ -38,7 +38,7 @@ func TestAnOrderBelowZeroIsRefused(t *testing.T) {
// **The assignment generation it was composed from, and whether it is a put-back** (novox/hq issue 234):
// absent is no claim; below zero is none the mesh assigns; a carried bundle puts nothing back.
func TestADeclarationCarriesItsGenerationAndWhetherItIsAPutBack(t *testing.T) {
func testADeclarationCarriesItsGenerationAndWhetherItIsAPutBack(t *testing.T) {
d, err := Parse([]byte(withOrder(`"sequence":3,"generation":41,"put_back":true,`)))
if err != nil {
t.Fatalf("a declaration carrying its generation was refused: %v", err)
@@ -57,3 +57,10 @@ func TestADeclarationCarriesItsGenerationAndWhetherItIsAPutBack(t *testing.T) {
t.Errorf("a carried bundle said it was a put-back and was not refused for it: %v", err)
}
}
// TestOrder holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestOrder(t *testing.T) {
t.Run("ADeclarationCarriesItsEpochAndSequence", testADeclarationCarriesItsEpochAndSequence)
t.Run("AnOrderBelowZeroIsRefused", testAnOrderBelowZeroIsRefused)
t.Run("ADeclarationCarriesItsGenerationAndWhetherItIsAPutBack", testADeclarationCarriesItsGenerationAndWhetherItIsAPutBack)
}
+14 -5
View File
@@ -9,7 +9,7 @@ import (
// — owned, seed or managed — and the declaration names the files the provisioner fills. The words are
// read and judged here before any controller sends them.
func TestAFileSaysWhoOwnsItAtRuntime(t *testing.T) {
func testAFileSaysWhoOwnsItAtRuntime(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"o","type":"file","path":"/etc/o","content":"a","owner-at-runtime":"owned"},
{"id":"s","type":"file","path":"/etc/s","content":"a","owner-at-runtime":"seed"},
@@ -31,7 +31,7 @@ func TestAFileSaysWhoOwnsItAtRuntime(t *testing.T) {
}
// A file that does not say is owned by its old form, so the word means exactly what that form does.
func TestAFileThatDoesNotSayIsOwnedByItsOldForm(t *testing.T) {
func testAFileThatDoesNotSayIsOwnedByItsOldForm(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"o","type":"file","path":"/etc/o","content":"a"},
{"id":"s","type":"file","path":"/etc/s","content":"a","create-once":true},
@@ -53,7 +53,7 @@ func TestAFileThatDoesNotSayIsOwnedByItsOldForm(t *testing.T) {
}
}
func TestAnOwnershipThatContradictsTheFileIsRefused(t *testing.T) {
func testAnOwnershipThatContradictsTheFileIsRefused(t *testing.T) {
for name, c := range map[string]struct{ resource, refusal string }{
"another word": {`{"id":"f","type":"file","path":"/etc/x","content":"a","owner-at-runtime":"mine"}`,
`owner-at-runtime "mine"`},
@@ -78,7 +78,7 @@ func TestAnOwnershipThatContradictsTheFileIsRefused(t *testing.T) {
}
}
func TestTheDeclarationNamesTheFilesTheProvisionerFills(t *testing.T) {
func testTheDeclarationNamesTheFilesTheProvisionerFills(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"filled_files":["/etc/a","/etc/b"],"resources":[
{"id":"a","type":"file","path":"/etc/a","content":"a","owner-at-runtime":"owned"},
{"id":"b","type":"file","path":"/etc/b","into":"block","content":"b\n","owner-at-runtime":"managed"},
@@ -104,7 +104,7 @@ func TestTheDeclarationNamesTheFilesTheProvisionerFills(t *testing.T) {
}
}
func TestAFilledFileMustBeADeclaredFileThatSaysItsOwner(t *testing.T) {
func testAFilledFileMustBeADeclaredFileThatSaysItsOwner(t *testing.T) {
for name, c := range map[string]struct{ filled, resources, refusal string }{
"not declared": {`["/etc/none"]`,
`{"id":"a","type":"file","path":"/etc/a","content":"a","owner-at-runtime":"owned"}`,
@@ -128,3 +128,12 @@ func TestAFilledFileMustBeADeclaredFileThatSaysItsOwner(t *testing.T) {
}
}
}
// TestOwnership holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestOwnership(t *testing.T) {
t.Run("AFileSaysWhoOwnsItAtRuntime", testAFileSaysWhoOwnsItAtRuntime)
t.Run("AFileThatDoesNotSayIsOwnedByItsOldForm", testAFileThatDoesNotSayIsOwnedByItsOldForm)
t.Run("AnOwnershipThatContradictsTheFileIsRefused", testAnOwnershipThatContradictsTheFileIsRefused)
t.Run("TheDeclarationNamesTheFilesTheProvisionerFills", testTheDeclarationNamesTheFilesTheProvisionerFills)
t.Run("AFilledFileMustBeADeclaredFileThatSaysItsOwner", testAFilledFileMustBeADeclaredFileThatSaysItsOwner)
}
+24 -10
View File
@@ -15,7 +15,7 @@ func aProcess() *Process {
}
// A process is part of the vocabulary, or a declaration carrying one is refused whole.
func TestAProcessIsSomethingTheHostSpeaks(t *testing.T) {
func testAProcessIsSomethingTheHostSpeaks(t *testing.T) {
var found bool
for _, kind := range Vocabulary() {
if kind == TypeProcess {
@@ -33,7 +33,7 @@ func TestAProcessIsSomethingTheHostSpeaks(t *testing.T) {
// **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) {
func testAProcesssBundleMustBePinned(t *testing.T) {
for _, bad := range []string{"", "latest", "sha256:short", strings.Repeat("a", 64)} {
d := aProcess()
d.Digest = bad
@@ -45,7 +45,7 @@ func TestAProcesssBundleMustBePinned(t *testing.T) {
// 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) {
func testAProcessMustSayWhatToRun(t *testing.T) {
d := aProcess()
d.Run = nil
if problems := d.validate("a process", false); len(problems) == 0 {
@@ -54,7 +54,7 @@ func TestAProcessMustSayWhatToRun(t *testing.T) {
}
// Its name becomes a unit name and a path, so a separator in it would write somewhere nobody meant.
func TestAProcesssNameCannotEscapeItsUnit(t *testing.T) {
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.
@@ -68,7 +68,7 @@ func TestAProcesssNameCannotEscapeItsUnit(t *testing.T) {
}
// And a well-formed one is accepted, or the tests above prove only that everything is refused.
func TestAWellFormedDaemonIsAccepted(t *testing.T) {
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)
}
@@ -78,7 +78,7 @@ func TestAWellFormedDaemonIsAccepted(t *testing.T) {
// 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) {
func testTheModesAreExclusive(t *testing.T) {
both := aProcess()
both.RunOnce = true
both.Schedule = "0 3 * * *"
@@ -110,7 +110,7 @@ func TestTheModesAreExclusive(t *testing.T) {
// 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) {
func testAScheduleMustBeACadence(t *testing.T) {
for _, bad := range []string{"often", "0 3 * *", "99 3 * * *"} {
p := aProcess()
p.Schedule = bad
@@ -121,7 +121,7 @@ func TestAScheduleMustBeACadence(t *testing.T) {
}
// And each mode on its own is accepted, or the tests above prove only that everything is refused.
func TestEachModeOnItsOwnIsAccepted(t *testing.T) {
func testEachModeOnItsOwnIsAccepted(t *testing.T) {
once := aProcess()
once.RunOnce = true
if problems := once.validate("a process", false); len(problems) != 0 {
@@ -148,7 +148,7 @@ func TestEachModeOnItsOwnIsAccepted(t *testing.T) {
//
// 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) {
func testAnEnvironmentValueCannotCarryALineBreak(t *testing.T) {
for _, bad := range []string{
"safe\nExecStart=/usr/bin/whatever",
"carriage\rreturn",
@@ -173,10 +173,24 @@ func TestAnEnvironmentValueCannotCarryALineBreak(t *testing.T) {
// 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) {
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)
}
+8 -2
View File
@@ -8,7 +8,7 @@ import (
// Defends novox/hq ADR 0349 §4 (issue 668): the declaration names the account the provisioner's client runs as,
// the only one whose write of a filled file the node-engine accepts. Read here before any controller sends it.
func TestTheDeclarationNamesTheProvisionersAccount(t *testing.T) {
func testTheDeclarationNamesTheProvisionersAccount(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"provisioner_account":"mesh-node-provisioner","filled_files":["/etc/a"],
"resources":[{"id":"a","type":"file","path":"/etc/a","content":"a","owner-at-runtime":"owned"}]}`))
if err != nil {
@@ -26,7 +26,7 @@ func TestTheDeclarationNamesTheProvisionersAccount(t *testing.T) {
}
}
func TestAProvisionersAccountThatIsNoAccountIsRefused(t *testing.T) {
func testAProvisionersAccountThatIsNoAccountIsRefused(t *testing.T) {
for name, account := range map[string]string{"root": "root", "not a name": "a b", "a path": "../x"} {
_, err := Parse([]byte(`{"declaration":1,"provisioner_account":"` + account + `",
"resources":[{"id":"a","type":"file","path":"/etc/a","content":"a"}]}`))
@@ -35,3 +35,9 @@ func TestAProvisionersAccountThatIsNoAccountIsRefused(t *testing.T) {
}
}
}
// TestProvisioner holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestProvisioner(t *testing.T) {
t.Run("TheDeclarationNamesTheProvisionersAccount", testTheDeclarationNamesTheProvisionersAccount)
t.Run("AProvisionersAccountThatIsNoAccountIsRefused", testAProvisionersAccountThatIsNoAccountIsRefused)
}
+14 -5
View File
@@ -15,7 +15,7 @@ func replacing(extra string) string {
return `{"declaration":1,"resources":[` + strings.Replace(aReplacingProcess, "%s", extra, 1) + `]}`
}
func TestAProcessMayNameWhatItReplaces(t *testing.T) {
func testAProcessMayNameWhatItReplaces(t *testing.T) {
d, err := Parse([]byte(replacing(`,"replaces":["m.server"]`)))
if err != nil {
t.Fatalf("a process replacing an undeclared container was refused: %v", err)
@@ -27,7 +27,7 @@ func TestAProcessMayNameWhatItReplaces(t *testing.T) {
// What is replaced is what the declaration no longer says. A resource still declared is applied,
// and handing it over as well would remove something the same declaration asks to keep.
func TestAProcessMayNotReplaceSomethingStillDeclared(t *testing.T) {
func testAProcessMayNotReplaceSomethingStillDeclared(t *testing.T) {
raw := `{"declaration":1,"resources":[
{"id":"m.server","type":"directory","path":"/tmp/x"},
` + strings.Replace(aReplacingProcess, "%s", `,"replaces":["m.server"]`, 1) + `]}`
@@ -36,7 +36,7 @@ func TestAProcessMayNotReplaceSomethingStillDeclared(t *testing.T) {
}
}
func TestOnlyAProcessThatStaysUpReplacesAnything(t *testing.T) {
func testOnlyAProcessThatStaysUpReplacesAnything(t *testing.T) {
for _, mode := range []string{`,"run-once":true`, `,"schedule":"0 3 * * *"`} {
if _, err := Parse([]byte(replacing(mode + `,"replaces":["m.server"]`))); err == nil {
t.Errorf("a process with %s was allowed to replace something", mode)
@@ -44,7 +44,7 @@ func TestOnlyAProcessThatStaysUpReplacesAnything(t *testing.T) {
}
}
func TestAProcessCannotReplaceItselfOrNothing(t *testing.T) {
func testAProcessCannotReplaceItselfOrNothing(t *testing.T) {
for _, bad := range []string{`,"replaces":["m.controller"]`, `,"replaces":[""]`} {
if _, err := Parse([]byte(replacing(bad))); err == nil {
t.Errorf("replaces %s was accepted", bad)
@@ -52,7 +52,7 @@ func TestAProcessCannotReplaceItselfOrNothing(t *testing.T) {
}
}
func TestOneThingHasOneReplacement(t *testing.T) {
func testOneThingHasOneReplacement(t *testing.T) {
second := strings.NewReplacer(`"id":"m.controller"`, `"id":"m.other"`, `"name":"m"`, `"name":"other"`).
Replace(strings.Replace(aReplacingProcess, "%s", `,"replaces":["m.server"]`, 1))
raw := `{"declaration":1,"resources":[` +
@@ -61,3 +61,12 @@ func TestOneThingHasOneReplacement(t *testing.T) {
t.Fatal("two processes replacing one resource were accepted")
}
}
// TestReplaces holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestReplaces(t *testing.T) {
t.Run("AProcessMayNameWhatItReplaces", testAProcessMayNameWhatItReplaces)
t.Run("AProcessMayNotReplaceSomethingStillDeclared", testAProcessMayNotReplaceSomethingStillDeclared)
t.Run("OnlyAProcessThatStaysUpReplacesAnything", testOnlyAProcessThatStaysUpReplacesAnything)
t.Run("AProcessCannotReplaceItselfOrNothing", testAProcessCannotReplaceItselfOrNothing)
t.Run("OneThingHasOneReplacement", testOneThingHasOneReplacement)
}
+10 -3
View File
@@ -11,7 +11,7 @@ import (
func schedulePinned() string { return "registry.example/runtime@sha256:" + strings.Repeat("a", 64) }
func TestAScheduledContainerCarriesTheCronField(t *testing.T) {
func testAScheduledContainerCarriesTheCronField(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"sync","type":"container","name":"sync","image":"` + schedulePinned() + `","schedule":"0 3 * * *"}
]}`))
@@ -27,7 +27,7 @@ func TestAScheduledContainerCarriesTheCronField(t *testing.T) {
}
}
func TestAMalformedScheduleIsRefused(t *testing.T) {
func testAMalformedScheduleIsRefused(t *testing.T) {
_, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"sync","type":"container","name":"sync","image":"` + schedulePinned() + `","schedule":"every night"}
]}`))
@@ -39,7 +39,7 @@ func TestAMalformedScheduleIsRefused(t *testing.T) {
}
}
func TestAContainerCannotBeBothRunOnceAndScheduled(t *testing.T) {
func testAContainerCannotBeBothRunOnceAndScheduled(t *testing.T) {
// A container runs once and gates, or on a cadence, or stays up — never two (novox/hq ADR 0053).
_, err := Parse([]byte(`{"declaration":1,"resources":[
{"id":"sync","type":"container","name":"sync","image":"` + schedulePinned() + `","run-once":true,"schedule":"0 3 * * *"}
@@ -51,3 +51,10 @@ func TestAContainerCannotBeBothRunOnceAndScheduled(t *testing.T) {
t.Errorf("refused for the wrong reason: %v", err)
}
}
// TestScheduleDeclaration holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestScheduleDeclaration(t *testing.T) {
t.Run("AScheduledContainerCarriesTheCronField", testAScheduledContainerCarriesTheCronField)
t.Run("AMalformedScheduleIsRefused", testAMalformedScheduleIsRefused)
t.Run("AContainerCannotBeBothRunOnceAndScheduled", testAContainerCannotBeBothRunOnceAndScheduled)
}
+8 -2
View File
@@ -7,7 +7,7 @@ import (
// novox/hq ADR 0177: a unit is in the system manager or an account's own; a user-scoped one names
// the account, a system one may not, and any other word is refused.
func TestAUserScopedUnitNamesItsAccountAndASystemOneMayNot(t *testing.T) {
func testAUserScopedUnitNamesItsAccountAndASystemOneMayNot(t *testing.T) {
cases := []struct{ scope, user, wants string }{
{"user", "ops", ""},
{"", "", ""},
@@ -30,7 +30,7 @@ func TestAUserScopedUnitNamesItsAccountAndASystemOneMayNot(t *testing.T) {
}
// novox/hq ADR 0177: lingering is a field of the account, absent meaning nothing asserted.
func TestAnAccountMayBeDeclaredToLinger(t *testing.T) {
func testAnAccountMayBeDeclaredToLinger(t *testing.T) {
d, err := Parse([]byte(`{"declaration":1,"resources":[{"id":"m.login","type":"user","name":"ops","linger":true}]}`))
if err != nil {
t.Fatal(err)
@@ -47,3 +47,9 @@ func TestAnAccountMayBeDeclaredToLinger(t *testing.T) {
t.Fatal("an account that said nothing about lingering asserts it")
}
}
// TestUserscope holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestUserscope(t *testing.T) {
t.Run("AUserScopedUnitNamesItsAccountAndASystemOneMayNot", testAUserScopedUnitNamesItsAccountAndASystemOneMayNot)
t.Run("AnAccountMayBeDeclaredToLinger", testAnAccountMayBeDeclaredToLinger)
}
+12 -4
View File
@@ -46,7 +46,7 @@ func (w *movedWorld) settled() {
// The logins the grant file gives are asked for: made as the grant path makes them, never offered for retirement,
// beside a moved consumer the helper makes from its plan.
func TestAConsumerOnlyTheGrantFileGivesIsAskedForAndMade(t *testing.T) {
func testAConsumerOnlyTheGrantFileGivesIsAskedForAndMade(t *testing.T) {
bound, logins := bindings(1)
w := newMovedWorld(t, bound)
w.a.inv.Active = []string{"mesh_ace_baserow", "mesh_ace_letta", logins[0]}
@@ -78,7 +78,7 @@ func TestAConsumerOnlyTheGrantFileGivesIsAskedForAndMade(t *testing.T) {
}
// A login both a plan and the grant file name is the plan's: made once, with the plan's credential.
func TestALoginAPlanNamesIsNotMadeFromTheGrantFile(t *testing.T) {
func testALoginAPlanNamesIsNotMadeFromTheGrantFile(t *testing.T) {
bound, logins := bindings(1)
w := newMovedWorld(t, bound)
w.bus.bind("ace", "app1", nil)
@@ -93,7 +93,7 @@ func TestALoginAPlanNamesIsNotMadeFromTheGrantFile(t *testing.T) {
}
// An unreadable grant file is not nobody asking (issue 241): nothing is retired while it cannot be read.
func TestAnUnreadableGrantFileRetiresNothing(t *testing.T) {
func testAnUnreadableGrantFileRetiresNothing(t *testing.T) {
bound, logins := bindings(1)
w := newMovedWorld(t, bound)
w.a.inv.Active = []string{"mesh_ace_baserow", logins[0]}
@@ -107,7 +107,7 @@ func TestAnUnreadableGrantFileRetiresNothing(t *testing.T) {
// A login the grant file stops giving is not retired by the provider itself (novox/hq ADR 0570 clause 5): every
// retirement waits for the operator's yes on a provision's key.
func TestALoginTheGrantFileStopsGivingIsRetired(t *testing.T) {
func testALoginTheGrantFileStopsGivingIsRetired(t *testing.T) {
bound, _ := bindings(1)
w := newMovedWorld(t, bound)
w.bus.bind("ace", "app1", nil)
@@ -122,3 +122,11 @@ func TestALoginTheGrantFileStopsGivingIsRetired(t *testing.T) {
t.Fatalf("retired %v, deleted %v, by itself", w.a.removed, w.a.deleted)
}
}
// TestGrantsMoved holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestGrantsMoved(t *testing.T) {
t.Run("AConsumerOnlyTheGrantFileGivesIsAskedForAndMade", testAConsumerOnlyTheGrantFileGivesIsAskedForAndMade)
t.Run("ALoginAPlanNamesIsNotMadeFromTheGrantFile", testALoginAPlanNamesIsNotMadeFromTheGrantFile)
t.Run("AnUnreadableGrantFileRetiresNothing", testAnUnreadableGrantFileRetiresNothing)
t.Run("ALoginTheGrantFileStopsGivingIsRetired", testALoginTheGrantFileStopsGivingIsRetired)
}
+16 -6
View File
@@ -45,7 +45,7 @@ func (w *world) give(given ...map[string]any) {
}
}
func TestAConsumerIsCreatedOnceUnderTheMeshsLoginAndPassword(t *testing.T) {
func testAConsumerIsCreatedOnceUnderTheMeshsLoginAndPassword(t *testing.T) {
w := newWorld(t)
w.give(map[string]any{"as": "mesh_ace_letta", "node": "ace", "values": map[string]any{"name": "letta"}})
w.h.Reconcile(ctx)
@@ -59,7 +59,7 @@ func TestAConsumerIsCreatedOnceUnderTheMeshsLoginAndPassword(t *testing.T) {
}
}
func TestAConsumerNoLongerAskedForIsRetiredOnceStable(t *testing.T) {
func testAConsumerNoLongerAskedForIsRetiredOnceStable(t *testing.T) {
w := newWorld(t)
w.give(map[string]any{"as": "a"}, map[string]any{"as": "b"})
w.h.Reconcile(ctx)
@@ -76,7 +76,7 @@ func TestAConsumerNoLongerAskedForIsRetiredOnceStable(t *testing.T) {
}
}
func TestNothingReadIsNotNobodyAsking(t *testing.T) {
func testNothingReadIsNotNobodyAsking(t *testing.T) {
for name, content := range map[string]string{
"unreadable": "",
"not JSON": "{",
@@ -100,7 +100,7 @@ func TestNothingReadIsNotNobodyAsking(t *testing.T) {
}
}
func TestALostConsumerIsAppliedAgainAndBraked(t *testing.T) {
func testALostConsumerIsAppliedAgainAndBraked(t *testing.T) {
w := newWorld(t)
w.give(map[string]any{"as": "a"})
w.h.Reconcile(ctx)
@@ -120,7 +120,7 @@ func TestALostConsumerIsAppliedAgainAndBraked(t *testing.T) {
}
}
func TestAFailingCreateIsRetriedAndSaidOnce(t *testing.T) {
func testAFailingCreateIsRetriedAndSaidOnce(t *testing.T) {
w := newWorld(t)
w.a.failing = &pgErr{"extension \"nope\" refused, password pw-a"}
w.give(map[string]any{"as": "a"})
@@ -147,8 +147,18 @@ type pgErr struct{ s string }
func (e *pgErr) Error() string { return e.s }
func TestScrubRemovesThePassword(t *testing.T) {
func testScrubRemovesThePassword(t *testing.T) {
if got := scrub(&pgErr{"bad pw a/b c and a%2Fb+c"}, "a/b c"); strings.Contains(got, "a/b c") || strings.Contains(got, "a%2Fb+c") {
t.Fatal(got)
}
}
// TestHarness holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestHarness(t *testing.T) {
t.Run("AConsumerIsCreatedOnceUnderTheMeshsLoginAndPassword", testAConsumerIsCreatedOnceUnderTheMeshsLoginAndPassword)
t.Run("AConsumerNoLongerAskedForIsRetiredOnceStable", testAConsumerNoLongerAskedForIsRetiredOnceStable)
t.Run("NothingReadIsNotNobodyAsking", testNothingReadIsNotNobodyAsking)
t.Run("ALostConsumerIsAppliedAgainAndBraked", testALostConsumerIsAppliedAgainAndBraked)
t.Run("AFailingCreateIsRetriedAndSaidOnce", testAFailingCreateIsRetriedAndSaidOnce)
t.Run("ScrubRemovesThePassword", testScrubRemovesThePassword)
}
+20 -8
View File
@@ -188,7 +188,7 @@ func bindings(n int) (map[[2]string]string, []string) {
}
// The consumers' file makes the same calls on the adapter as the equivalent grant files do (the harness).
func TestTheConsumersFileMakesWhatTheGrantFilesMake(t *testing.T) {
func testTheConsumersFileMakesWhatTheGrantFilesMake(t *testing.T) {
letta := provider.ConsumerIdentity("ace", "letta")
plain := provider.ConsumerIdentity("ace", "plain")
@@ -242,7 +242,7 @@ func TestTheConsumersFileMakesWhatTheGrantFilesMake(t *testing.T) {
// A consumer whose plan goes retires nothing by itself, however long (novox/hq ADR 0570 clause 5): its login is retired,
// never dropped, and its entry removed only once its provision is retiring with the operator's yes.
func TestAConsumerMissingFromOneReadRetiresNothing(t *testing.T) {
func testAConsumerMissingFromOneReadRetiresNothing(t *testing.T) {
bound, logins := bindings(2)
w := newMovedWorld(t, bound)
w.bus.bind("ace", "app1", nil)
@@ -271,7 +271,7 @@ func TestAConsumerMissingFromOneReadRetiresNothing(t *testing.T) {
}
// A plan list that was never read is not nobody asking.
func TestNoPlansReadRetiresNothing(t *testing.T) {
func testNoPlansReadRetiresNothing(t *testing.T) {
bound, _ := bindings(1)
w := newMovedWorld(t, bound)
w.bus.bind("ace", "app1", nil)
@@ -288,7 +288,7 @@ func TestNoPlansReadRetiresNothing(t *testing.T) {
}
// A consumer whose credential is not in the file yet is waited for: nothing is made for it.
func TestAConsumerWithoutACredentialIsWaitedFor(t *testing.T) {
func testAConsumerWithoutACredentialIsWaitedFor(t *testing.T) {
w := newMovedWorld(t, map[[2]string]string{})
w.bus.bind("ace", "letta", map[string]any{"name": "letta"})
outcomes := w.pass()
@@ -301,7 +301,7 @@ func TestAConsumerWithoutACredentialIsWaitedFor(t *testing.T) {
// The grant path restarts itself when the consumers file is first filled.
// A consumer whose module has a slug keeps the login its plan names, the slug first (issue 788): the adapter makes it
// under that login, and the retirement counts it as asked for, so a pass retires nothing.
func TestASluggedConsumerKeepsTheLoginItsPlanNames(t *testing.T) {
func testASluggedConsumerKeepsTheLoginItsPlanNames(t *testing.T) {
agent := provider.ConsumerIdentity("ace", "agent")
w := newMovedWorld(t, map[[2]string]string{{"ace", "claude-code"}: "pw-agent"})
w.bus.putPlan("ace", "claude-code", map[string]any{"provision": ProvisionName, "provider": "novox",
@@ -328,7 +328,7 @@ func TestASluggedConsumerKeepsTheLoginItsPlanNames(t *testing.T) {
// A provider whose spec names the plan's `as` as the login and no grant file (the keycloak shape) makes the consumer
// under that name with the values its spec composes, and a grant file that cannot be read does not hold up its
// retirement pass.
func TestASpecWithoutGrantsMakesUnderThePlansAsAndIgnoresTheGrantFile(t *testing.T) {
func testASpecWithoutGrantsMakesUnderThePlansAsAndIgnoresTheGrantFile(t *testing.T) {
a := &recorder{}
bus := &bucketBus{buckets: map[string]map[string][]byte{}}
now := time.Date(2026, 10, 15, 12, 0, 0, 0, time.UTC)
@@ -391,7 +391,7 @@ var keycloakSpec = MovedSpec{Module: "keycloak", Provision: ProvisionName,
// The consumers' file makes the same call on the adapter as the equivalent grant file does (the harness), for a
// provider of the keycloak shape: the same client id, secret and values; and the entry tells the consumer what the
// provider serves.
func TestTheConsumersFileMakesWhatTheGrantFileMakesForTheKeycloakShape(t *testing.T) {
func testTheConsumersFileMakesWhatTheGrantFileMakesForTheKeycloakShape(t *testing.T) {
grafana := provider.ConsumerIdentity("home", "grafana")
values := map[string]any{"name": grafanaNames["name"], "internal-name": grafanaNames["internal-name"]}
for k, v := range grafanaContributes {
@@ -439,7 +439,7 @@ func TestTheConsumersFileMakesWhatTheGrantFileMakesForTheKeycloakShape(t *testin
}
// A consumer whose plan names its client id (a slugged module) keeps it, and the retirement counts it as asked for.
func TestAConsumerNamedByItsPlanKeepsItsClientId(t *testing.T) {
func testAConsumerNamedByItsPlanKeepsItsClientId(t *testing.T) {
agent := provider.ConsumerIdentity("home", "dashboard")
w := newMovedWorldOf(t, map[[2]string]string{{"home", "grafana-2"}: "pw"}, keycloakSpec)
w.bus.putPlan("home", "grafana-2", map[string]any{"provision": ProvisionName, "provider": "novox", "provider-module": "keycloak",
@@ -462,3 +462,15 @@ func TestAConsumerNamedByItsPlanKeepsItsClientId(t *testing.T) {
t.Fatalf("retired %v: the plan's client id was counted unasked", w.a.removed)
}
}
// TestMoved holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestMoved(t *testing.T) {
t.Run("TheConsumersFileMakesWhatTheGrantFilesMake", testTheConsumersFileMakesWhatTheGrantFilesMake)
t.Run("AConsumerMissingFromOneReadRetiresNothing", testAConsumerMissingFromOneReadRetiresNothing)
t.Run("NoPlansReadRetiresNothing", testNoPlansReadRetiresNothing)
t.Run("AConsumerWithoutACredentialIsWaitedFor", testAConsumerWithoutACredentialIsWaitedFor)
t.Run("ASluggedConsumerKeepsTheLoginItsPlanNames", testASluggedConsumerKeepsTheLoginItsPlanNames)
t.Run("ASpecWithoutGrantsMakesUnderThePlansAsAndIgnoresTheGrantFile", testASpecWithoutGrantsMakesUnderThePlansAsAndIgnoresTheGrantFile)
t.Run("TheConsumersFileMakesWhatTheGrantFileMakesForTheKeycloakShape", testTheConsumersFileMakesWhatTheGrantFileMakesForTheKeycloakShape)
t.Run("AConsumerNamedByItsPlanKeepsItsClientId", testAConsumerNamedByItsPlanKeepsItsClientId)
}
+38 -17
View File
@@ -148,7 +148,7 @@ func namesOf(body map[string]any) string {
// settle passes every five seconds until the same answer has held for StableFor, and one pass more.
func (w *world) settle() { w.passes(StableFor + 5*time.Second) }
func TestATransientEmptyListForFourPassesRetiresNothing(t *testing.T) {
func testATransientEmptyListForFourPassesRetiresNothing(t *testing.T) {
w, said := standingWorld(t)
given := holding(w, 1)
w.give()
@@ -164,7 +164,7 @@ func TestATransientEmptyListForFourPassesRetiresNothing(t *testing.T) {
// Five identical passes are twenty-five seconds — shorter than a controller restart. Both must hold:
// five passes AND ten minutes of the same answer (novox/hq ADR 0230).
func TestFivePassesInTwentyFiveSecondsRetireNothingTenMinutesDo(t *testing.T) {
func testFivePassesInTwentyFiveSecondsRetireNothingTenMinutesDo(t *testing.T) {
w, said := standingWorld(t)
holding(w, 1)
w.give()
@@ -198,7 +198,7 @@ func TestFivePassesInTwentyFiveSecondsRetireNothingTenMinutesDo(t *testing.T) {
}
}
func TestAStableSetIsRetiredAndAskedAgainReEnables(t *testing.T) {
func testAStableSetIsRetiredAndAskedAgainReEnables(t *testing.T) {
w, said := standingWorld(t)
given := holding(w, 3)
w.give(given[:2]...)
@@ -229,7 +229,7 @@ func TestAStableSetIsRetiredAndAskedAgainReEnables(t *testing.T) {
}
}
func TestAnUnreadablePassStartsTheCountAgain(t *testing.T) {
func testAnUnreadablePassStartsTheCountAgain(t *testing.T) {
w := newWorld(t)
holding(w, 1)
w.give()
@@ -247,7 +247,7 @@ func TestAnUnreadablePassStartsTheCountAgain(t *testing.T) {
}
}
func TestADifferentSetStartsTheCountAgain(t *testing.T) {
func testADifferentSetStartsTheCountAgain(t *testing.T) {
w := newWorld(t)
given := holding(w, 5)
w.give(given[:4]...)
@@ -263,7 +263,7 @@ func TestADifferentSetStartsTheCountAgain(t *testing.T) {
}
}
func TestAdditionsAndChangesAreNeverDelayed(t *testing.T) {
func testAdditionsAndChangesAreNeverDelayed(t *testing.T) {
w := newWorld(t)
holding(w, 1)
w.give(map[string]any{"as": "c1", "node": "anchor"}, map[string]any{"as": "c2"})
@@ -278,7 +278,7 @@ func TestAdditionsAndChangesAreNeverDelayed(t *testing.T) {
}
}
func TestTooManyWaitsForAPersonAndApproveRetiresExactlyThatSet(t *testing.T) {
func testTooManyWaitsForAPersonAndApproveRetiresExactlyThatSet(t *testing.T) {
w, said := standingWorld(t)
holding(w, 4)
w.give()
@@ -327,7 +327,7 @@ func TestTooManyWaitsForAPersonAndApproveRetiresExactlyThatSet(t *testing.T) {
}
}
func TestRejectedIsKeptAndNotAskedAgainUntilTheSetChanges(t *testing.T) {
func testRejectedIsKeptAndNotAskedAgainUntilTheSetChanges(t *testing.T) {
w, said := standingWorld(t)
given := holding(w, 4)
w.give()
@@ -372,7 +372,7 @@ func TestRejectedIsKeptAndNotAskedAgainUntilTheSetChanges(t *testing.T) {
}
}
func TestAWaitingSetAskedForAgainSettles(t *testing.T) {
func testAWaitingSetAskedForAgainSettles(t *testing.T) {
w, said := standingWorld(t)
given := holding(w, 4)
w.give()
@@ -387,7 +387,7 @@ func TestAWaitingSetAskedForAgainSettles(t *testing.T) {
}
}
func TestDeleteRemovesOnlyThatRetiredConsumer(t *testing.T) {
func testDeleteRemovesOnlyThatRetiredConsumer(t *testing.T) {
w, said := standingWorld(t)
given := holding(w, 5)
w.give(given[:3]...)
@@ -423,7 +423,7 @@ func TestDeleteRemovesOnlyThatRetiredConsumer(t *testing.T) {
}
}
func TestTheBound(t *testing.T) {
func testTheBound(t *testing.T) {
h := &Harness{}
h.init()
for _, c := range []struct{ n, held int }{{1, 1}, {1, 2}, {1, 3}, {3, 7}, {3, 6}, {2, 5}} {
@@ -438,7 +438,7 @@ func TestTheBound(t *testing.T) {
}
}
func TestARestartRetiresWhatTheBackendHoldsUnaskedAndAdoptsWhatItFindsDisabled(t *testing.T) {
func testARestartRetiresWhatTheBackendHoldsUnaskedAndAdoptsWhatItFindsDisabled(t *testing.T) {
w, said := standingWorld(t)
w.a.inv = Inventory{Active: []string{"kept", "orphan"}, Retired: []Retired{
{Consumer: "locked-before", SizeBytes: 7, Kind: KindConsumer},
@@ -458,7 +458,7 @@ func TestARestartRetiresWhatTheBackendHoldsUnaskedAndAdoptsWhatItFindsDisabled(t
}
}
func TestABackendThatCannotBeListedIsSaidAndAskedAgain(t *testing.T) {
func testABackendThatCannotBeListedIsSaidAndAskedAgain(t *testing.T) {
w := newWorld(t)
w.a.invErr = errors.New("connection refused")
holding(w, 1)
@@ -474,7 +474,7 @@ func TestABackendThatCannotBeListedIsSaidAndAskedAgain(t *testing.T) {
}
}
func TestTheToolsAnswer(t *testing.T) {
func testTheToolsAnswer(t *testing.T) {
w, _ := standingWorld(t)
holding(w, 4)
w.give()
@@ -512,7 +512,7 @@ func TestTheToolsAnswer(t *testing.T) {
}
}
func TestAFailingConsumerRetiredIsSaidRecovered(t *testing.T) {
func testAFailingConsumerRetiredIsSaidRecovered(t *testing.T) {
w, said := standingWorld(t)
given := holding(w, 2)
w.a.held = false
@@ -542,7 +542,7 @@ func everyWord(t *testing.T) (*world, *[]announced) {
// A restarted provider that finds every consumer it holds asked for says once that nothing waits, so the controller
// clears a waiting condition an earlier process raised and this one never knew (issue 937); it says it no more.
func TestARestartedProviderSaysOnceThatNothingWaits(t *testing.T) {
func testARestartedProviderSaysOnceThatNothingWaits(t *testing.T) {
w, said := everyWord(t)
holding(w, 2)
w.pass()
@@ -559,7 +559,7 @@ func TestARestartedProviderSaysOnceThatNothingWaits(t *testing.T) {
}
// A provider whose own set waits does not say that nothing waits.
func TestAProviderThatWaitsDoesNotSayNothingWaits(t *testing.T) {
func testAProviderThatWaitsDoesNotSayNothingWaits(t *testing.T) {
w, said := everyWord(t)
w.a.inv.Active = []string{"c1", "c2", "c3", "c4", "c5"}
w.give(map[string]any{"as": "c1", "node": "anchor"})
@@ -573,3 +573,24 @@ func TestAProviderThatWaitsDoesNotSayNothingWaits(t *testing.T) {
t.Fatal("nothing waited: the test does not hold the case")
}
}
// TestRetirement holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestRetirement(t *testing.T) {
t.Run("ATransientEmptyListForFourPassesRetiresNothing", testATransientEmptyListForFourPassesRetiresNothing)
t.Run("FivePassesInTwentyFiveSecondsRetireNothingTenMinutesDo", testFivePassesInTwentyFiveSecondsRetireNothingTenMinutesDo)
t.Run("AStableSetIsRetiredAndAskedAgainReEnables", testAStableSetIsRetiredAndAskedAgainReEnables)
t.Run("AnUnreadablePassStartsTheCountAgain", testAnUnreadablePassStartsTheCountAgain)
t.Run("ADifferentSetStartsTheCountAgain", testADifferentSetStartsTheCountAgain)
t.Run("AdditionsAndChangesAreNeverDelayed", testAdditionsAndChangesAreNeverDelayed)
t.Run("TooManyWaitsForAPersonAndApproveRetiresExactlyThatSet", testTooManyWaitsForAPersonAndApproveRetiresExactlyThatSet)
t.Run("RejectedIsKeptAndNotAskedAgainUntilTheSetChanges", testRejectedIsKeptAndNotAskedAgainUntilTheSetChanges)
t.Run("AWaitingSetAskedForAgainSettles", testAWaitingSetAskedForAgainSettles)
t.Run("DeleteRemovesOnlyThatRetiredConsumer", testDeleteRemovesOnlyThatRetiredConsumer)
t.Run("TheBound", testTheBound)
t.Run("ARestartRetiresWhatTheBackendHoldsUnaskedAndAdoptsWhatItFindsDisabled", testARestartRetiresWhatTheBackendHoldsUnaskedAndAdoptsWhatItFindsDisabled)
t.Run("ABackendThatCannotBeListedIsSaidAndAskedAgain", testABackendThatCannotBeListedIsSaidAndAskedAgain)
t.Run("TheToolsAnswer", testTheToolsAnswer)
t.Run("AFailingConsumerRetiredIsSaidRecovered", testAFailingConsumerRetiredIsSaidRecovered)
t.Run("ARestartedProviderSaysOnceThatNothingWaits", testARestartedProviderSaysOnceThatNothingWaits)
t.Run("AProviderThatWaitsDoesNotSayNothingWaits", testAProviderThatWaitsDoesNotSayNothingWaits)
}
+20 -8
View File
@@ -47,7 +47,7 @@ func events(said []announced) string {
return strings.Join(out, ",")
}
func TestAConsumerFailedForMinutesIsAnnouncedNamingItAndTheClass(t *testing.T) {
func testAConsumerFailedForMinutesIsAnnouncedNamingItAndTheClass(t *testing.T) {
w, said := standingWorld(t)
w.a.failing = errors.New(`token request failed: 401 {"error":"invalid_grant","error_description":"Invalid user credentials"}`)
w.give(map[string]any{"as": "mesh_home_grafana", "node": "home-server"})
@@ -87,7 +87,7 @@ func TestAConsumerFailedForMinutesIsAnnouncedNamingItAndTheClass(t *testing.T) {
}
}
func TestOneSuccessBetweenFailuresStartsTheRunAgain(t *testing.T) {
func testOneSuccessBetweenFailuresStartsTheRunAgain(t *testing.T) {
w, said := standingWorld(t)
w.a.failing = errors.New("connection refused")
w.give(map[string]any{"as": "a"})
@@ -104,7 +104,7 @@ func TestOneSuccessBetweenFailuresStartsTheRunAgain(t *testing.T) {
// The check that failed for a day on 2026-10-05: clients already made, every minute's check refused
// at the token. A check that cannot be asked is a failure too.
func TestACheckThatKeepsFailingIsAFailureToo(t *testing.T) {
func testACheckThatKeepsFailingIsAFailureToo(t *testing.T) {
w, said := standingWorld(t)
w.give(map[string]any{"as": "a"})
w.h.Reconcile(ctx)
@@ -120,7 +120,7 @@ func TestACheckThatKeepsFailingIsAFailureToo(t *testing.T) {
}
}
func TestAnUnreadableSecretIsAnnouncedAsSuch(t *testing.T) {
func testAnUnreadableSecretIsAnnouncedAsSuch(t *testing.T) {
w, said := standingWorld(t)
w.give(map[string]any{"as": "a"})
os.Remove(w.dir + "/a.secret")
@@ -130,7 +130,7 @@ func TestAnUnreadableSecretIsAnnouncedAsSuch(t *testing.T) {
}
}
func TestAConsumerNoLongerAskedForIsNoLongerFailing(t *testing.T) {
func testAConsumerNoLongerAskedForIsNoLongerFailing(t *testing.T) {
w, said := standingWorld(t)
w.a.failing = errors.New("boom")
w.give(map[string]any{"as": "a"}, map[string]any{"as": "b"})
@@ -146,7 +146,7 @@ func TestAConsumerNoLongerAskedForIsNoLongerFailing(t *testing.T) {
}
}
func TestAnErrorIsClassedByItsWords(t *testing.T) {
func testAnErrorIsClassedByItsWords(t *testing.T) {
for text, want := range map[string]string{
`Keycloak token request failed: 401 {"error":"invalid_grant"}`: ClassCredentials,
`FATAL: password authentication failed for user "postgres"`: ClassCredentials,
@@ -160,7 +160,7 @@ func TestAnErrorIsClassedByItsWords(t *testing.T) {
}
}
func TestAnAdapterThatClassesItsOwnErrorsIsBelieved(t *testing.T) {
func testAnAdapterThatClassesItsOwnErrorsIsBelieved(t *testing.T) {
w, said := standingWorld(t)
w.h.Adapter = classing{w.a}
w.a.failing = errors.New("anything")
@@ -177,7 +177,7 @@ func (classing) Class(error) string { return "its-own" }
// A provider restarted after announcing a failure has forgotten it; its first success for each
// consumer is announced, so the controller clears what it kept rather than naming it for ever.
func TestTheFirstSuccessSinceStartIsAnnouncedOnce(t *testing.T) {
func testTheFirstSuccessSinceStartIsAnnouncedOnce(t *testing.T) {
w := newWorld(t)
var said []announced
w.h.Announce = func(e string, b map[string]any) {
@@ -191,3 +191,15 @@ func TestTheFirstSuccessSinceStartIsAnnouncedOnce(t *testing.T) {
t.Fatalf("%v", said)
}
}
// TestStanding holds this file's cases, each a subtest of its own name (mesh-sdk's test budget: at most 500 unit tests).
func TestStanding(t *testing.T) {
t.Run("AConsumerFailedForMinutesIsAnnouncedNamingItAndTheClass", testAConsumerFailedForMinutesIsAnnouncedNamingItAndTheClass)
t.Run("OneSuccessBetweenFailuresStartsTheRunAgain", testOneSuccessBetweenFailuresStartsTheRunAgain)
t.Run("ACheckThatKeepsFailingIsAFailureToo", testACheckThatKeepsFailingIsAFailureToo)
t.Run("AnUnreadableSecretIsAnnouncedAsSuch", testAnUnreadableSecretIsAnnouncedAsSuch)
t.Run("AConsumerNoLongerAskedForIsNoLongerFailing", testAConsumerNoLongerAskedForIsNoLongerFailing)
t.Run("AnErrorIsClassedByItsWords", testAnErrorIsClassedByItsWords)
t.Run("AnAdapterThatClassesItsOwnErrorsIsBelieved", testAnAdapterThatClassesItsOwnErrorsIsBelieved)
t.Run("TheFirstSuccessSinceStartIsAnnouncedOnce", testTheFirstSuccessSinceStartIsAnnouncedOnce)
}