Files
e2b-dev--e2b/packages/python-sdk/tests/async/sandbox_async/files/test_metadata.py
T
2026-07-13 12:47:58 +08:00

173 lines
5.8 KiB
Python

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)