package host import ( "context" "os" "testing" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostguard" "github.com/carlosframework/platform/internal/instancectl" "github.com/carlosframework/platform/internal/rootstate" ) type generationExclusiveStore struct { rootstate.Store held bool nested int } func (s *generationExclusiveStore) Lock(ctx context.Context, name string) (func(), error) { if s.held { s.nested++ return nil, os.ErrPermission } unlock, err := s.Store.Lock(ctx, name) if err != nil { return nil, err } s.held = true return func() { s.held = false; unlock() }, nil } func TestPlan14GenerationLaunchDoesNotReenterRootLock(t *testing.T) { for _, validator := range []bool{false, true} { t.Run(map[bool]string{false: "reservation", true: "production-validator"}[validator], func(t *testing.T) { f, disk, rec := generationLaunchFixture(t) rec.Schema, rec.Channel = 1, "canary/console" plan14PutRecord(t, f.root.generations.store, rec) store := &generationExclusiveStore{Store: &rollbackDisk{dir: t.TempDir()}} f.root.Guard.Root = hostguard.NewRootAuthority(store) in := hostguard.RootInstallation{Host: rec.Host, Account: rec.Account, App: rec.App, Record: "apps/" + rec.Account + "/" + rec.App + "/instances/" + rec.Host + ".json", Incarnation: f.target.Incarnation, Stamp: f.target.Stamp, Box: f.target.Box, Enrollment: f.target.Enrollment, Migration: 1, InventoryRevision: 1} if err := f.root.Guard.EstablishRoot(t.Context(), in, func(*hostclaim.Claim) error { return nil }); err != nil { t.Fatal(err) } if validator { f.root.ValidateExecutable = claimStagedExecutable(&instancectl.Server{OptDir: f.root.generations.optDir, HostApp: rootInstallationHostApp(f.root.Guard, f.root.generations.store)}) } if _, err := f.root.Serve(t.Context(), f.peer, f.req); err != nil { t.Fatalf("launch refused: %v; recursive locks=%d", err, store.nested) } if store.nested != 0 { t.Fatalf("recursive root locks: %d", store.nested) } if r := readGenerationLaunch(t, disk); r.Process.PID == 0 { t.Fatal("launch was not recorded") } }) } }