package hostrelocate import ( "context" "errors" "testing" "time" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostexec" ) type plan14TargetAcknowledgement struct{ *fakeBox } func (b plan14TargetAcknowledgement) Acknowledge(ctx context.Context, o hostclaim.Observed) (hostclaim.ExecutionAcknowledgement, error) { if hostexec.PreinstallationParticipant(o.Claim, b.box, enrollment(b.box)) != nil { return hostclaim.ExecutionAcknowledgement{}, ErrRefused } return b.fakeBox.Acknowledge(ctx, o) } func TestPlan14PreinstallationTargetAcknowledgement(t *testing.T) { for _, kind := range []string{"drain", "failover", "converted-landing"} { t.Run(kind, func(t *testing.T) { f := newFixture(t) target, executor, next := "dst", "src", hostclaim.PhaseReleasing if kind == "converted-landing" { f.convertedLanding() f.worker(nil) target, executor, next = "spa", "none", hostclaim.PhasePinning } else { reason := hostclaim.ReasonDrain if kind == "failover" { f.terminate("src") reason, executor, next = hostclaim.ReasonFailover, "none", hostclaim.PhasePinning } if _, err := f.w.Start(t.Context(), host, Request{Reason: reason, Source: "src", Target: target}); err != nil { t.Fatal(err) } } if kind == "drain" { f.ack("src") } before := f.claim() if before.Claim.Op.Phase != hostclaim.PhaseStarting || before.Claim.Op.Exec != executor || before.Claim.Op.Intent["target_box"] != target { t.Fatalf("unexpected starting authority: %+v", before.Claim.Op) } box := &fakeBox{f: f, box: target} p := Participant{Claims: f.s, Box: target, Enrollment: enrollment(target), Now: func() time.Time { return f.now }, Effects: plan14TargetAcknowledgement{box}} for _, attack := range []string{"wrong phase", "unnamed box"} { bad := *before.Claim bad.Op = before.Claim.Op bad.Op.Intent = map[string]string{} for k, v := range before.Claim.Op.Intent { bad.Op.Intent[k] = v } if attack == "wrong phase" { bad.Op.Phase = hostclaim.PhaseRelocatingProbing bad.Op.Exec = target } else { bad.Op.Intent["target_box"] = "elsewhere" } if _, err := (plan14TargetAcknowledgement{box}).Acknowledge(t.Context(), hostclaim.Observed{Host: host, Claim: &bad}); !errors.Is(err, ErrRefused) { t.Fatalf("%s: %v", attack, err) } } if after := f.claim(); after.ETag != before.ETag || box.opened != 0 || len(box.effects) != 0 || len(f.leases) != 0 { t.Fatal("refusal had effects") } if _, err := p.Step(t.Context(), host); err != nil { t.Fatal(err) } if o := f.worker(nil); o.Claim.Op.Phase != next || o.Claim.Op.Exec != executor { t.Fatalf("named-target acknowledgement did not advance without executor handoff: %+v", o.Claim.Op) } if box.opened != 1 || len(box.effects) != 0 { t.Fatal("acknowledgement performed installation effects") } }) } }