mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 03:15:46 -06:00
test(qa): cover media reference intake (#118858)
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
title: Media reference intake
|
||||
|
||||
scenario:
|
||||
id: media-reference-intake
|
||||
surface: media
|
||||
category: media.media-intake-and-access
|
||||
coverage:
|
||||
primary:
|
||||
- media.local-and-remote-media-references
|
||||
- media.mime-and-type-detection
|
||||
objective: Prove the raw media loader resolves local, remote, and media-store references while deriving MIME family from bytes.
|
||||
successCriteria:
|
||||
- Plain paths and file URLs read the same real local PNG bytes through allowed-root policy.
|
||||
- A real loopback HTTP response crosses guarded remote fetch and returns the served bytes.
|
||||
- A media-store URI resolves an isolated real inbound artifact.
|
||||
- PNG bytes produce image/png and image kind despite misleading text extensions and HTTP headers.
|
||||
docsRefs:
|
||||
- docs/concepts/qa-e2e-automation.md
|
||||
- docs/help/testing.md
|
||||
codeRefs:
|
||||
- src/media/web-media.ts
|
||||
- src/media/fetch.ts
|
||||
- src/media/store.ts
|
||||
- packages/media-core/src/mime.ts
|
||||
- test/e2e/qa-lab/media/media-reference-intake.product.test.ts
|
||||
execution:
|
||||
kind: vitest
|
||||
path: test/e2e/qa-lab/media/media-reference-intake.product.test.ts
|
||||
summary: Load plain-path, file URL, guarded loopback HTTP, and media-store references and verify byte-sniffed MIME and kind.
|
||||
@@ -0,0 +1,104 @@
|
||||
import fs from "node:fs/promises";
|
||||
import { createServer, type Server } from "node:http";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { saveMediaBuffer } from "../../../../src/media/store.js";
|
||||
import { loadWebMediaRaw } from "../../../../src/media/web-media.js";
|
||||
import { withEnvAsync } from "../../../../src/test-utils/env.js";
|
||||
import { createSolidPngBuffer } from "../../../helpers/image-fixtures.js";
|
||||
import { useAutoCleanupTempDirTracker } from "../../../helpers/temp-dir.js";
|
||||
|
||||
async function listenOnLoopback(server: Server): Promise<number> {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
server.once("error", reject);
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
server.off("error", reject);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
const address = server.address();
|
||||
if (!address || typeof address === "string") {
|
||||
throw new Error("media fixture server did not expose a TCP port");
|
||||
}
|
||||
return address.port;
|
||||
}
|
||||
|
||||
async function closeServer(server: Server): Promise<void> {
|
||||
const closed = new Promise<void>((resolve, reject) => {
|
||||
server.close((error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
server.closeAllConnections();
|
||||
await closed;
|
||||
}
|
||||
|
||||
describe("media reference intake product proof", () => {
|
||||
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
|
||||
let server: Server | undefined;
|
||||
|
||||
afterEach(async () => {
|
||||
if (server) {
|
||||
await closeServer(server);
|
||||
server = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
it("loads every supported reference and trusts PNG bytes over text hints", async () => {
|
||||
const root = await fs.realpath(tempDirs.make("openclaw-media-reference-intake-"));
|
||||
const png = createSolidPngBuffer(2, 2, { r: 32, g: 96, b: 224 });
|
||||
const localPath = path.join(root, "misleading.txt");
|
||||
await fs.writeFile(localPath, png);
|
||||
|
||||
const requestedPaths: string[] = [];
|
||||
server = createServer((request, response) => {
|
||||
requestedPaths.push(request.url ?? "");
|
||||
response.writeHead(200, {
|
||||
"content-disposition": 'attachment; filename="remote.txt"',
|
||||
"content-length": String(png.byteLength),
|
||||
"content-type": "text/plain",
|
||||
});
|
||||
response.end(png);
|
||||
});
|
||||
const port = await listenOnLoopback(server);
|
||||
const remoteUrl = `http://127.0.0.1:${port}/misleading.txt`;
|
||||
|
||||
await withEnvAsync({ OPENCLAW_STATE_DIR: path.join(root, "state") }, async () => {
|
||||
const stored = await saveMediaBuffer(png, "text/plain", "inbound", 1024 * 1024, "stored.txt");
|
||||
expect(stored.contentType).toBe("image/png");
|
||||
expect(stored.id).toMatch(/\.txt$/);
|
||||
|
||||
const plainPath = await loadWebMediaRaw(localPath, {
|
||||
localRoots: [root],
|
||||
maxBytes: 1024 * 1024,
|
||||
});
|
||||
const fileUrl = await loadWebMediaRaw(pathToFileURL(localPath).toString(), {
|
||||
localRoots: [root],
|
||||
maxBytes: 1024 * 1024,
|
||||
});
|
||||
const remote = await loadWebMediaRaw(remoteUrl, {
|
||||
maxBytes: 1024 * 1024,
|
||||
ssrfPolicy: { allowedHostnames: ["127.0.0.1"] },
|
||||
});
|
||||
const mediaStore = await loadWebMediaRaw(`media://inbound/${stored.id}`, {
|
||||
maxBytes: 1024 * 1024,
|
||||
});
|
||||
|
||||
for (const result of [plainPath, fileUrl, remote, mediaStore]) {
|
||||
expect(result.buffer).toEqual(png);
|
||||
expect(result.contentType).toBe("image/png");
|
||||
expect(result.kind).toBe("image");
|
||||
}
|
||||
|
||||
expect(plainPath.fileName).toBe("misleading.txt");
|
||||
expect(fileUrl.fileName).toBe("misleading.txt");
|
||||
expect(remote.fileName).toBe("remote.txt");
|
||||
expect(requestedPaths).toEqual(["/misleading.txt"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user