101 lines
3.2 KiB
JavaScript
101 lines
3.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { createHash } from 'node:crypto';
|
|
import { test } from 'node:test';
|
|
import { buildAssetMappings } from '../../../apps/server/scripts/asset-mapping.mjs';
|
|
const hash = (value) => createHash('sha256').update(value).digest('hex');
|
|
function fixture() {
|
|
const sourceRef = 'cloud://legacy.env/assets/previews/math/a.jpg';
|
|
const asset = {
|
|
id: 'keep-original-id',
|
|
sourceRef,
|
|
sourceRefHash: hash(sourceRef),
|
|
purpose: 'preview',
|
|
visibility: 'public',
|
|
ownerUserId: null,
|
|
status: 'pending',
|
|
};
|
|
const file = {
|
|
relativePath: 'assets/previews/math/a.jpg',
|
|
key: 'doodle-assets/assets/previews/math/a.jpg',
|
|
bucket: 'test-public',
|
|
visibility: 'public',
|
|
mimeType: 'image/jpeg',
|
|
size: 10,
|
|
sha256: hash('local'),
|
|
etag: 'etag',
|
|
status: 'uploaded',
|
|
verifiedBy: 'qiniu-etag-and-size',
|
|
};
|
|
return {
|
|
asset,
|
|
file,
|
|
report: { schemaVersion: 1, mode: 'apply', ok: true, files: [file] },
|
|
config: { publicBucket: 'test-public', prefix: 'doodle-assets/' },
|
|
};
|
|
}
|
|
|
|
test('资产回填:保留 ID、完整 key 与原始来源;重复映射幂等', () => {
|
|
const { asset, file, report, config } = fixture();
|
|
const [mapped] = buildAssetMappings(report, [asset], config);
|
|
assert.equal(mapped.asset.id, asset.id);
|
|
assert.equal(mapped.data.objectKey, file.key);
|
|
assert.equal(
|
|
mapped.data.objectRefHash,
|
|
hash(JSON.stringify(['qiniu', file.bucket, file.key])),
|
|
);
|
|
assert.equal(mapped.data.status, 'ready');
|
|
assert.equal(mapped.unchanged, false);
|
|
assert.equal(
|
|
buildAssetMappings(report, [{ ...asset, ...mapped.data }], config)[0]
|
|
.unchanged,
|
|
true,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
buildAssetMappings(
|
|
report,
|
|
[{ ...asset, ...mapped.data, objectKey: 'edited-key' }],
|
|
config,
|
|
),
|
|
/READY_ASSET_CONFLICT/,
|
|
);
|
|
});
|
|
|
|
test('资产回填:预演报告、未核对对象、缺失映射和来源不一致整批拒绝', () => {
|
|
const { asset, file, report, config } = fixture();
|
|
assert.throws(
|
|
() =>
|
|
buildAssetMappings({ ...report, mode: 'dry-run' }, [asset], config),
|
|
/INVALID_SYNC_REPORT/,
|
|
);
|
|
for (const changed of [
|
|
{ status: 'planned' },
|
|
{ bucket: 'another-bucket' },
|
|
{ key: 'wrong-prefix/a.jpg' },
|
|
{ verifiedBy: null },
|
|
{ sha256: 'bad' },
|
|
])
|
|
assert.throws(
|
|
() =>
|
|
buildAssetMappings(
|
|
{ ...report, files: [{ ...file, ...changed }] },
|
|
[asset],
|
|
config,
|
|
),
|
|
/INVALID_REPORT_FILE/,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
buildAssetMappings(
|
|
report,
|
|
[{ ...asset, sourceRefHash: 'bad' }],
|
|
config,
|
|
),
|
|
/INVALID_SOURCE_REFERENCE/,
|
|
);
|
|
assert.throws(
|
|
() => buildAssetMappings({ ...report, files: [] }, [asset], config),
|
|
/ASSET_MAPPING_MISSING_OR_INELIGIBLE/,
|
|
);
|
|
});
|