Files
2026-07-13 12:47:58 +08:00

195 lines
5.8 KiB
TypeScript

import { assert, expect } from 'vitest'
import { WriteEntry } from '../../../src/sandbox/filesystem'
import { InvalidArgumentError } from '../../../src/errors.js'
import { isDebug, sandboxTest } from '../../setup.js'
sandboxTest('write file with metadata', async ({ sandbox }) => {
const filename = 'test_metadata.txt'
const content = 'This is a test file with metadata.'
const metadata = { author: 'mish', purpose: 'upload' }
const info = await sandbox.files.write(filename, content, { metadata })
assert.isFalse(Array.isArray(info))
assert.deepEqual(info.metadata, metadata)
// Metadata is persisted and surfaced on subsequent reads.
const stat = await sandbox.files.getInfo(filename)
assert.deepEqual(stat.metadata, metadata)
if (isDebug) {
await sandbox.files.remove(filename)
}
})
sandboxTest(
'write file with metadata using octet-stream',
async ({ sandbox }) => {
const filename = 'test_metadata_octet.txt'
const content = 'This is a test file with metadata.'
const metadata = { author: 'mish', purpose: 'upload' }
const info = await sandbox.files.write(filename, content, {
metadata,
useOctetStream: true,
})
assert.deepEqual(info.metadata, metadata)
const stat = await sandbox.files.getInfo(filename)
assert.deepEqual(stat.metadata, metadata)
if (isDebug) {
await sandbox.files.remove(filename)
}
}
)
sandboxTest('write file without metadata', async ({ sandbox }) => {
const filename = 'test_no_metadata.txt'
const info = await sandbox.files.write(filename, 'no metadata here')
assert.isUndefined(info.metadata)
const stat = await sandbox.files.getInfo(filename)
assert.isUndefined(stat.metadata)
if (isDebug) {
await sandbox.files.remove(filename)
}
})
sandboxTest(
'writeFiles applies metadata to every file',
async ({ sandbox }) => {
// The same metadata is applied to every file in the upload.
const metadata = { source: 'test-suite' }
const files: WriteEntry[] = [
{ path: 'metadata_multi_1.txt', data: 'File 1' },
{ path: 'metadata_multi_2.txt', data: 'File 2' },
]
const infos = await sandbox.files.writeFiles(files, { metadata })
assert.equal(infos.length, files.length)
for (const info of infos) {
assert.deepEqual(info.metadata, metadata)
const stat = await sandbox.files.getInfo(info.path)
assert.deepEqual(stat.metadata, metadata)
}
if (isDebug) {
for (const file of files) {
await sandbox.files.remove(file.path)
}
}
}
)
sandboxTest('metadata is surfaced when listing', async ({ sandbox }) => {
const dirname = 'metadata_list_dir'
const filename = 'listed.txt'
const metadata = { tag: 'listed' }
await sandbox.files.makeDir(dirname)
await sandbox.files.write(`${dirname}/${filename}`, 'content', { metadata })
const entries = await sandbox.files.list(dirname)
const entry = entries.find((e) => e.name === filename)
assert.isDefined(entry)
assert.deepEqual(entry?.metadata, metadata)
if (isDebug) {
await sandbox.files.remove(dirname)
}
})
sandboxTest('metadata is surfaced after rename', async ({ sandbox }) => {
const oldPath = 'metadata_rename_old.txt'
const newPath = 'metadata_rename_new.txt'
const metadata = { stage: 'renamed' }
await sandbox.files.write(oldPath, 'content', { metadata })
const info = await sandbox.files.rename(oldPath, newPath)
assert.deepEqual(info.metadata, metadata)
if (isDebug) {
await sandbox.files.remove(newPath)
}
})
sandboxTest('overwriting a file clears stale metadata', async ({ sandbox }) => {
const filename = 'metadata_overwrite.txt'
await sandbox.files.write(filename, 'first', {
metadata: { author: 'mish' },
})
// Overwriting without metadata removes the previously stored metadata.
const info = await sandbox.files.write(filename, 'second')
assert.isUndefined(info.metadata)
const stat = await sandbox.files.getInfo(filename)
assert.isUndefined(stat.metadata)
if (isDebug) {
await sandbox.files.remove(filename)
}
})
sandboxTest(
'metadata set via xattrs is surfaced in getInfo',
async ({ sandbox }) => {
const filename = 'metadata_xattr.txt'
await sandbox.files.write(filename, 'content')
const { stdout: filePath } = await sandbox.commands.run(
`realpath ${filename}`
)
// 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 sandbox.commands.run(
`python3 -c "import os; os.setxattr('${filePath.trim()}', 'user.e2b.author', b'mish')"`
)
const info = await sandbox.files.getInfo(filename)
assert.deepEqual(info.metadata, { author: 'mish' })
if (isDebug) {
await sandbox.files.remove(filename)
}
}
)
sandboxTest('rejects invalid metadata', async ({ sandbox }) => {
const filename = 'invalid_metadata.txt'
// Key with a space is not a valid HTTP header token.
await expect(
sandbox.files.write(filename, 'x', { metadata: { 'bad key': 'value' } })
).rejects.toThrow(InvalidArgumentError)
// Empty key.
await expect(
sandbox.files.write(filename, 'x', { metadata: { '': 'value' } })
).rejects.toThrow(InvalidArgumentError)
// Value with a non-printable / non-ASCII character.
await expect(
sandbox.files.write(filename, 'x', { metadata: { good: 'bad\nvalue' } })
).rejects.toThrow(InvalidArgumentError)
// Trailing newline in value or key.
await expect(
sandbox.files.write(filename, 'x', { metadata: { good: 'value\n' } })
).rejects.toThrow(InvalidArgumentError)
await expect(
sandbox.files.write(filename, 'x', { metadata: { 'key\n': 'value' } })
).rejects.toThrow(InvalidArgumentError)
// The file must not have been created by a rejected write.
assert.isFalse(await sandbox.files.exists(filename))
})