102 lines
3.6 KiB
TypeScript
102 lines
3.6 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
createAliyunOssStorageProvider,
|
|
getAliyunOssSignedDownloadUrl,
|
|
readAliyunOssObjectBuffer,
|
|
validateAliyunOssConfig,
|
|
} from "../src/lib/boss-storage-aliyun-oss.ts";
|
|
import { encryptStorageSecret } from "../src/lib/boss-storage-secrets.ts";
|
|
|
|
async function createConfig() {
|
|
process.env.BOSS_STORAGE_SECRET_KEY = "aliyun-oss-storage-test-key";
|
|
return {
|
|
enabled: true,
|
|
accessKeyId: "test-access-key",
|
|
accessKeySecretEncrypted: await encryptStorageSecret("test-secret"),
|
|
bucket: "boss-bucket",
|
|
endpoint: "oss-cn-hangzhou.aliyuncs.com",
|
|
region: "oss-cn-hangzhou",
|
|
prefix: "uploads",
|
|
};
|
|
}
|
|
|
|
test("aliyun oss storage uploads attachments through signed REST requests", async () => {
|
|
const config = await createConfig();
|
|
const originalFetch = globalThis.fetch;
|
|
const calls: Array<{ input: string; init?: RequestInit }> = [];
|
|
globalThis.fetch = (async (input, init) => {
|
|
calls.push({ input: String(input), init });
|
|
return new Response("", { status: 200 });
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const provider = createAliyunOssStorageProvider(config);
|
|
const record = await provider.storeAttachment({
|
|
account: "kris@example.com",
|
|
messageId: "msg-1",
|
|
fileName: "report.txt",
|
|
mimeType: "text/plain",
|
|
buffer: Buffer.from("hello"),
|
|
});
|
|
|
|
assert.equal(record.storageBackend, "aliyun_oss");
|
|
assert.match(record.storagePath, /^uploads\/acct-[a-f0-9]{16}\/\d{4}\/\d{2}\/msg-1-report\.txt$/);
|
|
assert.equal(calls.length, 1);
|
|
assert.match(calls[0].input, /^https:\/\/boss-bucket\.oss-cn-hangzhou\.aliyuncs\.com\/uploads\/acct-/);
|
|
assert.equal(calls[0].init?.method, "PUT");
|
|
const headers = calls[0].init?.headers as Record<string, string>;
|
|
assert.equal(headers["content-type"], "text/plain");
|
|
assert.match(headers.authorization, /^OSS test-access-key:/);
|
|
assert.ok(headers["x-oss-date"]);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|
|
|
|
test("aliyun oss signed download url is generated without network access", async () => {
|
|
const config = await createConfig();
|
|
|
|
const signedUrl = await getAliyunOssSignedDownloadUrl(config, "uploads/demo file.txt", 600);
|
|
const url = new URL(signedUrl);
|
|
|
|
assert.equal(url.hostname, "boss-bucket.oss-cn-hangzhou.aliyuncs.com");
|
|
assert.equal(url.pathname, "/uploads/demo%20file.txt");
|
|
assert.equal(url.searchParams.get("OSSAccessKeyId"), "test-access-key");
|
|
assert.ok(url.searchParams.get("Expires"));
|
|
assert.ok(url.searchParams.get("Signature"));
|
|
});
|
|
|
|
test("aliyun oss storage reads objects and validates bucket config", async () => {
|
|
const config = await createConfig();
|
|
const originalFetch = globalThis.fetch;
|
|
const calls: Array<{ input: string; init?: RequestInit }> = [];
|
|
globalThis.fetch = (async (input, init) => {
|
|
calls.push({ input: String(input), init });
|
|
if (String(input).endsWith("?bucketInfo")) {
|
|
return new Response("<BucketInfo><Bucket><Name>boss-bucket</Name></Bucket></BucketInfo>", {
|
|
status: 200,
|
|
});
|
|
}
|
|
return new Response("object-content", { status: 200 });
|
|
}) as typeof fetch;
|
|
|
|
try {
|
|
const buffer = await readAliyunOssObjectBuffer(config, "uploads/a.txt");
|
|
assert.equal(buffer.toString("utf8"), "object-content");
|
|
|
|
const validation = await validateAliyunOssConfig(config);
|
|
assert.deepEqual(validation, {
|
|
provider: "aliyun_oss",
|
|
bucket: "boss-bucket",
|
|
endpoint: "oss-cn-hangzhou.aliyuncs.com",
|
|
region: "oss-cn-hangzhou",
|
|
});
|
|
assert.equal(calls.length, 2);
|
|
assert.match(calls[1].input, /\/\?bucketInfo$/);
|
|
} finally {
|
|
globalThis.fetch = originalFetch;
|
|
}
|
|
});
|