| 1 | //go:build unix |
| 2 | |
| 3 | package hostguard |
| 4 | |
| 5 | import ( |
| 6 | "context" |
| 7 | "errors" |
| 8 | "github.com/carlosframework/platform/internal/hostclaim" |
| 9 | "testing" |
| 10 | "time" |
| 11 | ) |
| 12 | |
| 13 | func TestColdHandoverBarrierSurvivesFailureAndBlocksActivateBypass(t *testing.T) { |
| 14 | f, prior, _ := fenceFixture(t) |
| 15 | f.obs.Claim.Op.Kind = hostclaim.KindMoving |
| 16 | if _, err := f.g.BeginFence(t.Context(), prior); err != nil { |
| 17 | t.Fatal(err) |
| 18 | } |
| 19 | if err := f.g.CompleteFence(t.Context(), prior, []byte("root receipt"), time.Now().UTC(), func(context.Context, FenceTarget, []byte, time.Time) error { return nil }); err != nil { |
| 20 | t.Fatal(err) |
| 21 | } |
| 22 | barrier := prior |
| 23 | barrier.FenceID = "handover" |
| 24 | barrier.Stamp = 17 |
| 25 | barrier.Session = 17 |
| 26 | f.obs.Claim.Holder.Stamp = 17 |
| 27 | f.obs.Claim.Holder.Session = 17 |
| 28 | if err := f.g.BeginColdHandover(t.Context(), prior, barrier, allow); err != nil { |
| 29 | t.Fatal(err) |
| 30 | } |
| 31 | if err := f.g.Activate(t.Context(), prior.Host, prior.Box, nil); err != nil { |
| 32 | t.Fatal(err) |
| 33 | } |
| 34 | called := false |
| 35 | if err := f.g.With(t.Context(), prior.Host, Captured{Incarnation: prior.Incarnation, Stamp: 17}, allow, func() error { called = true; return nil }); !errors.Is(err, ErrFenced) || called { |
| 36 | t.Fatalf("barrier bypass = %v", err) |
| 37 | } |
| 38 | crash := errors.New("crash before handover commit") |
| 39 | if err := f.g.CompleteColdHandover(t.Context(), barrier, false, allow, func() error { return crash }); !errors.Is(err, crash) { |
| 40 | t.Fatal(err) |
| 41 | } |
| 42 | if err := f.g.With(t.Context(), prior.Host, Captured{Incarnation: prior.Incarnation, Stamp: 17}, allow, func() error { called = true; return nil }); !errors.Is(err, ErrFenced) || called { |
| 43 | t.Fatalf("failed commit lost barrier: %v", err) |
| 44 | } |
| 45 | if err := f.g.CompleteColdHandover(t.Context(), barrier, false, allow, func() error { return nil }); err != nil { |
| 46 | t.Fatal(err) |
| 47 | } |
| 48 | if err := f.g.With(t.Context(), prior.Host, Captured{Incarnation: prior.Incarnation, Stamp: 17}, allow, func() error { called = true; return nil }); err != nil || !called { |
| 49 | t.Fatal(err) |
| 50 | } |
| 51 | } |
| 52 | |