mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 04:57:40 +00:00
130 lines
3.9 KiB
TypeScript
130 lines
3.9 KiB
TypeScript
import JSZip from "jszip";
|
|
import fs from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { PassThrough } from "node:stream";
|
|
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { saveMediaSource, setMediaStoreNetworkDepsForTest } from "./store.js";
|
|
|
|
const HOME = path.join(os.tmpdir(), "openclaw-home-redirect");
|
|
const previousStateDir = process.env.OPENCLAW_STATE_DIR;
|
|
const mockRequest = vi.fn();
|
|
|
|
describe("media store redirects", () => {
|
|
beforeAll(async () => {
|
|
await fs.rm(HOME, { recursive: true, force: true });
|
|
process.env.OPENCLAW_STATE_DIR = HOME;
|
|
});
|
|
|
|
beforeEach(() => {
|
|
mockRequest.mockReset();
|
|
setMediaStoreNetworkDepsForTest({
|
|
httpRequest: (...args) => mockRequest(...args),
|
|
httpsRequest: (...args) => mockRequest(...args),
|
|
resolvePinnedHostname: async () => ({
|
|
lookup: async () => [{ address: "93.184.216.34", family: 4 }],
|
|
}),
|
|
});
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await fs.rm(HOME, { recursive: true, force: true });
|
|
if (previousStateDir === undefined) {
|
|
delete process.env.OPENCLAW_STATE_DIR;
|
|
} else {
|
|
process.env.OPENCLAW_STATE_DIR = previousStateDir;
|
|
}
|
|
setMediaStoreNetworkDepsForTest();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it("follows redirects and keeps detected mime/extension", async () => {
|
|
let call = 0;
|
|
mockRequest.mockImplementation((_url, _opts, cb) => {
|
|
call += 1;
|
|
const res = new PassThrough();
|
|
const req = {
|
|
on: (event: string, handler: (...args: unknown[]) => void) => {
|
|
if (event === "error") {
|
|
res.on("error", handler);
|
|
}
|
|
return req;
|
|
},
|
|
end: () => undefined,
|
|
destroy: () => res.destroy(),
|
|
} as const;
|
|
|
|
if (call === 1) {
|
|
res.statusCode = 302;
|
|
res.headers = { location: "https://example.com/final" };
|
|
setImmediate(() => {
|
|
cb(res as unknown);
|
|
res.end();
|
|
});
|
|
} else {
|
|
res.statusCode = 200;
|
|
res.headers = { "content-type": "text/plain" };
|
|
setImmediate(() => {
|
|
cb(res as unknown);
|
|
res.write("redirected");
|
|
res.end();
|
|
});
|
|
}
|
|
|
|
return req;
|
|
});
|
|
|
|
const saved = await saveMediaSource("https://example.com/start");
|
|
|
|
expect(mockRequest).toHaveBeenCalledTimes(2);
|
|
expect(saved.contentType).toBe("text/plain");
|
|
expect(path.extname(saved.path)).toBe(".txt");
|
|
expect(await fs.readFile(saved.path, "utf8")).toBe("redirected");
|
|
});
|
|
|
|
it("sniffs xlsx from zip content when headers and url extension are missing", async () => {
|
|
mockRequest.mockImplementationOnce((_url, _opts, cb) => {
|
|
const res = new PassThrough();
|
|
const req = {
|
|
on: (event: string, handler: (...args: unknown[]) => void) => {
|
|
if (event === "error") {
|
|
res.on("error", handler);
|
|
}
|
|
return req;
|
|
},
|
|
end: () => undefined,
|
|
destroy: () => res.destroy(),
|
|
} as const;
|
|
|
|
res.statusCode = 200;
|
|
res.headers = {};
|
|
setImmediate(() => {
|
|
cb(res as unknown);
|
|
const zip = new JSZip();
|
|
zip.file(
|
|
"[Content_Types].xml",
|
|
'<Types><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/></Types>',
|
|
);
|
|
zip.file("xl/workbook.xml", "<workbook/>");
|
|
void zip
|
|
.generateAsync({ type: "nodebuffer" })
|
|
.then((buf) => {
|
|
res.write(buf);
|
|
res.end();
|
|
})
|
|
.catch((err) => {
|
|
res.destroy(err);
|
|
});
|
|
});
|
|
|
|
return req;
|
|
});
|
|
|
|
const saved = await saveMediaSource("https://example.com/download");
|
|
expect(saved.contentType).toBe(
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
);
|
|
expect(path.extname(saved.path)).toBe(".xlsx");
|
|
});
|
|
});
|