c25fd47d16
Project CI / AI game creator shell Rust lane 1/2 (push) Failing after 1m18s
Project CI / AI game creator shell Rust smoke (push) Failing after 1m18s
Project CI / AI game creator shell Rust lane 2/2 (push) Failing after 1m18s
Project CI / AI game creator shell Rust crates (push) Successful in 1m51s
Project CI / Frontend tests (push) Successful in 4m46s
Project CI / Repository checks (push) Successful in 5m5s
Project CI / AI game creator shell web tests (push) Successful in 2m47s
Project CI / Backend tests (push) Successful in 9m1s
Project CI / Native shell tests (push) Successful in 10m4s
移除错误的独立主站 vhost 配置 补充官网现役 vhost 的精确下载接口 snippet 同步线上排障说明与回归测试
100 lines
2.9 KiB
TypeScript
100 lines
2.9 KiB
TypeScript
import { readFileSync } from 'node:fs';
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
const productionNginx = readFileSync('deploy/nginx/genarrative.conf', 'utf8');
|
|
const clientDownloadsSnippet = readFileSync(
|
|
'deploy/nginx/snippets/tsingnova-client-downloads.conf',
|
|
'utf8',
|
|
);
|
|
|
|
function extractServerBlocks(source: string): string[] {
|
|
const blocks: string[] = [];
|
|
const serverStart = /\bserver\s*\{/gu;
|
|
let match: RegExpExecArray | null;
|
|
|
|
while ((match = serverStart.exec(source)) !== null) {
|
|
const openBrace = source.indexOf('{', match.index);
|
|
let depth = 0;
|
|
let quote: '"' | "'" | null = null;
|
|
let escaped = false;
|
|
let inComment = false;
|
|
|
|
for (let index = openBrace; index < source.length; index += 1) {
|
|
const character = source[index];
|
|
|
|
if (inComment) {
|
|
if (character === '\n') {
|
|
inComment = false;
|
|
}
|
|
continue;
|
|
}
|
|
if (quote !== null) {
|
|
if (escaped) {
|
|
escaped = false;
|
|
} else if (character === '\\') {
|
|
escaped = true;
|
|
} else if (character === quote) {
|
|
quote = null;
|
|
}
|
|
continue;
|
|
}
|
|
if (character === '#') {
|
|
inComment = true;
|
|
} else if (character === '"' || character === "'") {
|
|
quote = character;
|
|
} else if (character === '{') {
|
|
depth += 1;
|
|
} else if (character === '}') {
|
|
depth -= 1;
|
|
if (depth === 0) {
|
|
blocks.push(source.slice(match.index, index + 1));
|
|
serverStart.lastIndex = index + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return blocks;
|
|
}
|
|
|
|
describe('清智创游官网引擎下载路由', () => {
|
|
it('主站模板不重复声明官网独立域名,下载路由由现役官网 vhost 单独维护', () => {
|
|
expect(productionNginx).not.toContain('tsingnovagames.com');
|
|
expect(clientDownloadsSnippet).toContain(
|
|
'location = /api/client-downloads {',
|
|
);
|
|
});
|
|
|
|
it('下载 snippet 只声明精确接口并复用主站保护与 upstream', () => {
|
|
expect(clientDownloadsSnippet).toContain(
|
|
'location = /api/client-downloads {',
|
|
);
|
|
expect(clientDownloadsSnippet).not.toMatch(
|
|
/location\s+(?:~|\^~)?\s*\/api(?:\/|\s|\{|\$)/u,
|
|
);
|
|
for (const directive of [
|
|
'limit_conn genarrative_api_conn 64;',
|
|
'limit_req zone=genarrative_api_rps burst=64 nodelay;',
|
|
'limit_conn_status 429;',
|
|
'limit_req_status 429;',
|
|
'if ($genarrative_maintenance) {',
|
|
'proxy_pass http://genarrative_api;',
|
|
'proxy_set_header Cookie "";',
|
|
'proxy_set_header Authorization "";',
|
|
'proxy_connect_timeout 3s;',
|
|
'proxy_read_timeout 15s;',
|
|
'proxy_send_timeout 15s;',
|
|
'proxy_buffering off;',
|
|
'proxy_cache off;',
|
|
'add_header X-Accel-Buffering no always;',
|
|
]) {
|
|
expect(clientDownloadsSnippet).toContain(directive);
|
|
}
|
|
expect(clientDownloadsSnippet).not.toMatch(
|
|
/^\s*add_header\s+Cache-Control\b/mu,
|
|
);
|
|
});
|
|
});
|