Every method of builds, build requests, rollouts, merges and assignments reads and writes the chain alone: the else branches that read the tables, the movers and MoveChain with their tests, chain_moved reads, ChainReads and the flags that switched a kind, the store's assignments mirror (KeepAssignmentPlans needs none of it: it uses only the AssignmentMirrored type, mirrors.go, and AssignmentValues, provisioning.go) and its tick, the move code of the controller's start, and ForTest's chain_moved row. The listed store tests of the move go with their functions; the tests of the readers, requests, assignments and plans that lived beside them stay in chain_store_test.go. Tests that replayed old data migrations over the build, assignment and pin tables are removed with the tables. The static test that no plan is written but through SavePlansMoving now reads the plan's chain path.
96 lines
3.9 KiB
Go
96 lines
3.9 KiB
Go
//go:build integration
|
|
|
|
package inventory
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A send keeps the provisioner's plans it handed (design 57 P6, issue 672, migration 0100): the assignments mirror
|
|
// carries the plan of the build that machine was sent, in the module's own assignment and no other, and a walk
|
|
// reads which templates the send handed.
|
|
func TestASendKeepsThePlansItHandedAndTheMirrorCarriesThem(t *testing.T) {
|
|
inv, node := aNodeWithModules(t, "dunst", "web")
|
|
ctx := t.Context()
|
|
for _, m := range []string{"dunst", "web"} {
|
|
if _, err := inv.Assign(ctx, node, m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
record, err := inv.NodeByName(ctx, node)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
digest := "sha256:" + strings.Repeat("d", 64)
|
|
plan := Provisioning{Templates: TemplatesArchive{Source: "http://store:5000/v2/dunst/files/blobs/" + digest,
|
|
Digest: digest}, Files: []ProvisionedFile{{ID: "configuration", Path: "/home/op/.config/dunst/dunstrc",
|
|
Template: "dunstrc", OwnerAtRuntime: "owned", Takes: "reload-on"}}}
|
|
// A plan for a module the machine no longer has assigned is kept with the send and mirrored nowhere; one for a
|
|
// module only pulled in by another is mirrored under its own key, saying what requires it (issue 765).
|
|
raw := []byte(`{"dunst":` + mustJSON(t, plan) + `,"gone":` + mustJSON(t, plan) + `,"notify":` +
|
|
strings.Replace(mustJSON(t, plan), `{`, `{"required-by":"desk",`, 1) + `}`)
|
|
if err := inv.RecordSentWith(ctx, record.ID, "first", nil, 0, 0, Send{Digest: "first", Provisioning: raw}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sent, _, err := inv.SentTo(ctx, node)
|
|
if err != nil || !reflect.DeepEqual(sent.Provisioned, map[string]string{"dunst": digest, "gone": digest,
|
|
"notify": digest}) {
|
|
t.Fatalf("the send says it handed %v (%v)", sent.Provisioned, err)
|
|
}
|
|
plans, err := inv.SentProvisioningPlans(ctx)
|
|
required := plan
|
|
required.RequiredBy = "desk"
|
|
if err != nil || !reflect.DeepEqual(plans, map[string]Provisioning{node + ".dunst": plan, node + ".notify": required}) {
|
|
t.Fatalf("the plans mirrored are %+v (%v)", plans, err)
|
|
}
|
|
inv.SetProvisioningPlans(inv.SentProvisioningPlans)
|
|
mirror := inv.PlanValuesForTest(t)
|
|
var dunst, web AssignmentMirrored
|
|
if err := json.Unmarshal(mirror[node+".dunst"], &dunst); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := json.Unmarshal(mirror[node+".web"], &web); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if dunst.Provisioning == nil || !reflect.DeepEqual(*dunst.Provisioning, plan) || web.Provisioning != nil {
|
|
t.Fatalf("the mirror carries %+v for dunst and %+v for web", dunst.Provisioning, web.Provisioning)
|
|
}
|
|
var notify AssignmentMirrored
|
|
if err := json.Unmarshal(mirror[node+".notify"], ¬ify); err != nil {
|
|
t.Fatalf("no value for the pulled-in module: %s (%v)", mirror[node+".notify"], err)
|
|
}
|
|
if notify.RequiredBy != "desk" || !notify.Assigned.IsZero() || notify.Provisioning == nil ||
|
|
!reflect.DeepEqual(*notify.Provisioning, plan) {
|
|
t.Fatalf("the mirror carries %s for the pulled-in module", mirror[node+".notify"])
|
|
}
|
|
if _, has := mirror[node+".gone"]; has {
|
|
t.Fatalf("a module no longer assigned is mirrored: %s", mirror[node+".gone"])
|
|
}
|
|
|
|
// The next send hands nothing: nothing is kept, and the assignment's value is the bytes it was.
|
|
if err := inv.RecordSentWith(ctx, record.ID, "second", nil, 0, 0, Send{Digest: "second"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if sent, _, err := inv.SentTo(ctx, node); err != nil || sent.Provisioned != nil {
|
|
t.Fatalf("a send handing nothing says it handed %v (%v)", sent.Provisioned, err)
|
|
}
|
|
if mirror := inv.PlanValuesForTest(t); strings.Contains(string(mirror[node+".dunst"]), "provisioning") {
|
|
t.Fatalf("dunst's assignment still carries a plan: %s", mirror[node+".dunst"])
|
|
} else if _, has := mirror[node+".notify"]; has {
|
|
t.Fatalf("a module the machine no longer runs is mirrored: %s", mirror[node+".notify"])
|
|
}
|
|
}
|
|
|
|
func mustJSON(t *testing.T, v any) string {
|
|
t.Helper()
|
|
raw, err := json.Marshal(v)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return string(raw)
|
|
}
|