package apply import ( "context" "fmt" "os" "path/filepath" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/declaration" "github.com/novox/mesh-host/internal/store" ) // Defends novox/hq ADR 0547 ยง8: the bus node writes the bus's user list alone, with no want, through the apply's own // file step: only when it differs, mode 0600, read back and recorded as the module's, and nothing else moves. func TestAFileWrittenAloneMovesNothingElse(t *testing.T) { const was, now = "user a\n", "user a\nuser b\n" for _, c := range []struct { name, fields, before string recorded bool recordedAs string // the id the record has, when not the composition's action, refused string after string }{ {name: "no record of it", fields: `"content":%q,"mode":"0600"`, before: was, refused: "holds no record", after: was}, {name: "changed", fields: `"content":%q,"mode":"0600"`, before: was, recorded: true, action: "updated", after: now}, {name: "the same", fields: `"content":%q,"mode":"0600"`, before: now, recorded: true, action: "unchanged", after: now}, {name: "recorded under the id from before the switch", fields: `"content":%q,"mode":"0600"`, before: was, recorded: true, recordedAs: "bus-users", action: "updated", after: now}, {name: "absent with a record", fields: `"content":%q,"mode":"0600"`, recorded: true, action: "created", after: now}, {name: "written into", fields: `"content":%q,"into":"block","owner-at-runtime":"managed"`, before: was, recorded: true, refused: "only such a file", after: was}, {name: "sealed", fields: `"sealed":"c2VhbGVk"`, before: was, recorded: true, refused: "only such a file", after: was}, } { t.Run(c.name, func(t *testing.T) { path := filepath.Join(t.TempDir(), "accounts.conf") if c.before != "" { if err := os.WriteFile(path, []byte(c.before), 0o600); err != nil { t.Fatal(err) } } fields := strings.Replace(c.fields, "%q", fmt.Sprintf("%q", now), 1) d := parseTrusted(t, fmt.Sprintf(`{"declaration":1,"resources":[{"id":"nats.bus-users","module":"nats", "type":"file","path":%q,`+fields+`}]}`, path)) file := d.Resources[0].(*declaration.File) known := store.State{} id := file.ID if c.recordedAs != "" { id = c.recordedAs } if c.recorded { known.Record(store.Applied{ID: id, Type: string(declaration.TypeFile), Module: "nats", Target: path, Origin: store.OriginDeclared, Wrote: digestOf(c.before)}) } calls := 0 counting := func(context.Context, string, ...string) (string, error) { calls++; return "", nil } out, after, err := WriteAlone(context.Background(), archHost(t), file, known, counting, nil) if c.refused != "" { if err == nil || !strings.Contains(err.Error(), c.refused) { t.Fatalf("not refused with %q: %v", c.refused, err) } } else if err != nil { t.Fatal(err) } else if out.Action != c.action { t.Errorf("action %q, want %q", out.Action, c.action) } if got := readText(t, path); got != c.after { t.Errorf("file holds %q, want %q", got, c.after) } if calls != 0 { t.Errorf("%d commands were run: a file written alone moves nothing", calls) } if c.refused != "" { return } if m := modeAt(t, path); m != 0o600 { t.Errorf("mode %o", m) } rec, ok := after.Find(id) if !ok || rec.Wrote != digestOf(now) || rec.Target != path { t.Errorf("record %+v (found %v), want it to say %s was written", rec, ok, digestOf(now)) } if n := len(after.Resources); n != 1 { t.Errorf("%d records of one file", n) } }) } }