95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
import * as qiniu from 'qiniu';
|
|
import { imageInput } from '../src/assets/image-input';
|
|
import { bufferEtag, QiniuGateway } from '../src/assets/qiniu.gateway';
|
|
import { testConfig } from './test-config';
|
|
import { ApiException } from '../src/common/api-exception';
|
|
|
|
test('图片上传按内容头校验格式/完整性/像素限制,拒绝 SVG 与超限文件', () => {
|
|
const png = Buffer.from(
|
|
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+kWQAAAABJRU5ErkJggg==',
|
|
'base64',
|
|
);
|
|
assert.equal(imageInput(png).mimeType, 'image/png');
|
|
assert.throws(() =>
|
|
imageInput(Buffer.from('<svg><script>x</script></svg>')),
|
|
);
|
|
assert.throws(() => imageInput(png.subarray(0, 30)));
|
|
assert.throws(() => imageInput(Buffer.alloc(2 * 1024 * 1024 + 1)));
|
|
const huge = Buffer.from(png);
|
|
huge.writeUInt32BE(100000, 16);
|
|
assert.throws(() => imageInput(huge));
|
|
assert.equal(
|
|
bufferEtag(Buffer.from('hello')),
|
|
'Fqr0xh3cxeii2r7eDztILNmuqUNN',
|
|
);
|
|
});
|
|
|
|
test('七牛 SDK 接口适配:正确处理 wrapper 612、新增和同内容恢复,不覆盖冲突', async (context) => {
|
|
const prototype = qiniu.rs.BucketManager.prototype;
|
|
const uploader = qiniu.form_up.FormUploader.prototype;
|
|
const originals = {
|
|
info: prototype.getBucketInfo,
|
|
stat: prototype.stat,
|
|
remove: prototype.delete,
|
|
put: uploader.put,
|
|
};
|
|
context.after(() => {
|
|
prototype.getBucketInfo = originals.info;
|
|
prototype.stat = originals.stat;
|
|
prototype.delete = originals.remove;
|
|
uploader.put = originals.put;
|
|
});
|
|
const bytes = Buffer.from('hello');
|
|
let stored: { hash: string; fsize: number } | null = null;
|
|
let putCount = 0;
|
|
prototype.getBucketInfo = (async () => ({
|
|
resp: { statusCode: 200 },
|
|
data: { private: 0 },
|
|
})) as unknown as typeof prototype.getBucketInfo;
|
|
prototype.stat = (async () =>
|
|
stored
|
|
? { resp: { statusCode: 200 }, data: stored }
|
|
: {
|
|
resp: { statusCode: 612 },
|
|
data: { error: 'missing' },
|
|
}) as unknown as typeof prototype.stat;
|
|
prototype.delete = (async () => ({
|
|
resp: { statusCode: 612 },
|
|
data: { error: 'missing' },
|
|
})) as unknown as typeof prototype.delete;
|
|
uploader.put = (async () => {
|
|
putCount++;
|
|
stored = { hash: bufferEtag(bytes), fsize: bytes.length };
|
|
return { resp: { statusCode: 200 }, data: stored };
|
|
}) as unknown as typeof uploader.put;
|
|
const gateway = new QiniuGateway({
|
|
...testConfig,
|
|
qiniuAk: 'test-ak',
|
|
qiniuSk: 'test-sk',
|
|
qiniuBucket: 'test-public',
|
|
qiniuPublicDomain: 'https://cdn.test',
|
|
});
|
|
await gateway.put('test/a.png', bytes, 'image/png');
|
|
await gateway.put('test/a.png', bytes, 'image/png');
|
|
assert.equal(putCount, 1);
|
|
await assert.rejects(
|
|
gateway.put('test/a.png', Buffer.from('different'), 'image/png'),
|
|
(error: unknown) =>
|
|
error instanceof ApiException &&
|
|
error.reason === 'ASSET_UPSTREAM_UNAVAILABLE',
|
|
);
|
|
assert.equal(putCount, 1);
|
|
await gateway.remove('test-public', 'test/missing.png');
|
|
prototype.getBucketInfo = (async () => ({
|
|
resp: { statusCode: 403 },
|
|
data: { error: 'private-message' },
|
|
})) as unknown as typeof prototype.getBucketInfo;
|
|
await assert.rejects(
|
|
gateway.put('new.png', bytes, 'image/png'),
|
|
(error: unknown) =>
|
|
error instanceof ApiException && error.getStatus() === 503,
|
|
);
|
|
});
|