package host import ( "context" "errors" "github.com/carlosframework/platform/internal/hostguard" "net/http/httptest" "testing" ) type fix1LiveRecovery struct{ recoveryKernelFunc } func (fix1LiveRecovery) CheckRecoveryController(context.Context, hostguard.FenceTarget) error { return ErrClaimStopControllerAlive } func TestPlan11Fix1PendingFenceRestartsWithLiveController(t *testing.T) { f := newLaunchFixture(t, servingOp()) if _, err := f.root.Serve(t.Context(), f.peer, f.req); err != nil { t.Fatal(err) } f.units.goneErr = errors.New("tenant unit still running") c, req := servingStopFixture(t) c.Inventory = exactFixtureInventory{c.Inventory} c.Drainer = stopDrainFunc(func(context.Context, StopRequest, string) (DrainAcknowledgement, error) { return DrainAcknowledgement{}, errors.New("root crashed after fence") }) if _, err := c.FenceAndStop(t.Context(), req); err == nil { t.Fatal("expected interrupted fence") } pending, err := c.Guard.PendingFences(t.Context()) if err != nil || len(pending) != 1 { t.Fatalf("pending=%v err=%v", pending, err) } c.Kernel = claimUnitStopKernel{Journal: f.journal, Units: f.units, Inner: fix1LiveRecovery{recoveryKernelFunc(func(context.Context, hostguard.FenceTarget, StopInventory) (StopKernelEvidence, DrainAcknowledgement, error) { t.Fatal("recovery ran while controller lives") return StopKernelEvidence{}, DrainAcknowledgement{}, nil })}} h := ClaimStopHTTP{Coordinator: c} if err := h.RecoverPending(t.Context()); err != nil { t.Fatalf("root control cannot restart: %v", err) } response := httptest.NewRecorder() h.ServeHTTP(response, httptest.NewRequest("GET", "/claim/stop", nil)) if response.Code == 0 { t.Fatal("root control did not serve") } pending, err = c.Guard.PendingFences(t.Context()) if err != nil || len(pending) != 1 { t.Fatalf("live fence was completed: %v %v", pending, err) } }