package host import ( "context" "encoding/json" "testing" "time" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostclaim" execlease "github.com/carlosframework/platform/internal/hostexec" "github.com/carlosframework/platform/internal/hostguard" ) func TestPlan14OrdinaryDeleteParticipation(t *testing.T) { t.Parallel() for _, mode := range []string{"live", "stopped", "parking", "retired", "serving stopped", "pending", "record present", "delete absent", "etag", "key", "enrollment", "foreign home", "session", "stamp", "op", "box", "inventory"} { t.Run(mode, func(t *testing.T) { f, root, iq := plan14InstallRegistration(t, hostclaim.KindServing, "") if _, err := root.commitRootInventory(t.Context(), iq); err != nil { t.Fatal(err) } actor, _ := root.InventoryActor(t.Context()) actor.FleetHomeRegion, actor.HomeRegion = "ie", "ie" root.InventoryActor = func(context.Context) (hostbox.Actor, error) { return actor, nil } o, err := hostclaim.Update(t.Context(), f.claims, f.read(), hostclaim.AdmitWriter(hostclaim.Admission{ObservedSession: f.read().Claim.Holder.Session, ObservedGeneration: f.read().Claim.Holder.Generation, Box: actor.Box, Region: "ie", Mode: "cold", NewGeneration: "delete-generation", KeepStamp: true})) if err != nil { t.Fatal(err) } target := iq.Target target.Session, target.ClaimETag, target.ClaimGen = o.Claim.Holder.Session, o.ETag, o.Claim.Gen target.FenceID, target.Region, target.BootID, target.ControllerID, target.DirectoryRevision, target.RosterRevision = "delete-stop", "ie", "boot", "controller", "1", 1 if mode != "live" { if target, err = root.Stop.Coordinator.Guard.BeginFence(t.Context(), target); err != nil { t.Fatal(err) } if mode != "pending" { at := time.Now().UTC() receipt := StopReceipt{V: 1, Kind: "stopped", ID: "delete-stop-receipt", FenceID: target.FenceID, Host: target.Host, Incarnation: target.Incarnation, InstallationStamp: target.Stamp, WriterSession: target.Session, Region: target.Region, ClaimETag: target.ClaimETag, ClaimGen: target.ClaimGen, Box: target.Box, Enrollment: target.Enrollment, BootID: target.BootID, ControllerID: target.ControllerID, DirectoryRevision: testReceiptNumeral(target), Binding: target.DirectoryRevision, EvidenceAt: at} raw, _ := json.Marshal(receipt) if err = root.Stop.Coordinator.Guard.CompleteFence(t.Context(), target, raw, at, func(ctx context.Context, t hostguard.FenceTarget, b []byte, at time.Time) error { return verifyRetirementReceipt(ctx, hostguard.FenceReceipt{Target: t, Bytes: b, EvidenceAt: at}) }); err != nil { t.Fatal(err) } } } if mode != "serving stopped" { o, err = hostclaim.Update(t.Context(), f.claims, f.read(), hostclaim.BeginDelete("delete", "console", iq.RecordETag, time.Now(), []string{"ie"}, []string{actor.Box}, "")) if err != nil { t.Fatal(err) } } if mode == "parking" || mode == "retired" || mode == "record present" { o, err = hostclaim.Update(t.Context(), f.claims, o, hostclaim.ToScopedParking("delete", []string{"ie"}, []string{actor.Box}, f.newID)) if err != nil { t.Fatal(err) } } if mode == "parking" || mode == "retired" || mode == "delete absent" { if err = f.claims.Delete(t.Context(), iq.RecordKey); err != nil { t.Fatal(err) } } if mode == "retired" { if err = root.Stop.Coordinator.Guard.RetireInstallationWith(t.Context(), o.Host, hostguard.Captured{Incarnation: target.Incarnation, Stamp: target.Stamp}, func(*hostclaim.Claim) error { return nil }, func() error { return nil }); err != nil { t.Fatal(err) } } if mode == "etag" || mode == "key" { o, err = hostclaim.Update(t.Context(), f.claims, o, func(c *hostclaim.Claim) error { c.Op.Intent[mode] = "forged"; return nil }) if err != nil { t.Fatal(err) } } q := execlease.ExecutionRequest{Schema: 1, ID: "delete-participation", Operation: "executionBegin", Host: o.Host, Incarnation: target.Incarnation, Stamp: target.Stamp, Session: target.Session, Op: o.Claim.Op.ID} switch mode { case "enrollment": actor.Enrollment = "foreign" case "foreign home": actor.FleetHomeRegion = "uk" case "session": q.Session++ case "stamp": q.Stamp++ case "op": q.Op = "foreign" case "box": actor.Box = "foreign" case "inventory": if err = root.Journals.Inventory.WriteStopInventory(t.Context(), iq.Inventory); err != nil { t.Fatal(err) } } a, err := root.executionAuthority(t.Context(), q, execlease.ControllerProcess{}) want := mode == "live" || mode == "stopped" || mode == "parking" || mode == "retired" || mode == "delete absent" if want { if err != nil || !a.ParticipationOnly || a.Installation == "" || a.RecordRevision != iq.RecordETag { t.Fatalf("participation: %+v %v", a, err) } } else if err == nil { t.Fatalf("unsafe participation: %+v", a) } if mode == "retired" { root.Stop.Coordinator.Kernel = f.kernel f.kernel.noProcess = true if err := root.cleanupExecution(t.Context(), execlease.ExecutionRecord{Request: q, Authority: a}); err != nil || f.kernel.noProcessCalls != 1 { t.Fatalf("retired participation cleanup: %v, kernel calls=%d", err, f.kernel.noProcessCalls) } a.Enrollment = "foreign" if err := root.cleanupExecution(t.Context(), execlease.ExecutionRecord{Request: q, Authority: a}); err == nil || f.kernel.noProcessCalls != 1 { t.Fatalf("foreign retired cleanup: %v, kernel calls=%d", err, f.kernel.noProcessCalls) } } }) } }