package host import ( "context" "errors" "testing" "github.com/carlosframework/platform/internal/activator" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/registry" ) type plan9D2RefuseSelect struct{ ClaimWakeInputs } func (p plan9D2RefuseSelect) Select(context.Context, registry.Route, hostclaim.Observed, activator.StartPolicy) (ClaimLaunchInputs, error) { return ClaimLaunchInputs{}, errors.New("selected input disappeared") } func plan9D2Unused(t *testing.T, c *recoveryController, o hostclaim.Observed) *claimWakeAttempt { t.Helper() live, cancel := context.WithCancel(context.Background()) done := make(chan struct{}) go func() { <-live.Done(); close(done) }() a := &claimWakeAttempt{observed: o, held: recoveryHeld{}, ctx: live, cancel: cancel, done: done} c.wake.mu.Lock() c.wake.pending[o.Host] = a c.wake.mu.Unlock() t.Cleanup(cancel) return a } func TestPlan9D2AdmissionFailureReleasesUnusedOperationLease(t *testing.T) { for _, stage := range []string{"select", "after-cas"} { t.Run(stage, func(t *testing.T) { p := activator.StartPolicy{Probe: true} f, c, _, _, _ := plan9D2Landing(t, "probing", p, true) if err := c.wake.release(t.Context(), recoveryHost, c.wake.get(recoveryHost)); err != nil { t.Fatal(err) } before := f.read() a := plan9D2Unused(t, c, before) stops := 0 c.wake.Stop = func(context.Context, hostclaim.Observed) error { stops++; return errors.New("unexpected root stop") } if stage == "select" { c.wake.Inputs = plan9D2RefuseSelect{c.wake.Inputs} } else { c.wake.AfterAdmission = func(context.Context, hostclaim.Observed, hostclaim.Observed) error { return errors.New("source evidence temporarily unavailable") } } if _, err := c.runtime.Admit(t.Context(), registry.Route{Host: recoveryHost}, before, p); err == nil { t.Fatal("admission unexpectedly succeeded") } if c.wake.get(recoveryHost) != nil || !a.released || a.ctx.Err() == nil || stops != 0 { t.Fatalf("unused operation retained or foreign stop attempted: pending=%v released=%v stopped=%d", c.wake.get(recoveryHost) != nil, a.released, stops) } after := f.read() if stage == "select" && after.ETag != before.ETag { t.Fatal("failed selection changed the claim") } if stage == "after-cas" && after.Claim.Holder.Session <= before.Claim.Holder.Session { t.Fatal("cleanup refunded or hid the successful admission") } }) } } func TestPlan9D2CloseNeverStopsAnUnusedForeignPredecessor(t *testing.T) { p := activator.StartPolicy{Probe: true} f, c, _, _, _ := plan9D2Landing(t, "probing", p, true) if err := c.wake.release(t.Context(), recoveryHost, c.wake.get(recoveryHost)); err != nil { t.Fatal(err) } o := f.read() o.Claim.Holder.WriterBox = "source" a := plan9D2Unused(t, c, o) c.wake.Stop = func(context.Context, hostclaim.Observed) error { t.Fatal("foreign predecessor sent to local root") return nil } if err := c.wake.Close(t.Context()); err != nil { t.Fatal(err) } if !a.released || c.wake.get(recoveryHost) != nil { t.Fatal("unused foreign predecessor kept the lease") } }