package activator import ( "context" "errors" "os/exec" "testing" "time" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostwrite" "github.com/carlosframework/platform/internal/registry" ) func TestStartAdmittedLazyLaunchFailureSettlesWithoutSpawn(t *testing.T) { o := hostclaim.Observed{Host: "app.example.test", ETag: "one", Claim: &hostclaim.Claim{Holder: &hostclaim.Holder{Location: "instances/app/inc", Session: 1, Generation: "new"}, Op: hostclaim.Op{Kind: hostclaim.KindServing, Exec: "box"}}} work, _ := (hostwrite.Config{}).Select(t.Context(), o.Host, "spawn") restored, materialized, built := false, false, false failures := 0 failure := errors.New("constructor failed") start := ClaimStart{Host: o.Host, Work: work, Identity: hostwrite.Identity{Config: "config", Release: "release"}, CurrentAttempt: func() hostclaim.WakeRetryAttempt { return hostclaim.WakeRetryAttempt{ID: "attempt"} }, Restore: func(context.Context) error { restored = true; return nil }, Materialize: func(context.Context) error { materialized = true; return nil }, Build: func() *exec.Cmd { built = true; return nil }, Ready: func(context.Context, *exec.Cmd) error { return nil }, Reserve: func(context.Context, int) error { return nil }, Failed: func(context.Context, int) error { failures++; return nil }, Healthy: func(context.Context, int, *exec.Cmd) error { return nil }, Replicate: func(context.Context, string) (Rep, error) { t.Fatal("replicator opened without launch") return nil, nil }, Publish: func(context.Context, hostclaim.Observed) (hostclaim.Observed, error) { return o, nil }, Retain: func(Proc, Rep, error) {}, PrepareLaunch: func(context.Context) (*RoleLaunch, error) { if !restored || !materialized { t.Fatal("launch constructor ran before state materialization") } return nil, failure }} a := &Service{cfg: Config{HostWrites: hostwrite.Config{Enabled: true}, Claims: &ClaimRuntime{Box: "box", Read: func(context.Context, string) (hostclaim.Observed, error) { return o, nil }, Prepare: func(context.Context, registry.Route, hostclaim.Observed, StartPolicy) (ClaimStart, error) { return start, nil }}}} err := a.startAdmitted(t.Context(), &actEntry{host: o.Host}, o, StartPolicy{MaxStarts: 1, Window: time.Second}) if !errors.Is(err, failure) || failures != 1 || built { t.Fatalf("err=%v failures=%d built=%v", err, failures, built) } live, cancel := context.WithCancel(context.Background()) cancel() start.Live = live restored = false if err = a.startAdmitted(t.Context(), &actEntry{host: o.Host}, o, StartPolicy{MaxStarts: 1, Window: time.Second}); !errors.Is(err, context.Canceled) || restored { t.Fatalf("lost lease restored=%v err=%v", restored, err) } }