diff --git a/packages/js-sdk/package.json b/packages/js-sdk/package.json index 6fc6cd57e..b8aab632e 100644 --- a/packages/js-sdk/package.json +++ b/packages/js-sdk/package.json @@ -35,7 +35,8 @@ "update-deps": "ncu -u && pnpm i", "postPublish": "./scripts/post-publish.sh || true", "test:bun": "bun test tests/runtimes/bun --env-file=.env", - "test:deno": "deno test tests/runtimes/deno/ --allow-net --allow-read --allow-env --unstable-sloppy-imports --trace-leaks" + "test:deno": "deno test tests/runtimes/deno/ --allow-net --allow-read --allow-env --unstable-sloppy-imports --trace-leaks", + "test:integration": "E2B_INTEGRATION_TEST=1 vitest run tests/integration/**" }, "devDependencies": { "@testing-library/react": "^16.0.1", diff --git a/packages/js-sdk/tests/integration/stress.test.ts b/packages/js-sdk/tests/integration/stress.test.ts new file mode 100644 index 000000000..69da1472d --- /dev/null +++ b/packages/js-sdk/tests/integration/stress.test.ts @@ -0,0 +1,77 @@ +import { test } from 'vitest' + +import Sandbox from '../../src/index.js' +import { isIntegrationTest, wait } from '../setup.js' + +const heavyArray = new ArrayBuffer(256 * 1024 * 1024) // 256 MiB = 256 * 1024 * 1024 bytes +const view = new Uint8Array(heavyArray) +for (let i = 0; i < view.length; i++) { + view[i] = Math.floor(Math.random() * 256) +} + +const integrationTestTemplate = 'integration-test-v1' +const sanboxCount = 10 + +test.skipIf(!isIntegrationTest)( + 'stress test heavy file writes and reads', + async () => { + const promises: Array> = [] + for (let i = 0; i < sanboxCount; i++) { + promises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60 }) + .then((sbx) => { + console.log(sbx.sandboxId) + return sbx.files + .write('heavy-file', heavyArray) + .then(() => sbx.files.read('heavy-file')) + }) + .catch(console.error) + ) + } + await wait(10_000) + await Promise.all(promises) + } +) + +test.skipIf(!isIntegrationTest)('stress requests to nextjs app', async ({}) => { + const hostPromises: Array> = [] + + for (let i = 0; i < sanboxCount; i++) { + hostPromises.push( + Sandbox.create(integrationTestTemplate, { timeoutMs: 60_000 }).then( + (sbx) => { + console.log('created sandbox', sbx.sandboxId) + return new Promise((resolve, reject) => { + try { + resolve(sbx.getHost(3000)) + } catch (e) { + console.error('error getting sbx host', e) + reject(e) + } + }) + } + ) + ) + } + + await wait(10_000) + const hosts = await Promise.all(hostPromises) + + const fetchPromises: Array> = [] + + for (let i = 0; i < 100; i++) { + for (const host of hosts) { + fetchPromises.push( + new Promise((resolve) => { + fetch('https://' + host) + .then((res) => { + console.log(`response for ${host}: ${res.status}`) + }) + .then(resolve) + }) + ) + } + } + + await Promise.all(fetchPromises) +}) diff --git a/packages/js-sdk/tests/integration/template/README.md b/packages/js-sdk/tests/integration/template/README.md new file mode 100644 index 000000000..7da9296a3 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/README.md @@ -0,0 +1,5 @@ +# Integration test template + +# Build the template + +`$ e2b template build -c "cd /basic-nextjs-app/ && sudo npm run dev"` diff --git a/packages/js-sdk/tests/integration/template/e2b.Dockerfile b/packages/js-sdk/tests/integration/template/e2b.Dockerfile new file mode 100644 index 000000000..2284ca7d3 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/e2b.Dockerfile @@ -0,0 +1,8 @@ +FROM e2bdev/code-interpreter:latest + +# Create a basic Next.js app +RUN npx -y create-next-app@latest test --yes --ts --use-npm + +# Install dependencies +RUN cd basic-nextjs-app && npm install + diff --git a/packages/js-sdk/tests/integration/template/e2b.toml b/packages/js-sdk/tests/integration/template/e2b.toml new file mode 100644 index 000000000..4f6dff736 --- /dev/null +++ b/packages/js-sdk/tests/integration/template/e2b.toml @@ -0,0 +1,18 @@ +# This is a config for E2B sandbox template. +# You can use template ID (2e2z80zhv34yumbrybvn) or template name (integration-test-v1) to create a sandbox: + +# Python SDK +# from e2b import Sandbox, AsyncSandbox +# sandbox = Sandbox("integration-test-v1") # Sync sandbox +# sandbox = await AsyncSandbox.create("integration-test-v1") # Async sandbox + +# JS SDK +# import { Sandbox } from 'e2b' +# const sandbox = await Sandbox.create('integration-test-v1') + +team_id = "b9c07023-d095-4bdc-9634-e25d5530ba47" +memory_mb = 1_024 +start_cmd = "npm run dev" +dockerfile = "e2b.Dockerfile" +template_name = "integration-test-v1" +template_id = "2e2z80zhv34yumbrybvn" diff --git a/packages/js-sdk/tests/setup.ts b/packages/js-sdk/tests/setup.ts index 7cdbd5e0c..5e5955f7f 100644 --- a/packages/js-sdk/tests/setup.ts +++ b/packages/js-sdk/tests/setup.ts @@ -30,6 +30,7 @@ export const sandboxTest = base.extend({ }) export const isDebug = process.env.E2B_DEBUG !== undefined +export const isIntegrationTest = process.env.E2B_INTEGRATION_TEST !== undefined export async function wait(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)) diff --git a/packages/js-sdk/vitest.workspace.mts b/packages/js-sdk/vitest.workspace.mts index 8ce2118f6..38006cd44 100644 --- a/packages/js-sdk/vitest.workspace.mts +++ b/packages/js-sdk/vitest.workspace.mts @@ -5,20 +5,11 @@ const env = config() export default defineWorkspace([ { test: { - include: [ - 'tests/**/*.test.ts', - ], - exclude: [ - 'tests/runtimes/**', - ], - poolOptions: { - threads: { - minThreads: 1, - maxThreads: 4, - }, - }, + include: ['tests/**/*.test.ts'], + exclude: ['tests/runtimes/**', 'tests/integration/**'], + isolate: false, // for projects that don't rely on side effects, disabling isolation will improve the speed of the tests globals: false, - testTimeout: 30000, + testTimeout: 30_000, environment: 'node', bail: 1, server: {}, @@ -26,7 +17,7 @@ export default defineWorkspace([ interopDefault: true, }, env: { - ...process.env as Record, + ...(process.env as Record), ...env.parsed, }, }, @@ -43,8 +34,8 @@ export default defineWorkspace([ providerOptions: {}, }, env: { - ...process.env as Record, - ...env.parsed, + ...(process.env as Record), + ...env.parsed, }, }, }, @@ -55,4 +46,16 @@ export default defineWorkspace([ environment: 'edge-runtime', }, }, + { + test: { + include: ['tests/integration/**/*.test.ts'], + globals: false, + testTimeout: 60_000, + environment: 'node', + env: { + ...(process.env as Record), + ...env.parsed, + }, + }, + }, ])