e2e: the reclaim witness's empty reason only for the unreadable holder; the recreated and two-moves witnesses say what they leave to other witnesses
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 file changed,
+19
−13
internal/e2e/selfserve/selfserve_rows_test.go+19 −13
diff --git a/internal/e2e/selfserve/selfserve_rows_test.go b/internal/e2e/selfserve/selfserve_rows_test.go| index ec945e62d..2ea8622b3 100644 |
| --- a/internal/e2e/selfserve/selfserve_rows_test.go |
| +++ b/internal/e2e/selfserve/selfserve_rows_test.go |
| @@ -102,7 +102,11 @@ func (w *jobWorld) lifetimeHost(hostname string, inc uint64) { |
| // finishes the row aborted "the instance was recreated" and never writes |
| // the new lifetime's record (no move, its sequence unchanged); nothing |
| // stays reserved; and the member's poll of the new instance shows nothing |
| -// of the old lifetime's move. |
| +// of the old lifetime's move. This is reconciliation's "gone" path (the |
| +// row's lifetime has no record before any write); a recreation between a |
| +// request's issue and its bound write, refused on the incarnation at the |
| +// write, is TestBoundWritesNeverLandAfterAVoid's "recreated at the same |
| +// sequence". |
| func TestSelfServeRecreatedBetweenRowAndRecord(t *testing.T) { |
| w := newMemberWorld(t) |
| id := w.prepare() |
| @@ -128,7 +132,10 @@ func TestSelfServeRecreatedBetweenRowAndRecord(t *testing.T) { |
| // the two boxes. A second instance's move on the same boxes waits before |
| // it reserves, its poll saying why; a third instance's move on two other |
| // boxes reserves at once, beside the first. Once the first is done and its |
| -// boxes released, the second takes them. The orderings on their own are |
| +// boxes released, the second takes them. The second and third rows are |
| +// admitted directly (admitFor), not through the member's door: their hosts |
| +// are fixture records with no replica on any box, so the door's source |
| +// facts could never pass. The orderings on their own are |
| // TestTwoMovesOnOneBoxQueueInOrder, TestTwoMovesOnDisjointBoxesRunAtOnce |
| // and TestQueueOrderAndDisjointProgress. |
| func TestSelfServeTwoMovesDisjointAndQueued(t *testing.T) { |
| @@ -212,9 +219,10 @@ func TestSelfServeReservationReclaimOnlyOnEvidence(t *testing.T) { |
| entry := func(w *jobWorld, at time.Time) moves.OfflineReservation { |
| return moves.OfflineReservation{Kind: moves.OfflineKindMove, ID: orphan, Host: holder, Account: w.acct, App: host.E2EApp, ReservedAt: at} |
| } |
| - // waits is the member's move kept in reserving over ticks, the entry |
| - // kept, its poll saying why. |
| - waits := func(w *jobWorld, id string) { |
| + // waits is the member's move kept in reserving over ticks with the |
| + // entry kept, its row saying reason ("" for an unreadable holder: the |
| + // job retries the reservation on the next tick without one). |
| + waits := func(w *jobWorld, id, reason string) { |
| w.t.Helper() |
| for i := 0; i < 3; i++ { |
| w.boxes() |
| @@ -224,13 +232,11 @@ func TestSelfServeReservationReclaimOnlyOnEvidence(t *testing.T) { |
| switch { |
| case r.Phase != "reserving" || !w.reservedBy(orphan) || w.reservedBy(id): |
| w.t.Fatalf("the holder's entry was not kept: %s, reservations %v", describe(r), w.reservations()) |
| - case r.Reason != "waiting for another move on this box": |
| - // The unreadable holder is retried without a reason. |
| - if r.Reason != "" { |
| - w.t.Fatalf("the waiting move's reason %q", r.Reason) |
| - } |
| + case r.Reason != reason: |
| + w.t.Fatalf("the waiting move's reason %q, want %q", r.Reason, reason) |
| } |
| } |
| + const busy = "waiting for another move on this box" |
| // reclaimed is the member's move past reserving on its own entry. |
| reclaimed := func(w *jobWorld, id string) { |
| w.t.Helper() |
| @@ -247,7 +253,7 @@ func TestSelfServeReservationReclaimOnlyOnEvidence(t *testing.T) { |
| {"no evidence: reclaimed after the fence", func(w *jobWorld) {}, nil}, |
| {"young: kept, then reclaimed once old", func(w *jobWorld) {}, func(w *jobWorld, id string) { |
| w.putEntry(w.e.Box(host.E2ESourceBox).BoxID(), entry(w, time.Now().UTC())) |
| - waits(w, id) |
| + waits(w, id, busy) |
| w.putEntry(w.e.Box(host.E2ESourceBox).BoxID(), entry(w, old)) |
| }}, |
| {"the holder's record carries the move: kept, nothing written", func(w *jobWorld) { |
| @@ -259,7 +265,7 @@ func TestSelfServeReservationReclaimOnlyOnEvidence(t *testing.T) { |
| } |
| }, func(w *jobWorld, id string) { |
| seq := w.recordOf(holder).RecordSeq |
| - waits(w, id) |
| + waits(w, id, busy) |
| if got := w.recordOf(holder).RecordSeq; got != seq { |
| w.t.Fatalf("the live holder's record was written: seq %d, was %d", got, seq) |
| } |
| @@ -280,7 +286,7 @@ func TestSelfServeReservationReclaimOnlyOnEvidence(t *testing.T) { |
| if err != nil { |
| w.t.Fatal(err) |
| } |
| - waits(w, id) |
| + waits(w, id, "") |
| if _, err := w.raw.Put(w.ctx, key, good, etag); err != nil { |
| w.t.Fatal(err) |
| } |