diff --git a/.github/workflows/code_interpreter_js_tests.yml b/.github/workflows/code_interpreter_js_tests.yml index 8d01fe7868..c6386fafe3 100644 --- a/.github/workflows/code_interpreter_js_tests.yml +++ b/.github/workflows/code_interpreter_js_tests.yml @@ -95,8 +95,8 @@ jobs: with: deno-version: 'v${{ env.TOOL_VERSION_DENO }}' - # The recovery suites (interrupt, systemd) exercise sandbox recovery - # paths that staging cannot serve, so callers can opt out of them. + # The interrupt suite exercises sandbox recovery paths that staging + # cannot serve, so callers can opt out of it. - name: Run test suite under ${{ matrix.runtime }} run: | case "${{ matrix.runtime }}" in @@ -107,7 +107,7 @@ jobs: if [[ "${{ inputs.run_recovery_tests }}" == "true" ]]; then pnpm "$script" else - pnpm "$script" --exclude tests/interrupt.test.ts --exclude tests/systemd.test.ts + pnpm "$script" --exclude tests/interrupt.test.ts fi env: E2B_API_KEY: ${{ secrets.E2B_API_KEY }} diff --git a/.github/workflows/code_interpreter_python_tests.yml b/.github/workflows/code_interpreter_python_tests.yml index 6a4b98805f..759a01dae4 100644 --- a/.github/workflows/code_interpreter_python_tests.yml +++ b/.github/workflows/code_interpreter_python_tests.yml @@ -57,9 +57,7 @@ jobs: else uv run pytest --verbose --numprocesses=1 \ --ignore=tests/async/test_async_interrupt.py \ - --ignore=tests/async/test_async_systemd.py \ - --ignore=tests/sync/test_interrupt.py \ - --ignore=tests/sync/test_systemd.py + --ignore=tests/sync/test_interrupt.py fi env: E2B_API_KEY: ${{ secrets.E2B_API_KEY }} diff --git a/packages/code-interpreter-js/tests/bash.test.ts b/packages/code-interpreter-js/tests/bash.test.ts deleted file mode 100644 index 7734499f72..0000000000 --- a/packages/code-interpreter-js/tests/bash.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest } from './setup' - -// Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. -sandboxTest.skipIf(isDebug)('bash', async ({ sandbox }) => { - const result = await sandbox.runCode('!pwd') - - expect(result.logs.stdout.join().trim()).toEqual('/home/user') -}) diff --git a/packages/code-interpreter-js/tests/charts/bar.test.ts b/packages/code-interpreter-js/tests/charts/bar.test.ts deleted file mode 100644 index 01a2b055bc..0000000000 --- a/packages/code-interpreter-js/tests/charts/bar.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -// Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. -sandboxTest('bar', async ({ sandbox }) => { - const code = ` -import matplotlib.pyplot as plt - -# Prepare data -authors = ['Author A', 'Author B', 'Author C', 'Author D'] -sales = [100, 200, 300, 400] - -# Create and customize the bar chart -plt.figure(figsize=(10, 6)) -plt.bar(authors, sales, label='Books Sold', color='blue') -plt.xlabel('Authors') -plt.ylabel('Number of Books Sold') -plt.title('Book Sales by Authors') - -# Display the chart -plt.tight_layout() -plt.show() -` - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - - expect(chart).toBeDefined() - expect(chart.type).toBe('bar') - expect(chart.title).toBe('Book Sales by Authors') - - expect(chart.x_label).toBe('Authors') - expect(chart.y_label).toBe('Number of Books Sold') - - expect(chart.x_unit).toBeNull() - expect(chart.y_unit).toBeNull() - - const bars = chart.elements - expect(bars.length).toBe(4) - - expect(bars.map((bar) => bar.value)).toEqual([100, 200, 300, 400]) - expect(bars.map((bar) => bar.group)).toEqual([ - 'Books Sold', - 'Books Sold', - 'Books Sold', - 'Books Sold', - ]) - expect(bars.map((bar) => bar.label)).toEqual([ - 'Author A', - 'Author B', - 'Author C', - 'Author D', - ]) -}) diff --git a/packages/code-interpreter-js/tests/charts/boxAndWhisker.test.ts b/packages/code-interpreter-js/tests/charts/boxAndWhisker.test.ts deleted file mode 100644 index 47f8985aed..0000000000 --- a/packages/code-interpreter-js/tests/charts/boxAndWhisker.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -sandboxTest('box-and-whisker', async ({ sandbox }) => { - const code = ` -import matplotlib.pyplot as plt -import numpy as np - -# Sample data -data = { - 'Class A': [85, 90, 78, 92, 88], - 'Class B': [95, 89, 76, 91, 84, 87], - 'Class C': [75, 82, 88, 79, 86] -} - -# Create figure and axis -fig, ax = plt.subplots(figsize=(10, 6)) - -# Customize plot -ax.set_title('Exam Scores Distribution') -ax.set_xlabel('Class') -ax.set_ylabel('Score') - -# Set custom colors -ax.boxplot(data.values(), labels=data.keys(), patch_artist=True) - -# Add legend -ax.legend() - -# Adjust layout and show plot -plt.tight_layout() -plt.show() -` - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - - expect(chart).toBeDefined() - - expect(chart.type).toBe('box_and_whisker') - expect(chart.title).toBe('Exam Scores Distribution') - - expect(chart.x_label).toBe('Class') - expect(chart.y_label).toBe('Score') - - expect(chart.x_unit).toBeNull() - expect(chart.y_unit).toBeNull() - - const bars = chart.elements - expect(bars.length).toBe(3) - - expect(bars.map((bar) => bar.label)).toEqual([ - 'Class A', - 'Class B', - 'Class C', - ]) - expect(bars.map((bar) => bar.outliers)).toEqual([[], [76], []]) - expect(bars.map((bar) => bar.min)).toEqual([78, 84, 75]) - expect(bars.map((bar) => bar.first_quartile)).toEqual([85, 84.75, 79]) - expect(bars.map((bar) => bar.median)).toEqual([88, 88, 82]) - expect(bars.map((bar) => bar.third_quartile)).toEqual([90, 90.5, 86]) - expect(bars.map((bar) => bar.max)).toEqual([92, 95, 88]) -}) diff --git a/packages/code-interpreter-js/tests/charts/line.test.ts b/packages/code-interpreter-js/tests/charts/line.test.ts deleted file mode 100644 index 1762bf417b..0000000000 --- a/packages/code-interpreter-js/tests/charts/line.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -sandboxTest('line', async ({ sandbox }) => { - const code = ` -import numpy as np -import matplotlib.pyplot as plt -import datetime - -# Generate x values -dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] - -x = np.linspace(0, 2*np.pi, 100) -# Calculate y values -y_sin = np.sin(x) -y_cos = np.cos(x) - -# Create the plot -plt.figure(figsize=(10, 6)) -plt.plot(dates, y_sin, label='sin(x)') -plt.plot(dates, y_cos, label='cos(x)') - -# Add labels and title -plt.xlabel("Time (s)") -plt.ylabel("Amplitude (Hz)") -plt.title('Plot of sin(x) and cos(x)') - -# Display the plot -plt.show() -` - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - - expect(chart).toBeDefined() - expect(chart.type).toBe('line') - - expect(chart.title).toBe('Plot of sin(x) and cos(x)') - expect(chart.x_label).toBe('Time (s)') - expect(chart.y_label).toBe('Amplitude (Hz)') - - expect(chart.x_scale).toBe('datetime') - expect(chart.y_scale).toBe('linear') - - expect(chart.x_unit).toBe('s') - expect(chart.y_unit).toBe('Hz') - - expect(chart.x_ticks.every((tick: number) => typeof tick === 'string')).toBe( - true - ) - expect(new Date(chart.x_ticks[0])).toBeInstanceOf(Date) - expect(chart.y_ticks.every((tick: number) => typeof tick === 'number')).toBe( - true - ) - - expect( - chart.y_tick_labels.every((label: string) => typeof label === 'string') - ).toBe(true) - expect( - chart.x_tick_labels.every((label: string) => typeof label === 'string') - ).toBe(true) - - const lines = chart.elements - expect(lines.length).toBe(2) - - const [firstLine, secondLine] = lines - - expect(firstLine.label).toBe('sin(x)') - expect(firstLine.points.length).toBe(100) - expect( - firstLine.points.every( - (point: [number, number]) => - typeof point[0] === 'string' && typeof point[1] === 'number' - ) - ).toBe(true) - expect(new Date(firstLine.points[0][0])).toEqual( - new Date('2023-09-01T00:00:00.000Z') - ) - - expect(secondLine.label).toBe('cos(x)') - expect(secondLine.points.length).toBe(100) - expect( - secondLine.points.every( - (point: [number, number]) => - typeof point[0] === 'string' && typeof point[1] === 'number' - ) - ).toBe(true) -}) diff --git a/packages/code-interpreter-js/tests/charts/log.test.ts b/packages/code-interpreter-js/tests/charts/log.test.ts deleted file mode 100644 index 1569b9a4e5..0000000000 --- a/packages/code-interpreter-js/tests/charts/log.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -sandboxTest('log', async ({ sandbox }) => { - const code = ` -import numpy as np -import matplotlib.pyplot as plt - -# Generate x values -x = np.linspace(0, 100, 100) -# Calculate y values -y = np.exp(x) - -# Create the plot -plt.figure(figsize=(10, 6)) -plt.plot(x, y, label='y = e^x') - -# Set log scale for the y-axis -plt.yscale('log') - -# Add labels and title -plt.xlabel('X-axis') -plt.ylabel('Y-axis (log scale)') -plt.title('Chart with Log Scale on Y-axis') - -plt.legend() -plt.grid(True) -plt.show() -` - - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - expect(chart).toBeDefined() - expect(chart.type).toBe('line') - - expect(chart.title).toBe('Chart with Log Scale on Y-axis') - - expect(chart.x_label).toBe('X-axis') - expect(chart.y_label).toBe('Y-axis (log scale)') - - expect(chart.x_unit).toBeNull() - expect(chart.y_unit).toBe('log scale') - - expect(chart.x_scale).toBe('linear') - expect(chart.y_scale).toBe('log') - - expect(chart.x_ticks.every((x) => typeof x === 'number')).toBe(true) - expect(chart.y_ticks.every((y) => typeof y === 'number')).toBe(true) - - expect(chart.x_tick_labels.every((x) => typeof x === 'string')).toBe(true) - expect(chart.y_tick_labels.every((y) => typeof y === 'string')).toBe(true) - - const lines = chart.elements - expect(lines.length).toBe(1) - - const line = lines[0] - expect(line.label).toBe('y = e^x') - expect(line.points.length).toBe(100) - - expect( - line.points.every( - ([x, y]) => typeof x === 'number' && typeof y === 'number' - ) - ).toBe(true) -}) diff --git a/packages/code-interpreter-js/tests/charts/pie.test.ts b/packages/code-interpreter-js/tests/charts/pie.test.ts deleted file mode 100644 index 6668c16ffa..0000000000 --- a/packages/code-interpreter-js/tests/charts/pie.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -sandboxTest('pie', async ({ sandbox }) => { - const code = ` -import matplotlib.pyplot as plt -import numpy as np - -# Step 1: Define the data for the pie chart -categories = ["No", "No, in blue"] -sizes = [90, 10] - -# Step 2: Create the figure and axis objects -fig, ax = plt.subplots(figsize=(8, 8)) - -plt.xlabel("x") -plt.ylabel("y") - -# Step 3: Create the pie chart -ax.pie(sizes, labels=categories, autopct='%1.1f%%', startangle=90, colors=plt.cm.Pastel1.colors[:len(categories)]) - -# Step 4: Add title and legend -ax.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle -plt.title('Will I wake up early tomorrow?') - -# Step 5: Show the plot -plt.show() -` - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - - expect(chart).toBeDefined() - expect(chart.type).toBe('pie') - - expect(chart.title).toBe('Will I wake up early tomorrow?') - - expect(chart.elements.length).toBe(2) - - const [firstData, secondData] = chart.elements - - expect(firstData.label).toBe('No') - expect(firstData.angle).toBe(324) // 90% of 360 degrees - expect(firstData.radius).toBe(1) - - expect(secondData.label).toBe('No, in blue') - expect(secondData.angle).toBe(36) // 10% of 360 degrees - expect(secondData.radius).toBe(1) -}) diff --git a/packages/code-interpreter-js/tests/charts/scales.test.ts b/packages/code-interpreter-js/tests/charts/scales.test.ts deleted file mode 100644 index 32a3ecb4e8..0000000000 --- a/packages/code-interpreter-js/tests/charts/scales.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' -sandboxTest('datetime scale', async ({ sandbox }) => { - const code = ` - import numpy as np - import matplotlib.pyplot as plt - import datetime - - # Generate x values - dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] - y_sin = np.sin(np.linspace(0, 2*np.pi, 100)) - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(dates, y_sin, label='sin(x)') - plt.show() - ` - - const result = await sandbox.runCode(code) - - const chart = result.results[0].chart - expect(chart).toBeDefined() - expect(chart.type).toBe('line') - - expect(chart.x_scale).toBe('datetime') - expect(chart.y_scale).toBe('linear') -}) - -sandboxTest('categorical scale', async ({ sandbox }) => { - const code = ` - import numpy as np - import matplotlib.pyplot as plt - - x = [1, 2, 3, 4, 5] - y = ['A', 'B', 'C', 'D', 'E'] - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(x, y) - plt.show() - ` - - const result = await sandbox.runCode(code) - - const chart = result.results[0].chart - expect(chart).toBeTruthy() - - expect(chart.type).toBe('line') - expect(chart.x_scale).toBe('linear') - expect(chart.y_scale).toBe('categorical') -}) diff --git a/packages/code-interpreter-js/tests/charts/scatter.test.ts b/packages/code-interpreter-js/tests/charts/scatter.test.ts deleted file mode 100644 index 2d51494523..0000000000 --- a/packages/code-interpreter-js/tests/charts/scatter.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -sandboxTest('scatter', async ({ sandbox }) => { - const code = ` -import matplotlib.pyplot as plt -import numpy as np - -# Create data -N = 5 -x1 = np.random.rand(N) -y1 = np.random.rand(N) -x2 = np.random.rand(2*N) -y2 = np.random.rand(2*N) - -plt.xlabel("A") -plt.ylabel("B") - -plt.scatter(x1, y1, c='blue', label='Dataset 1') -plt.scatter(x2, y2, c='red', label='Dataset 2') - -plt.show() -` - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - - expect(chart).toBeDefined() - expect(chart.type).toBe('scatter') - - expect(chart.title).toBeNull() - expect(chart.x_label).toBe('A') - expect(chart.y_label).toBe('B') - - expect(chart.x_ticks.every((tick: number) => typeof tick === 'number')).toBe( - true - ) - expect(chart.y_ticks.every((tick: number) => typeof tick === 'number')).toBe( - true - ) - - expect( - chart.x_tick_labels.every((label: string) => typeof label === 'string') - ).toBe(true) - expect( - chart.y_tick_labels.every((label: string) => typeof label === 'string') - ).toBe(true) - - expect(chart.elements.length).toBe(2) - - const [firstData, secondData] = chart.elements - - expect(firstData.label).toBe('Dataset 1') - expect(firstData.points.length).toBe(5) - expect( - firstData.points.every( - (point: [number, number]) => - typeof point[0] === 'number' && typeof point[1] === 'number' - ) - ).toBe(true) - - expect(secondData.label).toBe('Dataset 2') - expect(secondData.points.length).toBe(10) - expect( - secondData.points.every( - (point: [number, number]) => - typeof point[0] === 'number' && typeof point[1] === 'number' - ) - ).toBe(true) -}) diff --git a/packages/code-interpreter-js/tests/charts/superchart.test.ts b/packages/code-interpreter-js/tests/charts/superchart.test.ts deleted file mode 100644 index 33f3c2dda8..0000000000 --- a/packages/code-interpreter-js/tests/charts/superchart.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -sandboxTest('superchart', async ({ sandbox }) => { - const code = ` -import matplotlib.pyplot as plt -import numpy as np - -# Data for plotting -x1 = np.linspace(0, 10, 100) -y1 = np.sin(x1) - -# Create a figure with multiple subplots -fig, axs = plt.subplots(1, 2, figsize=(10, 8)) -fig.suptitle('Multiple Charts Example', fontsize=16) - -# Plotting on the different axes -axs[0].plot(x1, y1, 'r') -axs[0].set_title('Sine Wave') -axs[0].grid(True) - -N = 5 -x2 = np.random.rand(N) -y2 = np.random.rand(N) - -axs[1].scatter(x2, y2, c='blue', label='Dataset 1') -axs[1].set_xlabel('X') -axs[1].set_ylabel('Y') -axs[1].set_title('Scatter Plot') -axs[1].grid(True) - -plt.show() -` - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - - expect(chart).toBeDefined() - expect(chart.type).toBe('superchart') - expect(chart.title).toBe('Multiple Charts Example') - - const charts = chart.elements - expect(charts.length).toBe(2) - - const [firstChart, secondChart] = charts - - // Check the first chart (LineChart) - expect(firstChart.title).toBe('Sine Wave') - expect(firstChart.type).toBe('line') - - expect(firstChart.x_label).toBeNull() - expect(firstChart.y_label).toBeNull() - expect(firstChart.elements.length).toBe(1) - expect(firstChart.elements[0].points.length).toBe(100) - - // Check the second chart (ScatterChart) - expect(secondChart.title).toBe('Scatter Plot') - expect(secondChart.type).toBe('scatter') - - expect(secondChart.x_label).toBe('X') - expect(secondChart.y_label).toBe('Y') - expect(secondChart.elements.length).toBe(1) - expect(secondChart.elements[0].points.length).toBe(5) -}) diff --git a/packages/code-interpreter-js/tests/charts/unknown.test.ts b/packages/code-interpreter-js/tests/charts/unknown.test.ts deleted file mode 100644 index 8ab40ebf20..0000000000 --- a/packages/code-interpreter-js/tests/charts/unknown.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -// Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. -sandboxTest('unknown', async ({ sandbox }) => { - const code = ` -import matplotlib.pyplot as plt -import numpy as np - -# Create a figure and an axis -fig, ax = plt.subplots() - -# Create data for two concentric circles -circle1 = plt.Circle((0, 0), 1, color='blue', fill=False, linewidth=2) -circle2 = plt.Circle((0, 0), 2, color='red', fill=False, linewidth=2) - -# Add the circles to the axes -ax.add_artist(circle1) -ax.add_artist(circle2) - -# Set grid -ax.grid(True) - -# Set title -plt.title('Two Concentric Circles') - -# Show the plot -plt.show() -` - const result = await sandbox.runCode(code) - const chart = result.results[0].chart - - expect(chart).toBeDefined() - expect(chart.type).toBe('unknown') - expect(chart.title).toBe('Two Concentric Circles') - - expect(chart.elements.length).toBe(0) -}) diff --git a/packages/code-interpreter-js/tests/contexts.test.ts b/packages/code-interpreter-js/tests/contexts.test.ts index b0cf956750..fe39d82986 100644 --- a/packages/code-interpreter-js/tests/contexts.test.ts +++ b/packages/code-interpreter-js/tests/contexts.test.ts @@ -1,6 +1,7 @@ import { expect } from 'vitest' import { isDebug, sandboxTest, secureSandboxTest } from './setup' +import { InvalidArgumentError } from '../src' sandboxTest('create context with no options', async ({ sandbox }) => { const context = await sandbox.createCodeContext() @@ -62,6 +63,14 @@ sandboxTest('restart context', async ({ sandbox }) => { expect(execution.error?.value).toBe("name 'x' is not defined") }) +sandboxTest('pass context and language', async ({ sandbox }) => { + const context = await sandbox.createCodeContext({ language: 'python' }) + await expect( + // @ts-expect-error context and language are mutually exclusive + sandbox.runCode("console.log('Hello, World!')", { context, language: 'js' }) + ).rejects.toThrowError(InvalidArgumentError) +}) + secureSandboxTest.skipIf(isDebug)( 'create context (secure traffic)', async ({ sandbox }) => { diff --git a/packages/code-interpreter-js/tests/cwd.test.ts b/packages/code-interpreter-js/tests/cwd.test.ts deleted file mode 100644 index 683e1e283d..0000000000 --- a/packages/code-interpreter-js/tests/cwd.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest, waitForKernel } from './setup' - -// Skip these tests in debug mode — the pwd and user in the testing docker container -// are not the same as in the actual sandbox. - -sandboxTest.skipIf(isDebug)('cwd python', async ({ sandbox }) => { - const result = await sandbox.runCode( - 'from pathlib import Path; print(Path.cwd())', - { language: 'python' } - ) - expect(result.logs.stdout.join().trim()).toEqual('/home/user') -}) - -sandboxTest.skipIf(isDebug)('cwd javascript', async ({ sandbox }) => { - const result = await sandbox.runCode('process.cwd()', { - language: 'js', - }) - expect(result.text).toEqual('/home/user') -}) - -sandboxTest.skipIf(isDebug)('cwd typescript', async ({ sandbox }) => { - const result = await sandbox.runCode('process.cwd()', { - language: 'ts', - }) - expect(result.text).toEqual('/home/user') -}) - -sandboxTest.skipIf(isDebug)('cwd r', async ({ sandbox }) => { - await waitForKernel(sandbox, 'r') - - const result = await sandbox.runCode('getwd()', { - language: 'r', - }) - expect(result.results[0]?.text.trim()).toEqual('[1] "/home/user"') -}) - -sandboxTest.skipIf(isDebug)('cwd java', async ({ sandbox }) => { - await waitForKernel(sandbox, 'java') - - const result = await sandbox.runCode('System.getProperty("user.dir")', { - language: 'java', - }) - expect(result.results[0]?.text.trim()).toEqual('/home/user') -}) - -sandboxTest.skipIf(isDebug)('cwd bash', async ({ sandbox }) => { - const result = await sandbox.runCode('pwd', { - language: 'bash', - }) - expect(result.logs.stdout.join().trim()).toEqual('/home/user') -}) diff --git a/packages/code-interpreter-js/tests/data.test.ts b/packages/code-interpreter-js/tests/data.test.ts deleted file mode 100644 index b18eeedcbb..0000000000 --- a/packages/code-interpreter-js/tests/data.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from './setup' - -sandboxTest('get data', async ({ sandbox }) => { - const execution = await sandbox.runCode(` -import pandas as pd -pd.DataFrame({"a": [1, 2, 3]}) -`) - - const result = execution.results[0] - expect(result.data).toBeDefined() -}) diff --git a/packages/code-interpreter-js/tests/defaultKernels.test.ts b/packages/code-interpreter-js/tests/defaultKernels.test.ts deleted file mode 100644 index f5fce337fb..0000000000 --- a/packages/code-interpreter-js/tests/defaultKernels.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from './setup' - -sandboxTest('test js kernel', async ({ sandbox }) => { - const output = await sandbox.runCode('console.log("Hello World!")', { - language: 'js', - }) - expect(output.logs.stdout).toEqual(['Hello World!\n']) -}) - -sandboxTest('test esm imports', async ({ sandbox }) => { - const output = await sandbox.runCode( - ` - import { readFileSync } from 'fs' - console.log(typeof readFileSync) - `, - { - language: 'js', - } - ) - expect(output.logs.stdout).toEqual(['function\n']) -}) - -sandboxTest( - 'test top-level await and promise resolution', - async ({ sandbox }) => { - const output = await sandbox.runCode( - ` - await Promise.resolve('Hello World!') - `, - { - language: 'js', - } - ) - expect(output.text).toEqual('Hello World!') - } -) - -sandboxTest('test ts kernel', async ({ sandbox }) => { - const output = await sandbox.runCode( - 'const message: string = "Hello World!"; console.log(message)', - { language: 'ts' } - ) - expect(output.logs.stdout).toEqual(['Hello World!\n']) -}) diff --git a/packages/code-interpreter-js/tests/displayData.test.ts b/packages/code-interpreter-js/tests/displayData.test.ts deleted file mode 100644 index ee320c4bbe..0000000000 --- a/packages/code-interpreter-js/tests/displayData.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from './setup' - -sandboxTest('display data', async ({ sandbox }) => { - // plot random chart - const result = await sandbox.runCode(` - import matplotlib.pyplot as plt - import numpy as np - - x = np.linspace(0, 20, 100) - y = np.sin(x) - - plt.plot(x, y) - plt.show() - `) - - const image = result.results[0] - expect(image.png).toBeDefined() - expect(image.text).toBeDefined() - expect(image.extra).toEqual({}) -}) diff --git a/packages/code-interpreter-js/tests/envVars.test.ts b/packages/code-interpreter-js/tests/envVars.test.ts new file mode 100644 index 0000000000..4c5a841f6f --- /dev/null +++ b/packages/code-interpreter-js/tests/envVars.test.ts @@ -0,0 +1,15 @@ +import { expect } from 'vitest' + +import { sandboxTest } from './setup' + +sandboxTest('env vars per execution', async ({ sandbox }) => { + const result = await sandbox.runCode('import os; os.getenv("FOO")', { + envs: { FOO: 'bar' }, + }) + const resultEmpty = await sandbox.runCode( + "import os; os.getenv('FOO', 'default')" + ) + + expect(result.results[0]?.text.trim()).toEqual('bar') + expect(resultEmpty.results[0]?.text.trim()).toEqual('default') +}) diff --git a/packages/code-interpreter-js/tests/env_vars/bash.test.ts b/packages/code-interpreter-js/tests/env_vars/bash.test.ts deleted file mode 100644 index 496248566f..0000000000 --- a/packages/code-interpreter-js/tests/env_vars/bash.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest } from '../setup' -import { Sandbox } from '../../src' - -// Bash Env Vars -sandboxTest.skipIf(isDebug)( - 'env vars on sandbox (bash)', - async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - const result = await sandbox.runCode('echo $TEST_ENV_VAR', { - language: 'bash', - }) - - expect(result.logs.stdout[0]).toEqual('supertest\n') - } finally { - await sandbox.kill() - } - } -) - -sandboxTest('env vars per execution (bash)', async ({ sandbox }) => { - const result = await sandbox.runCode('echo $FOO', { - envs: { FOO: 'bar' }, - language: 'bash', - }) - - const result_empty = await sandbox.runCode('echo ${FOO:-default}', { - language: 'bash', - }) - - expect(result.logs.stdout[0]).toEqual('bar\n') - expect(result_empty.logs.stdout[0]).toEqual('default\n') -}) - -sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - const result = await sandbox.runCode('echo $TEST_ENV_VAR', { - language: 'bash', - envs: { TEST_ENV_VAR: 'overwrite' }, - }) - - const result_global_default = await sandbox.runCode('echo $TEST_ENV_VAR', { - language: 'bash', - }) - - expect(result.logs.stdout[0]).toEqual('overwrite\n') - expect(result_global_default.logs.stdout[0]).toEqual('supertest\n') - } finally { - await sandbox.kill() - } -}) diff --git a/packages/code-interpreter-js/tests/env_vars/java.test.ts b/packages/code-interpreter-js/tests/env_vars/java.test.ts deleted file mode 100644 index a2810cdbf3..0000000000 --- a/packages/code-interpreter-js/tests/env_vars/java.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest, waitForKernel } from '../setup' -import { Sandbox } from '../../src' - -// Java Env Vars -sandboxTest.skipIf(isDebug)( - 'env vars on sandbox (java)', - async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - await waitForKernel(sandbox, 'java') - - const result = await sandbox.runCode( - 'System.getProperty("TEST_ENV_VAR")', - { - language: 'java', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('supertest') - } finally { - await sandbox.kill() - } - } -) - -sandboxTest('env vars per execution (java)', async ({ sandbox }) => { - await waitForKernel(sandbox, 'java') - - const result = await sandbox.runCode('System.getProperty("FOO")', { - envs: { FOO: 'bar' }, - language: 'java', - }) - - const result_empty = await sandbox.runCode( - 'System.getProperty("FOO", "default")', - { - language: 'java', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('bar') - expect(result_empty.results[0]?.text.trim()).toEqual('default') -}) - -sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - await waitForKernel(sandbox, 'java') - - const result = await sandbox.runCode('System.getProperty("TEST_ENV_VAR")', { - language: 'java', - envs: { TEST_ENV_VAR: 'overwrite' }, - }) - - const result_global_default = await sandbox.runCode( - 'System.getProperty("TEST_ENV_VAR")', - { - language: 'java', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('overwrite') - expect(result_global_default.results[0]?.text.trim()).toEqual('supertest') - } finally { - await sandbox.kill() - } -}) diff --git a/packages/code-interpreter-js/tests/env_vars/js.test.ts b/packages/code-interpreter-js/tests/env_vars/js.test.ts deleted file mode 100644 index 7e87f7bb69..0000000000 --- a/packages/code-interpreter-js/tests/env_vars/js.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest } from '../setup' -import { Sandbox } from '../../src' - -// JavaScript Env Vars -sandboxTest.skipIf(isDebug)( - 'env vars on sandbox (javascript)', - async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - const result = await sandbox.runCode('process.env.TEST_ENV_VAR', { - language: 'javascript', - }) - - expect(result.results[0]?.text.trim()).toEqual('supertest') - } finally { - await sandbox.kill() - } - } -) - -sandboxTest('env vars per execution (javascript)', async ({ sandbox }) => { - const result = await sandbox.runCode('process.env.FOO', { - envs: { FOO: 'bar' }, - language: 'javascript', - }) - - const result_empty = await sandbox.runCode("process.env.FOO || 'default'", { - language: 'javascript', - }) - - expect(result.results[0]?.text.trim()).toEqual('bar') - expect(result_empty.results[0]?.text.trim()).toEqual('default') -}) - -sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - const result = await sandbox.runCode('process.env.TEST_ENV_VAR', { - language: 'javascript', - envs: { TEST_ENV_VAR: 'overwrite' }, - }) - - const result_global_default = await sandbox.runCode( - 'process.env.TEST_ENV_VAR', - { - language: 'javascript', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('overwrite') - expect(result_global_default.results[0]?.text.trim()).toEqual('supertest') - } finally { - await sandbox.kill() - } -}) diff --git a/packages/code-interpreter-js/tests/env_vars/python.test.ts b/packages/code-interpreter-js/tests/env_vars/python.test.ts deleted file mode 100644 index af1b7150ff..0000000000 --- a/packages/code-interpreter-js/tests/env_vars/python.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest } from '../setup' -import { Sandbox } from '../../src' - -// Python Env Vars -sandboxTest.skipIf(isDebug)( - 'env vars on sandbox (python)', - async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - const result = await sandbox.runCode( - 'import os; os.getenv("TEST_ENV_VAR")', - { - language: 'python', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('supertest') - } finally { - await sandbox.kill() - } - } -) - -sandboxTest('env vars per execution (python)', async ({ sandbox }) => { - const result = await sandbox.runCode('import os; os.getenv("FOO")', { - envs: { FOO: 'bar' }, - language: 'python', - }) - - const result_empty = await sandbox.runCode( - "import os; os.getenv('FOO', 'default')", - { - language: 'python', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('bar') - expect(result_empty.results[0]?.text.trim()).toEqual('default') -}) - -sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - const result = await sandbox.runCode( - 'import os; os.getenv("TEST_ENV_VAR")', - { - language: 'python', - envs: { TEST_ENV_VAR: 'overwrite' }, - } - ) - - const result_global_default = await sandbox.runCode( - 'import os; os.getenv("TEST_ENV_VAR")', - { - language: 'python', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('overwrite') - expect(result_global_default.results[0]?.text.trim()).toEqual('supertest') - } finally { - await sandbox.kill() - } -}) diff --git a/packages/code-interpreter-js/tests/env_vars/r.test.ts b/packages/code-interpreter-js/tests/env_vars/r.test.ts deleted file mode 100644 index 62ebdef443..0000000000 --- a/packages/code-interpreter-js/tests/env_vars/r.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest, waitForKernel } from '../setup' -import { Sandbox } from '../../src' - -// R Env Vars -sandboxTest.skipIf(isDebug)('env vars on sandbox (R)', async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - await waitForKernel(sandbox, 'r') - - const result = await sandbox.runCode('Sys.getenv("TEST_ENV_VAR")', { - language: 'r', - }) - - expect(result.results[0]?.text.trim()).toEqual('[1] "supertest"') - } finally { - await sandbox.kill() - } -}) - -sandboxTest('env vars per execution (R)', async ({ sandbox }) => { - await waitForKernel(sandbox, 'r') - - const result = await sandbox.runCode('Sys.getenv("FOO")', { - envs: { FOO: 'bar' }, - language: 'r', - }) - - const result_empty = await sandbox.runCode( - 'Sys.getenv("FOO", unset = "default")', - { - language: 'r', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('[1] "bar"') - expect(result_empty.results[0]?.text.trim()).toEqual('[1] "default"') -}) - -sandboxTest.skipIf(isDebug)('env vars overwrite', async ({ template }) => { - const sandbox = await Sandbox.create(template, { - envs: { TEST_ENV_VAR: 'supertest' }, - }) - - try { - await waitForKernel(sandbox, 'r') - - const result = await sandbox.runCode('Sys.getenv("TEST_ENV_VAR")', { - language: 'r', - envs: { TEST_ENV_VAR: 'overwrite' }, - }) - - const result_global_default = await sandbox.runCode( - 'Sys.getenv("TEST_ENV_VAR")', - { - language: 'r', - } - ) - - expect(result.results[0]?.text.trim()).toEqual('[1] "overwrite"') - expect(result_global_default.results[0]?.text.trim()).toEqual( - '[1] "supertest"' - ) - } finally { - await sandbox.kill() - } -}) diff --git a/packages/code-interpreter-js/tests/executionCount.test.ts b/packages/code-interpreter-js/tests/executionCount.test.ts deleted file mode 100644 index 750aa9158d..0000000000 --- a/packages/code-interpreter-js/tests/executionCount.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest } from './setup' - -// Skip this test if we are running in debug mode — we don't create new sandbox for each test so the execution number is not reset. -sandboxTest.skipIf(isDebug)('execution count', async ({ sandbox }) => { - await sandbox.runCode('!pwd') - const result = await sandbox.runCode('!pwd') - - expect(result.executionCount).toEqual(2) -}) diff --git a/packages/code-interpreter-js/tests/images/bar.test.ts b/packages/code-interpreter-js/tests/images/bar.test.ts deleted file mode 100644 index facde25144..0000000000 --- a/packages/code-interpreter-js/tests/images/bar.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from '../setup' - -// Skip this test if we are running in debug mode — the pwd and user in the testing docker container are not the same as in the actual sandbox. -sandboxTest('test show image', async ({ sandbox }) => { - const code = ` - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image.show() - print("done") - ` - - const execution = await sandbox.runCode(code) - - const image = execution.results[0].png - expect(image).toBeDefined() -}) - -sandboxTest('test image represent', async ({ sandbox }) => { - const code = ` - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image - ` - const execution = await sandbox.runCode(code) - - const image = execution.results[0].png - expect(image).toBeDefined() -}) - -sandboxTest('get image on save', async ({ sandbox }) => { - const code = ` - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image.save("test.png") - ` - - const execution = await sandbox.runCode(code) - - const image = execution.results[0].png - expect(image).toBeDefined() -}) diff --git a/packages/code-interpreter-js/tests/javaKernelReadiness.test.ts b/packages/code-interpreter-js/tests/javaKernelReadiness.test.ts deleted file mode 100644 index c9c68d05cb..0000000000 --- a/packages/code-interpreter-js/tests/javaKernelReadiness.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { expect, test, vi } from 'vitest' - -import { Sandbox, SandboxError } from '../src' -import { waitForKernel } from './setup' - -const javaNotReadyError = () => new SandboxError('500 Internal Server Error') - -function mockSandbox(runCode: ReturnType) { - return { runCode } as unknown as Sandbox -} - -test.each(['java', 'r'] as const)( - 'waits through repeated %s readiness 500s', - async (language) => { - const runCode = vi - .fn() - .mockRejectedValueOnce(javaNotReadyError()) - .mockRejectedValueOnce(javaNotReadyError()) - .mockRejectedValueOnce(javaNotReadyError()) - .mockResolvedValueOnce(undefined) - - await waitForKernel(mockSandbox(runCode), language) - - expect(runCode).toHaveBeenCalledTimes(4) - expect(runCode).toHaveBeenNthCalledWith(1, '1', { language }) - expect(runCode).toHaveBeenNthCalledWith(4, '1', { language }) - } -) - -test('propagates a persistent Java readiness 500', async () => { - const finalError = javaNotReadyError() - const runCode = vi - .fn() - .mockRejectedValueOnce(javaNotReadyError()) - .mockRejectedValueOnce(javaNotReadyError()) - .mockRejectedValueOnce(javaNotReadyError()) - .mockRejectedValueOnce(finalError) - - await expect(waitForKernel(mockSandbox(runCode), 'java')).rejects.toBe( - finalError - ) - expect(runCode).toHaveBeenCalledTimes(4) -}) - -test('does not retry an unrelated Java error', async () => { - const error = new SandboxError('401 Unauthorized') - const runCode = vi.fn().mockRejectedValueOnce(error) - - await expect(waitForKernel(mockSandbox(runCode), 'java')).rejects.toBe(error) - expect(runCode).toHaveBeenCalledTimes(1) -}) diff --git a/packages/code-interpreter-js/tests/kernels.test.ts b/packages/code-interpreter-js/tests/kernels.test.ts deleted file mode 100644 index b45c59db67..0000000000 --- a/packages/code-interpreter-js/tests/kernels.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { expect } from 'vitest' - -import { sandboxTest } from './setup' - -sandboxTest('create new kernel', async ({ sandbox }) => { - await sandbox.createCodeContext() -}) - -sandboxTest('independence of kernels', async ({ sandbox }) => { - await sandbox.runCode('x = 1') - const context = await sandbox.createCodeContext() - const output = await sandbox.runCode('x', { context }) - - expect(output.error!.value).toEqual("name 'x' is not defined") -}) - -sandboxTest('pass context and language', async ({ sandbox }) => { - const context = await sandbox.createCodeContext() - await expect( - sandbox.runCode({ context, language: 'python' }) - ).rejects.toThrowError() -}) diff --git a/packages/code-interpreter-js/tests/setup.ts b/packages/code-interpreter-js/tests/setup.ts index d828132c85..50817d5999 100644 --- a/packages/code-interpreter-js/tests/setup.ts +++ b/packages/code-interpreter-js/tests/setup.ts @@ -1,5 +1,5 @@ import { test as base } from 'vitest' -import { Sandbox, SandboxError, SandboxOpts } from '../src' +import { Sandbox, SandboxOpts } from '../src' interface SandboxFixture { sandbox: Sandbox @@ -9,7 +9,6 @@ interface SandboxFixture { } const template = process.env.E2B_TESTS_TEMPLATE || 'code-interpreter-v1' -const KERNEL_READINESS_ATTEMPTS = 4 export const sandboxTest = base.extend({ template, @@ -67,24 +66,4 @@ export async function wait(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)) } -export async function waitForKernel(sandbox: Sandbox, language: 'java' | 'r') { - for (let attempt = 1; attempt <= KERNEL_READINESS_ATTEMPTS; attempt++) { - try { - await sandbox.runCode('1', { language }) - return - } catch (error) { - // A newly running sandbox can briefly return this response while - // Foxtrot initializes a lazy language context. Retry only that known - // readiness failure; the test's actual execution still runs once. - const isReadinessError = - error instanceof SandboxError && - error.message === '500 Internal Server Error' - - if (!isReadinessError || attempt === KERNEL_READINESS_ATTEMPTS) { - throw error - } - } - } -} - export { template } diff --git a/packages/code-interpreter-js/tests/statefulness.test.ts b/packages/code-interpreter-js/tests/statefulness.test.ts deleted file mode 100644 index fd5a7e4e07..0000000000 --- a/packages/code-interpreter-js/tests/statefulness.test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { expect } from 'vitest' - -import { isDebug, sandboxTest } from './setup' - -// Skip this test if we are running in debug mode — the execution is persisted between all tests so the result is not reset. -sandboxTest.skipIf(isDebug)('statefulness', async ({ sandbox }) => { - await sandbox.runCode('x = 1') - - const result = await sandbox.runCode('x += 1; x') - - expect(result.text).toEqual('2') -}) diff --git a/packages/code-interpreter-js/tests/systemd.test.ts b/packages/code-interpreter-js/tests/systemd.test.ts deleted file mode 100644 index 28f5939823..0000000000 --- a/packages/code-interpreter-js/tests/systemd.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { expect } from 'vitest' -import { isDebug, sandboxTest, wait } from './setup' - -async function waitForHealth(sandbox: any, maxRetries = 10, intervalMs = 100) { - for (let i = 0; i < maxRetries; i++) { - try { - const result = await sandbox.commands.run( - 'curl -s -o /dev/null -w "%{http_code}" http://0.0.0.0:49999/health' - ) - if (result.stdout.trim() === '200') { - return true - } - } catch { - // Connection refused or other error, retry - } - await wait(intervalMs) - } - return false -} - -sandboxTest.skipIf(isDebug)( - 'restart after jupyter kill', - async ({ sandbox }) => { - // Verify health is up initially - const initialHealth = await waitForHealth(sandbox) - expect(initialHealth).toBe(true) - - // Kill the jupyter process as root - // The command handle may get killed too (since killing jupyter cascades to code-interpreter), - // so we catch the error. - try { - await sandbox.commands.run("kill -9 $(pgrep -f 'jupyter server')", { - user: 'root', - }) - } catch { - // Expected — the kill cascade may terminate the command handle - } - - // Wait for systemd to restart both services - const recovered = await waitForHealth(sandbox, 60, 500) - expect(recovered).toBe(true) - - // Verify code execution works after recovery - const result = await sandbox.runCode('x = 1; x') - expect(result.text).toEqual('1') - } -) - -sandboxTest.skipIf(isDebug)( - 'restart after code-interpreter kill', - async ({ sandbox }) => { - // Verify health is up initially - const initialHealth = await waitForHealth(sandbox) - expect(initialHealth).toBe(true) - - // Kill the code-interpreter process as root - try { - await sandbox.commands.run("kill -9 $(pgrep -f 'uvicorn main:app')", { - user: 'root', - }) - } catch { - // Expected — killing code-interpreter may terminate the command handle - } - - // Wait for systemd to restart it and health to come back - const recovered = await waitForHealth(sandbox, 60, 500) - expect(recovered).toBe(true) - - // Verify code execution works after recovery - const result = await sandbox.runCode('x = 1; x') - expect(result.text).toEqual('1') - } -) diff --git a/packages/code-interpreter-python/tests/async/env_vars/test_bash.py b/packages/code-interpreter-python/tests/async/env_vars/test_bash.py deleted file mode 100644 index b94563f917..0000000000 --- a/packages/code-interpreter-python/tests/async/env_vars/test_bash.py +++ /dev/null @@ -1,43 +0,0 @@ -import pytest -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -@pytest.mark.skip_debug() -async def test_env_vars_on_sandbox(template): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - result = await sandbox.run_code("echo $TEST_ENV_VAR", language="bash") - assert result.logs.stdout[0] == "supertest\n" - finally: - await sandbox.kill() - - -async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code( - "echo $FOO", envs={"FOO": "bar"}, language="bash" - ) - - result_empty = await async_sandbox.run_code("echo ${FOO:-default}", language="bash") - - assert result.logs.stdout[0] == "bar\n" - assert result_empty.logs.stdout[0] == "default\n" - - -@pytest.mark.skip_debug() -async def test_env_vars_overwrite(template): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - result = await sandbox.run_code( - "echo $TEST_ENV_VAR", language="bash", envs={"TEST_ENV_VAR": "overwrite"} - ) - result_global_default = await sandbox.run_code( - "echo $TEST_ENV_VAR", language="bash" - ) - assert result.logs.stdout[0] == "overwrite\n" - assert result_global_default.logs.stdout[0] == "supertest\n" - finally: - await sandbox.kill() diff --git a/packages/code-interpreter-python/tests/async/env_vars/test_java.py b/packages/code-interpreter-python/tests/async/env_vars/test_java.py deleted file mode 100644 index f1195ef359..0000000000 --- a/packages/code-interpreter-python/tests/async/env_vars/test_java.py +++ /dev/null @@ -1,58 +0,0 @@ -import pytest -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -@pytest.mark.skip_debug() -async def test_env_vars_on_sandbox(template, wait_for_kernel_async): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - await wait_for_kernel_async(sandbox, "java") - - result = await sandbox.run_code( - 'System.getProperty("TEST_ENV_VAR")', language="java" - ) - assert result.text is not None - assert result.text.strip() == "supertest" - finally: - await sandbox.kill() - - -async def test_env_vars_per_execution(async_java_sandbox: AsyncSandbox): - result = await async_java_sandbox.run_code( - 'System.getProperty("FOO")', envs={"FOO": "bar"}, language="java" - ) - - result_empty = await async_java_sandbox.run_code( - 'System.getProperty("FOO", "default")', language="java" - ) - - assert result.text is not None - assert result.text.strip() == "bar" - assert result_empty.text is not None - assert result_empty.text.strip() == "default" - - -@pytest.mark.skip_debug() -async def test_env_vars_overwrite(template, wait_for_kernel_async): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - await wait_for_kernel_async(sandbox, "java") - - result = await sandbox.run_code( - 'System.getProperty("TEST_ENV_VAR")', - language="java", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = await sandbox.run_code( - 'System.getProperty("TEST_ENV_VAR")', language="java" - ) - assert result.text is not None - assert result.text.strip() == "overwrite" - assert result_global_default.text is not None - assert result_global_default.text.strip() == "supertest" - finally: - await sandbox.kill() diff --git a/packages/code-interpreter-python/tests/async/env_vars/test_js.py b/packages/code-interpreter-python/tests/async/env_vars/test_js.py deleted file mode 100644 index 3fa21f2718..0000000000 --- a/packages/code-interpreter-python/tests/async/env_vars/test_js.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -@pytest.mark.skip_debug() -async def test_env_vars_on_sandbox(template): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - result = await sandbox.run_code( - "process.env.TEST_ENV_VAR", language="javascript" - ) - assert result.text is not None - assert result.text.strip() == "supertest" - finally: - await sandbox.kill() - - -async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code( - "process.env.FOO", envs={"FOO": "bar"}, language="javascript" - ) - - result_empty = await async_sandbox.run_code( - "process.env.FOO || 'default'", language="javascript" - ) - - assert result.text is not None - assert result.text.strip() == "bar" - assert result_empty.text is not None - assert result_empty.text.strip() == "default" - - -@pytest.mark.skip_debug() -async def test_env_vars_overwrite(template): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - result = await sandbox.run_code( - "process.env.TEST_ENV_VAR", - language="javascript", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = await sandbox.run_code( - "process.env.TEST_ENV_VAR", language="javascript" - ) - assert result.text is not None - assert result.text.strip() == "overwrite" - assert result_global_default.text is not None - assert result_global_default.text.strip() == "supertest" - finally: - await sandbox.kill() diff --git a/packages/code-interpreter-python/tests/async/env_vars/test_python.py b/packages/code-interpreter-python/tests/async/env_vars/test_python.py deleted file mode 100644 index 3173efc9e5..0000000000 --- a/packages/code-interpreter-python/tests/async/env_vars/test_python.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -@pytest.mark.skip_debug() -async def test_env_vars_on_sandbox(template): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - result = await sandbox.run_code( - "import os; os.getenv('TEST_ENV_VAR')", language="python" - ) - assert result.text is not None - assert result.text.strip() == "supertest" - finally: - await sandbox.kill() - - -async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code( - "import os; os.getenv('FOO')", envs={"FOO": "bar"}, language="python" - ) - - result_empty = await async_sandbox.run_code( - "import os; os.getenv('FOO', 'default')", language="python" - ) - - assert result.text is not None - assert result.text.strip() == "bar" - assert result_empty.text is not None - assert result_empty.text.strip() == "default" - - -@pytest.mark.skip_debug() -async def test_env_vars_overwrite(template): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - result = await sandbox.run_code( - "import os; os.getenv('TEST_ENV_VAR')", - language="python", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = await sandbox.run_code( - "import os; os.getenv('TEST_ENV_VAR')", language="python" - ) - assert result.text is not None - assert result.text.strip() == "overwrite" - assert result_global_default.text is not None - assert result_global_default.text.strip() == "supertest" - finally: - await sandbox.kill() diff --git a/packages/code-interpreter-python/tests/async/env_vars/test_r.py b/packages/code-interpreter-python/tests/async/env_vars/test_r.py deleted file mode 100644 index e75b499ba9..0000000000 --- a/packages/code-interpreter-python/tests/async/env_vars/test_r.py +++ /dev/null @@ -1,57 +0,0 @@ -import pytest -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -@pytest.mark.skip_debug() -async def test_env_vars_on_sandbox(template, wait_for_kernel_async): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - await wait_for_kernel_async(sandbox, "r") - result = await sandbox.run_code('Sys.getenv("TEST_ENV_VAR")', language="r") - assert result.results[0].text is not None - assert result.results[0].text.strip() == '[1] "supertest"' - finally: - await sandbox.kill() - - -async def test_env_vars_per_execution( - async_sandbox: AsyncSandbox, wait_for_kernel_async -): - await wait_for_kernel_async(async_sandbox, "r") - result = await async_sandbox.run_code( - 'Sys.getenv("FOO")', envs={"FOO": "bar"}, language="r" - ) - - result_empty = await async_sandbox.run_code( - 'Sys.getenv("FOO", unset = "default")', language="r" - ) - - assert result.results[0].text is not None - assert result.results[0].text.strip() == '[1] "bar"' - assert result_empty.results[0].text is not None - assert result_empty.results[0].text.strip() == '[1] "default"' - - -@pytest.mark.skip_debug() -async def test_env_vars_overwrite(template, wait_for_kernel_async): - sandbox = await AsyncSandbox.create( - template=template, envs={"TEST_ENV_VAR": "supertest"} - ) - try: - await wait_for_kernel_async(sandbox, "r") - result = await sandbox.run_code( - 'Sys.getenv("TEST_ENV_VAR")', - language="r", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = await sandbox.run_code( - 'Sys.getenv("TEST_ENV_VAR")', language="r" - ) - assert result.results[0].text is not None - assert result.results[0].text.strip() == '[1] "overwrite"' - assert result_global_default.results[0].text is not None - assert result_global_default.results[0].text.strip() == '[1] "supertest"' - finally: - await sandbox.kill() diff --git a/packages/code-interpreter-python/tests/async/test_async_bash.py b/packages/code-interpreter-python/tests/async/test_async_bash.py deleted file mode 100644 index a9e2cb0ce8..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_bash.py +++ /dev/null @@ -1,6 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def test_bash(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code("!pwd") - assert "".join(result.logs.stdout).strip() == "/home/user" diff --git a/packages/code-interpreter-python/tests/async/test_async_contexts.py b/packages/code-interpreter-python/tests/async/test_async_contexts.py index d470025d91..42e40ae130 100644 --- a/packages/code-interpreter-python/tests/async/test_async_contexts.py +++ b/packages/code-interpreter-python/tests/async/test_async_contexts.py @@ -1,4 +1,5 @@ import pytest +from e2b import InvalidArgumentException from e2b_code_interpreter.code_interpreter_async import AsyncSandbox @@ -64,6 +65,14 @@ async def test_restart_context(async_sandbox: AsyncSandbox): assert execution.error.value == "name 'x' is not defined" +async def test_pass_context_and_language(async_sandbox: AsyncSandbox): + context = await async_sandbox.create_code_context(language="python") + with pytest.raises(InvalidArgumentException): + await async_sandbox.run_code( + "console.log('Hello, World!')", language="js", context=context + ) + + @pytest.mark.skip_debug async def test_create_context_secure_traffic(async_sandbox_factory): async_sandbox = await async_sandbox_factory(network={"allow_public_traffic": False}) diff --git a/packages/code-interpreter-python/tests/async/test_async_custom_repr_object.py b/packages/code-interpreter-python/tests/async/test_async_custom_repr_object.py deleted file mode 100644 index 7b35e9257a..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_custom_repr_object.py +++ /dev/null @@ -1,12 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - -code = """ -from IPython.display import display - -display({'text/latex': r'\text{CustomReprObject}'}, raw=True) -""" - - -async def test_bash(async_sandbox: AsyncSandbox): - execution = await async_sandbox.run_code(code) - assert execution.results[0].formats() == ["latex"] diff --git a/packages/code-interpreter-python/tests/async/test_async_cwd.py b/packages/code-interpreter-python/tests/async/test_async_cwd.py deleted file mode 100644 index 257ca89a3f..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_cwd.py +++ /dev/null @@ -1,42 +0,0 @@ -import pytest - -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -@pytest.mark.skip_debug() -async def test_cwd_python(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code("from pathlib import Path; print(Path.cwd())") - assert "".join(result.logs.stdout).strip() == "/home/user" - - -@pytest.mark.skip_debug() -async def test_cwd_javascript(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code("process.cwd()", language="js") - assert result.text == "/home/user" - - -@pytest.mark.skip_debug() -async def test_cwd_typescript(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code("process.cwd()", language="ts") - assert result.text == "/home/user" - - -@pytest.mark.skip_debug() -async def test_cwd_r(async_sandbox: AsyncSandbox, wait_for_kernel_async): - await wait_for_kernel_async(async_sandbox, "r") - result = await async_sandbox.run_code("getwd()", language="r") - assert result.results[0].text.strip() == '[1] "/home/user"' - - -@pytest.mark.skip_debug() -async def test_cwd_java(async_java_sandbox: AsyncSandbox): - result = await async_java_sandbox.run_code( - 'System.getProperty("user.dir")', language="java" - ) - assert result.results[0].text.strip() == "/home/user" - - -@pytest.mark.skip_debug() -async def test_cwd_bash(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code("pwd", language="bash") - assert "".join(result.logs.stdout).strip() == "/home/user" diff --git a/packages/code-interpreter-python/tests/async/test_async_data.py b/packages/code-interpreter-python/tests/async/test_async_data.py deleted file mode 100644 index d11a67b85c..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_data.py +++ /dev/null @@ -1,17 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def test_data(async_sandbox: AsyncSandbox): - # plot random chart - result = await async_sandbox.run_code( - """ - import pandas as pd - pd.DataFrame({"a": [1, 2, 3]}) - """ - ) - - # there's your image - data = result.results[0] - assert data.data - assert "a" in data.data - assert len(data.data["a"]) == 3 diff --git a/packages/code-interpreter-python/tests/async/test_async_default_kernels.py b/packages/code-interpreter-python/tests/async/test_async_default_kernels.py deleted file mode 100644 index b2df1dcadd..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_default_kernels.py +++ /dev/null @@ -1,36 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def test_js_kernel(async_sandbox: AsyncSandbox): - execution = await async_sandbox.run_code( - "console.log('Hello, World!')", language="js" - ) - assert execution.logs.stdout == ["Hello, World!\n"] - - -async def test_js_esm_imports(async_sandbox: AsyncSandbox): - execution = await async_sandbox.run_code( - """ - import { readFileSync } from 'fs' - console.log(typeof readFileSync) - """, - language="js", - ) - assert execution.logs.stdout == ["function\n"] - - -async def test_js_top_level_await(async_sandbox: AsyncSandbox): - execution = await async_sandbox.run_code( - """ - await Promise.resolve('Hello World!') - """, - language="js", - ) - assert execution.text == "Hello World!" - - -async def test_ts_kernel(async_sandbox: AsyncSandbox): - execution = await async_sandbox.run_code( - "const message: string = 'Hello, World!'; console.log(message);", language="ts" - ) - assert execution.logs.stdout == ["Hello, World!\n"] diff --git a/packages/code-interpreter-python/tests/async/test_async_display_data.py b/packages/code-interpreter-python/tests/async/test_async_display_data.py deleted file mode 100644 index bb50647fb0..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_display_data.py +++ /dev/null @@ -1,23 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def test_display_data(async_sandbox: AsyncSandbox): - # plot random chart - result = await async_sandbox.run_code( - """ - import matplotlib.pyplot as plt - import numpy as np - - x = np.linspace(0, 20, 100) - y = np.sin(x) - - plt.plot(x, y) - plt.show() - """ - ) - - # there's your image - data = result.results[0] - assert data.png - assert data.text - assert not data.extra diff --git a/packages/code-interpreter-python/tests/async/test_async_env_vars.py b/packages/code-interpreter-python/tests/async/test_async_env_vars.py new file mode 100644 index 0000000000..bd87967bd6 --- /dev/null +++ b/packages/code-interpreter-python/tests/async/test_async_env_vars.py @@ -0,0 +1,13 @@ +from e2b_code_interpreter.code_interpreter_async import AsyncSandbox + + +async def test_env_vars_per_execution(async_sandbox: AsyncSandbox): + result = await async_sandbox.run_code( + "import os; os.getenv('FOO')", envs={"FOO": "bar"} + ) + result_empty = await async_sandbox.run_code( + "import os; os.getenv('FOO', 'default')" + ) + + assert result.text == "bar" + assert result_empty.text == "default" diff --git a/packages/code-interpreter-python/tests/async/test_async_execution_count.py b/packages/code-interpreter-python/tests/async/test_async_execution_count.py deleted file mode 100644 index c49558387f..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_execution_count.py +++ /dev/null @@ -1,10 +0,0 @@ -import pytest - -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -@pytest.mark.skip_debug() -async def test_execution_count(async_sandbox: AsyncSandbox): - await async_sandbox.run_code("echo 'E2B is awesome!'") - result = await async_sandbox.run_code("!pwd") - assert result.execution_count == 2 diff --git a/packages/code-interpreter-python/tests/async/test_async_kernels.py b/packages/code-interpreter-python/tests/async/test_async_kernels.py deleted file mode 100644 index ce88967b5c..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_kernels.py +++ /dev/null @@ -1,25 +0,0 @@ -import pytest -from e2b import InvalidArgumentException - -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def test_create_new_kernel(async_sandbox: AsyncSandbox): - await async_sandbox.create_code_context() - - -async def test_independence_of_kernels(async_sandbox: AsyncSandbox): - context = await async_sandbox.create_code_context() - await async_sandbox.run_code("x = 1") - - r = await async_sandbox.run_code("x", context=context) - assert r.error is not None - assert r.error.value == "name 'x' is not defined" - - -async def test_pass_context_and_language(async_sandbox: AsyncSandbox): - context = await async_sandbox.create_code_context(language="python") - with pytest.raises(InvalidArgumentException): - await async_sandbox.run_code( - "console.log('Hello, World!')", language="js", context=context - ) diff --git a/packages/code-interpreter-python/tests/async/test_async_statefulness.py b/packages/code-interpreter-python/tests/async/test_async_statefulness.py deleted file mode 100644 index e33dd80896..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_statefulness.py +++ /dev/null @@ -1,8 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def test_stateful(async_sandbox: AsyncSandbox): - await async_sandbox.run_code("async_test_stateful = 1") - - result = await async_sandbox.run_code("async_test_stateful+=1; async_test_stateful") - assert result.text == "2" diff --git a/packages/code-interpreter-python/tests/async/test_async_systemd.py b/packages/code-interpreter-python/tests/async/test_async_systemd.py deleted file mode 100644 index 5a129abc3a..0000000000 --- a/packages/code-interpreter-python/tests/async/test_async_systemd.py +++ /dev/null @@ -1,63 +0,0 @@ -import asyncio - -import pytest - -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def wait_for_health(sandbox: AsyncSandbox, max_retries=10, interval_ms=100): - for _ in range(max_retries): - try: - result = await sandbox.commands.run( - 'curl -s -o /dev/null -w "%{http_code}" http://0.0.0.0:49999/health' - ) - if result.stdout.strip() == "200": - return True - except Exception: - pass - await asyncio.sleep(interval_ms / 1000) - return False - - -@pytest.mark.skip_debug -async def test_restart_after_jupyter_kill(async_sandbox: AsyncSandbox): - # Verify health is up initially - assert await wait_for_health(async_sandbox) - - # Kill the jupyter process as root - # The command handle may get killed too (killing jupyter cascades to code-interpreter), - # so we catch the error. - try: - await async_sandbox.commands.run( - "kill -9 $(pgrep -f 'jupyter server')", user="root" - ) - except Exception: - pass - - # Wait for systemd to restart both services - assert await wait_for_health(async_sandbox, 60, 500) - - # Verify code execution works after recovery - result = await async_sandbox.run_code("x = 1; x") - assert result.text == "1" - - -@pytest.mark.skip_debug -async def test_restart_after_code_interpreter_kill(async_sandbox: AsyncSandbox): - # Verify health is up initially - assert await wait_for_health(async_sandbox) - - # Kill the code-interpreter process as root - try: - await async_sandbox.commands.run( - "kill -9 $(pgrep -f 'uvicorn main:app')", user="root" - ) - except Exception: - pass - - # Wait for systemd to restart it and health to come back - assert await wait_for_health(async_sandbox, 60, 500) - - # Verify code execution works after recovery - result = await async_sandbox.run_code("x = 1; x") - assert result.text == "1" diff --git a/packages/code-interpreter-python/tests/charts/test_bar.py b/packages/code-interpreter-python/tests/charts/test_bar.py deleted file mode 100644 index a35b19c19f..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_bar.py +++ /dev/null @@ -1,50 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import ChartType, BarChart - -code = """ -import matplotlib.pyplot as plt - -# Prepare data -authors = ['Author A', 'Author B', 'Author C', 'Author D'] -sales = [100, 200, 300, 400] - -# Create and customize the bar chart -plt.figure(figsize=(10, 6)) -plt.bar(authors, sales, label='Books Sold', color='blue') -plt.xlabel('Authors') -plt.ylabel('Number of Books Sold') -plt.title('Book Sales by Authors') - -# Display the chart -plt.tight_layout() -plt.show() -""" - - -async def test_chart_bar(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, BarChart) - assert chart.type == ChartType.BAR - assert chart.title == "Book Sales by Authors" - - assert chart.x_label == "Authors" - assert chart.y_label == "Number of Books Sold" - - assert chart.x_unit is None - assert chart.y_unit is None - - bars = chart.elements - assert len(bars) == 4 - - assert [bar.value for bar in bars] == [100, 200, 300, 400] - assert [bar.label for bar in bars] == [ - "Author A", - "Author B", - "Author C", - "Author D", - ] - assert [bar.group for bar in bars] == ["Books Sold"] * 4 diff --git a/packages/code-interpreter-python/tests/charts/test_box_and_whiskers.py b/packages/code-interpreter-python/tests/charts/test_box_and_whiskers.py deleted file mode 100644 index 4328faf6de..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_box_and_whiskers.py +++ /dev/null @@ -1,60 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import BoxAndWhiskerChart, ChartType - -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Sample data -data = { - 'Class A': [85, 90, 78, 92, 88], - 'Class B': [95, 89, 76, 91, 84, 87], - 'Class C': [75, 82, 88, 79, 86] -} - -# Create figure and axis -fig, ax = plt.subplots(figsize=(10, 6)) - -# Customize plot -ax.set_title('Exam Scores Distribution') -ax.set_xlabel('Class') -ax.set_ylabel('Score') - -# Set custom colors -ax.boxplot(data.values(), labels=data.keys(), patch_artist=True) - -# Add legend -ax.legend() - -# Adjust layout and show plot -plt.tight_layout() -plt.show() -""" - - -async def test_box_and_whiskers(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, BoxAndWhiskerChart) - assert chart.type == ChartType.BOX_AND_WHISKER - assert chart.title == "Exam Scores Distribution" - - assert chart.x_label == "Class" - assert chart.y_label == "Score" - - assert chart.x_unit is None - assert chart.y_unit is None - - bars = chart.elements - assert len(bars) == 3 - - assert [bar.outliers for bar in bars] == [[], [76], []] - assert [bar.min for bar in bars] == [78, 84, 75] - assert [bar.first_quartile for bar in bars] == [85, 84.75, 79] - assert [bar.median for bar in bars] == [88, 88, 82] - assert [bar.third_quartile for bar in bars] == [90, 90.5, 86] - assert [bar.max for bar in bars] == [92, 95, 88] - assert [bar.label for bar in bars] == ["Class A", "Class B", "Class C"] diff --git a/packages/code-interpreter-python/tests/charts/test_deserialize.py b/packages/code-interpreter-python/tests/charts/test_deserialize.py new file mode 100644 index 0000000000..d3c2f7859c --- /dev/null +++ b/packages/code-interpreter-python/tests/charts/test_deserialize.py @@ -0,0 +1,133 @@ +import json + +import pytest + +from e2b_code_interpreter.charts import ( + BarChart, + BoxAndWhiskerChart, + Chart, + ChartType, + LineChart, + PieChart, + ScaleType, + ScatterChart, + SuperChart, + _deserialize_chart, +) +from e2b_code_interpreter.models import Execution, Result + +AXES = {"x_label": "x", "y_label": "y", "x_unit": None, "y_unit": None} +TICKS = { + "x_ticks": [0, 1], + "x_tick_labels": ["0", "1"], + "x_scale": "linear", + "y_ticks": [0, 1], + "y_tick_labels": ["0", "1"], + "y_scale": "log", +} + +LINE = { + "type": "line", + "title": "line", + **AXES, + **TICKS, + "elements": [{"label": "a", "points": [[0, 0], [1, 1]]}], +} +SCATTER = {**LINE, "type": "scatter", "title": "scatter"} +BAR = { + "type": "bar", + "title": "bar", + **AXES, + "elements": [{"label": "a", "value": "1", "group": "g"}], +} +PIE = { + "type": "pie", + "title": "pie", + "elements": [{"label": "a", "angle": 180.0, "radius": 1.0}], +} +BOX = { + "type": "box_and_whisker", + "title": "box", + **AXES, + "elements": [ + { + "label": "a", + "min": 0.0, + "first_quartile": 1.0, + "median": 2.0, + "third_quartile": 3.0, + "max": 4.0, + "outliers": None, + } + ], +} +SUPERCHART = {"type": "superchart", "title": "super", "elements": [LINE, SCATTER]} +UNKNOWN = {"type": "unknown", "title": "unknown", "elements": []} + + +@pytest.mark.parametrize( + ("payload", "cls", "chart_type"), + [ + (LINE, LineChart, ChartType.LINE), + (SCATTER, ScatterChart, ChartType.SCATTER), + (BAR, BarChart, ChartType.BAR), + (PIE, PieChart, ChartType.PIE), + (BOX, BoxAndWhiskerChart, ChartType.BOX_AND_WHISKER), + (SUPERCHART, SuperChart, ChartType.SUPERCHART), + (UNKNOWN, Chart, ChartType.UNKNOWN), + ], +) +def test_deserialize_chart(payload, cls, chart_type): + chart = _deserialize_chart(payload) + + assert isinstance(chart, cls) + assert chart.type == chart_type + assert chart.title == payload["title"] + assert chart.to_dict() == payload + + +def test_deserialize_point_chart_fields(): + chart = _deserialize_chart(LINE) + + assert isinstance(chart, LineChart) + assert chart.x_label == "x" + assert chart.x_scale == ScaleType.LINEAR + assert chart.y_scale == ScaleType.LOG + assert chart.x_ticks == [0, 1] + assert chart.elements[0].label == "a" + assert chart.elements[0].points == [(0, 0), (1, 1)] + + +def test_deserialize_unknown_scale_falls_back(): + chart = _deserialize_chart({**LINE, "x_scale": "weird"}) + + assert isinstance(chart, LineChart) + assert chart.x_scale == ScaleType.UNKNOWN + + +def test_deserialize_box_and_whisker_outliers_default(): + chart = _deserialize_chart(BOX) + + assert isinstance(chart, BoxAndWhiskerChart) + assert chart.elements[0].median == 2.0 + assert chart.elements[0].outliers == [] + + +def test_deserialize_superchart_nests_charts(): + chart = _deserialize_chart(SUPERCHART) + + assert isinstance(chart, SuperChart) + assert [type(c) for c in chart.elements] == [LineChart, ScatterChart] + + +def test_deserialize_empty_chart(): + assert _deserialize_chart(None) is None + assert _deserialize_chart({}) is None + + +def test_result_chart_round_trips_through_to_json(): + execution = Execution(results=[Result(chart=BAR, is_main_result=True)]) + + assert isinstance(execution.results[0].chart, BarChart) + assert "chart" in execution.results[0].formats() + assert json.loads(execution.to_json())["results"][0]["chart"] == BAR diff --git a/packages/code-interpreter-python/tests/charts/test_line.py b/packages/code-interpreter-python/tests/charts/test_line.py deleted file mode 100644 index e90b4bd35c..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_line.py +++ /dev/null @@ -1,76 +0,0 @@ -import datetime - -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import LineChart - -code = """ -import numpy as np -import matplotlib.pyplot as plt -import datetime - -# Generate x values -dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] - -x = np.linspace(0, 2*np.pi, 100) -# Calculate y values -y_sin = np.sin(x) -y_cos = np.cos(x) - -# Create the plot -plt.figure(figsize=(10, 6)) -plt.plot(dates, y_sin, label='sin(x)') -plt.plot(dates, y_cos, label='cos(x)') - -# Add labels and title -plt.xlabel("Time (s)") -plt.ylabel("Amplitude (Hz)") -plt.title('Plot of sin(x) and cos(x)') - -# Display the plot -plt.show() -""" - - -async def test_line_chart(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, LineChart) - assert chart.title == "Plot of sin(x) and cos(x)" - - assert chart.x_label == "Time (s)" - assert chart.y_label == "Amplitude (Hz)" - - assert chart.x_unit == "s" - assert chart.y_unit == "Hz" - - assert chart.x_scale == "datetime" - assert chart.y_scale == "linear" - - assert all(isinstance(x, str) for x in chart.x_ticks) - parsed_date = datetime.datetime.fromisoformat(chart.x_ticks[0]) - assert isinstance(parsed_date, datetime.datetime) - assert all(isinstance(y, float) for y in chart.y_ticks) - - assert all(isinstance(x, str) for x in chart.y_tick_labels) - assert all(isinstance(y, str) for y in chart.y_tick_labels) - - lines = chart.elements - assert len(lines) == 2 - - first_line = lines[0] - assert first_line.label == "sin(x)" - assert len(first_line.points) == 100 - assert all(isinstance(point, tuple) for point in first_line.points) - assert all( - isinstance(x, str) and isinstance(y, float) for x, y in first_line.points - ) - - parsed_date = datetime.datetime.fromisoformat(first_line.points[0][0]) - assert isinstance(parsed_date, datetime.datetime) - - second_line = lines[1] - assert second_line.label == "cos(x)" - assert len(second_line.points) == 100 diff --git a/packages/code-interpreter-python/tests/charts/test_log_chart.py b/packages/code-interpreter-python/tests/charts/test_log_chart.py deleted file mode 100644 index e74c9ec554..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_log_chart.py +++ /dev/null @@ -1,64 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import LineChart - -# Log chart -code = """ -import numpy as np -import matplotlib.pyplot as plt - -# Generate x values -x = np.linspace(0, 100, 100) -# Calculate y values -y = np.exp(x) - -# Create the plot -plt.figure(figsize=(10, 6)) -plt.plot(x, y, label='y = e^x') - -# Set log scale for the y-axis -plt.yscale('log') - -# Add labels and title -plt.xlabel('X-axis') -plt.ylabel('Y-axis (log scale)') -plt.title('Chart with Log Scale on Y-axis') - -plt.legend() -plt.grid(True) -plt.show() -""" - - -async def test_log_chart(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, LineChart) - assert chart.title == "Chart with Log Scale on Y-axis" - - assert chart.x_label == "X-axis" - assert chart.y_label == "Y-axis (log scale)" - - assert chart.x_unit is None - assert chart.y_unit == "log scale" - - assert chart.x_scale == "linear" - assert chart.y_scale == "log" - - assert all(isinstance(x, float) for x in chart.x_ticks) - assert all(isinstance(y, float) for y in chart.y_ticks) - - assert all(isinstance(x, str) for x in chart.x_tick_labels) - assert all(isinstance(y, str) for y in chart.y_tick_labels) - - lines = chart.elements - assert len(lines) == 1 - - line = lines[0] - assert line.label == "y = e^x" - assert len(line.points) == 100 - - assert all(isinstance(x, tuple) for x in line.points) - assert all(isinstance(x, float) and isinstance(y, float) for x, y in line.points) diff --git a/packages/code-interpreter-python/tests/charts/test_pie.py b/packages/code-interpreter-python/tests/charts/test_pie.py deleted file mode 100644 index 574b2b9125..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_pie.py +++ /dev/null @@ -1,50 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import PieChart - -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Step 1: Define the data for the pie chart -categories = ["No", "No, in blue"] -sizes = [90, 10] - -# Step 2: Create the figure and axis objects -fig, ax = plt.subplots(figsize=(8, 8)) - -plt.xlabel("x") -plt.ylabel("y") - -# Step 3: Create the pie chart -ax.pie(sizes, labels=categories, autopct='%1.1f%%', startangle=90, colors=plt.cm.Pastel1.colors[:len(categories)]) - -# Step 4: Add title and legend -ax.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle -plt.title('Will I wake up early tomorrow?') - -# Step 5: Show the plot -plt.show() -""" - - -async def test_pie_chart(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, PieChart) - - assert chart.title == "Will I wake up early tomorrow?" - - assert len(chart.elements) == 2 - - first_data = chart.elements[0] - assert first_data.label == "No" - assert first_data.angle == 324 - assert first_data.radius == 1 - - second_data = chart.elements[1] - assert second_data.label == "No, in blue" - assert second_data.angle == 36 - assert second_data.radius == 1 diff --git a/packages/code-interpreter-python/tests/charts/test_scale.py b/packages/code-interpreter-python/tests/charts/test_scale.py deleted file mode 100644 index 221ef04ef9..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_scale.py +++ /dev/null @@ -1,52 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import LineChart - - -async def test_datetime_scale(async_sandbox: AsyncSandbox): - code = """ - import numpy as np - import matplotlib.pyplot as plt - import datetime - - # Generate x values - dates = [datetime.date(2023, 9, 1) + datetime.timedelta(seconds=i) for i in range(100)] - y_sin = np.sin(np.linspace(0, 2*np.pi, 100)) - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(dates, y_sin, label='sin(x)') - plt.show() - """ - - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, LineChart) - assert chart.x_scale == "datetime" - assert chart.y_scale == "linear" - - -async def test_categorical_scale(async_sandbox: AsyncSandbox): - code = """ - import numpy as np - import matplotlib.pyplot as plt - - x = [1, 2, 3, 4, 5] - y = ['A', 'B', 'C', 'D', 'E'] - - # Create the plot - plt.figure(figsize=(10, 6)) - plt.plot(x, y) - plt.show() - """ - - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, LineChart) - assert chart.x_scale == "linear" - assert chart.y_scale == "categorical" diff --git a/packages/code-interpreter-python/tests/charts/test_scatter.py b/packages/code-interpreter-python/tests/charts/test_scatter.py deleted file mode 100644 index 1668f4cc49..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_scatter.py +++ /dev/null @@ -1,57 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import ScatterChart - -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Create data -N = 5 -x1 = np.random.rand(N) -y1 = np.random.rand(N) -x2 = np.random.rand(2*N) -y2 = np.random.rand(2*N) - -plt.xlabel("A") -plt.ylabel("B") - -plt.scatter(x1, y1, c='blue', label='Dataset 1') -plt.scatter(x2, y2, c='red', label='Dataset 2') - -plt.show() -""" - - -async def test_scatter_chart(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, ScatterChart) - - assert chart.title is None - assert chart.x_label == "A" - assert chart.y_label == "B" - - assert chart.x_scale == "linear" - assert chart.y_scale == "linear" - - assert all(isinstance(x, float) for x in chart.x_ticks) - assert all(isinstance(y, float) for y in chart.y_ticks) - - assert all(isinstance(x, str) for x in chart.y_tick_labels) - assert all(isinstance(y, str) for y in chart.y_tick_labels) - - assert len(chart.elements) == 2 - - first_data = chart.elements[0] - assert first_data.label == "Dataset 1" - assert len(first_data.points) == 5 - print(first_data.points) - assert all(isinstance(x, tuple) for x in first_data.points) - - second_data = chart.elements[1] - assert second_data.label == "Dataset 2" - assert len(second_data.points) == 10 - assert all(isinstance(x, tuple) for x in second_data.points) diff --git a/packages/code-interpreter-python/tests/charts/test_superchart.py b/packages/code-interpreter-python/tests/charts/test_superchart.py deleted file mode 100644 index ee2e324e5c..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_superchart.py +++ /dev/null @@ -1,61 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import ChartType, SuperChart, LineChart, ScatterChart - -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Data for plotting -x1 = np.linspace(0, 10, 100) -y1 = np.sin(x1) - -# Create a figure with multiple subplots -fig, axs = plt.subplots(1, 2, figsize=(10, 8)) -fig.suptitle('Multiple Charts Example', fontsize=16) - -# Plotting on the different axes -axs[0].plot(x1, y1, 'r') -axs[0].set_title('Sine Wave') -axs[0].grid(True) - -N = 5 -x2 = np.random.rand(N) -y2 = np.random.rand(N) - -axs[1].scatter(x2, y2, c='blue', label='Dataset 1') -axs[1].set_xlabel('X') -axs[1].set_ylabel('Y') -axs[1].set_title('Scatter Plot') -axs[1].grid(True) - -plt.show() -""" - - -async def test_super_chart(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - chart = result.results[0].chart - assert chart - - assert isinstance(chart, SuperChart) - assert chart.type == ChartType.SUPERCHART - assert chart.title == "Multiple Charts Example" - - charts = chart.elements - assert len(charts) == 2 - - first_chart = charts[0] - assert first_chart.title == "Sine Wave" - assert isinstance(first_chart, LineChart) - assert first_chart.x_label is None - assert first_chart.y_label is None - assert len(first_chart.elements) == 1 - assert len(first_chart.elements[0].points) == 100 - - second_chart = charts[1] - assert second_chart.title == "Scatter Plot" - assert isinstance(second_chart, ScatterChart) - assert second_chart.x_label == "X" - assert second_chart.y_label == "Y" - assert len(second_chart.elements) == 1 - assert len(second_chart.elements[0].points) == 5 diff --git a/packages/code-interpreter-python/tests/charts/test_unknown.py b/packages/code-interpreter-python/tests/charts/test_unknown.py deleted file mode 100644 index 87ca36b3d9..0000000000 --- a/packages/code-interpreter-python/tests/charts/test_unknown.py +++ /dev/null @@ -1,40 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox -from e2b_code_interpreter.charts import ChartType, Chart - -code = """ -import matplotlib.pyplot as plt -import numpy as np - -# Create a figure and an axis -fig, ax = plt.subplots() - -# Create data for two concentric circles -circle1 = plt.Circle((0, 0), 1, color='blue', fill=False, linewidth=2) -circle2 = plt.Circle((0, 0), 2, color='red', fill=False, linewidth=2) - -# Add the circles to the axes -ax.add_artist(circle1) -ax.add_artist(circle2) - -# Set grid -ax.grid(True) - -# Set title -plt.title('Two Concentric Circles') - -# Show the plot -plt.show() -""" - - -async def test_unknown_charts(async_sandbox: AsyncSandbox): - result = await async_sandbox.run_code(code) - - chart = result.results[0].chart - assert chart - - assert isinstance(chart, Chart) - assert chart.type == ChartType.UNKNOWN - assert chart.title == "Two Concentric Circles" - - assert len(chart.elements) == 0 diff --git a/packages/code-interpreter-python/tests/conftest.py b/packages/code-interpreter-python/tests/conftest.py index b0a434ed1d..987d54a4d1 100644 --- a/packages/code-interpreter-python/tests/conftest.py +++ b/packages/code-interpreter-python/tests/conftest.py @@ -4,7 +4,6 @@ import pytest -from e2b import SandboxException from e2b_code_interpreter import ( AsyncSandbox, Sandbox, @@ -12,7 +11,6 @@ DEFAULT_TEST_SANDBOX_TIMEOUT = 180 -KERNEL_READINESS_ATTEMPTS = 4 @pytest.fixture(scope="session") @@ -73,53 +71,6 @@ async def async_sandbox(async_sandbox_factory): return await async_sandbox_factory() -def _wait_for_kernel(sandbox: Sandbox, language: str) -> None: - for attempt in range(KERNEL_READINESS_ATTEMPTS): - try: - sandbox.run_code("1", language=language) - return - except SandboxException as error: - # A newly running sandbox can briefly return this response while - # Foxtrot initializes a lazy language context. Retry only that known - # readiness failure; the test's actual execution still runs once. - is_readiness_error = str(error) == "500 Internal Server Error" - if not is_readiness_error or attempt == KERNEL_READINESS_ATTEMPTS - 1: - raise - - -async def _wait_for_kernel_async(sandbox: AsyncSandbox, language: str) -> None: - for attempt in range(KERNEL_READINESS_ATTEMPTS): - try: - await sandbox.run_code("1", language=language) - return - except SandboxException as error: - is_readiness_error = str(error) == "500 Internal Server Error" - if not is_readiness_error or attempt == KERNEL_READINESS_ATTEMPTS - 1: - raise - - -@pytest.fixture() -def wait_for_kernel(): - return _wait_for_kernel - - -@pytest.fixture() -def wait_for_kernel_async(): - return _wait_for_kernel_async - - -@pytest.fixture() -def java_sandbox(sandbox: Sandbox): - _wait_for_kernel(sandbox, "java") - return sandbox - - -@pytest.fixture() -async def async_java_sandbox(async_sandbox: AsyncSandbox): - await _wait_for_kernel_async(async_sandbox, "java") - return async_sandbox - - @pytest.fixture def debug(): return os.getenv("E2B_DEBUG") is not None diff --git a/packages/code-interpreter-python/tests/images/test_images.py b/packages/code-interpreter-python/tests/images/test_images.py deleted file mode 100644 index 19988319ac..0000000000 --- a/packages/code-interpreter-python/tests/images/test_images.py +++ /dev/null @@ -1,53 +0,0 @@ -from e2b_code_interpreter.code_interpreter_async import AsyncSandbox - - -async def test_show_image(async_sandbox: AsyncSandbox): - code = """ - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image.show() - print("Image shown.") - """ - - execution = await async_sandbox.run_code(code) - - image = execution.results[0].png - assert image - - -async def test_image_as_last_command(async_sandbox: AsyncSandbox): - code = """ - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image - """ - execution = await async_sandbox.run_code(code) - - image = execution.results[0].png - assert image - - -async def test_get_image_on_save(async_sandbox: AsyncSandbox): - code = """ - import numpy - from PIL import Image - - imarray = numpy.random.rand(16,16,3) * 255 - image = Image.fromarray(imarray.astype('uint8')).convert('RGBA') - - image.save("test.png") - print("Image saved.") - """ - - execution = await async_sandbox.run_code(code) - - image = execution.results[0].png - assert image diff --git a/packages/code-interpreter-python/tests/sync/env_vars/test_bash.py b/packages/code-interpreter-python/tests/sync/env_vars/test_bash.py deleted file mode 100644 index 9f5ea72821..0000000000 --- a/packages/code-interpreter-python/tests/sync/env_vars/test_bash.py +++ /dev/null @@ -1,35 +0,0 @@ -import pytest -from e2b_code_interpreter import Sandbox - - -@pytest.mark.skip_debug() -def test_env_vars_on_sandbox(template): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - result = sandbox.run_code("echo $TEST_ENV_VAR", language="bash") - assert result.logs.stdout[0] == "supertest\n" - finally: - sandbox.kill() - - -def test_env_vars_per_execution(sandbox: Sandbox): - result = sandbox.run_code("echo $FOO", envs={"FOO": "bar"}, language="bash") - - result_empty = sandbox.run_code("echo ${FOO:-default}", language="bash") - - assert result.logs.stdout[0] == "bar\n" - assert result_empty.logs.stdout[0] == "default\n" - - -@pytest.mark.skip_debug() -def test_env_vars_overwrite(template): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - result = sandbox.run_code( - "echo $TEST_ENV_VAR", language="bash", envs={"TEST_ENV_VAR": "overwrite"} - ) - result_global_default = sandbox.run_code("echo $TEST_ENV_VAR", language="bash") - assert result.logs.stdout[0] == "overwrite\n" - assert result_global_default.logs.stdout[0] == "supertest\n" - finally: - sandbox.kill() diff --git a/packages/code-interpreter-python/tests/sync/env_vars/test_java.py b/packages/code-interpreter-python/tests/sync/env_vars/test_java.py deleted file mode 100644 index 465aea946d..0000000000 --- a/packages/code-interpreter-python/tests/sync/env_vars/test_java.py +++ /dev/null @@ -1,55 +0,0 @@ -import pytest -from e2b_code_interpreter import Sandbox - - -@pytest.mark.skip_debug() -def test_env_vars_on_sandbox(template, wait_for_kernel): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - wait_for_kernel(sandbox, "java") - - result = sandbox.run_code('System.getProperty("TEST_ENV_VAR")', language="java") - assert result.text is not None - assert result.text.strip() == "supertest" - finally: - sandbox.kill() - - -def test_env_vars_per_execution(java_sandbox: Sandbox): - try: - result = java_sandbox.run_code( - 'System.getProperty("FOO")', envs={"FOO": "bar"}, language="java" - ) - - result_empty = java_sandbox.run_code( - 'System.getProperty("FOO", "default")', language="java" - ) - - assert result.text is not None - assert result.text.strip() == "bar" - assert result_empty.text is not None - assert result_empty.text.strip() == "default" - finally: - java_sandbox.kill() - - -@pytest.mark.skip_debug() -def test_env_vars_overwrite(template, wait_for_kernel): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - wait_for_kernel(sandbox, "java") - - result = sandbox.run_code( - 'System.getProperty("TEST_ENV_VAR")', - language="java", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = sandbox.run_code( - 'System.getProperty("TEST_ENV_VAR")', language="java" - ) - assert result.text is not None - assert result.text.strip() == "overwrite" - assert result_global_default.text is not None - assert result_global_default.text.strip() == "supertest" - finally: - sandbox.kill() diff --git a/packages/code-interpreter-python/tests/sync/env_vars/test_js.py b/packages/code-interpreter-python/tests/sync/env_vars/test_js.py deleted file mode 100644 index 6561d65b44..0000000000 --- a/packages/code-interpreter-python/tests/sync/env_vars/test_js.py +++ /dev/null @@ -1,51 +0,0 @@ -import pytest -from e2b_code_interpreter import Sandbox - - -@pytest.mark.skip_debug() -def test_env_vars_on_sandbox(template): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - result = sandbox.run_code("process.env.TEST_ENV_VAR", language="javascript") - assert result.text is not None - assert result.text.strip() == "supertest" - finally: - sandbox.kill() - - -def test_env_vars_per_execution(sandbox: Sandbox): - try: - result = sandbox.run_code( - "process.env.FOO", envs={"FOO": "bar"}, language="javascript" - ) - - result_empty = sandbox.run_code( - "process.env.FOO || 'default'", language="javascript" - ) - - assert result.text is not None - assert result.text.strip() == "bar" - assert result_empty.text is not None - assert result_empty.text.strip() == "default" - finally: - sandbox.kill() - - -@pytest.mark.skip_debug() -def test_env_vars_overwrite(template): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - result = sandbox.run_code( - "process.env.TEST_ENV_VAR", - language="javascript", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = sandbox.run_code( - "process.env.TEST_ENV_VAR", language="javascript" - ) - assert result.text is not None - assert result.text.strip() == "overwrite" - assert result_global_default.text is not None - assert result_global_default.text.strip() == "supertest" - finally: - sandbox.kill() diff --git a/packages/code-interpreter-python/tests/sync/env_vars/test_python.py b/packages/code-interpreter-python/tests/sync/env_vars/test_python.py deleted file mode 100644 index 95170c75f8..0000000000 --- a/packages/code-interpreter-python/tests/sync/env_vars/test_python.py +++ /dev/null @@ -1,53 +0,0 @@ -import pytest -from e2b_code_interpreter import Sandbox - - -@pytest.mark.skip_debug() -def test_env_vars_on_sandbox(template): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - result = sandbox.run_code( - "import os; os.getenv('TEST_ENV_VAR')", language="python" - ) - assert result.text is not None - assert result.text.strip() == "supertest" - finally: - sandbox.kill() - - -def test_env_vars_per_execution(sandbox: Sandbox): - try: - result = sandbox.run_code( - "import os; os.getenv('FOO')", envs={"FOO": "bar"}, language="python" - ) - - result_empty = sandbox.run_code( - "import os; os.getenv('FOO', 'default')", language="python" - ) - - assert result.text is not None - assert result.text.strip() == "bar" - assert result_empty.text is not None - assert result_empty.text.strip() == "default" - finally: - sandbox.kill() - - -@pytest.mark.skip_debug() -def test_env_vars_overwrite(template): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - result = sandbox.run_code( - "import os; os.getenv('TEST_ENV_VAR')", - language="python", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = sandbox.run_code( - "import os; os.getenv('TEST_ENV_VAR')", language="python" - ) - assert result.text is not None - assert result.text.strip() == "overwrite" - assert result_global_default.text is not None - assert result_global_default.text.strip() == "supertest" - finally: - sandbox.kill() diff --git a/packages/code-interpreter-python/tests/sync/env_vars/test_r.py b/packages/code-interpreter-python/tests/sync/env_vars/test_r.py deleted file mode 100644 index 9b44bd9241..0000000000 --- a/packages/code-interpreter-python/tests/sync/env_vars/test_r.py +++ /dev/null @@ -1,54 +0,0 @@ -import pytest -from e2b_code_interpreter import Sandbox - - -@pytest.mark.skip_debug() -def test_env_vars_on_sandbox(template, wait_for_kernel): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - wait_for_kernel(sandbox, "r") - result = sandbox.run_code("Sys.getenv('TEST_ENV_VAR')", language="r") - assert result.results[0].text is not None - assert result.results[0].text.strip() == '[1] "supertest"' - finally: - sandbox.kill() - - -def test_env_vars_per_execution(sandbox: Sandbox, wait_for_kernel): - try: - wait_for_kernel(sandbox, "r") - result = sandbox.run_code( - "Sys.getenv('FOO')", envs={"FOO": "bar"}, language="r" - ) - - result_empty = sandbox.run_code( - "Sys.getenv('FOO', unset = 'default')", language="r" - ) - - assert result.results[0].text is not None - assert result.results[0].text.strip() == '[1] "bar"' - assert result_empty.results[0].text is not None - assert result_empty.results[0].text.strip() == '[1] "default"' - finally: - sandbox.kill() - - -@pytest.mark.skip_debug() -def test_env_vars_overwrite(template, wait_for_kernel): - sandbox = Sandbox.create(template=template, envs={"TEST_ENV_VAR": "supertest"}) - try: - wait_for_kernel(sandbox, "r") - result = sandbox.run_code( - "Sys.getenv('TEST_ENV_VAR')", - language="r", - envs={"TEST_ENV_VAR": "overwrite"}, - ) - result_global_default = sandbox.run_code( - "Sys.getenv('TEST_ENV_VAR')", language="r" - ) - assert result.results[0].text is not None - assert result.results[0].text.strip() == '[1] "overwrite"' - assert result_global_default.results[0].text is not None - assert result_global_default.results[0].text.strip() == '[1] "supertest"' - finally: - sandbox.kill() diff --git a/packages/code-interpreter-python/tests/sync/test_bash.py b/packages/code-interpreter-python/tests/sync/test_bash.py deleted file mode 100644 index 7de9ccb68c..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_bash.py +++ /dev/null @@ -1,6 +0,0 @@ -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -def test_bash(sandbox: Sandbox): - result = sandbox.run_code("!pwd") - assert "".join(result.logs.stdout).strip() == "/home/user" diff --git a/packages/code-interpreter-python/tests/sync/test_contexts.py b/packages/code-interpreter-python/tests/sync/test_contexts.py index 2672af7ff1..3718452dda 100644 --- a/packages/code-interpreter-python/tests/sync/test_contexts.py +++ b/packages/code-interpreter-python/tests/sync/test_contexts.py @@ -1,4 +1,5 @@ import pytest +from e2b import InvalidArgumentException from e2b_code_interpreter.code_interpreter_sync import Sandbox @@ -64,6 +65,12 @@ def test_restart_context(sandbox: Sandbox): assert execution.error.value == "name 'x' is not defined" +def test_pass_context_and_language(sandbox: Sandbox): + context = sandbox.create_code_context(language="python") + with pytest.raises(InvalidArgumentException): + sandbox.run_code("console.log('Hello, World!')", language="js", context=context) + + # Secure traffic tests (public traffic disabled) @pytest.mark.skip_debug def test_create_context_secure_traffic(sandbox_factory): diff --git a/packages/code-interpreter-python/tests/sync/test_custom_repr_object.py b/packages/code-interpreter-python/tests/sync/test_custom_repr_object.py deleted file mode 100644 index 8423c95074..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_custom_repr_object.py +++ /dev/null @@ -1,12 +0,0 @@ -from e2b_code_interpreter.code_interpreter_sync import Sandbox - -code = """ -from IPython.display import display - -display({'text/latex': r'\text{CustomReprObject}'}, raw=True) -""" - - -def test_bash(sandbox: Sandbox): - execution = sandbox.run_code(code) - assert execution.results[0].formats() == ["latex"] diff --git a/packages/code-interpreter-python/tests/sync/test_cwd.py b/packages/code-interpreter-python/tests/sync/test_cwd.py deleted file mode 100644 index d9ae3c985b..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_cwd.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest - -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -@pytest.mark.skip_debug() -def test_cwd_python(sandbox: Sandbox): - result = sandbox.run_code("from pathlib import Path; print(Path.cwd())") - assert "".join(result.logs.stdout).strip() == "/home/user" - - -@pytest.mark.skip_debug() -def test_cwd_javascript(sandbox: Sandbox): - result = sandbox.run_code("process.cwd()", language="js") - assert result.text == "/home/user" - - -@pytest.mark.skip_debug() -def test_cwd_typescript(sandbox: Sandbox): - result = sandbox.run_code("process.cwd()", language="ts") - assert result.text == "/home/user" - - -@pytest.mark.skip_debug() -def test_cwd_r(sandbox: Sandbox, wait_for_kernel): - wait_for_kernel(sandbox, "r") - result = sandbox.run_code("getwd()", language="r") - assert result.results[0].text.strip() == '[1] "/home/user"' - - -@pytest.mark.skip_debug() -def test_cwd_java(java_sandbox: Sandbox): - result = java_sandbox.run_code('System.getProperty("user.dir")', language="java") - assert result.results[0].text.strip() == "/home/user" - - -@pytest.mark.skip_debug() -def test_cwd_bash(sandbox: Sandbox): - result = sandbox.run_code("pwd", language="bash") - assert "".join(result.logs.stdout).strip() == "/home/user" diff --git a/packages/code-interpreter-python/tests/sync/test_data.py b/packages/code-interpreter-python/tests/sync/test_data.py deleted file mode 100644 index 4db51d650f..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_data.py +++ /dev/null @@ -1,17 +0,0 @@ -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -def test_data(sandbox: Sandbox): - # plot random chart - result = sandbox.run_code( - """ - import pandas as pd - pd.DataFrame({"a": [1, 2, 3]}) - """ - ) - - # there's your image - data = result.results[0] - assert data.data - assert "a" in data.data - assert len(data.data["a"]) == 3 diff --git a/packages/code-interpreter-python/tests/sync/test_default_kernels.py b/packages/code-interpreter-python/tests/sync/test_default_kernels.py deleted file mode 100644 index a4ce420126..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_default_kernels.py +++ /dev/null @@ -1,52 +0,0 @@ -import pytest - -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -def test_js_kernel(sandbox: Sandbox): - execution = sandbox.run_code("console.log('Hello, World!')", language="js") - assert execution.logs.stdout == ["Hello, World!\n"] - - -@pytest.mark.skip_debug() -def test_r_kernel(sandbox: Sandbox, wait_for_kernel): - wait_for_kernel(sandbox, "r") - execution = sandbox.run_code('print("Hello, World!")', language="r") - assert execution.logs.stdout == ['[1] "Hello, World!"\n'] - - -@pytest.mark.skip_debug() -def test_java_kernel(java_sandbox: Sandbox): - execution = java_sandbox.run_code( - 'System.out.println("Hello, World!")', language="java" - ) - assert execution.logs.stdout[0] == "Hello, World!" - - -def test_js_esm_imports(sandbox: Sandbox): - execution = sandbox.run_code( - """ - import { readFileSync } from 'fs' - console.log(typeof readFileSync) - """, - language="js", - ) - assert execution.logs.stdout == ["function\n"] - - -def test_js_top_level_await(sandbox: Sandbox): - execution = sandbox.run_code( - """ - await Promise.resolve('Hello World!') - """, - language="js", - ) - assert execution.text == "Hello World!" - - -@pytest.mark.skip_debug() -def test_ts_kernel(sandbox: Sandbox): - execution = sandbox.run_code( - "const message: string = 'Hello, World!'; console.log(message)", language="ts" - ) - assert execution.logs.stdout == ["Hello, World!\n"] diff --git a/packages/code-interpreter-python/tests/sync/test_display_data.py b/packages/code-interpreter-python/tests/sync/test_display_data.py deleted file mode 100644 index 1cb44b9735..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_display_data.py +++ /dev/null @@ -1,23 +0,0 @@ -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -def test_display_data(sandbox: Sandbox): - # plot random chart - result = sandbox.run_code( - """ - import matplotlib.pyplot as plt - import numpy as np - - x = np.linspace(0, 20, 100) - y = np.sin(x) - - plt.plot(x, y) - plt.show() - """ - ) - - # there's your image - data = result.results[0] - assert data.png - assert data.text - assert not data.extra diff --git a/packages/code-interpreter-python/tests/sync/test_env_vars.py b/packages/code-interpreter-python/tests/sync/test_env_vars.py new file mode 100644 index 0000000000..d4280cedfa --- /dev/null +++ b/packages/code-interpreter-python/tests/sync/test_env_vars.py @@ -0,0 +1,9 @@ +from e2b_code_interpreter.code_interpreter_sync import Sandbox + + +def test_env_vars_per_execution(sandbox: Sandbox): + result = sandbox.run_code("import os; os.getenv('FOO')", envs={"FOO": "bar"}) + result_empty = sandbox.run_code("import os; os.getenv('FOO', 'default')") + + assert result.text == "bar" + assert result_empty.text == "default" diff --git a/packages/code-interpreter-python/tests/sync/test_execution_count.py b/packages/code-interpreter-python/tests/sync/test_execution_count.py deleted file mode 100644 index 98e2039f53..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_execution_count.py +++ /dev/null @@ -1,10 +0,0 @@ -import pytest - -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -@pytest.mark.skip_debug() -def test_execution_count(sandbox: Sandbox): - sandbox.run_code("echo 'E2B is awesome!'") - result = sandbox.run_code("!pwd") - assert result.execution_count == 2 diff --git a/packages/code-interpreter-python/tests/sync/test_kernels.py b/packages/code-interpreter-python/tests/sync/test_kernels.py deleted file mode 100644 index 17d6430f97..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_kernels.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest -from e2b import InvalidArgumentException - -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -def test_create_new_kernel(sandbox: Sandbox): - sandbox.create_code_context() - - -def test_independence_of_kernels(sandbox: Sandbox): - context = sandbox.create_code_context() - sandbox.run_code("x = 1") - - r = sandbox.run_code("x", context=context) - assert r.error is not None - assert r.error.value == "name 'x' is not defined" - - -def test_pass_context_and_language(sandbox: Sandbox): - context = sandbox.create_code_context(language="python") - with pytest.raises(InvalidArgumentException): - sandbox.run_code("console.log('Hello, World!')", language="js", context=context) diff --git a/packages/code-interpreter-python/tests/sync/test_statefulness.py b/packages/code-interpreter-python/tests/sync/test_statefulness.py deleted file mode 100644 index 044478db14..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_statefulness.py +++ /dev/null @@ -1,8 +0,0 @@ -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -def test_stateful(sandbox: Sandbox): - sandbox.run_code("test_stateful = 1") - - result = sandbox.run_code("test_stateful+=1; test_stateful") - assert result.text == "2" diff --git a/packages/code-interpreter-python/tests/sync/test_systemd.py b/packages/code-interpreter-python/tests/sync/test_systemd.py deleted file mode 100644 index 574ed7d044..0000000000 --- a/packages/code-interpreter-python/tests/sync/test_systemd.py +++ /dev/null @@ -1,59 +0,0 @@ -import time - -import pytest - -from e2b_code_interpreter.code_interpreter_sync import Sandbox - - -def wait_for_health(sandbox: Sandbox, max_retries=10, interval_ms=100): - for _ in range(max_retries): - try: - result = sandbox.commands.run( - 'curl -s -o /dev/null -w "%{http_code}" http://0.0.0.0:49999/health' - ) - if result.stdout.strip() == "200": - return True - except Exception: - pass - time.sleep(interval_ms / 1000) - return False - - -@pytest.mark.skip_debug -def test_restart_after_jupyter_kill(sandbox: Sandbox): - # Verify health is up initially - assert wait_for_health(sandbox) - - # Kill the jupyter process as root - # The command handle may get killed too (killing jupyter cascades to code-interpreter), - # so we catch the error. - try: - sandbox.commands.run("kill -9 $(pgrep -f 'jupyter server')", user="root") - except Exception: - pass - - # Wait for systemd to restart both services - assert wait_for_health(sandbox, 60, 500) - - # Verify code execution works after recovery - result = sandbox.run_code("x = 1; x") - assert result.text == "1" - - -@pytest.mark.skip_debug -def test_restart_after_code_interpreter_kill(sandbox: Sandbox): - # Verify health is up initially - assert wait_for_health(sandbox) - - # Kill the code-interpreter process as root - try: - sandbox.commands.run("kill -9 $(pgrep -f 'uvicorn main:app')", user="root") - except Exception: - pass - - # Wait for systemd to restart it and health to come back - assert wait_for_health(sandbox, 60, 500) - - # Verify code execution works after recovery - result = sandbox.run_code("x = 1; x") - assert result.text == "1" diff --git a/packages/code-interpreter-python/tests/test_java_kernel_readiness.py b/packages/code-interpreter-python/tests/test_java_kernel_readiness.py deleted file mode 100644 index 624827a09b..0000000000 --- a/packages/code-interpreter-python/tests/test_java_kernel_readiness.py +++ /dev/null @@ -1,108 +0,0 @@ -from unittest.mock import AsyncMock, Mock - -import pytest - -from e2b import SandboxException -from tests.conftest import _wait_for_kernel, _wait_for_kernel_async - - -def java_not_ready_error() -> SandboxException: - return SandboxException("500 Internal Server Error") - - -@pytest.mark.parametrize("language", ["java", "r"]) -def test_waits_through_repeated_kernel_readiness_500s(language): - run_code = Mock( - side_effect=[ - java_not_ready_error(), - java_not_ready_error(), - java_not_ready_error(), - None, - ] - ) - sandbox = Mock(run_code=run_code) - - _wait_for_kernel(sandbox, language) - - assert run_code.call_count == 4 - run_code.assert_called_with("1", language=language) - - -def test_propagates_a_persistent_java_readiness_500(): - final_error = java_not_ready_error() - run_code = Mock( - side_effect=[ - java_not_ready_error(), - java_not_ready_error(), - java_not_ready_error(), - final_error, - ] - ) - sandbox = Mock(run_code=run_code) - - with pytest.raises(SandboxException) as raised: - _wait_for_kernel(sandbox, "java") - - assert raised.value is final_error - assert run_code.call_count == 4 - - -def test_does_not_retry_an_unrelated_java_error(): - error = SandboxException("401: unauthorized") - run_code = Mock(side_effect=error) - sandbox = Mock(run_code=run_code) - - with pytest.raises(SandboxException) as raised: - _wait_for_kernel(sandbox, "java") - - assert raised.value is error - run_code.assert_called_once_with("1", language="java") - - -@pytest.mark.parametrize("language", ["java", "r"]) -async def test_async_waits_through_repeated_kernel_readiness_500s(language): - run_code = AsyncMock( - side_effect=[ - java_not_ready_error(), - java_not_ready_error(), - java_not_ready_error(), - None, - ] - ) - sandbox = Mock(run_code=run_code) - - await _wait_for_kernel_async(sandbox, language) - - assert run_code.await_count == 4 - run_code.assert_awaited_with("1", language=language) - - -async def test_async_propagates_a_persistent_java_readiness_500(): - final_error = java_not_ready_error() - run_code = AsyncMock( - side_effect=[ - java_not_ready_error(), - java_not_ready_error(), - java_not_ready_error(), - final_error, - ] - ) - sandbox = Mock(run_code=run_code) - - with pytest.raises(SandboxException) as raised: - await _wait_for_kernel_async(sandbox, "java") - - assert raised.value is final_error - assert run_code.await_count == 4 - - -async def test_async_does_not_retry_an_unrelated_java_error(): - error = SandboxException("401: unauthorized") - run_code = AsyncMock(side_effect=error) - sandbox = Mock(run_code=run_code) - - with pytest.raises(SandboxException) as raised: - await _wait_for_kernel_async(sandbox, "java") - - assert raised.value is error - run_code.assert_awaited_once_with("1", language="java")