chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:47:58 +08:00
commit b16403ea71
789 changed files with 115226 additions and 0 deletions
@@ -0,0 +1,62 @@
from e2b import AsyncSandbox
from e2b.sandbox.filesystem.filesystem import WriteEntry
async def test_write_and_read_with_gzip(async_sandbox: AsyncSandbox, debug):
filename = "test_gzip_write.txt"
content = "This is a test file with gzip encoding."
info = await async_sandbox.files.write(filename, content, gzip=True)
assert info.path == f"/home/user/{filename}"
read_content = await async_sandbox.files.read(filename, gzip=True)
assert read_content == content
if debug:
await async_sandbox.files.remove(filename)
async def test_write_gzip_read_plain(async_sandbox: AsyncSandbox, debug):
filename = "test_gzip_write_plain_read.txt"
content = "Written with gzip, read without."
await async_sandbox.files.write(filename, content, gzip=True)
read_content = await async_sandbox.files.read(filename)
assert read_content == content
if debug:
await async_sandbox.files.remove(filename)
async def test_write_files_with_gzip(async_sandbox: AsyncSandbox, debug):
files = [
WriteEntry(path="gzip_multi_1.txt", data="File 1 content"),
WriteEntry(path="gzip_multi_2.txt", data="File 2 content"),
WriteEntry(path="gzip_multi_3.txt", data="File 3 content"),
]
infos = await async_sandbox.files.write_files(files, gzip=True)
assert len(infos) == len(files)
for file in files:
read_content = await async_sandbox.files.read(file["path"])
assert read_content == file["data"]
if debug:
for file in files:
await async_sandbox.files.remove(file["path"])
async def test_read_bytes_with_gzip(async_sandbox: AsyncSandbox, debug):
filename = "test_gzip_bytes.txt"
content = "Binary content with gzip."
await async_sandbox.files.write(filename, content)
read_bytes = await async_sandbox.files.read(filename, format="bytes", gzip=True)
assert isinstance(read_bytes, bytearray)
assert read_bytes.decode("utf-8") == content
if debug:
await async_sandbox.files.remove(filename)
@@ -0,0 +1,8 @@
from e2b import AsyncSandbox
async def test_exists(async_sandbox: AsyncSandbox):
filename = "test_exists.txt"
await async_sandbox.files.write(filename, "test")
assert await async_sandbox.files.exists(filename)
@@ -0,0 +1,248 @@
import uuid
from typing import Any
from e2b import AsyncSandbox, FileType
async def test_list_directory(async_sandbox: AsyncSandbox):
home_dir_name = "/home/user"
parent_dir_name = f"test_directory_{uuid.uuid4()}"
await async_sandbox.files.make_dir(parent_dir_name)
await async_sandbox.files.make_dir(f"{parent_dir_name}/subdir1")
await async_sandbox.files.make_dir(f"{parent_dir_name}/subdir2")
await async_sandbox.files.make_dir(f"{parent_dir_name}/subdir1/subdir1_1")
await async_sandbox.files.make_dir(f"{parent_dir_name}/subdir1/subdir1_2")
await async_sandbox.files.make_dir(f"{parent_dir_name}/subdir2/subdir2_1")
await async_sandbox.files.make_dir(f"{parent_dir_name}/subdir2/subdir2_2")
await async_sandbox.files.write(f"{parent_dir_name}/file1.txt", "Hello, world!")
test_cases: list[dict[str, Any]] = [
{
"name": "default depth (1)",
"depth": None,
"expected_len": 3,
"expected_file_names": [
"file1.txt",
"subdir1",
"subdir2",
],
"expected_file_types": [
FileType.FILE,
FileType.DIR,
FileType.DIR,
],
"expected_file_paths": [
f"{home_dir_name}/{parent_dir_name}/file1.txt",
f"{home_dir_name}/{parent_dir_name}/subdir1",
f"{home_dir_name}/{parent_dir_name}/subdir2",
],
},
{
"name": "explicit depth 1",
"depth": 1,
"expected_len": 3,
"expected_file_names": [
"file1.txt",
"subdir1",
"subdir2",
],
"expected_file_types": [
FileType.FILE,
FileType.DIR,
FileType.DIR,
],
"expected_file_paths": [
f"{home_dir_name}/{parent_dir_name}/file1.txt",
f"{home_dir_name}/{parent_dir_name}/subdir1",
f"{home_dir_name}/{parent_dir_name}/subdir2",
],
},
{
"name": "explicit depth 2",
"depth": 2,
"expected_len": 7,
"expected_file_types": [
FileType.FILE,
FileType.DIR,
FileType.DIR,
FileType.DIR,
FileType.DIR,
FileType.DIR,
FileType.DIR,
],
"expected_file_names": [
"file1.txt",
"subdir1",
"subdir1_1",
"subdir1_2",
"subdir2",
"subdir2_1",
"subdir2_2",
],
"expected_file_paths": [
f"{home_dir_name}/{parent_dir_name}/file1.txt",
f"{home_dir_name}/{parent_dir_name}/subdir1",
f"{home_dir_name}/{parent_dir_name}/subdir1/subdir1_1",
f"{home_dir_name}/{parent_dir_name}/subdir1/subdir1_2",
f"{home_dir_name}/{parent_dir_name}/subdir2",
f"{home_dir_name}/{parent_dir_name}/subdir2/subdir2_1",
f"{home_dir_name}/{parent_dir_name}/subdir2/subdir2_2",
],
},
{
"name": "explicit depth 3 (should be the same as depth 2)",
"depth": 3,
"expected_len": 7,
"expected_file_names": [
"file1.txt",
"subdir1",
"subdir1_1",
"subdir1_2",
"subdir2",
"subdir2_1",
"subdir2_2",
],
"expected_file_types": [
FileType.FILE,
FileType.DIR,
FileType.DIR,
FileType.DIR,
FileType.DIR,
FileType.DIR,
FileType.DIR,
],
"expected_file_paths": [
f"{home_dir_name}/{parent_dir_name}/file1.txt",
f"{home_dir_name}/{parent_dir_name}/subdir1",
f"{home_dir_name}/{parent_dir_name}/subdir1/subdir1_1",
f"{home_dir_name}/{parent_dir_name}/subdir1/subdir1_2",
f"{home_dir_name}/{parent_dir_name}/subdir2",
f"{home_dir_name}/{parent_dir_name}/subdir2/subdir2_1",
f"{home_dir_name}/{parent_dir_name}/subdir2/subdir2_2",
],
},
]
for test_case in test_cases:
files = await async_sandbox.files.list(
parent_dir_name,
depth=test_case["depth"] if test_case["depth"] is not None else None,
)
assert len(files) == test_case["expected_len"]
for i in range(len(test_case["expected_file_names"])):
assert files[i].name == test_case["expected_file_names"][i]
assert files[i].path == test_case["expected_file_paths"][i]
assert files[i].type == test_case["expected_file_types"][i]
await async_sandbox.files.remove(parent_dir_name)
async def test_list_directory_error_cases(async_sandbox: AsyncSandbox):
parent_dir_name = f"test_directory_{uuid.uuid4()}"
await async_sandbox.files.make_dir(parent_dir_name)
expected_error_message = "depth should be at least 1"
try:
await async_sandbox.files.list(parent_dir_name, depth=-1)
assert False, "Expected error but none was thrown"
except Exception as err:
assert expected_error_message in str(err), (
f'expected error message to include "{expected_error_message}"'
)
await async_sandbox.files.remove(parent_dir_name)
async def test_file_entry_details(async_sandbox: AsyncSandbox):
test_dir = "test-file-entry"
file_path = f"{test_dir}/test.txt"
content = "Hello, World!"
await async_sandbox.files.make_dir(test_dir)
await async_sandbox.files.write(file_path, content)
files = await async_sandbox.files.list(test_dir, depth=1)
assert len(files) == 1
file_entry = files[0]
assert file_entry.name == "test.txt"
assert file_entry.path == f"/home/user/{file_path}"
assert file_entry.type == FileType.FILE
assert file_entry.mode == 0o644
assert file_entry.permissions == "-rw-r--r--"
assert file_entry.owner == "user"
assert file_entry.group == "user"
assert file_entry.size == len(content)
assert file_entry.modified_time is not None
assert file_entry.symlink_target is None
await async_sandbox.files.remove(test_dir)
async def test_directory_entry_details(async_sandbox: AsyncSandbox):
test_dir = "test-entry-info"
sub_dir = f"{test_dir}/subdir"
await async_sandbox.files.make_dir(test_dir)
await async_sandbox.files.make_dir(sub_dir)
files = await async_sandbox.files.list(test_dir, depth=1)
assert len(files) == 1
dir_entry = files[0]
assert dir_entry.name == "subdir"
assert dir_entry.path == f"/home/user/{sub_dir}"
assert dir_entry.type == FileType.DIR
assert dir_entry.mode == 0o755
assert dir_entry.permissions == "drwxr-xr-x"
assert dir_entry.owner == "user"
assert dir_entry.group == "user"
assert dir_entry.modified_time is not None
assert dir_entry.symlink_target is None
await async_sandbox.files.remove(test_dir)
async def test_mixed_entries(async_sandbox: AsyncSandbox):
test_dir = "test-mixed-entries"
sub_dir = f"{test_dir}/subdir"
file_path = f"{test_dir}/test.txt"
content = "Hello, World!"
await async_sandbox.files.make_dir(test_dir)
await async_sandbox.files.make_dir(sub_dir)
await async_sandbox.files.write(file_path, content)
files = await async_sandbox.files.list(test_dir, depth=1)
assert len(files) == 2
# Create a dictionary of entries by name for easier verification
entries = {entry.name: entry for entry in files}
# Verify directory entry
dir_entry = entries.get("subdir")
assert dir_entry is not None
assert dir_entry.path == f"/home/user/{sub_dir}"
assert dir_entry.type == FileType.DIR
assert dir_entry.mode == 0o755
assert dir_entry.permissions == "drwxr-xr-x"
assert dir_entry.owner == "user"
assert dir_entry.group == "user"
assert dir_entry.modified_time is not None
# Verify file entry
file_entry = entries.get("test.txt")
assert file_entry is not None
assert file_entry.path == f"/home/user/{file_path}"
assert file_entry.type == FileType.FILE
assert file_entry.mode == 0o644
assert file_entry.permissions == "-rw-r--r--"
assert file_entry.owner == "user"
assert file_entry.group == "user"
assert file_entry.size == len(content)
assert file_entry.modified_time is not None
await async_sandbox.files.remove(test_dir)
@@ -0,0 +1,79 @@
import pytest
from e2b.exceptions import FileNotFoundException
from e2b import AsyncSandbox, FileType
@pytest.mark.asyncio
async def test_get_info_of_file(async_sandbox: AsyncSandbox):
filename = "test_file.txt"
await async_sandbox.files.write(filename, "test")
info = await async_sandbox.files.get_info(filename)
current_path = await async_sandbox.commands.run("pwd")
assert info.name == filename
assert info.type == FileType.FILE
assert info.path == f"{current_path.stdout.strip()}/{filename}"
assert info.size == 4
assert info.mode == 0o644
assert info.permissions == "-rw-r--r--"
assert info.owner == "user"
assert info.group == "user"
assert info.modified_time is not None
assert info.modified_time.tzinfo is not None
@pytest.mark.asyncio
async def test_get_info_of_nonexistent_file(async_sandbox: AsyncSandbox):
filename = "test_does_not_exist.txt"
with pytest.raises(FileNotFoundException):
await async_sandbox.files.get_info(filename)
@pytest.mark.asyncio
async def test_get_info_of_directory(async_sandbox: AsyncSandbox):
dirname = "test_dir"
await async_sandbox.files.make_dir(dirname)
info = await async_sandbox.files.get_info(dirname)
current_path = await async_sandbox.commands.run("pwd")
assert info.name == dirname
assert info.type == FileType.DIR
assert info.path == f"{current_path.stdout.strip()}/{dirname}"
assert info.size > 0
assert info.mode == 0o755
assert info.permissions == "drwxr-xr-x"
assert info.owner == "user"
assert info.group == "user"
assert info.modified_time is not None
assert info.modified_time.tzinfo is not None
@pytest.mark.asyncio
async def test_get_info_of_nonexistent_directory(async_sandbox: AsyncSandbox):
dirname = "test_does_not_exist_dir"
with pytest.raises(FileNotFoundException):
await async_sandbox.files.get_info(dirname)
async def test_file_symlink(async_sandbox: AsyncSandbox):
test_dir = "test-simlink-entry"
file_name = "test.txt"
content = "Hello, World!"
await async_sandbox.files.make_dir(test_dir)
await async_sandbox.files.write(f"{test_dir}/{file_name}", content)
symlink_name = "symlink_to_test.txt"
await async_sandbox.commands.run(f"ln -s {file_name} {symlink_name}", cwd=test_dir)
file = await async_sandbox.files.get_info(f"{test_dir}/{symlink_name}")
pwd = await async_sandbox.commands.run("pwd")
assert file.type == FileType.FILE
assert file.symlink_target == f"{pwd.stdout.strip()}/{test_dir}/{file_name}"
await async_sandbox.files.remove(test_dir)
@@ -0,0 +1,29 @@
import uuid
from e2b import AsyncSandbox
async def test_make_directory(async_sandbox: AsyncSandbox):
dir_name = f"test_directory_{uuid.uuid4()}"
await async_sandbox.files.make_dir(dir_name)
exists = await async_sandbox.files.exists(dir_name)
assert exists
async def test_make_directory_already_exists(async_sandbox: AsyncSandbox):
dir_name = f"test_directory_{uuid.uuid4()}"
created = await async_sandbox.files.make_dir(dir_name)
assert created
created = await async_sandbox.files.make_dir(dir_name)
assert not created
async def test_make_nested_directory(async_sandbox: AsyncSandbox):
nested_dir_name = f"test_directory_{uuid.uuid4()}/nested_directory"
await async_sandbox.files.make_dir(nested_dir_name)
exists = await async_sandbox.files.exists(nested_dir_name)
assert exists
@@ -0,0 +1,172 @@
import pytest
from e2b import AsyncSandbox
from e2b.exceptions import InvalidArgumentException
from e2b.sandbox.filesystem.filesystem import WriteEntry
async def test_write_file_with_metadata(async_sandbox: AsyncSandbox, debug):
filename = "test_metadata.txt"
content = "This is a test file with metadata."
metadata = {"author": "mish", "purpose": "upload"}
info = await async_sandbox.files.write(filename, content, metadata=metadata)
assert info.metadata == metadata
# Metadata is persisted and surfaced on subsequent reads.
stat = await async_sandbox.files.get_info(filename)
assert stat.metadata == metadata
if debug:
await async_sandbox.files.remove(filename)
async def test_write_file_with_metadata_octet_stream(
async_sandbox: AsyncSandbox, debug
):
filename = "test_metadata_octet.txt"
content = "This is a test file with metadata."
metadata = {"author": "mish", "purpose": "upload"}
info = await async_sandbox.files.write(
filename, content, metadata=metadata, use_octet_stream=True
)
assert info.metadata == metadata
stat = await async_sandbox.files.get_info(filename)
assert stat.metadata == metadata
if debug:
await async_sandbox.files.remove(filename)
async def test_write_file_without_metadata(async_sandbox: AsyncSandbox, debug):
filename = "test_no_metadata.txt"
info = await async_sandbox.files.write(filename, "no metadata here")
assert info.metadata is None
stat = await async_sandbox.files.get_info(filename)
assert stat.metadata is None
if debug:
await async_sandbox.files.remove(filename)
async def test_write_files_applies_metadata_to_every_file(
async_sandbox: AsyncSandbox, debug
):
# The same metadata is applied to every file in the upload.
metadata = {"source": "test-suite"}
files = [
WriteEntry(path="metadata_multi_1.txt", data="File 1"),
WriteEntry(path="metadata_multi_2.txt", data="File 2"),
]
infos = await async_sandbox.files.write_files(files, metadata=metadata)
assert len(infos) == len(files)
for info in infos:
assert info.metadata == metadata
stat = await async_sandbox.files.get_info(info.path)
assert stat.metadata == metadata
if debug:
for file in files:
await async_sandbox.files.remove(file["path"])
async def test_metadata_surfaced_when_listing(async_sandbox: AsyncSandbox, debug):
dirname = "metadata_list_dir"
filename = "listed.txt"
metadata = {"tag": "listed"}
await async_sandbox.files.make_dir(dirname)
await async_sandbox.files.write(
f"{dirname}/{filename}", "content", metadata=metadata
)
entries = await async_sandbox.files.list(dirname)
entry = next((e for e in entries if e.name == filename), None)
assert entry is not None
assert entry.metadata == metadata
if debug:
await async_sandbox.files.remove(dirname)
async def test_metadata_surfaced_after_rename(async_sandbox: AsyncSandbox, debug):
old_path = "metadata_rename_old.txt"
new_path = "metadata_rename_new.txt"
metadata = {"stage": "renamed"}
await async_sandbox.files.write(old_path, "content", metadata=metadata)
info = await async_sandbox.files.rename(old_path, new_path)
assert info.metadata == metadata
if debug:
await async_sandbox.files.remove(new_path)
async def test_overwriting_clears_stale_metadata(async_sandbox: AsyncSandbox, debug):
filename = "metadata_overwrite.txt"
await async_sandbox.files.write(filename, "first", metadata={"author": "mish"})
# Overwriting without metadata removes the previously stored metadata.
info = await async_sandbox.files.write(filename, "second")
assert info.metadata is None
stat = await async_sandbox.files.get_info(filename)
assert stat.metadata is None
if debug:
await async_sandbox.files.remove(filename)
async def test_metadata_set_via_xattrs_surfaced_in_get_info(
async_sandbox: AsyncSandbox, debug
):
filename = "metadata_xattr.txt"
await async_sandbox.files.write(filename, "content")
cmd = await async_sandbox.commands.run(f"realpath {filename}")
file_path = cmd.stdout.strip()
# Set an xattr directly in the `user.e2b.` namespace (out-of-band, not via
# the SDK upload); it should surface as metadata (with the namespace prefix
# stripped) when reading the file info.
await async_sandbox.commands.run(
f"python3 -c \"import os; os.setxattr('{file_path}', 'user.e2b.author', b'mish')\""
)
info = await async_sandbox.files.get_info(filename)
assert info.metadata == {"author": "mish"}
if debug:
await async_sandbox.files.remove(filename)
async def test_write_rejects_invalid_metadata(async_sandbox: AsyncSandbox):
filename = "invalid_metadata.txt"
# Key with a space is not a valid HTTP header token.
with pytest.raises(InvalidArgumentException):
await async_sandbox.files.write(filename, "x", metadata={"bad key": "value"})
# Empty key.
with pytest.raises(InvalidArgumentException):
await async_sandbox.files.write(filename, "x", metadata={"": "value"})
# Value with a non-printable / non-ASCII character.
with pytest.raises(InvalidArgumentException):
await async_sandbox.files.write(filename, "x", metadata={"good": "bad\nvalue"})
# Trailing newline (Python's `$` would accept it; `\Z` must not).
with pytest.raises(InvalidArgumentException):
await async_sandbox.files.write(filename, "x", metadata={"good": "value\n"})
with pytest.raises(InvalidArgumentException):
await async_sandbox.files.write(filename, "x", metadata={"key\n": "value"})
# The file must not have been created by a rejected write.
assert not await async_sandbox.files.exists(filename)
@@ -0,0 +1,95 @@
import pytest
from e2b import FileNotFoundException, NotFoundException, AsyncSandbox
async def test_read_file(async_sandbox: AsyncSandbox):
filename = "test_read.txt"
content = "Hello, world!"
await async_sandbox.files.write(filename, content)
read_content = await async_sandbox.files.read(filename)
assert read_content == content
async def test_read_non_existing_file(async_sandbox: AsyncSandbox):
filename = "non_existing_file.txt"
with pytest.raises(FileNotFoundException):
await async_sandbox.files.read(filename)
async def test_read_non_existing_file_catches_with_deprecated_not_found_exception(
async_sandbox: AsyncSandbox,
):
filename = "non_existing_file.txt"
with pytest.raises(NotFoundException):
await async_sandbox.files.read(filename)
async def test_read_empty_file(async_sandbox: AsyncSandbox):
filename = "empty_file.txt"
content = ""
await async_sandbox.commands.run(f"touch {filename}")
read_content = await async_sandbox.files.read(filename)
assert read_content == content
async def test_read_file_as_stream(async_sandbox: AsyncSandbox):
filename = "test_read_stream.txt"
content = "Streamed read content. " * 10_000
await async_sandbox.files.write(filename, content)
stream = await async_sandbox.files.read(filename, format="stream")
chunks = []
async for chunk in stream:
chunks.append(chunk)
read_content = b"".join(chunks).decode("utf-8")
assert read_content == content
async def test_read_file_as_stream_with_gzip(async_sandbox: AsyncSandbox):
filename = "test_read_stream_gzip.txt"
content = "Streamed gzipped read content. " * 10_000
await async_sandbox.files.write(filename, content)
stream = await async_sandbox.files.read(filename, format="stream", gzip=True)
chunks = []
async for chunk in stream:
chunks.append(chunk)
read_content = b"".join(chunks).decode("utf-8")
assert read_content == content
async def test_read_non_existing_file_as_stream(async_sandbox: AsyncSandbox):
filename = "non_existing_file.txt"
with pytest.raises(FileNotFoundException):
await async_sandbox.files.read(filename, format="stream")
async def test_read_file_as_stream_context_manager(async_sandbox: AsyncSandbox):
filename = "test_read_stream_ctx.txt"
content = "Streamed read content. " * 10_000
await async_sandbox.files.write(filename, content)
chunks = []
async with await async_sandbox.files.read(filename, format="stream") as stream:
async for chunk in stream:
chunks.append(chunk)
read_content = b"".join(chunks).decode("utf-8")
assert read_content == content
async def test_read_file_as_stream_partial_then_close(async_sandbox: AsyncSandbox):
filename = "test_read_stream_partial.txt"
content = "Streamed read content. " * 10_000
await async_sandbox.files.write(filename, content)
# Reading only the first chunk and closing must not raise or leak.
stream = await async_sandbox.files.read(filename, format="stream")
first = await stream.__anext__()
assert len(first) > 0
await stream.aclose()
@@ -0,0 +1,18 @@
from e2b import AsyncSandbox
async def test_remove_file(async_sandbox: AsyncSandbox):
filename = "test_remove.txt"
content = "This file will be removed."
await async_sandbox.files.write(filename, content)
await async_sandbox.files.remove(filename)
exists = await async_sandbox.files.exists(filename)
assert not exists
async def test_remove_non_existing_file(async_sandbox: AsyncSandbox):
filename = "non_existing_file.txt"
await async_sandbox.files.remove(filename)
@@ -0,0 +1,29 @@
import pytest
from e2b import FileNotFoundException, AsyncSandbox
async def test_rename_file(async_sandbox: AsyncSandbox):
old_filename = "test_rename_old.txt"
new_filename = "test_rename_new.txt"
content = "This file will be renamed."
await async_sandbox.files.write(old_filename, content)
info = await async_sandbox.files.rename(old_filename, new_filename)
assert info.path == f"/home/user/{new_filename}"
exists_old = await async_sandbox.files.exists(old_filename)
exists_new = await async_sandbox.files.exists(new_filename)
assert not exists_old
assert exists_new
read_content = await async_sandbox.files.read(new_filename)
assert read_content == content
async def test_rename_non_existing_file(async_sandbox: AsyncSandbox):
old_filename = "non_existing_file.txt"
new_filename = "new_non_existing_file.txt"
with pytest.raises(FileNotFoundException):
await async_sandbox.files.rename(old_filename, new_filename)
@@ -0,0 +1,60 @@
import urllib.request
import urllib.error
import json
import pytest
from e2b.sandbox_async.main import AsyncSandbox
@pytest.mark.skip_debug()
async def test_download_url_with_signing(async_sandbox: AsyncSandbox):
file_path = "test_download_url_with_signing.txt"
file_content = "This file will be watched."
await async_sandbox.files.write(file_path, file_content)
signed_url = async_sandbox.download_url(file_path, "user")
with urllib.request.urlopen(signed_url) as resp:
assert resp.status == 200
body_bytes = resp.read()
body_text = body_bytes.decode()
assert body_text == file_content
@pytest.mark.skip_debug()
async def test_download_url_with_signing_and_expiration(async_sandbox: AsyncSandbox):
file_path = "test_download_url_with_signing.txt"
file_content = "This file will be watched."
await async_sandbox.files.write(file_path, file_content)
signed_url = async_sandbox.download_url(file_path, "user", 120)
with urllib.request.urlopen(signed_url) as resp:
assert resp.status == 200
body_bytes = resp.read()
body_text = body_bytes.decode()
assert body_text == file_content
@pytest.mark.skip_debug()
async def test_download_url_with_expired_signing(async_sandbox: AsyncSandbox):
file_path = "test_download_url_with_signing.txt"
file_content = "This file will be watched."
await async_sandbox.files.write(file_path, file_content)
signed_url = async_sandbox.download_url(
file_path, "user", use_signature_expiration=-120
)
with pytest.raises(urllib.error.HTTPError) as exc_info:
urllib.request.urlopen(signed_url)
err = exc_info.value
assert err.code == 401, f"Unexpected status {err.code}"
error_json_str = err.read().decode() # bytes ➜ str
error_payload = json.loads(error_json_str) # str ➜ dict
expected_payload = {"code": 401, "message": "signature is already expired"}
assert error_payload == expected_payload
@@ -0,0 +1,185 @@
import pytest
from asyncio import Event
from e2b import (
FileNotFoundException,
AsyncSandbox,
FilesystemEvent,
FilesystemEventType,
FileType,
SandboxException,
)
async def test_watch_directory_changes_with_entry_info(async_sandbox: AsyncSandbox):
dirname = "test_watch_dir_entry"
filename = "test_watch.txt"
content = "This file will be watched."
new_content = "This file has been modified."
await async_sandbox.files.make_dir(dirname)
await async_sandbox.files.write(f"{dirname}/{filename}", content)
event_triggered = Event()
received: list[FilesystemEvent] = []
def handle_event(e: FilesystemEvent):
if e.type == FilesystemEventType.WRITE and e.name == filename:
received.append(e)
event_triggered.set()
handle = await async_sandbox.files.watch_dir(
dirname, on_event=handle_event, include_entry=True
)
await async_sandbox.files.write(f"{dirname}/{filename}", new_content)
await event_triggered.wait()
write_event = received[0]
# The entry is populated best-effort for events where the path still exists.
assert write_event.entry is not None
assert write_event.entry.name == filename
assert write_event.entry.path == f"/home/user/{dirname}/{filename}"
assert write_event.entry.type == FileType.FILE
await handle.stop()
async def test_watch_directory_changes_with_network_mounts_allowed(
async_sandbox: AsyncSandbox,
):
dirname = "test_watch_dir_network_mounts"
filename = "test_watch.txt"
content = "This file will be watched."
new_content = "This file has been modified."
await async_sandbox.files.make_dir(dirname)
await async_sandbox.files.write(f"{dirname}/{filename}", content)
event_triggered = Event()
def handle_event(e: FilesystemEvent):
if e.type == FilesystemEventType.WRITE and e.name == filename:
event_triggered.set()
# The flag only lifts the network-mount restriction — watching a regular
# directory must work the same with it enabled.
handle = await async_sandbox.files.watch_dir(
dirname, on_event=handle_event, allow_network_mounts=True
)
await async_sandbox.files.write(f"{dirname}/{filename}", new_content)
await event_triggered.wait()
await handle.stop()
async def test_watch_directory_changes(async_sandbox: AsyncSandbox):
dirname = "test_watch_dir"
filename = "test_watch.txt"
content = "This file will be watched."
new_content = "This file has been modified."
await async_sandbox.files.make_dir(dirname)
await async_sandbox.files.write(f"{dirname}/{filename}", content)
event_triggered = Event()
def handle_event(e: FilesystemEvent):
if e.type == FilesystemEventType.WRITE and e.name == filename:
event_triggered.set()
handle = await async_sandbox.files.watch_dir(dirname, on_event=handle_event)
await async_sandbox.files.write(f"{dirname}/{filename}", new_content)
await event_triggered.wait()
await handle.stop()
async def test_watch_recursive_directory_changes(async_sandbox: AsyncSandbox):
dirname = "test_recursive_watch_dir"
nested_dirname = "test_nested_watch_dir"
filename = "test_watch.txt"
content = "This file will be watched."
await async_sandbox.files.remove(dirname)
await async_sandbox.files.make_dir(f"{dirname}/{nested_dirname}")
event_triggered = Event()
expected_filename = f"{nested_dirname}/{filename}"
def handle_event(e: FilesystemEvent):
if e.type == FilesystemEventType.WRITE and e.name == expected_filename:
event_triggered.set()
handle = await async_sandbox.files.watch_dir(
dirname, on_event=handle_event, recursive=True
)
await async_sandbox.files.write(f"{dirname}/{nested_dirname}/{filename}", content)
await event_triggered.wait()
await handle.stop()
async def test_watch_recursive_directory_after_nested_folder_addition(
async_sandbox: AsyncSandbox,
):
dirname = "test_recursive_watch_dir_add"
nested_dirname = "test_nested_watch_dir"
filename = "test_watch.txt"
content = "This file will be watched."
await async_sandbox.files.remove(dirname)
await async_sandbox.files.make_dir(dirname)
event_triggered_file = Event()
event_triggered_folder = Event()
expected_filename = f"{nested_dirname}/{filename}"
def handle_event(e: FilesystemEvent):
if e.type == FilesystemEventType.WRITE and e.name == expected_filename:
event_triggered_file.set()
return
if e.type == FilesystemEventType.CREATE and e.name == nested_dirname:
event_triggered_folder.set()
handle = await async_sandbox.files.watch_dir(
dirname, on_event=handle_event, recursive=True
)
await async_sandbox.files.make_dir(f"{dirname}/{nested_dirname}")
await event_triggered_folder.wait()
await async_sandbox.files.write(f"{dirname}/{nested_dirname}/{filename}", content)
await event_triggered_file.wait()
await handle.stop()
async def test_watch_non_existing_directory(async_sandbox: AsyncSandbox):
dirname = "non_existing_watch_dir"
with pytest.raises(FileNotFoundException):
await async_sandbox.files.watch_dir(dirname, on_event=lambda e: None)
async def test_watch_file(async_sandbox: AsyncSandbox):
filename = "test_watch.txt"
await async_sandbox.files.write(filename, "This file will be watched.")
with pytest.raises(SandboxException):
await async_sandbox.files.watch_dir(filename, on_event=lambda e: None)
async def test_watch_file_with_secured_envd(async_sandbox):
await async_sandbox.files.watch_dir("/home/user/", on_event=lambda e: None)
await async_sandbox.files.write("test_watch.txt", "This file will be watched.")
@@ -0,0 +1,220 @@
import io
import uuid
from e2b import AsyncSandbox
from e2b.sandbox.filesystem.filesystem import FileType, WriteEntry
from e2b.sandbox_async.filesystem.filesystem import WriteInfo
async def test_write_text_file(async_sandbox: AsyncSandbox, debug):
filename = "test_write.txt"
content = "This is a test file."
info = await async_sandbox.files.write(filename, content)
assert info.path == f"/home/user/{filename}"
assert info.type == FileType.FILE
exists = await async_sandbox.files.exists(filename)
assert exists
read_content = await async_sandbox.files.read(filename)
assert read_content == content
if debug:
await async_sandbox.files.remove(filename)
async def test_write_binary_file(async_sandbox: AsyncSandbox, debug):
filename = "test_write.bin"
text = "This is a test binary file."
# equivalent to `open("path/to/local/file", "rb")`
content = io.BytesIO(text.encode("utf-8"))
info = await async_sandbox.files.write(filename, content)
assert info.path == f"/home/user/{filename}"
exists = await async_sandbox.files.exists(filename)
assert exists
read_content = await async_sandbox.files.read(filename)
assert read_content == text
if debug:
await async_sandbox.files.remove(filename)
async def test_write_multiple_files(async_sandbox: AsyncSandbox, debug):
num_test_files = 10
# Attempt to write with empty files array
empty_info = await async_sandbox.files.write_files([])
assert isinstance(empty_info, list)
assert len(empty_info) == 0
# Attempt to write with one file in array
one_file_path = "one_test_file.txt"
info = await async_sandbox.files.write_files(
[WriteEntry(path=one_file_path, data="This is a test file.")]
)
assert isinstance(info, list)
assert len(info) == 1
info = info[0]
assert isinstance(info, WriteInfo)
assert info.path == "/home/user/one_test_file.txt"
exists = await async_sandbox.files.exists(info.path)
assert exists
read_content = await async_sandbox.files.read(info.path)
assert read_content == "This is a test file."
# Attempt to write with multiple files in array
files = []
for i in range(num_test_files):
path = f"test_write_{i}.txt"
content = f"This is a test file {i}."
files.append(WriteEntry(path=path, data=content))
infos = await async_sandbox.files.write_files(files)
assert isinstance(infos, list)
assert len(infos) == len(files)
for i, info in enumerate(infos):
assert isinstance(info, WriteInfo)
assert info.path == f"/home/user/test_write_{i}.txt"
assert info.type == FileType.FILE
exists = await async_sandbox.files.exists(path)
assert exists
read_content = await async_sandbox.files.read(info.path)
assert read_content == files[i]["data"]
if debug:
await async_sandbox.files.remove(one_file_path)
for i in range(num_test_files):
await async_sandbox.files.remove(f"test_write_{i}.txt")
async def test_overwrite_file(async_sandbox: AsyncSandbox, debug):
filename = "test_overwrite.txt"
initial_content = "Initial content."
new_content = "New content."
await async_sandbox.files.write(filename, initial_content)
await async_sandbox.files.write(filename, new_content)
read_content = await async_sandbox.files.read(filename)
assert read_content == new_content
if debug:
await async_sandbox.files.remove(filename)
async def test_write_to_non_existing_directory(async_sandbox: AsyncSandbox, debug):
filename = f"non_existing_dir_{uuid.uuid4()}/test_write.txt"
content = "This should succeed too."
await async_sandbox.files.write(filename, content)
exists = await async_sandbox.files.exists(filename)
assert exists
read_content = await async_sandbox.files.read(filename)
assert read_content == content
if debug:
await async_sandbox.files.remove(filename)
async def test_write_with_secured_envd(async_sandbox_factory):
filename = f"non_existing_dir_{uuid.uuid4()}/test_write.txt"
content = "This should succeed too."
sbx = await async_sandbox_factory(timeout=30, secure=True)
assert await sbx.is_running()
assert sbx._envd_version is not None
assert sbx._envd_access_token is not None
await sbx.files.write(filename, content)
exists = await sbx.files.exists(filename)
assert exists
read_content = await sbx.files.read(filename)
assert read_content == content
async def test_write_files_with_different_data_types(
async_sandbox: AsyncSandbox, debug
):
text_data = "Text string data"
bytes_data = b"Bytes data"
bytes_io_data = io.BytesIO(b"BytesIO data")
string_io_data = io.StringIO("StringIO data")
files = [
WriteEntry(path="writefiles_text.txt", data=text_data),
WriteEntry(path="writefiles_bytes.bin", data=bytes_data),
WriteEntry(path="writefiles_bytesio.bin", data=bytes_io_data),
WriteEntry(path="writefiles_stringio.txt", data=string_io_data),
]
infos = await async_sandbox.files.write_files(files)
assert len(infos) == 4
text_content = await async_sandbox.files.read("writefiles_text.txt")
assert text_content == text_data
bytes_content = await async_sandbox.files.read("writefiles_bytes.bin")
assert bytes_content == "Bytes data"
bytes_io_content = await async_sandbox.files.read("writefiles_bytesio.bin")
assert bytes_io_content == "BytesIO data"
string_io_content = await async_sandbox.files.read("writefiles_stringio.txt")
assert string_io_content == "StringIO data"
if debug:
for file in files:
await async_sandbox.files.remove(file["path"])
async def test_write_io_with_octet_stream(async_sandbox: AsyncSandbox, debug):
filename = "test_write_octet_io.bin"
text = "Streamed octet-stream upload. " * 10_000
content = io.BytesIO(text.encode("utf-8"))
info = await async_sandbox.files.write(filename, content, use_octet_stream=True)
assert info.path == f"/home/user/{filename}"
read_content = await async_sandbox.files.read(filename)
assert read_content == text
if debug:
await async_sandbox.files.remove(filename)
async def test_write_text_io_with_octet_stream(async_sandbox: AsyncSandbox, debug):
filename = "test_write_octet_text_io.txt"
text = "Streamed text octet-stream upload."
await async_sandbox.files.write(filename, io.StringIO(text), use_octet_stream=True)
read_content = await async_sandbox.files.read(filename)
assert read_content == text
if debug:
await async_sandbox.files.remove(filename)
async def test_write_io_with_octet_stream_and_gzip(async_sandbox: AsyncSandbox, debug):
filename = "test_write_octet_io_gzip.bin"
text = "Streamed gzipped octet-stream upload. " * 10_000
content = io.BytesIO(text.encode("utf-8"))
await async_sandbox.files.write(filename, content, use_octet_stream=True, gzip=True)
read_content = await async_sandbox.files.read(filename)
assert read_content == text
if debug:
await async_sandbox.files.remove(filename)