D47 / R-1269 (P2): a new install never writes into an earlier install's backup — every install has an identity (install_id), the unit records it, every unit writer asks first; another install's unit is set aside whole (backups/set-aside/<app>/<stamp>, a D25 kept copy, „Visszaállítás” + „Eltávolítás” on the restore page); a move that fails refuses the write. Red-proved. Commit only.
gates / gates (push) Successful in 1m33s
gates / gates (push) Successful in 1m33s
This commit is contained in:
1 parent
e1613aea8d
commit
02daebe9c5
30 files changed
+1990
-17
No files matched your search
@@ -0,0 +1,71 @@
|
||||
package stacks
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// D47 (operator ruling 2026-10-25; R-1269) — the app's record names the install its data belongs to. Through the
|
||||
// PRODUCTION writers: the restore write (PersistUnitRedeployConfigGate), a later load-then-save, EnsureInstallID.
|
||||
// COMPANION RED-PROOF: drop the `case gate.InstallID != ""` branch in PersistUnitRedeployConfigGate →
|
||||
// TestD47_ARestoreTakesTheUnitsInstall fails (the app keeps the replaced install's id, and its next backup would
|
||||
// set aside the very unit it was restored from).
|
||||
|
||||
// A restore from a unit that records an install: the app now holds that unit's data, so it IS that install.
|
||||
func TestD47_ARestoreTakesTheUnitsInstall(t *testing.T) {
|
||||
m := gateManager(t, gatedYml)
|
||||
writeAppYaml(t, gappDir(m), "deployed: true\ninstall_id: bbbb000000000002\nenv:\n SUBDOMAIN: gapp\n")
|
||||
must(t, m.PersistUnitRedeployConfigGate("gapp", gateEnv, GateAtBackup{InstallID: "aaaa000000000001"}))
|
||||
if got := LoadAppConfig(gappDir(m)); got == nil || got.InstallID != "aaaa000000000001" {
|
||||
t.Fatalf("the restored app must be the unit's install, got %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// A unit that records no install (before D47): the app keeps its own identity — a restore is not a new install.
|
||||
func TestD47_ARestoreOfAnUnrecordedUnitKeepsTheAppsInstall(t *testing.T) {
|
||||
m := gateManager(t, gatedYml)
|
||||
writeAppYaml(t, gappDir(m), "deployed: true\ninstall_id: bbbb000000000002\nenv:\n SUBDOMAIN: gapp\n")
|
||||
must(t, m.PersistUnitRedeployConfigGate("gapp", gateEnv, GateAtBackup{}))
|
||||
if got := LoadAppConfig(gappDir(m)); got == nil || got.InstallID != "bbbb000000000002" {
|
||||
t.Fatalf("an unrecorded unit's restore keeps the app's own install, got %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// A removed app restored from an unrecorded unit gets an identity (never empty after a restore).
|
||||
func TestD47_ARemovedAppRestoredGetsAnInstall(t *testing.T) {
|
||||
m := gateManager(t, gatedYml)
|
||||
must(t, m.PersistUnitRedeployConfigGate("gapp", gateEnv, GateAtBackup{}))
|
||||
if got := LoadAppConfig(gappDir(m)); got == nil || len(got.InstallID) != 16 {
|
||||
t.Fatalf("a restored app must have an install id, got %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
// An app installed before D47 gets one identity once; a second call returns the same one.
|
||||
func TestD47_EnsureInstallIDMintsOnce(t *testing.T) {
|
||||
m := gateManager(t, gatedYml)
|
||||
writeAppYaml(t, gappDir(m), "deployed: true\nenv:\n SUBDOMAIN: gapp\ndesired_state: running\n")
|
||||
m.mu.Lock()
|
||||
m.stacks["gapp"].Deployed = true
|
||||
m.mu.Unlock()
|
||||
a, err := m.EnsureInstallID("gapp")
|
||||
must(t, err)
|
||||
b, err := m.EnsureInstallID("gapp")
|
||||
must(t, err)
|
||||
if len(a) != 16 || a != b {
|
||||
t.Fatalf("one identity, minted once: %q then %q", a, b)
|
||||
}
|
||||
if got := LoadAppConfig(gappDir(m)); got.DesiredState != DesiredStateRunning {
|
||||
t.Fatalf("minting the identity must change nothing else: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func writeAppYaml(t *testing.T, dir, body string) {
|
||||
t.Helper()
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte(body), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user