package activator import ( "context" "errors" "testing" "time" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostwrite" "github.com/carlosframework/platform/internal/registry" ) func TestPlan12RecoveryResumeReachesPrepare(t *testing.T) { for _, mode := range []string{"verified", "missing", "refused", "changed", "changed-after-resume", "session", "op", "writer", "stamp", "kind", "phase", "exec"} { t.Run(mode, func(t *testing.T) { o := hostclaim.Observed{Host: "x.example", ETag: "etag", Claim: &hostclaim.Claim{Holder: &hostclaim.Holder{Incarnation: "inc", Session: 3, Stamp: 3, Generation: "gen", WriterBox: "box"}, Op: hostclaim.Op{ID: "move", Kind: hostclaim.KindRestoring, Phase: hostclaim.PhaseProbing, Exec: "box"}}} prepared := errors.New("prepare reached") current := o r := &ClaimRuntime{Box: "box", Read: func(context.Context, string) (hostclaim.Observed, error) { return current, nil }, StopForeign: func(context.Context, string) error { return nil }, Prerequisites: func(context.Context, registry.Route, hostclaim.Observed, startPolicy) error { return nil }, Admit: func(context.Context, registry.Route, hostclaim.Observed, startPolicy) (hostclaim.Observed, error) { next := o claim := *o.Claim holder := *claim.Holder next.Claim = &claim claim.Holder = &holder switch mode { case "session": holder.Session-- case "op": claim.Op.ID = "other" case "writer": holder.WriterBox = "other" case "stamp": holder.Stamp++ case "kind": claim.Op.Kind = hostclaim.KindReverting case "phase": claim.Op.Phase = "other" case "exec": claim.Op.Exec = "other" } if mode == "changed" { next.ETag = "changed" } current = next return next, nil }, Prepare: func(context.Context, registry.Route, hostclaim.Observed, startPolicy) (ClaimStart, error) { return ClaimStart{}, prepared }, FailedAdmission: func(context.Context, hostclaim.Observed, error) error { return nil }} if mode != "missing" { r.ResumedAdmission = func(context.Context, hostclaim.Observed, hostclaim.Observed) error { if mode == "changed-after-resume" { current.ETag = "changed" } if mode == "refused" { return hostbox.ErrChanged } return nil } } s := &Service{cfg: Config{HostWrites: hostwrite.Config{Enabled: true}, Claims: r}} _, err := s.doClaimWake(t.Context(), &actEntry{host: o.Host, route: registry.Route{Host: o.Host}, recoveryPolicy: &StartPolicy{Probe: true, MaxStarts: 5, Window: 30 * time.Second}}) if mode == "verified" || mode == "changed" || mode == "changed-after-resume" { if !errors.Is(err, prepared) { t.Fatalf("resume did not reach prepare: %v", err) } } else if !errors.Is(err, hostbox.ErrChanged) { t.Fatalf("unverified resume: %v", err) } }) } }