84 lines
3.6 KiB
JavaScript
84 lines
3.6 KiB
JavaScript
import assert from 'node:assert/strict';
|
||
import dns from 'node:dns/promises';
|
||
import fs from 'node:fs';
|
||
import path from 'node:path';
|
||
|
||
const repoRoot = path.resolve(import.meta.dirname, '..');
|
||
|
||
async function runTest(name, fn) {
|
||
try {
|
||
await fn();
|
||
console.log(`PASS ${name}`);
|
||
} catch (error) {
|
||
console.error(`FAIL ${name}`);
|
||
console.error(error);
|
||
process.exitCode = 1;
|
||
}
|
||
}
|
||
|
||
function read(relativePath) {
|
||
return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
|
||
}
|
||
|
||
await runTest('元界 GPT Image 2 Manifest keeps task_id as poll query parameter', () => {
|
||
const source = read('src/lib/yuanjie-image-model-templates.ts');
|
||
const pollPath = source.indexOf("path: 'v1/media/status'");
|
||
const pollQuery = source.indexOf("task_id: '{task_id}'");
|
||
const legacyPath = source.indexOf("path: 'v1/media/status?task_id={task_id}'");
|
||
|
||
assert.ok(pollPath > -1, '元界轮询 path 必须是纯路径 v1/media/status');
|
||
assert.ok(pollQuery > pollPath, 'task_id 必须通过 poll.query 传入');
|
||
assert.equal(legacyPath, -1, '不能把 task_id 拼进 path,避免被编码成错误路径');
|
||
});
|
||
|
||
await runTest('public image fetch sends browser-like headers and retries transient image download failures', async () => {
|
||
const originalLookup = dns.lookup;
|
||
const originalFetch = globalThis.fetch;
|
||
const calls = [];
|
||
|
||
dns.lookup = async () => [{ address: '93.184.216.34', family: 4 }];
|
||
globalThis.fetch = async (url, init = {}) => {
|
||
calls.push({ url: String(url), headers: new Headers(init.headers) });
|
||
if (calls.length === 1) return new Response('forbidden once', { status: 403 });
|
||
return new Response('ok', { status: 200, headers: { 'content-type': 'image/png' } });
|
||
};
|
||
|
||
try {
|
||
const { fetchPublicHttpUrlWithRetry } = await import(`../src/lib/remote-fetch.ts?test=${Date.now()}`);
|
||
const response = await fetchPublicHttpUrlWithRetry('https://example.com/generated.png', {}, {
|
||
attempts: 2,
|
||
retryDelayMs: 0,
|
||
timeoutMs: 1_000,
|
||
});
|
||
|
||
assert.equal(response.status, 200);
|
||
assert.equal(calls.length, 2);
|
||
assert.match(calls[0].headers.get('accept') || '', /image\/\*/);
|
||
assert.match(calls[0].headers.get('user-agent') || '', /Mozilla\/5\.0/);
|
||
} finally {
|
||
dns.lookup = originalLookup;
|
||
globalThis.fetch = originalFetch;
|
||
}
|
||
});
|
||
|
||
await runTest('manifest result persistence failures are reported as download or storage failures, not low resolution', () => {
|
||
const source = read('src/app/api/generate/image/route.ts');
|
||
const manifestBlockStart = source.indexOf("'User API Manifest Image'");
|
||
const manifestFailure = source.indexOf('generatedImagePersistenceError(persisted)', manifestBlockStart);
|
||
const oldLowResolution = source.indexOf('lowResolutionError(targetSize, persisted.rejected)', manifestBlockStart);
|
||
|
||
assert.ok(manifestBlockStart > -1, '应保留 Manifest 图片持久化上下文');
|
||
assert.ok(manifestFailure > manifestBlockStart, 'Manifest 结果持久化失败应走专门错误文案');
|
||
assert.equal(oldLowResolution, -1, 'Manifest 结果下载/保存失败不能再包装成分辨率不符合');
|
||
assert.match(source, /上游已返回生成结果,但平台下载或保存结果图片失败/);
|
||
});
|
||
|
||
await runTest('media storage uses retrying public fetch for external generated image URLs', () => {
|
||
const source = read('src/lib/media-storage.ts');
|
||
|
||
assert.match(source, /import \{ fetchPublicHttpUrl,\s*fetchPublicHttpUrlWithRetry \} from '@\/lib\/remote-fetch';/);
|
||
assert.match(source, /fetchPublicHttpUrlWithRetry\(url,\s*\{\},\s*\{\s*attempts:\s*3,/s);
|
||
});
|
||
|
||
if (process.exitCode) process.exit(process.exitCode);
|