Resources are applied in the order they were declared, and now something says so
Half of novox/hq work breakdown 1.3, and it needed no change: the apply loop walks d.Resources and sorts nothing, so a module that needs one thing before another says so by writing it first. Asserted because it is the kind of property a later change breaks silently. Sorting the resources for any good reason at all — by type, by identity, for a tidier report — would still pass every other test in this package. It is sequence, not readiness. A container started is not a container ready, and nothing here waits: what depends on something being usable retries, which is what both example provisioners do and is the more robust answer anyway, because a dependency can restart long after everything was applied. Two mistakes worth keeping in the test's own comments. The first version stubbed the runner to always succeed, so verify passed, every action counted as already done, and nothing ran — the assertion was measuring an empty list. The second declared the actions over the link, which refuses them: only a bundle may carry an action (ADR 0005).
This commit is contained in:
@@ -1298,3 +1298,65 @@ func TestAContainerGivenNoNamesIsRunAsBefore(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Defends the ordering half of novox/hq work breakdown 1.3: resources are applied in the order
|
||||
// the module declared them.
|
||||
//
|
||||
// **Already true, and untested until now** — the apply loop walks `d.Resources` and sorts nothing,
|
||||
// so a module that needs one thing before another says so by writing it first. Worth an assertion
|
||||
// because it is the kind of property a later change would break silently: sorting the resources
|
||||
// for any good reason at all — by type, by identity, for a tidier report — would still pass every
|
||||
// other test in this package.
|
||||
//
|
||||
// It is sequence, not readiness. A container started is not a container ready, and nothing here
|
||||
// waits: what depends on something being *usable* retries, which is what both example
|
||||
// provisioners do and is more robust than start ordering, because a dependency can also restart
|
||||
// long after everything was applied.
|
||||
func TestResourcesAreAppliedInTheOrderTheyWereDeclared(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
var order []string
|
||||
done := map[string]bool{}
|
||||
run := func(_ context.Context, name string, args ...string) (string, error) {
|
||||
order = append(order, name+" "+strings.Join(args, " "))
|
||||
// `verify` is the idempotency check, so it has to fail before the step and pass after —
|
||||
// a stub that always succeeds means every action is already done and nothing ever runs,
|
||||
// which is what the first version of this test measured.
|
||||
if name == "check" {
|
||||
if !done[args[0]] {
|
||||
return "", fmt.Errorf("not yet")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
done[args[0]] = true
|
||||
return "", nil
|
||||
}
|
||||
|
||||
_ = dir
|
||||
// Trusted, because the link may not carry an action and only a bundle may (novox/hq ADR 0005).
|
||||
// Actions are used here because they are the one shape whose execution is observable through
|
||||
// the runner, which is what makes the order visible at all.
|
||||
d, err := declaration.ParseTrusted([]byte(`{"declaration":1,"resources":[` +
|
||||
`{"id":"first","type":"action","command":["step","one"],"verify":["check","one"]},` +
|
||||
`{"id":"second","type":"action","command":["step","two"],"verify":["check","two"]},` +
|
||||
`{"id":"third","type":"action","command":["step","three"],"verify":["check","three"]}]}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, _, err := Apply(context.Background(), archHost(t), d, store.State{},
|
||||
store.OriginCarried, run, nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var ran []string
|
||||
for _, line := range order {
|
||||
if strings.HasPrefix(line, "step ") {
|
||||
ran = append(ran, strings.TrimPrefix(line, "step "))
|
||||
}
|
||||
}
|
||||
want := []string{"one", "two", "three"}
|
||||
if strings.Join(ran, ",") != strings.Join(want, ",") {
|
||||
t.Fatalf("declared one, two, three and ran %v — a module that needs one thing before "+
|
||||
"another has no way to say so", ran)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user