114 lines
4.9 KiB
TypeScript
114 lines
4.9 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
|
|
import { DreaminaProviderArtifactStore } from "../src/dreamina-provider-artifacts.js";
|
|
|
|
test("provider artifact store is private, binding-scoped, crash-readable, and scavenges only orphan sets", async () => {
|
|
const sandbox = await fs.mkdtemp(path.join(os.tmpdir(), "dreamina-provider-artifacts-"));
|
|
const root = path.join(sandbox, "private");
|
|
let nowMs = Date.now();
|
|
const store = new DreaminaProviderArtifactStore({
|
|
root,
|
|
now: () => new Date(nowMs),
|
|
});
|
|
const bytes = Buffer.from([0x00, 0x00, 0x00, 0x10, 0x66, 0x74, 0x79, 0x70, 0x69, 0x73, 0x6f, 0x6d]);
|
|
const binding = {
|
|
ownerId: "owner-runtime-0001",
|
|
idempotencyKey: "dreamina-artifact-0001",
|
|
accountBinding: "a".repeat(64),
|
|
fenceEpoch: 17,
|
|
mode: "video" as const,
|
|
};
|
|
|
|
try {
|
|
const outputs = await store.persistResult({
|
|
mode: "video",
|
|
video: {
|
|
dataUrl: `data:video/mp4;base64,${bytes.toString("base64")}`,
|
|
mimeType: "video/mp4",
|
|
bytes: bytes.byteLength,
|
|
},
|
|
}, binding);
|
|
|
|
assert.equal(outputs.length, 1);
|
|
assert.match(outputs[0]!.providerArtifactRef, /^dreamina-provider-artifact:[a-f0-9-]{36}:0$/);
|
|
const entries = await fs.readdir(root);
|
|
assert.equal(entries.length, 1);
|
|
assert.match(entries[0]!, /^set-[a-f0-9-]{36}$/);
|
|
|
|
const setRoot = path.join(root, entries[0]!);
|
|
const manifestPath = path.join(setRoot, "manifest.json");
|
|
const manifest = await fs.readFile(manifestPath, "utf8");
|
|
assert.equal(manifest.includes(binding.ownerId), false);
|
|
assert.equal(manifest.includes(binding.idempotencyKey), false);
|
|
assert.equal(manifest.includes(root), false);
|
|
assert.doesNotMatch(manifest, /data:|base64|stdout|stderr|token|cookie/i);
|
|
|
|
if (process.platform !== "win32") {
|
|
assert.equal((await fs.stat(root)).mode & 0o777, 0o700);
|
|
assert.equal((await fs.stat(setRoot)).mode & 0o777, 0o700);
|
|
assert.equal((await fs.stat(manifestPath)).mode & 0o777, 0o600);
|
|
assert.equal((await fs.stat(path.join(setRoot, "000.media"))).mode & 0o777, 0o600);
|
|
}
|
|
|
|
const recovered = await new DreaminaProviderArtifactStore({ root }).readResult(outputs, binding);
|
|
assert.deepEqual(recovered, {
|
|
mode: "video",
|
|
video: {
|
|
dataUrl: `data:video/mp4;base64,${bytes.toString("base64")}`,
|
|
mimeType: "video/mp4",
|
|
bytes: bytes.byteLength,
|
|
},
|
|
});
|
|
await assert.rejects(store.readResult(outputs, { ...binding, ownerId: "owner-runtime-0002" }));
|
|
await assert.rejects(store.readResult(outputs, { ...binding, accountBinding: "b".repeat(64) }));
|
|
await assert.rejects(store.readResult(outputs, { ...binding, fenceEpoch: 18 }));
|
|
|
|
nowMs += 25 * 60 * 60 * 1_000;
|
|
await store.scavenge(outputs);
|
|
assert.deepEqual(await fs.readdir(root), entries);
|
|
await store.scavenge([]);
|
|
assert.deepEqual(await fs.readdir(root), []);
|
|
} finally {
|
|
await fs.rm(sandbox, { recursive: true, force: true, maxRetries: 10, retryDelay: 10 });
|
|
}
|
|
});
|
|
|
|
test("artifact scavenge tolerates only an enumerated candidate disappearing before lstat", async () => {
|
|
const sandbox = await fs.mkdtemp(path.join(os.tmpdir(), "dreamina-provider-artifact-race-"));
|
|
const root = path.join(sandbox, "private");
|
|
const candidate = path.join(root, ".tmp-11111111-1111-4111-8111-111111111111");
|
|
let statCalls = 0;
|
|
try {
|
|
await fs.mkdir(candidate, { recursive: true });
|
|
const store = new DreaminaProviderArtifactStore({
|
|
root,
|
|
now: () => new Date(Date.now() + 25 * 60 * 60 * 1_000),
|
|
statScavengeCandidate: async (target) => {
|
|
statCalls += 1;
|
|
assert.equal(target, candidate);
|
|
await fs.rm(target, { recursive: true });
|
|
return fs.lstat(target);
|
|
},
|
|
});
|
|
await assert.doesNotReject(store.scavenge([]));
|
|
assert.equal(statCalls, 1);
|
|
assert.deepEqual(await fs.readdir(root), []);
|
|
|
|
await fs.mkdir(candidate);
|
|
const denied = new DreaminaProviderArtifactStore({
|
|
root,
|
|
statScavengeCandidate: async () => {
|
|
throw Object.assign(new Error("denied"), { code: "EACCES" });
|
|
},
|
|
});
|
|
await assert.rejects(denied.scavenge([]), (error: unknown) => (error as NodeJS.ErrnoException).code === "EACCES");
|
|
assert.deepEqual(await fs.readdir(root), [path.basename(candidate)]);
|
|
} finally {
|
|
await fs.rm(sandbox, { recursive: true, force: true, maxRetries: 10, retryDelay: 10 });
|
|
}
|
|
});
|