diff --git a/tests/sandbox.test.ts b/tests/sandbox.test.ts index 7cb12a2..853aa95 100644 --- a/tests/sandbox.test.ts +++ b/tests/sandbox.test.ts @@ -11,6 +11,36 @@ const sandbox = async (...args: string[]) => { return (await $.raw`deno sandbox ${args.join(" ")}`.text()).trim(); }; +/** + * `sandbox volumes create` returns the volume id immediately, but the + * backend takes a moment to make the volume mountable inside a sandbox + * even after it's queryable via `volumes list`. Poll the list endpoint + * first, then sleep `postListSleepMs` to let the cluster sync — without + * that extra sleep we still hit `VOLUME_NOT_FOUND` when the follow-up + * `sandbox create --volume :path` runs. + */ +async function waitForVolumeReady( + volumeId: string, + { + timeoutMs = 30_000, + intervalMs = 500, + postListSleepMs = 5_000, + } = {}, +): Promise { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + const list = await sandbox("volumes", "list"); + if (list.includes(volumeId)) { + await new Promise((r) => setTimeout(r, postListSleepMs)); + return; + } + await new Promise((r) => setTimeout(r, intervalMs)); + } + throw new Error( + `Timed out waiting for volume ${volumeId} to become visible via 'volumes list'`, + ); +} + Deno.test("sandbox create", async () => { const sandboxId = await sandbox( "create", @@ -143,15 +173,39 @@ Deno.test("sandbox with volume mount", async () => { "--region", "ord", ); - - const sandboxId = await sandbox( - "create", - "--quiet", - "--timeout", - "60s", - "--volume", - `${volumeId}:/data/dataset`, - ); + await waitForVolumeReady(volumeId); + + // The sandbox-side volume lookup hits a different service from the + // volumes list endpoint we just polled; that service propagates the + // new volume asynchronously, so a one-shot wait isn't enough. Retry + // the mount-bearing create a few times. + let sandboxId: string | undefined; + let lastErr: unknown; + for (let attempt = 0; attempt < 6; attempt++) { + try { + sandboxId = await sandbox( + "create", + "--quiet", + "--timeout", + "60s", + "--region", + "ord", + "--volume", + `${volumeId}:/data/dataset`, + ); + break; + } catch (err) { + lastErr = err; + await new Promise((r) => setTimeout(r, 5_000)); + } + } + if (!sandboxId) { + throw new Error( + `sandbox create with --volume kept failing: ${ + lastErr instanceof Error ? lastErr.message : String(lastErr) + }`, + ); + } await sandbox( "exec",