e2e: the shared job world runs with lifetimes on, as production runs every self-serve move
newJobWorld writes the cutover marker before its console opens and every console it opens turns lifetimes on; newMemberWorld only adds the member's token. The whole suite (89 top-level tests) passes this way.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 files changed,
+18
−19
internal/e2e/selfserve/job_world_test.go+5 −1internal/e2e/selfserve/member_test.go+13 −18
CI failed — run details
CI log
=== gate === .amadan/test-gate.sh gate: 2026-10-23T22:29:00Z on aarch64, 32 cpus, 61387 MB available, go1.26.8 linux/arm64 gate: +0s start launchctx gate: +0s start vet gate: +0s start gofmt gate: +1s start rest gate: +17s start internal_console@0 gate: +17s start internal_console@1 gate: +17s start internal_console@2 gate: +17s start internal_console@3 gate: +17s start internal_console@4 gate: +17s start internal_console@5 gate: +17s start internal_console@6 gate: +18s start internal_console@7 gate: +20s start root@0 gate: +20s start root@1 gate: +20s start root@2 amadan: step gate failed: signal: terminated amadan: job failed at step gate — its output is above, not at the tail of this log
diff --git a/internal/e2e/selfserve/job_world_test.go b/internal/e2e/selfserve/job_world_test.go| index 2a42b0a36..c11f290da 100644 |
| --- a/internal/e2e/selfserve/job_world_test.go |
| +++ b/internal/e2e/selfserve/job_world_test.go |
| @@ -234,7 +234,7 @@ func switchOf(off bool) string { |
| const jobConsole = "console-e2e-job" |
| // newJobWorld builds the bridge with a lifetime record (incarnation 1) and |
| -// a console beside it in self-serve mode. |
| +// a console beside it in self-serve mode with lifetimes on. |
| func newJobWorld(t *testing.T) *jobWorld { |
| t.Helper() |
| raw := release.NewDirStore(t.TempDir()) |
| @@ -242,6 +242,10 @@ func newJobWorld(t *testing.T) *jobWorld { |
| w := &jobWorld{t: t, ctx: context.Background(), e: e, raw: raw, fs: &faultStore{Store: raw}, dir: t.TempDir(), acct: e.Account(), hits: map[string]int{}, |
| failKinds: map[string]bool{}} |
| w.fs.failing = func() bool { return w.failing } |
| + // Lifetimes on, as production runs every self-serve move (the request |
| + // door admits only then): the cutover marker before the console opens. |
| + w.writeCutoverMarker() |
| + w.lifetimes = true |
| w.open() |
| // The boxes serve no HTTP: the health probe is the witness's answer, |
| // a pass unless a witness says otherwise. |
diff --git a/internal/e2e/selfserve/member_test.go b/internal/e2e/selfserve/member_test.go| index 0679fb166..03a1cec55 100644 |
| --- a/internal/e2e/selfserve/member_test.go |
| +++ b/internal/e2e/selfserve/member_test.go |
| @@ -21,37 +21,32 @@ import ( |
| // an account owner's move-capable instance token on the console, over |
| // HTTP, as the member's own code would call the three self-serve doors and |
| // the status poll. The request door admits only on a console that has |
| -// turned lifetimes on, so a member world writes the cutover marker and |
| -// turns lifetimes on in every console it opens. |
| +// turned lifetimes on, which every job world's console has (newJobWorld). |
| const ownerAddr = "owner@example.com" |
| -// newMemberWorld is newJobWorld with lifetimes on and the member's token. |
| +// newMemberWorld is newJobWorld with the member's token. |
| func newMemberWorld(t *testing.T) *jobWorld { |
| t.Helper() |
| w := newJobWorld(t) |
| - w.lifetimesOn() |
| w.member() |
| return w |
| } |
| -// lifetimesOn writes the cutover marker and turns lifetimes on in this |
| -// console and every console the world opens after it. |
| -func (w *jobWorld) lifetimesOn() { |
| +// writeCutoverMarker writes the cutover marker (once), so every console |
| +// the world opens turns lifetimes on (open, console.TestHooks.LifetimesOn). |
| +func (w *jobWorld) writeCutoverMarker() { |
| w.t.Helper() |
| const key = "control/lifetimes-cutover.json" |
| - if _, _, err := w.raw.Get(w.ctx, key); err != nil { |
| - body, _ := json.Marshal(struct { |
| - At time.Time `json:"at"` |
| - By string `json:"by"` |
| - }{time.Now().UTC(), ownerAddr}) |
| - if _, err := w.raw.Put(w.ctx, key, body, ""); err != nil && !errors.Is(err, release.ErrCASConflict) { |
| - w.t.Fatal(err) |
| - } |
| + if _, _, err := w.raw.Get(w.ctx, key); err == nil { |
| + return |
| } |
| - w.lifetimes = true |
| - if !console.TestHooks.LifetimesOn(w.ctx, w.srv) { |
| - w.t.Fatal("lifetimes did not turn on") |
| + body, _ := json.Marshal(struct { |
| + At time.Time `json:"at"` |
| + By string `json:"by"` |
| + }{time.Now().UTC(), ownerAddr}) |
| + if _, err := w.raw.Put(w.ctx, key, body, ""); err != nil && !errors.Is(err, release.ErrCASConflict) { |
| + w.t.Fatal(err) |
| } |
| } |