Run the equality test only when named, on three stores at once, with its phases timed (issue 1384)

The live try took 1074 s for it. It now skips unless the tests pattern (-run) names it, which a try sets and a whole-suite merge check does not; its three independent pieces of work (both ways of Foreseeing on a fresh store, the controller's sends and readings, mesh-sdk's sends) run together; mesh-sdk's Input is read once for a phase of questions; and each phase logs its elapsed time, so the next run says where the time goes. A machine refused on either side is left out of the comparison of the send.
This commit is contained in:
2026-10-20 09:54:51 +00:00
parent b317dfef45
commit 9f773e0b3c
@@ -4,11 +4,14 @@ package main
import ( import (
"context" "context"
"flag"
"fmt" "fmt"
"os" "os"
"sort" "sort"
"strings" "strings"
"sync"
"testing" "testing"
"time"
"git.novox.be/novox/mesh-sdk/go/compose" "git.novox.be/novox/mesh-sdk/go/compose"
snapshot "git.novox.be/novox/mesh-sdk/go/facts" snapshot "git.novox.be/novox/mesh-sdk/go/facts"
@@ -20,6 +23,8 @@ import (
// scrubbed as the snapshot is), else the snapshot of a small mesh of its own; raises it into throwaway stores as the merge // scrubbed as the snapshot is), else the snapshot of a small mesh of its own; raises it into throwaway stores as the merge
// gate does; and composes every machine both ways. // gate does; and composes every machine both ways.
// //
// It runs only when named (a try with this test's name as the tests pattern); a whole-suite run skips it.
//
// (a) Foreseeing on the fresh store: the same error or none, the same validator problems, LeftOut and its reasons, Withheld, // (a) Foreseeing on the fresh store: the same error or none, the same validator problems, LeftOut and its reasons, Withheld,
// Unbound, Unplaced, HandedOnly and the own secrets named foreseen; and the ports mesh-sdk names foreseen are the ones the // Unbound, Unplaced, HandedOnly and the own secrets named foreseen; and the ports mesh-sdk names foreseen are the ones the
// controller allocates when it sends. // controller allocates when it sends.
@@ -31,11 +36,19 @@ import (
// field that differs; a machine both paths refuse alike is said, not failed. The test is deleted with the controller's // field that differs; a machine both paths refuse alike is said, not failed. The test is deleted with the controller's
// composition (issue 1389). // composition (issue 1389).
func TestEveryMachineComposesAlikeBothWays(t *testing.T) { func TestEveryMachineComposesAlikeBothWays(t *testing.T) {
// It is slow (it composes every machine of the live mesh several times each way) and is deleted with the controller's
// composition (issue 1389), so it runs only when asked for by name: a try or a `go test -run` that names it. A merge check
// runs every test and does not.
if run := flag.Lookup("test.run"); run == nil || !strings.Contains(run.Value.String(), "TestEveryMachineComposesAlikeBothWays") {
t.Skip("runs only when named: a try with the tests pattern TestEveryMachineComposesAlikeBothWays")
}
ctx := t.Context() ctx := t.Context()
admin := os.Getenv("MESH_TEST_POSTGRES") admin := os.Getenv("MESH_TEST_POSTGRES")
if admin == "" { if admin == "" {
t.Skip("no throwaway PostgreSQL (MESH_TEST_POSTGRES) to raise the mesh in") t.Skip("no throwaway PostgreSQL (MESH_TEST_POSTGRES) to raise the mesh in")
} }
started := time.Now()
phase := func(what string) { t.Logf("[%s] %s", time.Since(started).Round(time.Second), what) }
f, source := equalityFacts(t) f, source := equalityFacts(t)
t.Logf("the facts of %s (%s): %d machine(s)", f.Taken.Format("2006-01-02 15:04:05"), source, len(f.Machines)) t.Logf("the facts of %s (%s): %d machine(s)", f.Taken.Format("2006-01-02 15:04:05"), source, len(f.Machines))
shelf, err := shelfOfFacts(f) shelf, err := shelfOfFacts(f)
@@ -43,108 +56,149 @@ func TestEveryMachineComposesAlikeBothWays(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
sources := sourcesOfFacts(f) sources := sourcesOfFacts(f)
var failures []string
// (a) on the fresh store. mesh-sdk's composition first: it writes nothing, where the controller's makes every pair // Three stores, raised from the same snapshot, are three independent pieces of work and run together: (a) both ways on a
// credential on the way. // fresh store, (b) and (c) the controller's sends and readings, (b) mesh-sdk's sends.
fresh, dropFresh, err := throwawayStores(ctx, admin) var (
if err != nil { wg sync.WaitGroup
t.Fatal(err) oldForeseen, sdkForeseen = map[string]composedBoth{}, map[string]composedBoth{}
} foreseenPorts = map[string][]string{}
if _, err := raiseFromFacts(ctx, fresh, f, shelf, sources); err != nil { readOld, readSDK = map[string]composedBoth{}, map[string]composedBoth{}
dropFresh() oldMade, sdkMade made
t.Fatal(err) oldRefused = map[string]bool{}
} sendRefused = map[string]string{}
sdkForeseen := map[string]composedBoth{} errA, errOld, errSDK error
foreseenPorts := map[string][]string{} )
for _, m := range f.Machines { wg.Add(3)
in, err := readComposeInput(ctx, fresh) go func() { // (a) Foreseeing on the fresh store.
defer wg.Done()
fresh, drop, err := throwawayStores(ctx, admin)
if err != nil { if err != nil {
dropFresh() errA = err
t.Fatalf("%s: the adapter cannot read the mesh: %v", m.Name, err) return
} }
d, problems, cerr := compose.ComposeIn(in.Input, m.Name, compose.Foreseeing) defer drop()
if cerr == nil { if _, err := raiseFromFacts(ctx, fresh, f, shelf, sources); err != nil {
foreseenPorts[m.Name] = append([]string(nil), d.ForeseenPorts...) errA = err
sort.Strings(foreseenPorts[m.Name]) return
}
// mesh-sdk's composition first: it writes nothing, where the controller's makes every pair credential on the way. The
// Input is read once for all of its machines.
cached := withInputCache(ctx)
for _, m := range f.Machines {
in, err := inputFor(cached, fresh)
if err != nil {
errA = fmt.Errorf("%s: the adapter cannot read the mesh: %w", m.Name, err)
return
}
d, problems, cerr := compose.ComposeIn(in.Input, m.Name, compose.Foreseeing)
if cerr == nil {
foreseenPorts[m.Name] = append([]string(nil), d.ForeseenPorts...)
sort.Strings(foreseenPorts[m.Name])
}
sdkForeseen[m.Name] = capturedFrom(sendableOf(d), problems, cerr)
}
phase("(a) mesh-sdk's Foreseeing of every machine")
gens, gensErr := generators(ctx, fresh)
for _, m := range f.Machines {
if gensErr != nil {
oldForeseen[m.Name] = composedBoth{Err: gensErr.Error()}
continue
}
d, problems, err := composedAndValidated(ctx, fresh, m.Name, gens, Foreseeing)
oldForeseen[m.Name] = capturedFrom(d, problems, err)
}
phase("(a) the controller's Foreseeing of every machine")
}()
go func() { // (b) and (c): the controller's send of every machine, then both ways of reading.
defer wg.Done()
oldStore, drop, err := throwawayStores(ctx, admin)
if err != nil {
errOld = err
return
}
defer drop()
if _, err := raiseFromFacts(ctx, oldStore, f, shelf, sources); err != nil {
errOld = err
return
}
oldGens, oldGensErr := generators(ctx, oldStore)
for _, m := range f.Machines {
if oldGensErr != nil {
break
}
if _, _, err := composedAndValidated(ctx, oldStore, m.Name, oldGens, Allocating); err != nil {
oldRefused[m.Name] = true
}
}
phase("(b) the controller's send of every machine")
if oldMade, err = madeIn(ctx, oldStore); err != nil {
errOld = err
return
}
cached := withInputCache(ctx)
for _, m := range f.Machines {
if oldGensErr != nil {
readOld[m.Name] = composedBoth{Err: oldGensErr.Error()}
} else {
d, problems, err := composedAndValidated(ctx, oldStore, m.Name, oldGens, Reading)
readOld[m.Name] = capturedFrom(d, problems, err)
}
d, problems, err := composeQuestion(cached, oldStore, m.Name, compose.Reading, true)
readSDK[m.Name] = capturedFrom(d, problems, err)
}
phase("(c) both ways of reading every machine after the controller's send")
}()
go func() { // (b) mesh-sdk's send of every machine.
defer wg.Done()
sdkStore, drop, err := throwawayStores(ctx, admin)
if err != nil {
errSDK = err
return
}
defer drop()
if _, err := raiseFromFacts(ctx, sdkStore, f, shelf, sources); err != nil {
errSDK = err
return
}
for _, m := range f.Machines {
if _, err := composeSend(ctx, sdkStore, m.Name); err != nil {
sendRefused[m.Name] = err.Error()
}
}
phase("(b) mesh-sdk's send of every machine")
sdkMade, errSDK = madeIn(ctx, sdkStore)
}()
wg.Wait()
for _, err := range []error{errA, errOld, errSDK} {
if err != nil {
t.Fatal(err)
} }
sdkForeseen[m.Name] = capturedFrom(sendableOf(d), problems, cerr)
} }
oldForeseen := map[string]composedBoth{}
gens, gensErr := generators(ctx, fresh) var failures []string
for _, m := range f.Machines {
if gensErr != nil {
oldForeseen[m.Name] = composedBoth{Err: gensErr.Error()}
continue
}
d, problems, err := composedAndValidated(ctx, fresh, m.Name, gens, Foreseeing)
oldForeseen[m.Name] = capturedFrom(d, problems, err)
}
dropFresh()
for _, m := range f.Machines { for _, m := range f.Machines {
failures = append(failures, bothWaysDiffer(m.Name, "(a) Foreseeing", oldForeseen[m.Name], sdkForeseen[m.Name], false)...) failures = append(failures, bothWaysDiffer(m.Name, "(a) Foreseeing", oldForeseen[m.Name], sdkForeseen[m.Name], false)...)
}
// (b) and (c): the controller's send of every machine, then both ways of reading, on one store.
oldStore, dropOld, err := throwawayStores(ctx, admin)
if err != nil {
t.Fatal(err)
}
if _, err := raiseFromFacts(ctx, oldStore, f, shelf, sources); err != nil {
dropOld()
t.Fatal(err)
}
oldGens, oldGensErr := generators(ctx, oldStore)
for _, m := range f.Machines {
if oldGensErr != nil {
break
}
_, _, _ = composedAndValidated(ctx, oldStore, m.Name, oldGens, Allocating)
}
oldMade, err := madeIn(ctx, oldStore)
if err != nil {
dropOld()
t.Fatal(err)
}
readOld, readSDK := map[string]composedBoth{}, map[string]composedBoth{}
for _, m := range f.Machines {
if oldGensErr != nil {
readOld[m.Name] = composedBoth{Err: oldGensErr.Error()}
} else {
d, problems, err := composedAndValidated(ctx, oldStore, m.Name, oldGens, Reading)
readOld[m.Name] = capturedFrom(d, problems, err)
}
d, problems, err := composeQuestion(ctx, oldStore, m.Name, compose.Reading, true)
readSDK[m.Name] = capturedFrom(d, problems, err)
}
dropOld()
for _, m := range f.Machines {
failures = append(failures, bothWaysDiffer(m.Name, "(c) Reading after the send", readOld[m.Name], readSDK[m.Name], true)...) failures = append(failures, bothWaysDiffer(m.Name, "(c) Reading after the send", readOld[m.Name], readSDK[m.Name], true)...)
} }
// A machine refused on either side sends nothing, so what the controller made on the way to refusing it is no send's.
sdkStore, dropSDK, err := throwawayStores(ctx, admin) refused := map[string]bool{}
if err != nil { for m := range sendRefused {
t.Fatal(err) refused[m] = true
} }
if _, err := raiseFromFacts(ctx, sdkStore, f, shelf, sources); err != nil { for m := range oldRefused {
dropSDK() refused[m] = true
t.Fatal(err)
} }
sendRefused := map[string]string{} for m := range refused {
for _, m := range f.Machines { t.Logf("%s: refused on one side or both, so its ports and secrets are left out of the comparison of the send", m)
if _, err := composeSend(ctx, sdkStore, m.Name); err != nil {
sendRefused[m.Name] = err.Error()
}
} }
sdkMade, err := madeIn(ctx, sdkStore) failures = append(failures, madeDiffer("(b) the send", oldMade, sdkMade, refused)...)
dropSDK()
if err != nil {
t.Fatal(err)
}
failures = append(failures, madeDiffer("(b) the send", oldMade, sdkMade)...)
// (a)'s ports: those mesh-sdk names foreseen, for each machine, are the ones the controller's send allocated to it. // (a)'s ports: those mesh-sdk names foreseen, for each machine, are the ones the controller's send allocated to it.
for _, m := range f.Machines { for _, m := range f.Machines {
if refused[m.Name] {
continue
}
var allocated []string var allocated []string
for _, p := range oldMade.Ports { for _, p := range oldMade.Ports {
if node, rest, ok := strings.Cut(p, " "); ok && node == m.Name { if node, rest, ok := strings.Cut(p, " "); ok && node == m.Name {
@@ -162,7 +216,7 @@ func TestEveryMachineComposesAlikeBothWays(t *testing.T) {
} }
if !found { if !found {
failures = append(failures, fmt.Sprintf("%s, (a) Foreseeing: mesh-sdk names the port %s foreseen and the "+ failures = append(failures, fmt.Sprintf("%s, (a) Foreseeing: mesh-sdk names the port %s foreseen and the "+
"controller's send allocates none for it (it allocates %v)", m.Name, want, allocated)) "controller's send allocates none for it", m.Name, want))
} }
} }
} }