// 已读取AGENTS.md import * as fs from 'fs'; import * as path from 'path'; /** * 第一百二十批闸门:小程序与服务端全栈性能深度优化与稳定性守护门禁 */ describe('第一百二十批全栈性能深度优化与稳定性守护门禁', () => { const rootDir = path.resolve(__dirname, '../../'); const repoPath = path.join(rootDir, 'server/src/db/repository.ts'); const indexPath = path.join(rootDir, 'server/src/index.ts'); const privacyModalPath = path.join(rootDir, 'pwuniapp/components/PrivacyModal.vue'); it('repository.ts 中 getActivities 必须带 WHERE p.activity_id IN (?) 精确范围查询,杜绝全表扫描 participants', () => { const content = fs.readFileSync(repoPath, 'utf-8'); expect(content).toContain('WHERE p.activity_id IN (?)'); // 确保没有直接从 participants 无条件 SELECT * expect(content).not.toMatch(/FROM participants p\s+LEFT JOIN users u\s*`\s*\);/); }); it('repository.ts 中 getMyActivities 必须通过索引查用户参与和发起的活动,禁止全量查出后内存 filter', () => { const content = fs.readFileSync(repoPath, 'utf-8'); expect(content).toContain('SELECT DISTINCT activity_id FROM participants WHERE user_id = ?'); expect(content).toContain('this.getActivities({ creatorId: uid })'); expect(content).not.toContain('allActivities.filter((a: any) => Number(a.creatorId) === Number(userId))'); }); it('repository.ts 中 getPosts 必须将点赞与报名状态限定在当前页 post_id IN (?) 范围内', () => { const content = fs.readFileSync(repoPath, 'utf-8'); expect(content).toContain('SELECT post_id FROM post_likes WHERE user_id = ? AND post_id IN (?)'); expect(content).toContain('SELECT post_id, applicant_id, status FROM post_applies WHERE post_id IN (?)'); }); it('高频查询业务函数中严禁在每次读写请求中执行 ALTER TABLE 产生独占锁,建表必须有单例初始化防护', () => { const content = fs.readFileSync(repoPath, 'utf-8'); // 确保 getCompanions, applyCompanion, auditCompanion, getOrderReviews, replyOrderReview 中不包含 ALTER TABLE const getCompanionsSection = content.substring(content.indexOf('async getCompanions('), content.indexOf('async getCompanionById(')); expect(getCompanionsSection).not.toContain('ALTER TABLE'); const getOrderReviewsSection = content.substring(content.indexOf('async getOrderReviews('), content.indexOf('async getOrderReviewById(')); expect(getOrderReviewsSection).not.toContain('ALTER TABLE'); // 确保 ensureExpertServicesTable 具备静态单例标志防护 expect(content).toContain('private static expertServicesTableInitialized = false'); expect(content).toContain('if (MysqlRepository.expertServicesTableInitialized) return'); }); it('服务端必须包含定时 sweep 淘汰器,防止防爆破与缓存 Map 无界内存泄漏', () => { const content = fs.readFileSync(indexPath, 'utf-8'); expect(content).toContain('securitySweepTimer'); expect(content).toContain('loginFailureMap.delete(k)'); expect(content).toContain('geocodeCache.delete(k)'); }); it('服务端高频静态读接口必须提供内存 TTL 缓存及写时主动淘汰机制', () => { const content = fs.readFileSync(indexPath, 'utf-8'); expect(content).toContain('STATIC_CACHE_TTL_MS'); expect(content).toContain('cachedBanners'); expect(content).toContain('cachedNavCategories'); expect(content).toContain('cachedPlatformConfigs'); expect(content).toContain('invalidateBannersCache()'); expect(content).toContain('invalidateNavCategoriesCache()'); expect(content).toContain('invalidatePlatformConfigsCache()'); }); it('小程序前端 PrivacyModal 组件必须在 onUnmounted 中成对使用 uni.$off 注销全局事件监听', () => { const content = fs.readFileSync(privacyModalPath, 'utf-8'); expect(content).toContain("uni.$on('theme-change', onThemeChanged)"); expect(content).toContain("uni.$off('theme-change', onThemeChanged)"); expect(content).toContain('onUnmounted'); }); it('本次性能优化涉及的文件与新增测试严禁引入任何系统 Emoji', () => { const emojiRegex = /[\u{1F300}-\u{1F5FF}\u{1F600}-\u{1F64F}\u{1F680}-\u{1F6FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{1F900}-\u{1F9FF}\u{1F018}-\u{1F270}]/u; const filesToCheck = [repoPath, indexPath, privacyModalPath, __filename]; for (const f of filesToCheck) { const text = fs.readFileSync(f, 'utf-8'); expect(emojiRegex.test(text)).toBe(false); } }); });