//go:build linux package host import ( "os" "path/filepath" "testing" "github.com/carlosframework/platform/internal/activator" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/release" ) // The wired LocalSeedID and RemoveLocal are Plan 4's marker read and purge // (preflight M12), through instancefs: the marker names the seed, and the // removal takes the database, its WAL and SHM, the marker and the seed // fetch leftovers, and leaves anything else in the directory. func TestWiredRollbackReadsAndRemovesTheLocalSeed(t *testing.T) { h := wiredSeedHooks(t, &fakeFence{gens: map[string]uint64{}}, restartTestRegistry(t), release.NewDirStore(t.TempDir()), release.NewDirStore(t.TempDir())) const id = "sd_aaaaaaaaaaaaaaaaaaaaaaaaaa" dir := filepath.Join(t.TempDir(), "shop-1.example.com") if err := os.MkdirAll(dir, 0o700); err != nil { t.Fatal(err) } db := filepath.Join(dir, "shop-1.example.com.db") gone := []string{db, db + "-wal", db + "-shm", db + activator.SeedMarkerSuffix, filepath.Join(dir, ".seed-sd_x.tmp")} for _, p := range gone { body := "data" if p == db+activator.SeedMarkerSuffix { body = id + "\n" } if err := os.WriteFile(p, []byte(body), 0o600); err != nil { t.Fatal(err) } } kept := filepath.Join(dir, "uploads.txt") if err := os.WriteFile(kept, []byte("keep"), 0o600); err != nil { t.Fatal(err) } if got, err := h.LocalSeedID(db); err != nil || got != id { t.Fatalf("LocalSeedID = %q, %v; want %q", got, err, id) } if err := h.RemoveLocal(registry.Route{Host: "shop-1.example.com", Kind: "instance", DBPath: db}); err != nil { t.Fatal(err) } for _, p := range gone { if _, err := os.Lstat(p); !os.IsNotExist(err) { t.Errorf("%s survived the removal (%v)", p, err) } } if _, err := os.Stat(kept); err != nil { t.Errorf("an unrelated file went: %v", err) } if got, err := h.LocalSeedID(db); err != nil || got != "" { t.Fatalf("LocalSeedID after the removal = %q, %v", got, err) } if err := h.RemoveLocal(registry.Route{Host: "shop-1.example.com", Kind: "instance", DBPath: db}); err != nil { t.Fatalf("a second removal: %v", err) } } // Merge review S1: the wired EnvBefore and RetireKey are the activator's // read of the host's own env file and its retirement of the import's key. // A file the import created goes; a key that was there before stays. func TestWiredSwapAndRollbackKnowTheImportsInstanceKey(t *testing.T) { h := wiredSeedHooks(t, &fakeFence{gens: map[string]uint64{}}, restartTestRegistry(t), release.NewDirStore(t.TempDir()), release.NewDirStore(t.TempDir())) const host = "shop-1.example.com" dir := filepath.Join(t.TempDir(), host) if err := os.MkdirAll(dir, 0o700); err != nil { t.Fatal(err) } db, env := filepath.Join(dir, host+".db"), filepath.Join(dir, host+".env") if got, err := h.EnvBefore(db, host); err != nil || got != registry.EnvBeforeAbsent { t.Fatalf("EnvBefore with no file = %q, %v", got, err) } body := activator.InstanceKeyVar + "=minted-by-the-import\n" if err := os.WriteFile(env, []byte(body), 0o600); err != nil { t.Fatal(err) } if got, err := h.EnvBefore(db, host); err != nil || got != registry.EnvBeforeKey { t.Fatalf("EnvBefore with a key = %q, %v", got, err) } if err := h.RetireKey(db, host, registry.EnvBeforeKey); err != nil { t.Fatal(err) } if got, err := os.ReadFile(env); err != nil || string(got) != body { t.Fatalf("a key that predated the import was touched: %q, %v", got, err) } if err := h.RetireKey(db, host, registry.EnvBeforeAbsent); err != nil { t.Fatal(err) } if _, err := os.Lstat(env); !os.IsNotExist(err) { t.Fatalf("the env file the import created survived (%v)", err) } }