Serve a removed verb as its refusal, not as a verb this build is behind on, and fit the tests of the verbs and the stopped checks (issue 1851, A11a; issue 1299, C1; issue 1318, C3)
This commit is contained in:
@@ -33,6 +33,12 @@ func TestThePullRequestChecksAreAskedOnlyForARepositoryTheCheckerDoesNotJudge(t
|
||||
inventory.Source{Repository: "novox/mesh-controller", Ref: "main", BuiltFrom: "c0", Head: "c0"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// hq is cloned as a module built from it is, from its URL: no forge is held in this test.
|
||||
if err := open.inventory.RegisterModule(ctx, catalogue.Manifest{Module: "hq-docs", Version: "1"},
|
||||
inventory.Source{Repository: "http://forge.invalid/novox/hq.git", Ref: "main", Path: "docs", BuiltFrom: "c0",
|
||||
Head: "c0"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
required := map[string][]string{"novox/mesh-controller": {"mesh/check"}, "novox/hq": {"mesh/repo-check"}}
|
||||
was := requiredStatusesOf
|
||||
requiredStatusesOf = func(_ context.Context, owner, repo, _ string) ([]string, error) {
|
||||
|
||||
@@ -495,5 +495,11 @@ func removedByName(command string) error {
|
||||
"forget-checks": "build-agent makes no check build from R4e (ADR 0503 §3), so there is nothing to let go of",
|
||||
"delivery-plan": "a delivery's plan is read with `delivery-order` and the checker's verdict (ADR 0503 §3)",
|
||||
}[command]
|
||||
return fmt.Errorf("`%s` is removed: %s", command, replacement)
|
||||
return &removedCommand{msg: fmt.Sprintf("`%s` is removed: %s", command, replacement)}
|
||||
}
|
||||
|
||||
// removedCommand is a command or verb the controller no longer has: a refusal that is the verb's whole answer, not a
|
||||
// verb of a newer build this one cannot run.
|
||||
type removedCommand struct{ msg string }
|
||||
|
||||
func (r *removedCommand) Error() string { return r.msg }
|
||||
|
||||
@@ -241,7 +241,7 @@ func notRegistered(ctx context.Context, open *stores, node, module string, opts
|
||||
"at the controller's terminal, and the indexer holds no %s", inventory.ErrNoSuchModule, where.said, module)
|
||||
}
|
||||
answer := strings.TrimPrefix(where.said, inventory.ErrNoSuchModule.Error()) +
|
||||
"\n a module in a repository is registered from the builder's done key once a merge adds it, then assigned"
|
||||
"\n a module in a repository is registered from the builder's done key of it, then assigned"
|
||||
if opts.Build {
|
||||
answer += "\n build \"true\" asks for nothing: the controller asks no build (ADR 0501 §5), and the indexer " +
|
||||
"holds no module of that name"
|
||||
|
||||
@@ -323,44 +323,3 @@ exit 1
|
||||
t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH"))
|
||||
t.Setenv("GOTOOLCHAIN", "local")
|
||||
}
|
||||
|
||||
// A recheck runs as a command of its own (`delivery check` with one member), where the controller is not the serving
|
||||
// one and holds no connection: it dials the bus for the moment and asks mesh-delivery's `groups` as the daemon does.
|
||||
// This drives the verb on a test bus with a fake mesh-delivery answering `groups`, with no stub of the seam between.
|
||||
func TestTheRecheckVerbAsksMeshDeliveryOnABusOfItsOwn(t *testing.T) {
|
||||
realAsk := askDeliveryOwner
|
||||
r := theGroupOfIssue867(t)
|
||||
askDeliveryOwner = realAsk
|
||||
js, _ := aBuildQueue(t)
|
||||
if servingBus.Load() != nil {
|
||||
t.Fatal("this test is of a process that is not the serving controller")
|
||||
}
|
||||
asked := 0
|
||||
wrapped, _ := json.Marshal(map[string]any{"content": []map[string]any{{"type": "text", "text": r.groups}}})
|
||||
sub, err := js.Conn().Subscribe(link.SeatToolSubject(catalogue.DeliverySeat, "groups"), func(m *nats.Msg) {
|
||||
asked++
|
||||
body, _ := json.Marshal(link.Answer{Result: wrapped})
|
||||
_ = m.Respond(body)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = sub.Unsubscribe() })
|
||||
member := `[{"id":"novox/mesh-host@` + r.hostHead[:12] + `","repository":"novox/mesh-host","base":"main","head":"` +
|
||||
r.hostHead + `","number":114,"paths":["notes.txt"],"module_dirs_said":true}]`
|
||||
if err := deliveryCommand(t.Context(), []string{"check", "--members", member}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
q, err := link.ReadQueue(t.Context(), js, link.TheBuildMachine)
|
||||
if err != nil || len(q.Asks) == 0 {
|
||||
t.Fatalf("nothing was asked of the build seat: %v", err)
|
||||
}
|
||||
c := q.Asks[len(q.Asks)-1].Request.Check
|
||||
if c.SiblingsUnknown != "" || len(c.Siblings) != 1 || c.Siblings[0].Repository != "novox/mesh-controller" ||
|
||||
c.Siblings[0].Number != 346 || c.Siblings[0].Head != r.controllerHead {
|
||||
t.Fatalf("the recheck learned siblings %+v, unknown %q", c.Siblings, c.SiblingsUnknown)
|
||||
}
|
||||
if asked != 1 {
|
||||
t.Fatalf("mesh-delivery was asked %d times", asked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1325,7 +1325,8 @@ func seatToolHandlers() (map[string]link.ToolHandler, []string, error) {
|
||||
continue
|
||||
}
|
||||
var policy *heldAtTheTerminal
|
||||
if _, err := argvFor(verb, sampleArguments(v)); err != nil && !errors.As(err, &policy) {
|
||||
var removed *removedCommand
|
||||
if _, err := argvFor(verb, sampleArguments(v)); err != nil && !errors.As(err, &policy) && !errors.As(err, &removed) {
|
||||
// **A row ahead of this binary is not a reason to go silent.**
|
||||
//
|
||||
// The row is the store's and a control plane follows it (novox/hq ADR 0154), so a verb
|
||||
|
||||
@@ -38,7 +38,7 @@ func servedSchemas(t *testing.T) map[string]catalogue.Verb {
|
||||
|
||||
func TestNoArgumentAVerbIsGivenIsPassedOver(t *testing.T) {
|
||||
for name, v := range servedSchemas(t) {
|
||||
if inProcess[name] {
|
||||
if inProcess[name] || removedVerbs[name] {
|
||||
continue
|
||||
}
|
||||
names, switches := declaredArguments(v)
|
||||
@@ -78,7 +78,7 @@ func TestAnArgumentAVerbDoesNotDeclareIsRefused(t *testing.T) {
|
||||
args := sampleArguments(v)
|
||||
args[stranger] = "x"
|
||||
_, err := argvFor(name, args)
|
||||
if inProcess[name] {
|
||||
if inProcess[name] || removedVerbs[name] {
|
||||
_, err = readArguments(name, args)
|
||||
}
|
||||
if err == nil || !strings.Contains(err.Error(), strconv.Quote(stranger)) {
|
||||
@@ -105,7 +105,7 @@ func TestEveryFlagOfAVerbsCommandIsAnArgumentOrAccountedFor(t *testing.T) {
|
||||
reached := map[string]map[string]bool{} // verb → flag sets its command lines reach
|
||||
served := servedSchemas(t)
|
||||
for name, v := range served {
|
||||
if inProcess[name] || name == "command" {
|
||||
if inProcess[name] || removedVerbs[name] || name == "command" {
|
||||
continue
|
||||
}
|
||||
names, switches := declaredArguments(v)
|
||||
|
||||
@@ -177,11 +177,8 @@ var accountedFlags = map[string]map[string]string{
|
||||
"all": "withheld: the verb naming no machine is --behind, and a push of every machine is said at a " +
|
||||
"shell (novox/hq ADR 0217); `command` reaches it",
|
||||
},
|
||||
"build": {
|
||||
"wait": "set by the verb to 0: the id follows the build (issue 176)",
|
||||
"self": "set by the verb from the repository's form: a path on the forge, or a URL",
|
||||
"dry-run": "withheld: a dry run answers only when the build ends, which a call cannot wait for; `command` reaches it",
|
||||
},
|
||||
// Kept only to be refused by name, naming what replaced it (novox/hq ADR 0501 §5, ADR 0429 §18).
|
||||
"replay": {"register": "withheld: refused by name, a registered replay being removed (ADR 0501 §5)"},
|
||||
"builds": {"n": "=limit"},
|
||||
"plans": {"n": "=limit", "what-if": "=repository"},
|
||||
// The machine's tunnel key, named as the verb's other arguments are (novox/hq ADR 0169).
|
||||
|
||||
@@ -230,48 +230,3 @@ func TestASeatsVerbGainsTheArgumentsTheBinaryNames(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **A stored row's build verb takes on and behind** (novox/hq ADR 0246: arguments added to a verb are
|
||||
// additive): a row seeded before them described build with a repository it required, so the console
|
||||
// would refuse both and a call naming neither would be refused for want of a repository. Re-seeding
|
||||
// gives the row this binary's build.
|
||||
func TestAStoredRowsBuildVerbTakesOnAndBehind(t *testing.T) {
|
||||
inv := ForTest(t)
|
||||
ctx := t.Context()
|
||||
if _, err := inv.SeedSeats(ctx, catalogue.DefaultSeats()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
old := `[{"name":"build","description":"Have the build machine build a repository.","input":{"type":"object",
|
||||
"properties":{"repository":{"type":"string"},"path":{"type":"string"},"ref":{"type":"string"}},
|
||||
"required":["repository"]}}]`
|
||||
if _, err := inv.store.Pool().Exec(ctx, `update seat set serves = $1 where name = $2`,
|
||||
[]byte(old), catalogue.ControllerSeatName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := inv.SeedSeats(ctx, catalogue.DefaultSeats()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
seats, err := inv.Seats(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var build catalogue.Verb
|
||||
for _, s := range seats {
|
||||
if s.Name == catalogue.ControllerSeatName {
|
||||
for _, v := range s.Serves {
|
||||
if v.Name == "build" {
|
||||
build = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
props, _ := build.Input["properties"].(map[string]any)
|
||||
for _, arg := range []string{"repository", "path", "ref", "on", "behind"} {
|
||||
if _, has := props[arg]; !has {
|
||||
t.Errorf("build in the row does not take %s: %v", arg, props)
|
||||
}
|
||||
}
|
||||
if req, _ := build.Input["required"].([]any); len(req) != 0 {
|
||||
t.Errorf("build in the row still requires %v, so on and behind alone are refused", req)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user