补充BgFilter全进程与真实链路冒烟验证

新增32/40/48并发、五类故障与harness自测。
新增真实OSS和BgFilter契约冒烟并严格清理临时对象。
补充本地运行方式、凭据边界与staging验收范围。
This commit is contained in:
2026-07-21 14:02:13 +00:00
parent 566f2f2194
commit 7ea7dce395
6 changed files with 2392 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+190
View File
@@ -0,0 +1,190 @@
import assert from 'node:assert/strict';
import http from 'node:http';
import { afterEach, describe, test } from 'node:test';
import {
buildIsolatedWorkerEnv,
createProviderGate,
createProviderSequenceBehavior,
SMOKE_PNG_BYTES,
startMockBgfilterProvider,
} from './bgfilter-worker-load-smoke.mjs';
const providers = [];
afterEach(async () => {
await Promise.all(providers.splice(0).map((provider) => provider.close()));
});
describe('bgfilter worker smoke harness', () => {
test('worker 环境不继承真实服务密钥并固定使用假 OSS 配置', () => {
const env = buildIsolatedWorkerEnv({
processEnv: {
ALIYUN_OSS_ACCESS_KEY_SECRET: 'real-oss-secret',
GENARRATIVE_BGFILTER_INTERNAL_TOKEN: 'real-internal-token',
GENARRATIVE_EDITOR_BGFILTER_TOKEN: 'real-provider-token',
PATH: '/safe/bin',
VECTOR_ENGINE_API_KEY: 'real-vector-secret',
},
providerBaseUrl: 'http://127.0.0.1:19001',
tempRoot: '/tmp/bgfilter-load-smoke-test',
token: 'ephemeral-test-token',
workerPort: 19002,
});
assert.equal(env.PATH, '/safe/bin');
assert.equal(
env.GENARRATIVE_BGFILTER_INTERNAL_TOKEN,
'ephemeral-test-token',
);
assert.equal(env.ALIYUN_OSS_ENDPOINT, 'oss-cn-shanghai.invalid');
assert.notEqual(env.ALIYUN_OSS_ACCESS_KEY_SECRET, 'real-oss-secret');
assert.equal(env.GENARRATIVE_EDITOR_BGFILTER_TOKEN, undefined);
assert.equal(env.VECTOR_ENGINE_API_KEY, undefined);
assert.ok(!Object.values(env).includes('real-internal-token'));
assert.ok(!Object.values(env).includes('real-provider-token'));
assert.ok(!Object.values(env).includes('real-vector-secret'));
});
test('loopback mock 完整读取 multipart 后记录并发并返回合法 PNG 字节', async () => {
const provider = await startMockBgfilterProvider({ delayMs: 25 });
providers.push(provider);
const request = multipartFixture();
const responses = await Promise.all([
postMultipart(provider.baseUrl, request),
postMultipart(provider.baseUrl, request),
]);
for (const response of responses) {
assert.equal(response.statusCode, 200);
assert.equal(response.contentType, 'image/png');
assert.ok(response.body.equals(SMOKE_PNG_BYTES));
}
const stats = provider.snapshot();
assert.equal(stats.active, 0);
assert.equal(stats.peak, 2);
assert.equal(stats.requests, 2);
assert.deepEqual(stats.violations, []);
assert.equal(stats.timeline.filter((event) => event.event === 'start').length, 2);
assert.equal(stats.timeline.filter((event) => event.event === 'finish').length, 2);
});
test('provider gate 与 sequence behavior 生成无重叠 timeline', async () => {
const gate = createProviderGate();
const provider = await startMockBgfilterProvider({
behavior: createProviderSequenceBehavior([503, 200]),
delayMs: 5,
gate,
});
providers.push(provider);
const request = multipartFixture();
let firstSettled = false;
const first = postMultipart(provider.baseUrl, request).finally(() => {
firstSettled = true;
});
await provider.waitFor((stats) => stats.active === 1, { timeoutMs: 1_000 });
await new Promise((resolve) => setTimeout(resolve, 20));
assert.equal(firstSettled, false);
gate.release();
assert.equal((await first).statusCode, 503);
assert.equal((await postMultipart(provider.baseUrl, request)).statusCode, 200);
const stats = provider.snapshot();
assert.equal(stats.peak, 1);
assert.deepEqual(
stats.timeline.map((event) => [
event.attempt,
event.event,
event.statusCode ?? null,
]),
[
[1, 'start', null],
[1, 'finish', 503],
[2, 'start', null],
[2, 'finish', 200],
],
);
});
test('provider 可在成功响应 body 中途 reset 并记录完成类型', async () => {
const provider = await startMockBgfilterProvider({
behavior: createProviderSequenceBehavior([
{ resetMidBody: true, statusCode: 200 },
]),
delayMs: 5,
});
providers.push(provider);
await assert.rejects(postMultipart(provider.baseUrl, multipartFixture()));
const stats = provider.snapshot();
assert.equal(stats.active, 0);
assert.equal(stats.peak, 1);
assert.equal(stats.requests, 1);
assert.deepEqual(stats.violations, []);
assert.equal(stats.timeline[1]?.completion, 'mid_body_reset');
});
});
function multipartFixture() {
const boundary = 'bgfilter-load-smoke-boundary';
const body = Buffer.from(
[
`--${boundary}`,
'Content-Disposition: form-data; name="image_url"',
'',
'https://example.invalid/source.png',
`--${boundary}`,
'Content-Disposition: form-data; name="seg_model"',
'',
'birefnet',
`--${boundary}`,
'Content-Disposition: form-data; name="background_mode"',
'',
'complex',
`--${boundary}`,
'Content-Disposition: form-data; name="cross_check"',
'',
'off',
`--${boundary}--`,
'',
].join('\r\n'),
'utf8',
);
return { body, boundary };
}
function postMultipart(baseUrl, { body, boundary }) {
return new Promise((resolve, reject) => {
const request = http.request(
`${baseUrl}/remove-background`,
{
agent: false,
headers: {
'Content-Length': String(body.length),
'Content-Type': `multipart/form-data; boundary=${boundary}`,
},
method: 'POST',
},
(response) => {
const chunks = [];
response.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
response.once('aborted', () => {
reject(new Error('mock provider 响应在 body 中途中止'));
});
response.once('error', reject);
response.once('end', () => {
resolve({
body: Buffer.concat(chunks),
contentType: String(response.headers['content-type'] ?? ''),
statusCode: response.statusCode ?? 0,
});
});
},
);
request.once('error', reject);
request.end(body);
});
}