sandbox.connect.resume.test.mjs
1 import assert from "node:assert/strict"; 2 import test from "node:test"; 3 4 import { 5 ConnectionConfig, 6 DEFAULT_EGRESS_PORT, 7 DEFAULT_EXECD_PORT, 8 Sandbox, 9 } from "../dist/index.js"; 10 11 function createAdapterFactory() { 12 const calls = []; 13 const sandboxes = { 14 async getSandboxEndpoint(sandboxId, port, useServerProxy) { 15 calls.push({ method: "getSandboxEndpoint", args: [sandboxId, port, useServerProxy] }); 16 return { 17 endpoint: `sandbox.internal:${port}`, 18 headers: { "x-port": String(port) }, 19 }; 20 }, 21 async resumeSandbox(sandboxId) { 22 calls.push({ method: "resumeSandbox", args: [sandboxId] }); 23 }, 24 async getSandbox() { 25 throw new Error("not implemented"); 26 }, 27 async listSandboxes() { 28 throw new Error("not implemented"); 29 }, 30 async createSandbox() { 31 throw new Error("not implemented"); 32 }, 33 async deleteSandbox() {}, 34 async pauseSandbox() {}, 35 async renewSandboxExpiration() { 36 throw new Error("not implemented"); 37 }, 38 }; 39 40 const adapterFactory = { 41 createLifecycleStack() { 42 return { sandboxes }; 43 }, 44 createExecdStack(opts) { 45 calls.push({ method: "createExecdStack", args: [opts] }); 46 return { 47 commands: { kind: "commands" }, 48 files: { kind: "files" }, 49 health: { async ping() { return true; } }, 50 metrics: { kind: "metrics" }, 51 }; 52 }, 53 createEgressStack(opts) { 54 calls.push({ method: "createEgressStack", args: [opts] }); 55 return { 56 egress: { 57 async getPolicy() { 58 return { defaultAction: "deny", egress: [] }; 59 }, 60 async patchRules() {}, 61 }, 62 }; 63 }, 64 }; 65 66 return { adapterFactory, calls }; 67 } 68 69 test("Sandbox.connect wires execd and egress stacks and getEndpointUrl uses protocol", async () => { 70 const { adapterFactory, calls } = createAdapterFactory(); 71 const connectionConfig = new ConnectionConfig({ domain: "https://api.opensandbox.test" }); 72 connectionConfig.withTransportIfMissing = () => connectionConfig; 73 74 const sandbox = await Sandbox.connect({ 75 sandboxId: "sbx-1", 76 connectionConfig, 77 adapterFactory, 78 skipHealthCheck: true, 79 }); 80 81 assert.equal(sandbox.id, "sbx-1"); 82 assert.equal(await sandbox.getEndpointUrl(8080), "https://sandbox.internal:8080"); 83 assert.deepEqual( 84 calls 85 .filter((entry) => entry.method === "getSandboxEndpoint") 86 .map((entry) => entry.args.slice(0, 2)), 87 [ 88 ["sbx-1", DEFAULT_EXECD_PORT], 89 ["sbx-1", DEFAULT_EGRESS_PORT], 90 ["sbx-1", 8080], 91 ], 92 ); 93 assert.equal(calls[2].method, "createExecdStack"); 94 assert.equal(calls[2].args[0].execdBaseUrl, `https://sandbox.internal:${DEFAULT_EXECD_PORT}`); 95 assert.deepEqual(calls[2].args[0].endpointHeaders, { "x-port": String(DEFAULT_EXECD_PORT) }); 96 }); 97 98 test("Sandbox.resume refreshes endpoints through connect after resuming lifecycle", async () => { 99 const { adapterFactory, calls } = createAdapterFactory(); 100 const connectionConfig = new ConnectionConfig({ domain: "http://127.0.0.1:8080" }); 101 connectionConfig.withTransportIfMissing = () => connectionConfig; 102 103 const sandbox = await Sandbox.connect({ 104 sandboxId: "sbx-2", 105 connectionConfig, 106 adapterFactory, 107 skipHealthCheck: true, 108 }); 109 110 calls.length = 0; 111 const resumed = await sandbox.resume({ skipHealthCheck: true }); 112 113 assert.equal(resumed.id, "sbx-2"); 114 assert.equal(calls[0].method, "resumeSandbox"); 115 assert.deepEqual(calls[0].args, ["sbx-2"]); 116 assert.deepEqual( 117 calls 118 .filter((entry) => entry.method === "getSandboxEndpoint") 119 .map((entry) => entry.args.slice(0, 2)), 120 [ 121 ["sbx-2", DEFAULT_EXECD_PORT], 122 ["sbx-2", DEFAULT_EGRESS_PORT], 123 ], 124 ); 125 });