diff --git a/go/bus_waits_for_serve_test.go b/go/bus_waits_for_serve_test.go index 90502be2..a1e5abf1 100644 --- a/go/bus_waits_for_serve_test.go +++ b/go/bus_waits_for_serve_test.go @@ -9,7 +9,7 @@ import ( // A bus function called before Serve waits for Serve and proceeds (issue 1966): a module that starts a goroutine // before stdio.Serve and calls the bus there is no longer refused. It is refused only when the process never serves. // The test drives the wait itself: serveWait is the test's own timer channel, no row sleeps on a clock. -func TestBusFunctionsWaitForServe(t *testing.T) { +func subBusFunctionsWaitForServe(t *testing.T) { const refusal = "before Serve: a bundle reaches the bus through the runtime that launched it" for _, tc := range []struct { name string @@ -72,3 +72,10 @@ func TestBusFunctionsWaitForServe(t *testing.T) { }) } } + +// TestBusFunctionsWaitForServe runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestBusFunctionsWaitForServe(t *testing.T) { + t.Run("BusFunctionsWaitForServe", subBusFunctionsWaitForServe) + t.Run("ACapabilityWordIsReadOnceAndNamedWhenNotStated", subACapabilityWordIsReadOnceAndNamedWhenNotStated) + t.Run("ABundleAsksAnAcknowledgedPublishAndASubscriptionForNewMessages", subABundleAsksAnAcknowledgedPublishAndASubscriptionForNewMessages) +} diff --git a/go/busarchive/verifyfile_test.go b/go/busarchive/verifyfile_test.go index be62737f..26a89d46 100644 --- a/go/busarchive/verifyfile_test.go +++ b/go/busarchive/verifyfile_test.go @@ -80,7 +80,7 @@ func put(t *testing.T, dir, name string, b []byte, at time.Time) { os.Chtimes(p, at, at) } -func TestAGoodSnapshotPassesAndSaysItsStreams(t *testing.T) { +func subAGoodSnapshotPassesAndSaysItsStreams(t *testing.T) { dir := t.TempDir() good := snapshotTar(t, nil) put(t, dir, "bus.tar", good, time.Now()) @@ -99,7 +99,7 @@ func TestAGoodSnapshotPassesAndSaysItsStreams(t *testing.T) { } } -func TestACorruptedChecksumFailsNamingTheFile(t *testing.T) { +func subACorruptedChecksumFailsNamingTheFile(t *testing.T) { dir := t.TempDir() put(t, dir, "bus.tar", snapshotTar(t, func(m *Manifest, files map[string][]byte) { m.Streams[1].ArchiveSHA256 = sum([]byte("something else")) @@ -116,7 +116,7 @@ func TestACorruptedChecksumFailsNamingTheFile(t *testing.T) { } } -func TestATruncatedSnapshotFails(t *testing.T) { +func subATruncatedSnapshotFails(t *testing.T) { dir := t.TempDir() good := snapshotTar(t, nil) put(t, dir, "bus.tar", good[:len(good)*2/3], time.Now()) @@ -129,7 +129,7 @@ func TestATruncatedSnapshotFails(t *testing.T) { } } -func TestAnArchiveThatDoesNotReadToItsEndFailsEvenWithMatchingChecksums(t *testing.T) { +func subAnArchiveThatDoesNotReadToItsEndFailsEvenWithMatchingChecksums(t *testing.T) { dir := t.TempDir() put(t, dir, "bus.tar", snapshotTar(t, func(m *Manifest, files map[string][]byte) { bad := []byte("not an s2 stream at all") @@ -143,7 +143,7 @@ func TestAnArchiveThatDoesNotReadToItsEndFailsEvenWithMatchingChecksums(t *testi } } -func TestTheNewestTarIsVerifiedAndOnlyInsideTheDirectory(t *testing.T) { +func subTheNewestTarIsVerifiedAndOnlyInsideTheDirectory(t *testing.T) { dir := t.TempDir() now := time.Now() put(t, dir, "old.tar", []byte("junk"), now.Add(-48*time.Hour)) @@ -171,3 +171,12 @@ func TestTheNewestTarIsVerifiedAndOnlyInsideTheDirectory(t *testing.T) { t.Error("an empty directory is not a snapshot") } } + +// TestAGoodSnapshotPassesAndSaysItsStreams runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestAGoodSnapshotPassesAndSaysItsStreams(t *testing.T) { + t.Run("AGoodSnapshotPassesAndSaysItsStreams", subAGoodSnapshotPassesAndSaysItsStreams) + t.Run("ACorruptedChecksumFailsNamingTheFile", subACorruptedChecksumFailsNamingTheFile) + t.Run("ATruncatedSnapshotFails", subATruncatedSnapshotFails) + t.Run("AnArchiveThatDoesNotReadToItsEndFailsEvenWithMatchingChecksums", subAnArchiveThatDoesNotReadToItsEndFailsEvenWithMatchingChecksums) + t.Run("TheNewestTarIsVerifiedAndOnlyInsideTheDirectory", subTheNewestTarIsVerifiedAndOnlyInsideTheDirectory) +} diff --git a/go/buscalls/buscalls_test.go b/go/buscalls/buscalls_test.go deleted file mode 100644 index 1779aa6e..00000000 --- a/go/buscalls/buscalls_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package buscalls - -import ( - "encoding/json" - "testing" -) - -// Design 47 G §587, §622: the ledger's upkeep calls have their requests and answers, and every family its word. -func TestTheLedgerUpkeepCallsAndTheirWords(t *testing.T) { - var removal LedgerRemoveRequest - if err := json.Unmarshal([]byte(`{"ledger":"records","instance":"r1"}`), &removal); err != nil || removal.Ledger != "records" || removal.Instance != "r1" { - t.Errorf("the removal read as %+v (%v)", removal, err) - } - raw, _ := json.Marshal(LedgerRemoved{Instance: "r1", Operations: 3, Bytes: 900}) - if string(raw) != `{"instance":"r1","operations":3,"bytes":900}` { - t.Errorf("the removal's answer reads %s", raw) - } - raw, _ = json.Marshal(Fill{Count: 2, Bytes: 10, MaxBytes: 100}) - if string(raw) != `{"count":2,"bytes":10,"max_bytes":100}` || LedgerFill != "mesh/ledger.fill" || LedgerRemove != "mesh/ledger.remove" { - t.Errorf("the fill reads %s, calls %s %s", raw, LedgerFill, LedgerRemove) - } - for word, want := range map[string]string{BusStateCalls: "bus-state-calls", LedgerCalls: "ledger-calls", - LedgerUpkeepCalls: "ledger-upkeep-calls", SentObjectsCalls: "sent-objects-calls"} { - if word != want { - t.Errorf("the word %q is %q", want, word) - } - } -} diff --git a/go/busretry/busretry_test.go b/go/busretry/busretry_test.go index 88ba04f6..53883f6f 100644 --- a/go/busretry/busretry_test.go +++ b/go/busretry/busretry_test.go @@ -14,7 +14,7 @@ import ( // Issue 774 (bus blackouts at every user-list reload): only a request that reached no one is asked again, within the // bound; a blackout probe that says the bus answers ends the wait at once. -func TestABusThatAnswersNothingIsWaitedOut(t *testing.T) { +func subABusThatAnswersNothingIsWaitedOut(t *testing.T) { for _, row := range []struct { name string errs []error // what each try answers; the last repeats @@ -71,7 +71,7 @@ func TestABusThatAnswersNothingIsWaitedOut(t *testing.T) { // Design 47 G §351, §460: a kept call is asked again only while its key is open and not replaced; an error of `open` is // logged naming the key and the ask is made again. -func TestAKeptCallIsAskedAgainOnlyWhileItsKeyIsOpen(t *testing.T) { +func subAKeptCallIsAskedAgainOnlyWhileItsKeyIsOpen(t *testing.T) { for _, row := range []struct { name string open func(n int) (bool, error) // by the number of asks made so far @@ -109,3 +109,9 @@ func TestAKeptCallIsAskedAgainOnlyWhileItsKeyIsOpen(t *testing.T) { t.Errorf("a kept call with no open function was made") } } + +// TestABusThatAnswersNothingIsWaitedOut runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestABusThatAnswersNothingIsWaitedOut(t *testing.T) { + t.Run("ABusThatAnswersNothingIsWaitedOut", subABusThatAnswersNothingIsWaitedOut) + t.Run("AKeptCallIsAskedAgainOnlyWhileItsKeyIsOpen", subAKeptCallIsAskedAgainOnlyWhileItsKeyIsOpen) +} diff --git a/go/busstate/buscalls_test.go b/go/busstate/buscalls_test.go new file mode 100644 index 00000000..d682afc9 --- /dev/null +++ b/go/busstate/buscalls_test.go @@ -0,0 +1,30 @@ +package busstate + +import ( + "encoding/json" + "testing" + + "git.novox.be/novox/mesh-sdk/go/buscalls" +) + +// Design 47 G §587, §622: the ledger's upkeep calls have their requests and answers, and every family its word. +func subTheLedgerUpkeepCallsAndTheirWords(t *testing.T) { + var removal buscalls.LedgerRemoveRequest + if err := json.Unmarshal([]byte(`{"ledger":"records","instance":"r1"}`), &removal); err != nil || removal.Ledger != "records" || removal.Instance != "r1" { + t.Errorf("the removal read as %+v (%v)", removal, err) + } + raw, _ := json.Marshal(buscalls.LedgerRemoved{Instance: "r1", Operations: 3, Bytes: 900}) + if string(raw) != `{"instance":"r1","operations":3,"bytes":900}` { + t.Errorf("the removal's answer reads %s", raw) + } + raw, _ = json.Marshal(buscalls.Fill{Count: 2, Bytes: 10, MaxBytes: 100}) + if string(raw) != `{"count":2,"bytes":10,"max_bytes":100}` || buscalls.LedgerFill != "mesh/ledger.fill" || buscalls.LedgerRemove != "mesh/ledger.remove" { + t.Errorf("the fill reads %s, calls %s %s", raw, buscalls.LedgerFill, buscalls.LedgerRemove) + } + for word, want := range map[string]string{buscalls.BusStateCalls: "bus-state-calls", buscalls.LedgerCalls: "ledger-calls", + buscalls.LedgerUpkeepCalls: "ledger-upkeep-calls", buscalls.SentObjectsCalls: "sent-objects-calls"} { + if word != want { + t.Errorf("the word %q is %q", want, word) + } + } +} diff --git a/go/busstate/busstate_test.go b/go/busstate/busstate_test.go index 3d1c3652..549d9725 100644 --- a/go/busstate/busstate_test.go +++ b/go/busstate/busstate_test.go @@ -14,7 +14,7 @@ import ( // A bundle keeps objects in its own object store through the runtime (ADR 0595 §2, §9; A3's request for distribution's // incoming): each call is the runtime's method of buscalls, naming the store by its local name, and answers as the // runtime answered; a method that is no bus-state call is refused before the runtime is asked. -func TestABundleKeepsObjectsThroughTheRuntime(t *testing.T) { +func subABundleKeepsObjectsThroughTheRuntime(t *testing.T) { t.Setenv(stdio.ServedAs, "distribution") inR, inW := io.Pipe() outR, outW := io.Pipe() @@ -100,3 +100,10 @@ func TestABundleKeepsObjectsThroughTheRuntime(t *testing.T) { t.Errorf("put asked %v", p) } } + +// TestABundleKeepsObjectsThroughTheRuntime runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestABundleKeepsObjectsThroughTheRuntime(t *testing.T) { + t.Run("ABundleKeepsObjectsThroughTheRuntime", subABundleKeepsObjectsThroughTheRuntime) + t.Run("TheLedgerUpkeepCallsAndTheirWords", subTheLedgerUpkeepCallsAndTheirWords) + t.Run("AValueLargerThanOneChunkIsPutAndGotBySession", subAValueLargerThanOneChunkIsPutAndGotBySession) +} diff --git a/go/busstate/session_test.go b/go/busstate/session_test.go index 7a9a3691..ab129c71 100644 --- a/go/busstate/session_test.go +++ b/go/busstate/session_test.go @@ -62,7 +62,7 @@ func serveRuntime(t *testing.T, fn func(), handle func(method string, params map // Design 47 G §518, §345, §490 (A-21): a value larger than one chunk is put as chunks in order under one call id, each // answered before the next, with the store named in each; a get the runtime answers as a session is read chunk by chunk and // checked against its digest. -func TestAValueLargerThanOneChunkIsPutAndGotBySession(t *testing.T) { +func subAValueLargerThanOneChunkIsPutAndGotBySession(t *testing.T) { value := bytes.Repeat([]byte("0123456789abcdef"), (2*buscalls.ChunkBytes+1000)/16) sum := sha256.Sum256(value) digest := "sha256:" + hex.EncodeToString(sum[:]) diff --git a/go/capabilities_test.go b/go/capabilities_test.go index 60532202..a8e65adb 100644 --- a/go/capabilities_test.go +++ b/go/capabilities_test.go @@ -9,7 +9,7 @@ import ( // Design 47 G §576: the words are read once, an unknown-call answer reads as none, and a word not stated fails naming it // and the node (from MESH_NODE). -func TestACapabilityWordIsReadOnceAndNamedWhenNotStated(t *testing.T) { +func subACapabilityWordIsReadOnceAndNamedWhenNotStated(t *testing.T) { t.Setenv("MESH_NODE", "ace") asked := 0 var c capabilityWords diff --git a/go/catalogue/a_service_process_test.go b/go/catalogue/a_service_process_test.go index 7762e24e..99b04be9 100644 --- a/go/catalogue/a_service_process_test.go +++ b/go/catalogue/a_service_process_test.go @@ -54,7 +54,7 @@ func indexOf(out []map[string]any, id string) int { // otherwise — and the controller declares the verbs it answers as tools. Its service bundle is run // by its own process; launched a second time by the runtime it would be a second controller // pretending to be an MCP server. -func TestABundleItsOwnProcessRunsIsNotServedByTheRuntime(t *testing.T) { +func subABundleItsOwnProcessRunsIsNotServedByTheRuntime(t *testing.T) { m := aServiceModule(t) if len(m.Bundles) != 1 { t.Fatalf("the service's bundle was not kept: %+v", m.Bundles) @@ -75,3 +75,10 @@ func TestABundleItsOwnProcessRunsIsNotServedByTheRuntime(t *testing.T) { t.Fatalf("a tools bundle nothing runs is no longer served: %v", loads) } } + +// TestABundleItsOwnProcessRunsIsNotServedByTheRuntime runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestABundleItsOwnProcessRunsIsNotServedByTheRuntime(t *testing.T) { + t.Run("ABundleItsOwnProcessRunsIsNotServedByTheRuntime", subABundleItsOwnProcessRunsIsNotServedByTheRuntime) + t.Run("TheBusNamesOfAnEntryAreOneRule", subTheBusNamesOfAnEntryAreOneRule) + t.Run("AStarEmitterHearsEachDeclaringModulesUnrestrictedStream", subAStarEmitterHearsEachDeclaringModulesUnrestrictedStream) +} diff --git a/go/catalogue/busnames_test.go b/go/catalogue/busnames_test.go index 087b6484..81990c2e 100644 --- a/go/catalogue/busnames_test.go +++ b/go/catalogue/busnames_test.go @@ -7,7 +7,7 @@ import ( // ADR 0666 §16: the bus names of an entry are one rule. A state entry answers its bucket's stream and the stream of // its object store; a local name that meets a name the mesh makes is a clash for the judge. -func TestTheBusNamesOfAnEntryAreOneRule(t *testing.T) { +func subTheBusNamesOfAnEntryAreOneRule(t *testing.T) { state := BusStateEntry{Name: "views", Storage: StorageKeyValue, Template: TemplateState} rows := []struct { name string diff --git a/go/catalogue/streams_test.go b/go/catalogue/streams_test.go index 4785fdf8..66ee46a2 100644 --- a/go/catalogue/streams_test.go +++ b/go/catalogue/streams_test.go @@ -155,7 +155,7 @@ func TestNarrowingTwoPatterns(t *testing.T) { // Design 47 G §386: `*.` reaches the unrestricted stream of each module that declares the event, and never a // restricted one; a wildcard before anything wider still reaches none. -func TestAStarEmitterHearsEachDeclaringModulesUnrestrictedStream(t *testing.T) { +func subAStarEmitterHearsEachDeclaringModulesUnrestrictedStream(t *testing.T) { mail, err := decodeForTest([]byte(mailManifest(t, mailStream, `"emits":["account.added"],`))) if err != nil { t.Fatal(err) diff --git a/go/process/account_test.go b/go/process/account_test.go index 12fbc3b8..03620ef3 100644 --- a/go/process/account_test.go +++ b/go/process/account_test.go @@ -19,7 +19,7 @@ import ( // 1171/AC2: given an account file broker- in the controller's form {url, fingerprint, node, // module, user, password, claims}, when the process package reads it, then it yields those fields and // tolerates claims. -func TestReadAccountYieldsEveryFieldAndToleratesClaims(t *testing.T) { +func subReadAccountYieldsEveryFieldAndToleratesClaims(t *testing.T) { path := writeAccount(t, map[string]any{ "url": "nats://novox:4222", "fingerprint": "sha256:ab", "node": "novox", "module": "mesh-mail", "user": "novox.mesh-mail.send", "password": "secret-pw", @@ -297,7 +297,7 @@ func TestModuleAccountNamesAndDialOptions(t *testing.T) { // W1.3 (design 47 *The fingerprint handover*): a process's own build is the fingerprint the node-engine handed it, read // once at its start; with none, or with one that is no single word, it says its own build is unknown and why. -func TestTheOwnBuildIsTheFingerprintTheProcessWasStartedWith(t *testing.T) { +func subTheOwnBuildIsTheFingerprintTheProcessWasStartedWith(t *testing.T) { for _, c := range []struct{ name, env, fp, unknown string }{ {"handed", "src2:1480985e", "src2:1480985e", ""}, {"handed with spaces around", " src2:1480985e\n", "src2:1480985e", ""}, @@ -341,3 +341,9 @@ func TestTheOwnBuildIsTheFingerprintTheProcessWasStartedWith(t *testing.T) { } } } + +// TestReadAccountYieldsEveryFieldAndToleratesClaims runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestReadAccountYieldsEveryFieldAndToleratesClaims(t *testing.T) { + t.Run("ReadAccountYieldsEveryFieldAndToleratesClaims", subReadAccountYieldsEveryFieldAndToleratesClaims) + t.Run("TheOwnBuildIsTheFingerprintTheProcessWasStartedWith", subTheOwnBuildIsTheFingerprintTheProcessWasStartedWith) +} diff --git a/go/process/event_hub_integration_test.go b/go/process/event_hub_integration_test.go index f3bcd924..749928a9 100644 --- a/go/process/event_hub_integration_test.go +++ b/go/process/event_hub_integration_test.go @@ -17,7 +17,7 @@ import ( // A module whose consumer the bus makes after the module started is not lost for that order: the hub tries again after // each wait and calls live once it is bound (the checker's "until it starts again" hole). -func TestTheHubBindsALateConsumerAndSaysItIsLive(t *testing.T) { +func subTheHubBindsALateConsumerAndSaysItIsLive(t *testing.T) { nc, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) @@ -69,7 +69,7 @@ func TestTheHubBindsALateConsumerAndSaysItIsLive(t *testing.T) { // W1.12: a module hears a seat's event kept last per subject on its own stream through its durable, made by the maker // after the events were said, and is handed the last of each subject; without the consumer the call says so. -func TestAModuleHearsASeatEventKeptOnItsOwnStream(t *testing.T) { +func subAModuleHearsASeatEventKeptOnItsOwnStream(t *testing.T) { nc, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) @@ -141,3 +141,9 @@ func TestAModuleHearsASeatEventKeptOnItsOwnStream(t *testing.T) { t.Fatal("the durable was not followed after the read") } } + +// TestTheHubBindsALateConsumerAndSaysItIsLive runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestTheHubBindsALateConsumerAndSaysItIsLive(t *testing.T) { + t.Run("TheHubBindsALateConsumerAndSaysItIsLive", subTheHubBindsALateConsumerAndSaysItIsLive) + t.Run("AModuleHearsASeatEventKeptOnItsOwnStream", subAModuleHearsASeatEventKeptOnItsOwnStream) +} diff --git a/go/seatdef/refs_test.go b/go/seatdef/refs_test.go index 9358da64..aa81ce42 100644 --- a/go/seatdef/refs_test.go +++ b/go/seatdef/refs_test.go @@ -6,7 +6,7 @@ import ( ) // A verb's schema has its named types in place (the seat list's readers take one schema, not a schema and its types). -func TestResolveRefsPutsNamedTypesInPlace(t *testing.T) { +func subResolveRefsPutsNamedTypesInPlace(t *testing.T) { defs := map[string]map[string]any{ "id": {"type": "string"}, "row": {"type": "object", "properties": map[string]any{"id": map[string]any{"$ref": "#/defs/id"}}}, @@ -34,3 +34,10 @@ func TestResolveRefsPutsNamedTypesInPlace(t *testing.T) { } } } + +// TestResolveRefsPutsNamedTypesInPlace runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestResolveRefsPutsNamedTypesInPlace(t *testing.T) { + t.Run("ResolveRefsPutsNamedTypesInPlace", subResolveRefsPutsNamedTypesInPlace) + t.Run("AVerbWithoutCallersTakesItsClassDefault", subAVerbWithoutCallersTakesItsClassDefault) + t.Run("AKeptEventsStreamIsNamedAndBoundedByItsKeep", subAKeptEventsStreamIsNamedAndBoundedByItsKeep) +} diff --git a/go/seatdef/seatdef_test.go b/go/seatdef/seatdef_test.go index b2b8a8ce..1f159a40 100644 --- a/go/seatdef/seatdef_test.go +++ b/go/seatdef/seatdef_test.go @@ -290,7 +290,7 @@ func TestAKeptEventsStreamIsNamedFromTheSeatAndTheEvent(t *testing.T) { } // Design 47 G §391: a verb that names no callers takes its class's default, a verb that names them keeps them. -func TestAVerbWithoutCallersTakesItsClassDefault(t *testing.T) { +func subAVerbWithoutCallersTakesItsClassDefault(t *testing.T) { for _, c := range []struct { verb Verb want string @@ -310,7 +310,7 @@ func TestAVerbWithoutCallersTakesItsClassDefault(t *testing.T) { // Design 47 G §260, §396, §331: a kept event's stream is named from the seat and the event, 90 days and 16 MiB unless // the keep says otherwise, and 0 is no age limit. -func TestAKeptEventsStreamIsNamedAndBoundedByItsKeep(t *testing.T) { +func subAKeptEventsStreamIsNamedAndBoundedByItsKeep(t *testing.T) { d, err := Parse([]byte(`{"format":1,"seat":"mesh-delivery","scope":"mesh","grain":"seat-list","domain":"Delivery","decision":"x", "events":[{"name":"owed","keep":{"max-age-days":7,"max-mib":64}},{"name":"toolchain-agreed","keep":{}}, {"name":"versions-filled","keep":{"max-age-days":0,"max-mib":1}}]}`)) diff --git a/go/stateobjects/ref_test.go b/go/stateobjects/ref_test.go index 1fe64ae8..b8f29382 100644 --- a/go/stateobjects/ref_test.go +++ b/go/stateobjects/ref_test.go @@ -6,7 +6,7 @@ import ( ) // ADR 0666 §16: a body is a reference when it is exactly `{"mesh-object": Ref}`; anything else is a value. -func TestABodyIsAReferenceOnlyWhenItIsExactlyOne(t *testing.T) { +func subABodyIsAReferenceOnlyWhenItIsExactlyOne(t *testing.T) { good := Ref{Store: "views-objects", Object: "k." + strings.Repeat("a", 64), Size: 3 << 20, Digest: strings.Repeat("a", 64), Form: FormVersion} got, ok := ReadRef(Wrap(good)) if !ok || got != good { @@ -29,3 +29,15 @@ func TestABodyIsAReferenceOnlyWhenItIsExactlyOne(t *testing.T) { } } } + +// TestABodyIsAReferenceOnlyWhenItIsExactlyOne runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestABodyIsAReferenceOnlyWhenItIsExactlyOne(t *testing.T) { + t.Run("ABodyIsAReferenceOnlyWhenItIsExactlyOne", subABodyIsAReferenceOnlyWhenItIsExactlyOne) + t.Run("ABodyOverTheMessageLimitIsSentAsAReference", subABodyOverTheMessageLimitIsSentAsAReference) + t.Run("ABundleReadsASentObjectThroughTheRuntime", subABundleReadsASentObjectThroughTheRuntime) + t.Run("AFoundationPartsSentStoreAgesFromItsSendLog", subAFoundationPartsSentStoreAgesFromItsSendLog) + t.Run("TheObjectToolsReadEverythingAndDropOnlyWhatIsNotLive", subTheObjectToolsReadEverythingAndDropOnlyWhatIsNotLive) + t.Run("ValuesOfAnySizeThroughTheRuntime", subValuesOfAnySizeThroughTheRuntime) + t.Run("AWriteLostLeavesNoObjectBehind", subAWriteLostLeavesNoObjectBehind) + t.Run("AValueLargerThanTheStoreTakesIsRefused", subAValueLargerThanTheStoreTakesIsRefused) +} diff --git a/go/stateobjects/send_test.go b/go/stateobjects/send_test.go index ea6b529f..f3d3591c 100644 --- a/go/stateobjects/send_test.go +++ b/go/stateobjects/send_test.go @@ -9,7 +9,7 @@ import ( // ADR 0666 §16: a reply or an event over the per-message limit carries the name of an object, and the receiver reads it // back whole; one that fits is sent as it is. -func TestABodyOverTheMessageLimitIsSentAsAReference(t *testing.T) { +func subABodyOverTheMessageLimitIsSentAsAReference(t *testing.T) { m := newMemory() s := Sender{Objects: memObjects{m}, Store: "m_sent-objects"} fetch := ProcessFetch(memObjects{m}) @@ -48,7 +48,7 @@ func TestABodyOverTheMessageLimitIsSentAsAReference(t *testing.T) { } // A bundle reads a sent object through the runtime's sent-get. -func TestABundleReadsASentObjectThroughTheRuntime(t *testing.T) { +func subABundleReadsASentObjectThroughTheRuntime(t *testing.T) { m := newMemory() body := []byte(`{"text":"` + strings.Repeat("y", 3<<20) + `"}`) sent, err := Sender{Objects: memObjects{m}, Store: "m_sent-objects"}.Send("reply.list", body) @@ -69,7 +69,7 @@ func TestABundleReadsASentObjectThroughTheRuntime(t *testing.T) { // Design 47 G §410, §330: a foundation part's sender keeps the sequence of its sends in its old state section // `sent-log` and deletes the sent objects past 7 days at a later send, at most 20 a send. -func TestAFoundationPartsSentStoreAgesFromItsSendLog(t *testing.T) { +func subAFoundationPartsSentStoreAgesFromItsSendLog(t *testing.T) { m := newMemory() clock := time.Date(2026, 11, 1, 0, 0, 0, 0, time.UTC) s := Sender{Objects: memObjects{m}, Store: "m_sent-objects", Log: m, Node: "n1", Now: func() time.Time { return clock }} diff --git a/go/stateobjects/tools_test.go b/go/stateobjects/tools_test.go index 323edc3c..3e4bc681 100644 --- a/go/stateobjects/tools_test.go +++ b/go/stateobjects/tools_test.go @@ -25,7 +25,7 @@ func (a *acts) RecordHandAct(h views.HandAct) error { // ADR 0666 §25: the four tools read what each store holds and drop only what is no longer live, each drop only with who // asks and why, recorded as a hand act first. -func TestTheObjectToolsReadEverythingAndDropOnlyWhatIsNotLive(t *testing.T) { +func subTheObjectToolsReadEverythingAndDropOnlyWhatIsNotLive(t *testing.T) { m := newMemory() m.modified = map[string]time.Time{} v := m.values() diff --git a/go/stateobjects/values_test.go b/go/stateobjects/values_test.go index a8f46de0..8309e411 100644 --- a/go/stateobjects/values_test.go +++ b/go/stateobjects/values_test.go @@ -104,7 +104,7 @@ func valueRows(t *testing.T, v Values, multiples ...int) { } // ADR 0666 §16, C-S3, C-S5: values of 1x, 10x and 100x the limit through a bundle's runtime, whole. -func TestValuesOfAnySizeThroughTheRuntime(t *testing.T) { +func subValuesOfAnySizeThroughTheRuntime(t *testing.T) { m := newMemory() out := runtimeOf(t, m, func() (any, error) { v := ForState("views") @@ -117,7 +117,7 @@ func TestValuesOfAnySizeThroughTheRuntime(t *testing.T) { } // A write another writer won first leaves the object it put removed and the key as it found it. -func TestAWriteLostLeavesNoObjectBehind(t *testing.T) { +func subAWriteLostLeavesNoObjectBehind(t *testing.T) { m := newMemory() v := m.values() if err := v.Put("k", big(3*kvlimit.ModuleStateValueBytes)); err != nil { @@ -158,7 +158,7 @@ func (r *raceKV) Get(key string) (*Entry, error) { } // A store that takes no object as large as the value refuses it, loudly, and writes nothing. -func TestAValueLargerThanTheStoreTakesIsRefused(t *testing.T) { +func subAValueLargerThanTheStoreTakesIsRefused(t *testing.T) { m := newMemory() m.most = 100_000 v := m.values() diff --git a/go/stdio_test.go b/go/stdio_test.go index 6f5458d1..2ae8bf27 100644 --- a/go/stdio_test.go +++ b/go/stdio_test.go @@ -346,7 +346,7 @@ func servesAlone(t *testing.T) { // Design 47 G §559: a bundle's acknowledged publish asks `ack: true` and fails on the runtime's `{error}`; its // subscription for new messages asks `deliver: new`. -func TestABundleAsksAnAcknowledgedPublishAndASubscriptionForNewMessages(t *testing.T) { +func subABundleAsksAnAcknowledgedPublishAndASubscriptionForNewMessages(t *testing.T) { servesAlone(t) t.Setenv(ServedAs, "keeper") inR, inW := io.Pipe() diff --git a/go/views/process_reader_integration_test.go b/go/views/process_reader_integration_test.go index 0c4d75f2..695e83d9 100644 --- a/go/views/process_reader_integration_test.go +++ b/go/views/process_reader_integration_test.go @@ -22,7 +22,7 @@ import ( // An owner's change is an ordinary event on the shared events stream (novox/hq ADR 0635 §5): a reader that follows the // owner's state by its read tool hears it on the module's durable consumer of that stream, with no stream of the owner's, // and a message that is no views event goes to Other. -func TestAReaderHearsAnOwnersChangesAsOrdinaryEvents(t *testing.T) { +func subAReaderHearsAnOwnersChangesAsOrdinaryEvents(t *testing.T) { nc, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) @@ -135,7 +135,7 @@ func TestAReaderHearsAnOwnersChangesAsOrdinaryEvents(t *testing.T) { // A module has one durable consumer on the shared events stream, so the loops that hear events in one module must share // one pull (process.EventHub): two handlers and the views reader on the hub each get their own messages and no other's, // and a message nobody takes is acknowledged. -func TestTheViewsReaderAndTwoHandlersShareTheModulesOneDurable(t *testing.T) { +func subTheViewsReaderAndTwoHandlersShareTheModulesOneDurable(t *testing.T) { nc, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) @@ -237,3 +237,10 @@ func TestTheViewsReaderAndTwoHandlersShareTheModulesOneDurable(t *testing.T) { t.Fatal("the hub started late heard nothing") } } + +// TestAReaderHearsAnOwnersChangesAsOrdinaryEvents runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestAReaderHearsAnOwnersChangesAsOrdinaryEvents(t *testing.T) { + t.Run("AReaderHearsAnOwnersChangesAsOrdinaryEvents", subAReaderHearsAnOwnersChangesAsOrdinaryEvents) + t.Run("TheViewsReaderAndTwoHandlersShareTheModulesOneDurable", subTheViewsReaderAndTwoHandlersShareTheModulesOneDurable) + t.Run("WriterSaysItsEventsAndHearsAsksOnTheBus", subWriterSaysItsEventsAndHearsAsksOnTheBus) +} diff --git a/go/views/stdio_writer_test.go b/go/views/stdio_writer_test.go index b74a7272..3519cea2 100644 --- a/go/views/stdio_writer_test.go +++ b/go/views/stdio_writer_test.go @@ -38,7 +38,7 @@ type swAsked struct { // A stdio module's writer says each of its events through the module's own publish, acknowledged, under the writer's // message id, and hears the asks through the module's subscription (design 47 G A-16). -func TestStdioWriterPublishesAndListensThroughTheModulesOwnPlumbing(t *testing.T) { +func subStdioWriterPublishesAndListensThroughTheModulesOwnPlumbing(t *testing.T) { type said struct { event string body string diff --git a/go/views/views_test.go b/go/views/views_test.go index de02253a..a93186a7 100644 --- a/go/views/views_test.go +++ b/go/views/views_test.go @@ -55,7 +55,7 @@ func markOf(state string, rev uint64, made time.Time) Entry { // The owners' and the readers' side of a first view (ADR 0615 §4-§6, ADR 0621 §2-§3, ADR 0622): one table of cases, // since mesh-delivery is over its test budget. -func TestViews(t *testing.T) { +func subViews(t *testing.T) { made := time.Date(2026, 11, 4, 12, 0, 0, 0, time.UTC) now := func() time.Time { return made.Add(time.Hour) } written := made.Add(-time.Minute) @@ -1210,3 +1210,9 @@ func (s *pagedSource) Page(after string, _ int, _ time.Duration) ([]KeyedEntry, } return out, "", nil } + +// TestViews runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestViews(t *testing.T) { + t.Run("Views", subViews) + t.Run("StdioWriterPublishesAndListensThroughTheModulesOwnPlumbing", subStdioWriterPublishesAndListensThroughTheModulesOwnPlumbing) +} diff --git a/go/views/writer_integration_test.go b/go/views/writer_integration_test.go index 1a9a309d..f7bf593f 100644 --- a/go/views/writer_integration_test.go +++ b/go/views/writer_integration_test.go @@ -18,7 +18,7 @@ import ( // Against a real bus: the writer's events are acknowledged by their stream, a start states what the observer observes, an // ask published before the writer's consumer existed is never answered, one published after is, and after the connection // is made again (Reconnected) the consumer is made again from the newest ask (design 47 G §383, §390, §485). -func TestWriterSaysItsEventsAndHearsAsksOnTheBus(t *testing.T) { +func subWriterSaysItsEventsAndHearsAsksOnTheBus(t *testing.T) { nc, err := nats.Connect(testbus.URL(t)) if err != nil { t.Fatal(err) diff --git a/go/views/writer_test.go b/go/views/writer_test.go index 17685785..a2ca9f00 100644 --- a/go/views/writer_test.go +++ b/go/views/writer_test.go @@ -81,7 +81,7 @@ var subjects = views.FindingSubjects("m", "n1") // asked is the subject the module gives the writer for findings-asked, as its seat's generated contract has it (design 47 G A-17). const asked = "mesh.seat.s.event.findings-asked" -func TestFindingSubjectsAreTheEventsStreamForm(t *testing.T) { +func subFindingSubjectsAreTheEventsStreamForm(t *testing.T) { want := views.WriterSubjects{ Written: "mesh.stream.m.event.finding-written.n1", Cleared: "mesh.stream.m.event.finding-cleared.n1", Stated: "mesh.stream.m.event.findings-stated.n1", @@ -154,7 +154,7 @@ func finding(id, summary string) testFinding { // A finding written says its event with the layout whole after the key, keeps the key's since, and says again only when // what it says changed; a finding cleared says its event, also of a key that does not exist (design 47 G §383, §485). -func TestWriterWritesAndClearsFindingsAsEvents(t *testing.T) { +func subWriterWritesAndClearsFindingsAsEvents(t *testing.T) { r := newRig(t) ctx := context.Background() first := r.now @@ -202,7 +202,7 @@ func TestWriterWritesAndClearsFindingsAsEvents(t *testing.T) { // An event the bus does not acknowledge is sent again for one minute, then written in the journal as an error naming the // finding (design 47 G §383). -func TestWriterSendsAgainForAMinuteThenLogs(t *testing.T) { +func subWriterSendsAgainForAMinuteThenLogs(t *testing.T) { r := newRig(t) r.fail = 2 if err := r.w.Write(context.Background(), finding("a", "one")); err != nil || len(r.events()) != 1 { @@ -225,7 +225,7 @@ func TestWriterSendsAgainForAMinuteThenLogs(t *testing.T) { // rest; an ask naming another module is not answered, one naming none or this one is, with its id; an observe that fails // says no set and is called again once a minute until a set is said; a connection made again makes the consumer again and // states again (design 47 G §384, §461, §485). -func TestWriterStatesAtStartAndOnAsksAndRecovers(t *testing.T) { +func subWriterStatesAtStartAndOnAsksAndRecovers(t *testing.T) { r := newRig(t) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -298,7 +298,7 @@ func waitEvent(t *testing.T, r *rig, n int) said { } // A write asked during a statement waits for it, so the statement never deletes the key the write made (design 47 G §485). -func TestWriterRunsOneActAtATime(t *testing.T) { +func subWriterRunsOneActAtATime(t *testing.T) { r := newRig(t) inside, release := make(chan struct{}), make(chan struct{}) r.observe = func(context.Context) (testObserved, error) { @@ -329,7 +329,7 @@ func TestWriterRunsOneActAtATime(t *testing.T) { // A writer owns its kinds (design 47 G §580), states them, deletes no key of another kind, and covers a views reader's // findings written through it beside observe's (§639); an owner or waiting-on of no form is refused, naming the field (§678). -func TestWriterKindsAndReaderFindings(t *testing.T) { +func subWriterKindsAndReaderFindings(t *testing.T) { ctx := context.Background() r := newRigKinds(t, "k") other := finding("x", "another bundle's") @@ -396,7 +396,7 @@ func TestWriterKindsAndReaderFindings(t *testing.T) { // kind, the scope module, the id escaped as a key's name is, a warning but urgent for view-too-large, the source views, the // subject the module on its node; and CheckFinding refuses a finding breaking a rule before it is written, naming the field // (§689). -func TestReaderFindingsAreLaidOutAndCheckFindingRefuses(t *testing.T) { +func subReaderFindingsAreLaidOutAndCheckFindingRefuses(t *testing.T) { r := newRig(t) for _, kind := range views.ViewKinds { if err := views.PutViewFinding(r.w, kind, "o.s.main", "sum "+kind, "head"); err != nil { @@ -441,7 +441,7 @@ func TestReaderFindingsAreLaidOutAndCheckFindingRefuses(t *testing.T) { // A finding body whose wire form lacks a field the contract names is refused when the writer is made, naming the field // (design 47 G A-3). -func TestWriterRefusesABodyWithoutAContractField(t *testing.T) { +func subWriterRefusesABodyWithoutAContractField(t *testing.T) { type noSince struct { Kind, Scope, ID, Observer string At time.Time `json:"at"` @@ -467,7 +467,7 @@ func TestWriterRefusesABodyWithoutAContractField(t *testing.T) { // A part whose findings are raised as they happen holds them in a writer that observes from its own state (design 47 G A-29): // the findings standing in the state are seeded before it starts, a statement says what is held, Write and Clear keep the held // set, and an Observe of the part's own is refused. -func TestHeldWriterStatesWhatItHoldsFromItsOwnState(t *testing.T) { +func subHeldWriterStatesWhatItHoldsFromItsOwnState(t *testing.T) { state := &fakeState{m: map[string][]byte{}} raw, _ := json.Marshal(finding("seeded", "stood")) state.m["module.seeded.k"] = raw @@ -508,3 +508,16 @@ func TestHeldWriterStatesWhatItHoldsFromItsOwnState(t *testing.T) { t.Fatalf("the statement says %+v after %d events", stated, len(sent)) } } + +// TestFindingSubjectsAreTheEventsStreamForm runs the tests of this package that were merged to keep the module within its test budget (design 47 G §419), each as a subtest. +func TestFindingSubjectsAreTheEventsStreamForm(t *testing.T) { + t.Run("FindingSubjectsAreTheEventsStreamForm", subFindingSubjectsAreTheEventsStreamForm) + t.Run("WriterWritesAndClearsFindingsAsEvents", subWriterWritesAndClearsFindingsAsEvents) + t.Run("WriterSendsAgainForAMinuteThenLogs", subWriterSendsAgainForAMinuteThenLogs) + t.Run("WriterStatesAtStartAndOnAsksAndRecovers", subWriterStatesAtStartAndOnAsksAndRecovers) + t.Run("WriterRunsOneActAtATime", subWriterRunsOneActAtATime) + t.Run("WriterKindsAndReaderFindings", subWriterKindsAndReaderFindings) + t.Run("ReaderFindingsAreLaidOutAndCheckFindingRefuses", subReaderFindingsAreLaidOutAndCheckFindingRefuses) + t.Run("WriterRefusesABodyWithoutAContractField", subWriterRefusesABodyWithoutAContractField) + t.Run("HeldWriterStatesWhatItHoldsFromItsOwnState", subHeldWriterStatesWhatItHoldsFromItsOwnState) +}