const assert = require('assert'); const fs = require('fs'); const path = require('path'); const projectRoot = path.resolve(__dirname, '..', '..'); const serverPath = path.join(projectRoot, 'backend', 'server.js'); const source = fs.readFileSync(serverPath, 'utf8'); const results = { passed: 0, failed: 0 }; function test(name, fn) { try { fn(); results.passed += 1; console.log(` [PASS] ${name}`); } catch (error) { results.failed += 1; console.error(` [FAIL] ${name}: ${error.message}`); } } console.log('\n========== 架构约束测试 ==========\n'); test('Express async 错误补丁在所有路由之前加载', () => { const patchIndex = source.indexOf("require('express-async-errors')"); const routeIndex = source.search(/\bapp\.(get|post|put|delete|patch)\s*\(/); assert.ok(patchIndex >= 0); assert.ok(routeIndex > patchIndex); }); test('全局错误中间件保持为最后一个 app.use', () => { const errorHandlerIndex = source.indexOf('app.use(expressErrorHandler);'); assert.ok(errorHandlerIndex >= 0); assert.strictEqual(source.lastIndexOf('app.use('), errorHandlerIndex); }); test('抽取的纯函数不在 server.js 保留第二份定义', () => { const extractedFunctions = [ 'normalizeVersion', 'normalizeSha256', 'normalizeVirtualPath', 'buildHttpDownloadUrl', 'parseDownloadTrafficLine', 'isShareIpAllowed', 'resolveClientType', 'parseBooleanLike' ]; for (const functionName of extractedFunctions) { assert.strictEqual(new RegExp(`function\\s+${functionName}\\s*\\(`).test(source), false, functionName); } }); test('旧占位路由已清除且真实系统路由已挂载', () => { assert.strictEqual(fs.existsSync(path.join(projectRoot, 'backend', 'routes', 'health.js')), false); assert.strictEqual(fs.existsSync(path.join(projectRoot, 'backend', 'routes', 'index.js')), false); assert.ok(source.includes("require('./routes/system.routes')")); assert.ok(source.includes("app.use('/api', createSystemRouter")); }); test('package.json 与 package-lock.json 顶层依赖同步', () => { const packageJson = require('../package.json'); const packageLock = require('../package-lock.json'); assert.deepStrictEqual(packageLock.packages[''].dependencies, packageJson.dependencies); }); test('前端 package.json 与 lock 文件依赖同步且没有手工缓存版本号', () => { const frontendPackage = require('../../frontend/package.json'); const frontendLock = require('../../frontend/package-lock.json'); assert.deepStrictEqual(frontendLock.packages[''].dependencies, frontendPackage.dependencies); assert.deepStrictEqual(frontendLock.packages[''].devDependencies, frontendPackage.devDependencies); const frontendDirectory = path.join(projectRoot, 'frontend'); for (const fileName of fs.readdirSync(frontendDirectory).filter((name) => name.endsWith('.html'))) { const html = fs.readFileSync(path.join(frontendDirectory, fileName), 'utf8'); assert.strictEqual(/\?v=\d+/.test(html), false, fileName); } }); test('生产部署统一使用 Vite dist 且不会删除 lock 文件', () => { const installer = fs.readFileSync(path.join(projectRoot, 'install.sh'), 'utf8'); const nginxConfig = fs.readFileSync(path.join(projectRoot, 'nginx', 'nginx.conf'), 'utf8'); assert.ok(installer.includes('npm ci --include=dev')); assert.ok(installer.includes('npm run build')); assert.ok(installer.includes('frontend/dist')); assert.strictEqual(/rm\s+-rf\s+node_modules\s+package-lock\.json/.test(installer), false); assert.ok(nginxConfig.includes('root /usr/share/nginx/html;')); assert.ok(nginxConfig.includes('alias /runtime/downloads/;')); }); test('Docker 构建上下文排除依赖、环境配置和运行时数据', () => { const dockerIgnore = fs.readFileSync(path.join(projectRoot, 'backend', '.dockerignore'), 'utf8'); for (const requiredEntry of ['node_modules', '.env', 'data/*', 'storage/*']) { assert.ok(dockerIgnore.split(/\r?\n/).includes(requiredEntry), requiredEntry); } }); test('install.sh 生成的 Nginx server 块花括号平衡', () => { const installer = fs.readFileSync(path.join(projectRoot, 'install.sh'), 'utf8'); const templates = [...installer.matchAll(/cat > .*?<< EOF\r?\n([\s\S]*?)\r?\nEOF/g)] .map((match) => match[1]) .filter((template) => template.includes('server {')); assert.strictEqual(templates.length, 3); for (const template of templates) { const openingBraces = (template.match(/\{/g) || []).length; const closingBraces = (template.match(/\}/g) || []).length; assert.strictEqual(openingBraces, closingBraces); } }); test('PM2 部署没有启用 cluster 或多实例参数', () => { const installer = fs.readFileSync(path.join(projectRoot, 'install.sh'), 'utf8'); assert.strictEqual(/pm2\s+start[^\n]*(?:\s-i\s|--instances)/.test(installer), false); }); console.log('\n========================================'); console.log('测试总结'); console.log('========================================'); console.log(`通过: ${results.passed}`); console.log(`失败: ${results.failed}`); process.exit(results.failed > 0 ? 1 : 0);