diff --git a/packages/js-sdk/tests/api/list.test.ts b/packages/js-sdk/tests/api/list.test.ts index 9d2ffe84ca..b59d71836b 100644 --- a/packages/js-sdk/tests/api/list.test.ts +++ b/packages/js-sdk/tests/api/list.test.ts @@ -1,7 +1,7 @@ import { assert } from 'vitest' import { Sandbox } from '../../src' -import { isDebug, sandboxTest } from '../setup.js' +import { isDebug, sandboxTest, template } from '../setup.js' sandboxTest.skipIf(isDebug)('list sandboxes', async ({ sandbox }) => { const sandboxes = await Sandbox.list() @@ -15,11 +15,11 @@ sandboxTest.skipIf(isDebug)('list sandboxes', async ({ sandbox }) => { sandboxTest.skipIf(isDebug)('list sandboxes with metadata filter', async () => { const uniqueId = Date.now().toString() // Create an extra sandbox with a uniqueId - const extraSbx = await Sandbox.create({ }) + const extraSbx = await Sandbox.create(template) try { - const sbx = await Sandbox.create({metadata: {uniqueId: uniqueId}}) + const sbx = await Sandbox.create(template, { metadata: { uniqueId: uniqueId } }) try { - const sandboxes = await Sandbox.list({query:{metadata: {uniqueId}}}) + const sandboxes = await Sandbox.list({ query: { metadata: { uniqueId } } }) assert.equal(sandboxes.length, 1) assert.equal(sandboxes[0].sandboxId, sbx.sandboxId) } finally { @@ -34,7 +34,7 @@ sandboxTest.skipIf(isDebug)('list sandboxes empty filter', async ({ sandbox }) = const sandboxes = await Sandbox.list() assert.isAtLeast(sandboxes.length, 1) assert.include( - sandboxes.map((s) => s.sandboxId), - sandbox.sandboxId + sandboxes.map((s) => s.sandboxId), + sandbox.sandboxId ) }) diff --git a/packages/js-sdk/tests/cmdHelper.ts b/packages/js-sdk/tests/cmdHelper.ts new file mode 100644 index 0000000000..511a429fd8 --- /dev/null +++ b/packages/js-sdk/tests/cmdHelper.ts @@ -0,0 +1,16 @@ +import { CommandHandle, CommandExitError } from '../src/index.js' +import { assert } from 'vitest' + +export function catchCmdExitErrorInBackground(cmd: CommandHandle) { + let disabled = false + + cmd.wait().catch((res: CommandExitError) => { + if (!disabled) { + assert.equal(res.exitCode, 0, `command failed with exit code ${res.exitCode}: ${res.stderr}`) + } + }) + + return () => { + disabled = true + } +} diff --git a/packages/js-sdk/tests/runtimes/browser/run.test.tsx b/packages/js-sdk/tests/runtimes/browser/run.test.tsx index add4724a16..bf65df2129 100644 --- a/packages/js-sdk/tests/runtimes/browser/run.test.tsx +++ b/packages/js-sdk/tests/runtimes/browser/run.test.tsx @@ -1,16 +1,18 @@ import { expect, inject, test } from 'vitest' import { render } from 'vitest-browser-react' +import { waitFor } from '@testing-library/react' import React from 'react' import { useEffect, useState } from 'react' + import { Sandbox } from '../../../src' -import { waitFor } from '@testing-library/react' +import { template } from '../../template' function E2BTest() { const [text, setText] = useState() useEffect(() => { const getText = async () => { - const sandbox = await Sandbox.create({apiKey: inject('E2B_API_KEY')}) + const sandbox = await Sandbox.create(template, { apiKey: inject('E2B_API_KEY') }) try { await sandbox.commands.run('echo "Hello World" > hello.txt') diff --git a/packages/js-sdk/tests/runtimes/bun/run.test.ts b/packages/js-sdk/tests/runtimes/bun/run.test.ts index 6fc4402436..7463b762e7 100644 --- a/packages/js-sdk/tests/runtimes/bun/run.test.ts +++ b/packages/js-sdk/tests/runtimes/bun/run.test.ts @@ -1,11 +1,12 @@ import { expect, test } from 'bun:test' import { Sandbox } from '../../../src' +import { template } from '../../template' test( 'Bun test', async () => { - const sbx = await Sandbox.create('base', { timeoutMs: 5_000 }) + const sbx = await Sandbox.create(template, { timeoutMs: 5_000 }) try { const isRunning = await sbx.isRunning() expect(isRunning).toBeTruthy() diff --git a/packages/js-sdk/tests/runtimes/deno/run.test.ts b/packages/js-sdk/tests/runtimes/deno/run.test.ts index c52feb2653..55f038b8c5 100644 --- a/packages/js-sdk/tests/runtimes/deno/run.test.ts +++ b/packages/js-sdk/tests/runtimes/deno/run.test.ts @@ -4,10 +4,11 @@ import { load } from 'https://deno.land/std@0.224.0/dotenv/mod.ts' await load({ envPath: '.env', export: true }) import { Sandbox } from '../../../dist/index.mjs' +import { template } from '../../template' Deno.test('Deno test', async () => { - const sbx = await Sandbox.create('base', { timeoutMs: 5_000 }) + const sbx = await Sandbox.create(template, { timeoutMs: 5_000 }) try { const isRunning = await sbx.isRunning() assert(isRunning) diff --git a/packages/js-sdk/tests/sandbox/closed_port.test.ts b/packages/js-sdk/tests/sandbox/closed_port.test.ts index a1fc79f136..914e844f02 100644 --- a/packages/js-sdk/tests/sandbox/closed_port.test.ts +++ b/packages/js-sdk/tests/sandbox/closed_port.test.ts @@ -2,16 +2,17 @@ import { assert, test } from 'vitest' import { Sandbox } from '../../src/index.js' import { isDebug, template, wait } from '../setup.js' +import { catchCmdExitErrorInBackground } from '../cmdHelper.js' test.skipIf(isDebug)('closed port in SDK', async () => { const sbx = await Sandbox.create(template, { timeoutMs: 60_000 }) const goodPort = 8000 - await sbx.commands.run(`python -m http.server ${goodPort}`, { + const cmd = await sbx.commands.run(`python -m http.server ${goodPort}`, { background: true, }) - await wait(1000) + const disable = catchCmdExitErrorInBackground(cmd) const goodHost = sbx.getHost(goodPort) // leave this here as a helper to visit host in browser @@ -44,16 +45,19 @@ test.skipIf(isDebug)('closed port in SDK', async () => { assert.equal(resp.message, 'The sandbox is running but port is not open') assert.equal(cleanedSbxId, resp.sandboxId) assert.equal(resp.port, badPort) + disable() }) test.skipIf(isDebug)('closed port in browser ', async () => { const sbx = await Sandbox.create(template, { timeoutMs: 60_000 }) const goodPort = 8000 - await sbx.commands.run(`python -m http.server ${goodPort}`, { + const cmd = await sbx.commands.run(`python -m http.server ${goodPort}`, { background: true, }) + const disable = catchCmdExitErrorInBackground(cmd) + await wait(1000) const goodHost = sbx.getHost(goodPort) @@ -87,4 +91,5 @@ test.skipIf(isDebug)('closed port in browser ', async () => { assert.equal(res.status, 502) const resp_text = await res.text() assert(resp_text.includes('Closed Port Error')) + disable() }) diff --git a/packages/js-sdk/tests/sandbox/commands/envVars.test.ts b/packages/js-sdk/tests/sandbox/commands/envVars.test.ts index 148b0a4f53..4b9406ac3b 100644 --- a/packages/js-sdk/tests/sandbox/commands/envVars.test.ts +++ b/packages/js-sdk/tests/sandbox/commands/envVars.test.ts @@ -1,6 +1,6 @@ import { assert } from 'vitest' -import { sandboxTest, isDebug } from '../../setup.js' +import { sandboxTest, isDebug, template } from '../../setup.js' import { Sandbox } from '../../../src' sandboxTest.skipIf(isDebug)('env vars', async ({ sandbox }) => { @@ -11,7 +11,7 @@ sandboxTest.skipIf(isDebug)('env vars', async ({ sandbox }) => { }) sandboxTest.skipIf(isDebug)('env vars on sandbox', async () => { - const sandbox = await Sandbox.create({ envs: { FOO: 'bar' } }) + const sandbox = await Sandbox.create(template, { envs: { FOO: 'bar' } }) try { const cmd = await sandbox.commands.run('echo "$FOO"') diff --git a/packages/js-sdk/tests/sandbox/commands/run.test.ts b/packages/js-sdk/tests/sandbox/commands/run.test.ts index d7262e5208..5c90966812 100644 --- a/packages/js-sdk/tests/sandbox/commands/run.test.ts +++ b/packages/js-sdk/tests/sandbox/commands/run.test.ts @@ -30,7 +30,7 @@ sandboxTest('run with multiline string', async ({ sandbox }) => { }) sandboxTest('run with timeout', async ({ sandbox }) => { - const cmd = await sandbox.commands.run('echo "Hello, World!"', { timeoutMs: 1000 }) + const cmd = await sandbox.commands.run('echo "Hello, World!"', { timeoutMs: 4000 }) assert.equal(cmd.exitCode, 0) }) diff --git a/packages/js-sdk/tests/sandbox/host.test.ts b/packages/js-sdk/tests/sandbox/host.test.ts index 219740326b..e361d7d424 100644 --- a/packages/js-sdk/tests/sandbox/host.test.ts +++ b/packages/js-sdk/tests/sandbox/host.test.ts @@ -1,7 +1,7 @@ import { assert } from 'vitest' import { isDebug, sandboxTest, wait } from '../setup.js' - +import { catchCmdExitErrorInBackground } from '../cmdHelper.js' sandboxTest( 'ping server in running sandbox', async ({ sandbox }) => { @@ -9,6 +9,8 @@ sandboxTest( background: true, }) + const disable = catchCmdExitErrorInBackground(cmd) + try { await wait(1000) @@ -25,6 +27,7 @@ sandboxTest( await wait(500) } assert.equal(res.status, 200) + disable() } finally { try { await cmd.kill() diff --git a/packages/js-sdk/tests/setup.ts b/packages/js-sdk/tests/setup.ts index 5e5955f7fa..1763129068 100644 --- a/packages/js-sdk/tests/setup.ts +++ b/packages/js-sdk/tests/setup.ts @@ -1,7 +1,6 @@ import { Sandbox } from '../src' import { test as base } from 'vitest' - -export const template = 'base' +import { template } from './template' interface SandboxFixture { sandbox: Sandbox @@ -9,7 +8,7 @@ interface SandboxFixture { export const sandboxTest = base.extend({ sandbox: [ - async ({}, use) => { + async ({ }, use) => { const sandbox = await Sandbox.create(template) try { await use(sandbox) @@ -25,7 +24,7 @@ export const sandboxTest = base.extend({ } } }, - { auto: true }, + { auto: false }, ], }) @@ -35,3 +34,5 @@ export const isIntegrationTest = process.env.E2B_INTEGRATION_TEST !== undefined export async function wait(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)) } + +export { template } \ No newline at end of file diff --git a/packages/js-sdk/tests/template.ts b/packages/js-sdk/tests/template.ts new file mode 100644 index 0000000000..388a5aaeaa --- /dev/null +++ b/packages/js-sdk/tests/template.ts @@ -0,0 +1 @@ +export const template = 'base' diff --git a/packages/python-sdk/tests/async/api_async/test_sbx_list.py b/packages/python-sdk/tests/async/api_async/test_sbx_list.py index 9274e3068b..40fb2f60bf 100644 --- a/packages/python-sdk/tests/async/api_async/test_sbx_list.py +++ b/packages/python-sdk/tests/async/api_async/test_sbx_list.py @@ -15,9 +15,9 @@ async def test_list_sandboxes(async_sandbox: AsyncSandbox): @pytest.mark.skip_debug() -async def test_list_sandboxes_with_filter(async_sandbox: AsyncSandbox): +async def test_list_sandboxes_with_filter(template): unique_id = "".join(random.choices(string.ascii_letters, k=5)) - sbx = await AsyncSandbox.create(metadata={"unique_id": unique_id}) + sbx = await AsyncSandbox.create(template=template, metadata={"unique_id": unique_id}) try: # There's an extra sandbox created by the test runner sandboxes = await AsyncSandbox.list( diff --git a/packages/python-sdk/tests/async/sandbox_async/commands/test_env_vars.py b/packages/python-sdk/tests/async/sandbox_async/commands/test_env_vars.py index e65b5d3c33..0e06ccc22f 100644 --- a/packages/python-sdk/tests/async/sandbox_async/commands/test_env_vars.py +++ b/packages/python-sdk/tests/async/sandbox_async/commands/test_env_vars.py @@ -9,7 +9,7 @@ async def test_command_envs(async_sandbox: AsyncSandbox): @pytest.mark.skip_debug() -async def test_sandbox_envs(template: str): +async def test_sandbox_envs(template): try: sbx = await AsyncSandbox.create(template, envs={"FOO": "bar"}) cmd = await sbx.commands.run("echo $FOO") diff --git a/packages/python-sdk/tests/async/sandbox_async/test_host.py b/packages/python-sdk/tests/async/sandbox_async/test_host.py index d16bcd4799..9b3c90d9a9 100644 --- a/packages/python-sdk/tests/async/sandbox_async/test_host.py +++ b/packages/python-sdk/tests/async/sandbox_async/test_host.py @@ -5,12 +5,14 @@ from e2b import AsyncSandbox -async def test_ping_server(async_sandbox: AsyncSandbox, debug): +async def test_ping_server(async_sandbox: AsyncSandbox, debug, helpers): cmd = await async_sandbox.commands.run( "python -m http.server 8000", background=True, ) + disable = helpers.catch_cmd_exit_error_in_background(cmd) + try: host = async_sandbox.get_host(8000) @@ -23,5 +25,6 @@ async def test_ping_server(async_sandbox: AsyncSandbox, debug): break await asyncio.sleep(0.5) assert status_code == 200 + disable() finally: await cmd.kill() diff --git a/packages/python-sdk/tests/async/sandbox_async/test_port_closed.py b/packages/python-sdk/tests/async/sandbox_async/test_port_closed.py index 1505301134..96bc8476e0 100644 --- a/packages/python-sdk/tests/async/sandbox_async/test_port_closed.py +++ b/packages/python-sdk/tests/async/sandbox_async/test_port_closed.py @@ -5,17 +5,20 @@ from e2b import AsyncSandbox -async def test_port_closed(template): +async def test_port_closed(template, helpers): sbx = await AsyncSandbox.create(template, timeout=60) try: assert await sbx.is_running() good_port = 8002 # Start a Python HTTP server on port 8002 - await sbx.commands.run( + cmd = await sbx.commands.run( f"python -m http.server {good_port}", background=True, ) + + disable = helpers.catch_cmd_exit_error_in_background(cmd) + await asyncio.sleep(1) # Wait for server to start # Test good port (8002) @@ -50,5 +53,6 @@ async def test_port_closed(template): assert resp["message"] == "The sandbox is running but port is not open" assert cleaned_sbx_id == resp["sandboxId"] assert resp["port"] == bad_port + disable() finally: await sbx.kill() diff --git a/packages/python-sdk/tests/conftest.py b/packages/python-sdk/tests/conftest.py index 7de27aa394..2ac14646d2 100644 --- a/packages/python-sdk/tests/conftest.py +++ b/packages/python-sdk/tests/conftest.py @@ -1,10 +1,18 @@ +import asyncio + import pytest import pytest_asyncio import os from logging import warning -from e2b import Sandbox, AsyncSandbox +from e2b import ( + Sandbox, + AsyncSandbox, + AsyncCommandHandle, + CommandExitException, + CommandHandle, +) @pytest.fixture() @@ -54,3 +62,40 @@ def skip_by_debug(request, debug): if request.node.get_closest_marker("skip_debug"): if debug: pytest.skip("skipped because E2B_DEBUG is set") + + +class Helpers: + @staticmethod + def catch_cmd_exit_error_in_background(cmd: AsyncCommandHandle): + disabled = False + + async def wait_for_exit(): + try: + await cmd.wait() + except CommandExitException as e: + if not disabled: + assert ( + False + ), f"command failed with exit code {e.exit_code}: {e.stderr}" + + asyncio.create_task(wait_for_exit()) + + def disable(): + nonlocal disabled + disabled = True + + return disable + + @staticmethod + def check_cmd_exit_error(cmd: CommandHandle): + try: + cmd.wait() + except CommandExitException as e: + assert False, f"command failed with exit code {e.exit_code}: {e.stderr}" + except Exception as e: + raise e + + +@pytest.fixture +def helpers(): + return Helpers diff --git a/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py b/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py index 0b78a1ee55..bab6ed91b4 100644 --- a/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py +++ b/packages/python-sdk/tests/sync/api_sync/test_sbx_list.py @@ -15,9 +15,9 @@ def test_list_sandboxes(sandbox: Sandbox): @pytest.mark.skip_debug() -def test_list_sandboxes_with_filter(sandbox: Sandbox): +def test_list_sandboxes_with_filter(template): unique_id = "".join(random.choices(string.ascii_letters, k=5)) - Sandbox(metadata={"unique_id": unique_id}) + Sandbox(template=template, metadata={"unique_id": unique_id}) sandboxes = Sandbox.list(query=SandboxQuery(metadata={"unique_id": unique_id})) assert len(sandboxes) == 1 assert sandboxes[0].metadata["unique_id"] == unique_id diff --git a/packages/python-sdk/tests/sync/sandbox_sync/commands/test_env_vars.py b/packages/python-sdk/tests/sync/sandbox_sync/commands/test_env_vars.py index 316274a144..572ca3f5fa 100644 --- a/packages/python-sdk/tests/sync/sandbox_sync/commands/test_env_vars.py +++ b/packages/python-sdk/tests/sync/sandbox_sync/commands/test_env_vars.py @@ -9,7 +9,7 @@ def test_command_envs(sandbox: Sandbox): @pytest.mark.skip_debug() -def test_sandbox_envs(template: str): +def test_sandbox_envs(template): sandbox = Sandbox(template, envs={"FOO": "bar"}) try: cmd = sandbox.commands.run("echo $FOO") diff --git a/packages/python-sdk/tests/sync/sandbox_sync/test_host.py b/packages/python-sdk/tests/sync/sandbox_sync/test_host.py index 5aea2d1193..00edae4e32 100644 --- a/packages/python-sdk/tests/sync/sandbox_sync/test_host.py +++ b/packages/python-sdk/tests/sync/sandbox_sync/test_host.py @@ -3,7 +3,7 @@ from time import sleep -def test_ping_server(sandbox, debug): +def test_ping_server(sandbox, debug, helpers): cmd = sandbox.commands.run("python -m http.server 8001", background=True) try: @@ -17,5 +17,8 @@ def test_ping_server(sandbox, debug): sleep(0.5) assert status_code == 200 + except Exception as e: + helpers.check_cmd_exit_error(cmd) + raise e finally: cmd.kill() diff --git a/packages/python-sdk/tests/sync/sandbox_sync/test_port_closed.py b/packages/python-sdk/tests/sync/sandbox_sync/test_port_closed.py index 7b30a820f3..7dd88bbcf5 100644 --- a/packages/python-sdk/tests/sync/sandbox_sync/test_port_closed.py +++ b/packages/python-sdk/tests/sync/sandbox_sync/test_port_closed.py @@ -5,14 +5,14 @@ from e2b import Sandbox -def test_port_closed(template): +def test_port_closed(template, helpers): sbx = Sandbox(template, timeout=60) try: assert sbx.is_running() good_port = 8004 # Start a Python HTTP server on port 8004 - sbx.commands.run( + cmd = sbx.commands.run( f"python -m http.server {good_port}", background=True, ) @@ -50,5 +50,8 @@ def test_port_closed(template): assert resp["message"] == "The sandbox is running but port is not open" assert cleaned_sbx_id == resp["sandboxId"] assert resp["port"] == bad_port + except Exception as e: + helpers.check_cmd_exit_error(cmd) + raise e finally: sbx.kill()