@dommaker/harness 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -4
  3. package/bin/harness.js +12 -37
  4. package/dist/cli/commands/check.d.ts +2 -2
  5. package/dist/cli/commands/check.d.ts.map +1 -1
  6. package/dist/cli/commands/check.js +7 -32
  7. package/dist/cli/commands/check.js.map +1 -1
  8. package/dist/cli/commands/definitions.d.ts +2 -0
  9. package/dist/cli/commands/definitions.d.ts.map +1 -1
  10. package/dist/cli/commands/definitions.js.map +1 -1
  11. package/dist/cli/commands/init.d.ts.map +1 -1
  12. package/dist/cli/commands/init.js +6 -37
  13. package/dist/cli/commands/init.js.map +1 -1
  14. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  15. package/dist/cli/commands/knowledge.js +1 -12
  16. package/dist/cli/commands/knowledge.js.map +1 -1
  17. package/dist/cli/commands/report.d.ts.map +1 -1
  18. package/dist/cli/commands/report.js +0 -2
  19. package/dist/cli/commands/report.js.map +1 -1
  20. package/dist/cli/commands/status.js +2 -2
  21. package/dist/cli/commands/status.js.map +1 -1
  22. package/dist/context/index.d.ts +9 -6
  23. package/dist/context/index.d.ts.map +1 -1
  24. package/dist/context/index.js +18 -20
  25. package/dist/context/index.js.map +1 -1
  26. package/dist/core/constraints/capabilities-parser.d.ts +3 -2
  27. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  28. package/dist/core/constraints/capabilities-parser.js +25 -47
  29. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  30. package/dist/core/constraints/checker.d.ts +29 -32
  31. package/dist/core/constraints/checker.d.ts.map +1 -1
  32. package/dist/core/constraints/checker.js +34 -126
  33. package/dist/core/constraints/checker.js.map +1 -1
  34. package/dist/core/constraints/checkers/index.d.ts +2 -1
  35. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  36. package/dist/core/constraints/checkers/index.js +3 -0
  37. package/dist/core/constraints/checkers/index.js.map +1 -1
  38. package/dist/core/constraints/checkers/types.d.ts +25 -0
  39. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  40. package/dist/core/constraints/checkers/types.js +24 -0
  41. package/dist/core/constraints/checkers/types.js.map +1 -1
  42. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  43. package/dist/core/constraints/definitions/guidelines.js +0 -2
  44. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  45. package/dist/core/constraints/definitions/prompts.d.ts.map +1 -1
  46. package/dist/core/constraints/definitions/prompts.js +0 -5
  47. package/dist/core/constraints/definitions/prompts.js.map +1 -1
  48. package/dist/core/constraints/index.d.ts +1 -2
  49. package/dist/core/constraints/index.d.ts.map +1 -1
  50. package/dist/core/constraints/index.js +1 -7
  51. package/dist/core/constraints/index.js.map +1 -1
  52. package/dist/core/constraints/usage-report.d.ts +1 -2
  53. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  54. package/dist/core/constraints/usage-report.js +2 -5
  55. package/dist/core/constraints/usage-report.js.map +1 -1
  56. package/dist/core/effective-constraints.d.ts +24 -4
  57. package/dist/core/effective-constraints.d.ts.map +1 -1
  58. package/dist/core/effective-constraints.js +28 -7
  59. package/dist/core/effective-constraints.js.map +1 -1
  60. package/dist/core/effective-set.d.ts +30 -0
  61. package/dist/core/effective-set.d.ts.map +1 -0
  62. package/dist/core/effective-set.js +35 -0
  63. package/dist/core/effective-set.js.map +1 -0
  64. package/dist/core/index.d.ts +13 -6
  65. package/dist/core/index.d.ts.map +1 -1
  66. package/dist/core/index.js +44 -21
  67. package/dist/core/index.js.map +1 -1
  68. package/dist/core/project-config-loader.d.ts +3 -6
  69. package/dist/core/project-config-loader.d.ts.map +1 -1
  70. package/dist/core/project-config-loader.js +47 -61
  71. package/dist/core/project-config-loader.js.map +1 -1
  72. package/dist/failure/constraint-handler.d.ts +1 -1
  73. package/dist/failure/constraint-handler.js +1 -1
  74. package/dist/gates/checker-gate.d.ts +1 -4
  75. package/dist/gates/checker-gate.d.ts.map +1 -1
  76. package/dist/gates/checker-gate.js +3 -11
  77. package/dist/gates/checker-gate.js.map +1 -1
  78. package/dist/gates/definitions.d.ts +9 -38
  79. package/dist/gates/definitions.d.ts.map +1 -1
  80. package/dist/gates/definitions.js +24 -13
  81. package/dist/gates/definitions.js.map +1 -1
  82. package/dist/gates/effective-gates.d.ts.map +1 -1
  83. package/dist/gates/effective-gates.js +14 -18
  84. package/dist/gates/effective-gates.js.map +1 -1
  85. package/dist/gates/index.d.ts +1 -1
  86. package/dist/gates/index.d.ts.map +1 -1
  87. package/dist/gates/index.js.map +1 -1
  88. package/dist/hooks/bootstrap.d.ts.map +1 -1
  89. package/dist/hooks/bootstrap.js +0 -3
  90. package/dist/hooks/bootstrap.js.map +1 -1
  91. package/dist/index.d.ts +43 -60
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +180 -143
  94. package/dist/index.js.map +1 -1
  95. package/dist/knowledge/query.d.ts +15 -0
  96. package/dist/knowledge/query.d.ts.map +1 -1
  97. package/dist/knowledge/query.js +23 -0
  98. package/dist/knowledge/query.js.map +1 -1
  99. package/dist/monitoring/analyzer-base.d.ts +0 -4
  100. package/dist/monitoring/analyzer-base.d.ts.map +1 -1
  101. package/dist/monitoring/analyzer-base.js +0 -21
  102. package/dist/monitoring/analyzer-base.js.map +1 -1
  103. package/dist/monitoring/index.d.ts +6 -12
  104. package/dist/monitoring/index.d.ts.map +1 -1
  105. package/dist/monitoring/index.js +13 -29
  106. package/dist/monitoring/index.js.map +1 -1
  107. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  108. package/dist/monitoring/trace-analyzer.js +2 -68
  109. package/dist/monitoring/trace-analyzer.js.map +1 -1
  110. package/dist/monitoring/traces.d.ts +0 -4
  111. package/dist/monitoring/traces.d.ts.map +1 -1
  112. package/dist/monitoring/traces.js +0 -14
  113. package/dist/monitoring/traces.js.map +1 -1
  114. package/dist/presets/index.d.ts +2 -2
  115. package/dist/presets/index.d.ts.map +1 -1
  116. package/dist/presets/index.js +3 -4
  117. package/dist/presets/index.js.map +1 -1
  118. package/dist/presets/standard.d.ts +10 -22
  119. package/dist/presets/standard.d.ts.map +1 -1
  120. package/dist/presets/standard.js +15 -75
  121. package/dist/presets/standard.js.map +1 -1
  122. package/dist/types/constraint.d.ts +1 -29
  123. package/dist/types/constraint.d.ts.map +1 -1
  124. package/dist/types/constraint.js +1 -1
  125. package/dist/types/constraint.js.map +1 -1
  126. package/dist/types/index.d.ts +0 -3
  127. package/dist/types/index.d.ts.map +1 -1
  128. package/dist/types/index.js +0 -4
  129. package/dist/types/index.js.map +1 -1
  130. package/dist/types/project-config.d.ts +4 -8
  131. package/dist/types/project-config.d.ts.map +1 -1
  132. package/dist/types/trace.d.ts +5 -18
  133. package/dist/types/trace.d.ts.map +1 -1
  134. package/package.json +2 -2
  135. package/src/CONTEXT.md +4 -5
  136. package/src/__tests__/checker-extra.test.ts +33 -139
  137. package/src/__tests__/checker.test.ts +0 -376
  138. package/src/__tests__/project-config-loader-extra.test.ts +42 -29
  139. package/src/__tests__/public-exports.test.ts +138 -0
  140. package/src/__tests__/trace-analyzer-extra.test.ts +6 -86
  141. package/src/__tests__/trace-analyzer.test.ts +4 -5
  142. package/src/__tests__/trace-collector.test.ts +0 -11
  143. package/src/__tests__/traces.test.ts +3 -22
  144. package/src/cli/commands/CONTEXT.md +2 -2
  145. package/src/cli/commands/__tests__/check-skip-output.test.ts +10 -7
  146. package/src/cli/commands/__tests__/check.test.ts +29 -69
  147. package/src/cli/commands/__tests__/constraints-report.test.ts +1 -1
  148. package/src/cli/commands/__tests__/knowledge.test.ts +90 -1
  149. package/src/cli/commands/__tests__/registry.test.ts +8 -6
  150. package/src/cli/commands/__tests__/status-extra.test.ts +6 -6
  151. package/src/cli/commands/__tests__/status.test.ts +6 -6
  152. package/src/cli/commands/check.ts +8 -34
  153. package/src/cli/commands/definitions.ts +2 -0
  154. package/src/cli/commands/init.ts +6 -37
  155. package/src/cli/commands/knowledge.ts +1 -16
  156. package/src/cli/commands/report.ts +0 -2
  157. package/src/cli/commands/status.ts +2 -2
  158. package/src/context/index.ts +29 -6
  159. package/src/core/CONTEXT.md +4 -3
  160. package/src/core/__tests__/effective-set.test.ts +80 -0
  161. package/src/core/constraints/capabilities-parser.ts +43 -49
  162. package/src/core/constraints/checker.ts +51 -145
  163. package/src/core/constraints/checkers/index.ts +2 -1
  164. package/src/core/constraints/checkers/types.ts +42 -0
  165. package/src/core/constraints/definitions/guidelines.ts +0 -2
  166. package/src/core/constraints/definitions/prompts.ts +0 -5
  167. package/src/core/constraints/index.ts +2 -17
  168. package/src/core/constraints/usage-report.ts +5 -8
  169. package/src/core/effective-constraints.ts +35 -7
  170. package/src/core/effective-set.ts +56 -0
  171. package/src/core/index.ts +80 -6
  172. package/src/core/project-config-loader.ts +53 -68
  173. package/src/failure/CONTEXT.md +1 -1
  174. package/src/failure/constraint-handler.ts +1 -1
  175. package/src/gates/CONTEXT.md +3 -3
  176. package/src/gates/checker-gate.ts +4 -12
  177. package/src/gates/definitions.ts +27 -50
  178. package/src/gates/effective-gates.ts +14 -21
  179. package/src/gates/index.ts +1 -1
  180. package/src/hooks/bootstrap.ts +0 -3
  181. package/src/index.ts +384 -148
  182. package/src/knowledge/CONTEXT.md +2 -2
  183. package/src/knowledge/__tests__/query.test.ts +64 -0
  184. package/src/knowledge/query.ts +28 -0
  185. package/src/monitoring/CONTEXT.md +7 -13
  186. package/src/monitoring/__tests__/traces.test.ts +0 -10
  187. package/src/monitoring/analyzer-base.ts +0 -22
  188. package/src/monitoring/index.ts +6 -12
  189. package/src/monitoring/trace-analyzer.ts +2 -73
  190. package/src/monitoring/traces.ts +0 -20
  191. package/src/presets/__tests__/standard.test.ts +48 -69
  192. package/src/presets/index.ts +3 -5
  193. package/src/presets/standard.ts +14 -79
  194. package/src/spec/CONTEXT.md +5 -13
  195. package/src/types/constraint.ts +1 -51
  196. package/src/types/index.ts +0 -12
  197. package/src/types/project-config.ts +4 -10
  198. package/src/types/trace.ts +5 -30
  199. package/dist/core/constraints/interceptor.d.ts +0 -39
  200. package/dist/core/constraints/interceptor.d.ts.map +0 -1
  201. package/dist/core/constraints/interceptor.js +0 -166
  202. package/dist/core/constraints/interceptor.js.map +0 -1
  203. package/dist/dashboard/data.d.ts +0 -31
  204. package/dist/dashboard/data.d.ts.map +0 -1
  205. package/dist/dashboard/data.js +0 -81
  206. package/dist/dashboard/data.js.map +0 -1
  207. package/dist/dashboard/index.d.ts +0 -4
  208. package/dist/dashboard/index.d.ts.map +0 -1
  209. package/dist/dashboard/index.js +0 -20
  210. package/dist/dashboard/index.js.map +0 -1
  211. package/dist/dashboard/stats.d.ts +0 -20
  212. package/dist/dashboard/stats.d.ts.map +0 -1
  213. package/dist/dashboard/stats.js +0 -115
  214. package/dist/dashboard/stats.js.map +0 -1
  215. package/dist/dashboard/types.d.ts +0 -110
  216. package/dist/dashboard/types.d.ts.map +0 -1
  217. package/dist/dashboard/types.js +0 -8
  218. package/dist/dashboard/types.js.map +0 -1
  219. package/dist/monitoring/constraint-doctor.d.ts +0 -76
  220. package/dist/monitoring/constraint-doctor.d.ts.map +0 -1
  221. package/dist/monitoring/constraint-doctor.js +0 -189
  222. package/dist/monitoring/constraint-doctor.js.map +0 -1
  223. package/dist/monitoring/diagnosis-rules.d.ts +0 -18
  224. package/dist/monitoring/diagnosis-rules.d.ts.map +0 -1
  225. package/dist/monitoring/diagnosis-rules.js +0 -119
  226. package/dist/monitoring/diagnosis-rules.js.map +0 -1
  227. package/dist/monitoring/knowledge-doctor.d.ts +0 -78
  228. package/dist/monitoring/knowledge-doctor.d.ts.map +0 -1
  229. package/dist/monitoring/knowledge-doctor.js +0 -266
  230. package/dist/monitoring/knowledge-doctor.js.map +0 -1
  231. package/dist/monitoring/knowledge-evolver.d.ts +0 -72
  232. package/dist/monitoring/knowledge-evolver.d.ts.map +0 -1
  233. package/dist/monitoring/knowledge-evolver.js +0 -205
  234. package/dist/monitoring/knowledge-evolver.js.map +0 -1
  235. package/dist/monitoring/performance-analyzer.d.ts +0 -92
  236. package/dist/monitoring/performance-analyzer.d.ts.map +0 -1
  237. package/dist/monitoring/performance-analyzer.js +0 -343
  238. package/dist/monitoring/performance-analyzer.js.map +0 -1
  239. package/dist/monitoring/performance-collector.d.ts +0 -103
  240. package/dist/monitoring/performance-collector.d.ts.map +0 -1
  241. package/dist/monitoring/performance-collector.js +0 -298
  242. package/dist/monitoring/performance-collector.js.map +0 -1
  243. package/dist/safety/index.d.ts +0 -6
  244. package/dist/safety/index.d.ts.map +0 -1
  245. package/dist/safety/index.js +0 -22
  246. package/dist/safety/index.js.map +0 -1
  247. package/dist/safety/input-guardrail.d.ts +0 -36
  248. package/dist/safety/input-guardrail.d.ts.map +0 -1
  249. package/dist/safety/input-guardrail.js +0 -118
  250. package/dist/safety/input-guardrail.js.map +0 -1
  251. package/dist/safety/output-guardrail.d.ts +0 -39
  252. package/dist/safety/output-guardrail.d.ts.map +0 -1
  253. package/dist/safety/output-guardrail.js +0 -147
  254. package/dist/safety/output-guardrail.js.map +0 -1
  255. package/dist/safety/sandbox.d.ts +0 -45
  256. package/dist/safety/sandbox.d.ts.map +0 -1
  257. package/dist/safety/sandbox.js +0 -134
  258. package/dist/safety/sandbox.js.map +0 -1
  259. package/dist/safety/tool-guardrail.d.ts +0 -51
  260. package/dist/safety/tool-guardrail.d.ts.map +0 -1
  261. package/dist/safety/tool-guardrail.js +0 -147
  262. package/dist/safety/tool-guardrail.js.map +0 -1
  263. package/dist/safety/types.d.ts +0 -104
  264. package/dist/safety/types.d.ts.map +0 -1
  265. package/dist/safety/types.js +0 -6
  266. package/dist/safety/types.js.map +0 -1
  267. package/dist/spec/annotation-checker.d.ts +0 -47
  268. package/dist/spec/annotation-checker.d.ts.map +0 -1
  269. package/dist/spec/annotation-checker.js +0 -279
  270. package/dist/spec/annotation-checker.js.map +0 -1
  271. package/dist/types/enforcement.d.ts +0 -42
  272. package/dist/types/enforcement.d.ts.map +0 -1
  273. package/dist/types/enforcement.js +0 -6
  274. package/dist/types/enforcement.js.map +0 -1
  275. package/dist/types/monitoring-types.d.ts +0 -53
  276. package/dist/types/monitoring-types.d.ts.map +0 -1
  277. package/dist/types/monitoring-types.js +0 -10
  278. package/dist/types/monitoring-types.js.map +0 -1
  279. package/dist/types/performance.d.ts +0 -204
  280. package/dist/types/performance.d.ts.map +0 -1
  281. package/dist/types/performance.js +0 -12
  282. package/dist/types/performance.js.map +0 -1
  283. package/dist/verification/index.d.ts +0 -4
  284. package/dist/verification/index.d.ts.map +0 -1
  285. package/dist/verification/index.js +0 -20
  286. package/dist/verification/index.js.map +0 -1
  287. package/dist/verification/loop.d.ts +0 -30
  288. package/dist/verification/loop.d.ts.map +0 -1
  289. package/dist/verification/loop.js +0 -114
  290. package/dist/verification/loop.js.map +0 -1
  291. package/dist/verification/rules-based.d.ts +0 -40
  292. package/dist/verification/rules-based.d.ts.map +0 -1
  293. package/dist/verification/rules-based.js +0 -130
  294. package/dist/verification/rules-based.js.map +0 -1
  295. package/dist/verification/types.d.ts +0 -69
  296. package/dist/verification/types.d.ts.map +0 -1
  297. package/dist/verification/types.js +0 -6
  298. package/dist/verification/types.js.map +0 -1
  299. package/src/__tests__/annotation-checker.test.ts +0 -183
  300. package/src/__tests__/constraint-doctor.test.ts +0 -271
  301. package/src/__tests__/doctor-extra.test.ts +0 -155
  302. package/src/__tests__/extend-exceptions.test.ts +0 -149
  303. package/src/__tests__/interceptor.test.ts +0 -89
  304. package/src/__tests__/performance-analyzer.test.ts +0 -499
  305. package/src/__tests__/performance-collector.test.ts +0 -276
  306. package/src/__tests__/presets.test.ts +0 -65
  307. package/src/core/constraints/__tests__/interceptor.test.ts +0 -267
  308. package/src/core/constraints/interceptor.ts +0 -217
  309. package/src/dashboard/CONTEXT.md +0 -21
  310. package/src/dashboard/__tests__/data.test.ts +0 -111
  311. package/src/dashboard/__tests__/stats.test.ts +0 -159
  312. package/src/dashboard/data.ts +0 -103
  313. package/src/dashboard/index.ts +0 -3
  314. package/src/dashboard/stats.ts +0 -127
  315. package/src/dashboard/types.ts +0 -130
  316. package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -278
  317. package/src/monitoring/__tests__/knowledge-evolver.test.ts +0 -368
  318. package/src/monitoring/__tests__/performance-analyzer.test.ts +0 -137
  319. package/src/monitoring/__tests__/performance-collector.test.ts +0 -331
  320. package/src/monitoring/constraint-doctor.ts +0 -228
  321. package/src/monitoring/diagnosis-rules.ts +0 -132
  322. package/src/monitoring/knowledge-doctor.ts +0 -322
  323. package/src/monitoring/knowledge-evolver.ts +0 -289
  324. package/src/monitoring/performance-analyzer.ts +0 -400
  325. package/src/monitoring/performance-collector.ts +0 -326
  326. package/src/safety/CONTEXT.md +0 -23
  327. package/src/safety/__tests__/input-guardrail.test.ts +0 -105
  328. package/src/safety/__tests__/output-guardrail.test.ts +0 -108
  329. package/src/safety/__tests__/sandbox.test.ts +0 -158
  330. package/src/safety/__tests__/tool-guardrail.test.ts +0 -127
  331. package/src/safety/index.ts +0 -5
  332. package/src/safety/input-guardrail.ts +0 -133
  333. package/src/safety/output-guardrail.ts +0 -170
  334. package/src/safety/sandbox.ts +0 -148
  335. package/src/safety/tool-guardrail.ts +0 -176
  336. package/src/safety/types.ts +0 -124
  337. package/src/spec/__tests__/annotation-checker.test.ts +0 -294
  338. package/src/spec/annotation-checker.ts +0 -320
  339. package/src/types/enforcement.ts +0 -48
  340. package/src/types/monitoring-types.ts +0 -68
  341. package/src/types/performance.ts +0 -295
  342. package/src/verification/CONTEXT.md +0 -23
  343. package/src/verification/__tests__/loop.test.ts +0 -303
  344. package/src/verification/__tests__/rules-based.test.ts +0 -240
  345. package/src/verification/index.ts +0 -3
  346. package/src/verification/loop.ts +0 -137
  347. package/src/verification/rules-based.ts +0 -152
  348. package/src/verification/types.ts +0 -81
@@ -1,499 +0,0 @@
1
- /**
2
- * PerformanceAnalyzer 测试
3
- */
4
-
5
- import { PerformanceAnalyzer, createPerformanceAnalyzer } from '../monitoring/performance-analyzer';
6
- import { PerformanceCollector } from '../monitoring/performance-collector';
7
- import type { PerformanceTrace, PerformanceSummary } from '../types/performance';
8
- import * as fs from 'fs';
9
-
10
- // Mock fs
11
- jest.mock('fs', () => ({
12
- existsSync: jest.fn(),
13
- mkdirSync: jest.fn(),
14
- readFileSync: jest.fn(),
15
- writeFileSync: jest.fn(),
16
- }));
17
-
18
- // Mock PerformanceCollector
19
- jest.mock('../monitoring/performance-collector', () => ({
20
- PerformanceCollector: jest.fn().mockImplementation(() => ({
21
- readRecent: jest.fn().mockReturnValue([]),
22
- readByOperation: jest.fn().mockReturnValue([]),
23
- })),
24
- }));
25
-
26
- const mockFs = fs as jest.Mocked<typeof fs>;
27
-
28
- describe('PerformanceAnalyzer', () => {
29
- let analyzer: PerformanceAnalyzer;
30
- let mockCollector: jest.Mocked<PerformanceCollector>;
31
-
32
- beforeEach(() => {
33
- jest.clearAllMocks();
34
- mockCollector = new PerformanceCollector() as jest.Mocked<PerformanceCollector>;
35
- analyzer = new PerformanceAnalyzer(mockCollector);
36
- });
37
-
38
- describe('summarize', () => {
39
- it('应该生成空的汇总列表(无 traces)', () => {
40
- const summaries = analyzer.summarize([]);
41
- expect(summaries).toEqual([]);
42
- });
43
-
44
- it('应该按操作类型分组', () => {
45
- const traces: PerformanceTrace[] = [
46
- { operation: 'op1', duration: 100, result: 'ok', timestamp: 1000 },
47
- { operation: 'op1', duration: 200, result: 'ok', timestamp: 2000 },
48
- { operation: 'op2', duration: 50, result: 'ok', timestamp: 3000 },
49
- ];
50
-
51
- const summaries = analyzer.summarize(traces);
52
-
53
- expect(summaries.length).toBe(2);
54
- expect(summaries.find(s => s.operation === 'op1')?.totalCalls).toBe(2);
55
- expect(summaries.find(s => s.operation === 'op2')?.totalCalls).toBe(1);
56
- });
57
-
58
- it('应该正确计算统计值', () => {
59
- const traces: PerformanceTrace[] = [
60
- { operation: 'test', duration: 100, result: 'ok', timestamp: 1000 },
61
- { operation: 'test', duration: 200, result: 'exceeded', timestamp: 2000 },
62
- { operation: 'test', duration: 300, result: 'error', timestamp: 3000 },
63
- ];
64
-
65
- const summaries = analyzer.summarize(traces);
66
- const summary = summaries[0];
67
-
68
- expect(summary.totalCalls).toBe(3);
69
- expect(summary.okCount).toBe(1);
70
- expect(summary.exceededCount).toBe(1);
71
- expect(summary.errorCount).toBe(1);
72
- expect(summary.avgDuration).toBe(200);
73
- expect(summary.maxDuration).toBe(300);
74
- expect(summary.minDuration).toBe(100);
75
- expect(summary.okRate).toBeCloseTo(1/3);
76
- expect(summary.exceededRate).toBeCloseTo(1/3);
77
- expect(summary.errorRate).toBeCloseTo(1/3);
78
- });
79
-
80
- it('应该计算百分位数', () => {
81
- // 生成 100 个数据点
82
- const traces: PerformanceTrace[] = [];
83
- for (let i = 1; i <= 100; i++) {
84
- traces.push({
85
- operation: 'test',
86
- duration: i * 10,
87
- result: 'ok',
88
- timestamp: i * 1000,
89
- });
90
- }
91
-
92
- const summaries = analyzer.summarize(traces);
93
- const summary = summaries[0];
94
-
95
- // P95 ≈ 95 * 10 = 950
96
- expect(summary.p95Duration).toBeGreaterThanOrEqual(900);
97
- // P99 ≈ 99 * 10 = 990
98
- expect(summary.p99Duration).toBeGreaterThanOrEqual(980);
99
- });
100
-
101
- it('应该判断趋势为 stable(少于10个数据)', () => {
102
- const traces: PerformanceTrace[] = [];
103
- for (let i = 0; i < 5; i++) {
104
- traces.push({
105
- operation: 'test',
106
- duration: 100,
107
- result: 'ok',
108
- timestamp: i * 1000,
109
- });
110
- }
111
-
112
- const summaries = analyzer.summarize(traces);
113
- expect(summaries[0]?.recentTrend).toBe('stable');
114
- });
115
-
116
- it('应该判断趋势为 rising', () => {
117
- const traces: PerformanceTrace[] = [];
118
- // 前半段 100ms,后半段 500ms,变化率 400%
119
- for (let i = 0; i < 5; i++) {
120
- traces.push({
121
- operation: 'test',
122
- duration: 100,
123
- result: 'ok',
124
- timestamp: i * 1000,
125
- });
126
- }
127
- for (let i = 5; i < 10; i++) {
128
- traces.push({
129
- operation: 'test',
130
- duration: 500,
131
- result: 'ok',
132
- timestamp: i * 1000,
133
- });
134
- }
135
-
136
- const summaries = analyzer.summarize(traces);
137
- expect(summaries[0]?.recentTrend).toBe('rising');
138
- });
139
-
140
- it('应该判断趋势为 falling', () => {
141
- const traces: PerformanceTrace[] = [];
142
- // 前半段 500ms,后半段 100ms
143
- for (let i = 0; i < 5; i++) {
144
- traces.push({
145
- operation: 'test',
146
- duration: 500,
147
- result: 'ok',
148
- timestamp: i * 1000,
149
- });
150
- }
151
- for (let i = 5; i < 10; i++) {
152
- traces.push({
153
- operation: 'test',
154
- duration: 100,
155
- result: 'ok',
156
- timestamp: i * 1000,
157
- });
158
- }
159
-
160
- const summaries = analyzer.summarize(traces);
161
- expect(summaries[0]?.recentTrend).toBe('falling');
162
- });
163
- });
164
-
165
- describe('detectAnomalies', () => {
166
- it('应该检测高平均耗时异常', () => {
167
- const summaries: PerformanceSummary[] = [{
168
- operation: 'slow-op',
169
- timeRange: { start: 1000, end: 2000 },
170
- totalCalls: 10,
171
- okCount: 10,
172
- exceededCount: 0,
173
- errorCount: 0,
174
- avgDuration: 6000, // 超过阈值 5000
175
- maxDuration: 8000,
176
- minDuration: 5000,
177
- p95Duration: 7000,
178
- p99Duration: 7500,
179
- okRate: 1,
180
- exceededRate: 0,
181
- errorRate: 0,
182
- recentTrend: 'stable',
183
- }];
184
-
185
- const anomalies = analyzer.detectAnomalies(summaries);
186
-
187
- expect(anomalies.length).toBeGreaterThan(0);
188
- expect(anomalies.some(a => a.type === 'high_avg_duration')).toBe(true);
189
- });
190
-
191
- it('应该检测高超阈值率异常', () => {
192
- const summaries: PerformanceSummary[] = [{
193
- operation: 'exceeded-op',
194
- timeRange: { start: 1000, end: 2000 },
195
- totalCalls: 10,
196
- okCount: 6,
197
- exceededCount: 4,
198
- errorCount: 0,
199
- avgDuration: 1000,
200
- maxDuration: 2000,
201
- minDuration: 500,
202
- p95Duration: 1800,
203
- p99Duration: 1900,
204
- okRate: 0.6,
205
- exceededRate: 0.4, // 超过阈值 0.3
206
- errorRate: 0,
207
- recentTrend: 'stable',
208
- }];
209
-
210
- const anomalies = analyzer.detectAnomalies(summaries);
211
-
212
- expect(anomalies.some(a => a.type === 'high_exceeded_rate')).toBe(true);
213
- });
214
-
215
- it('应该检测高错误率异常', () => {
216
- const summaries: PerformanceSummary[] = [{
217
- operation: 'error-op',
218
- timeRange: { start: 1000, end: 2000 },
219
- totalCalls: 10,
220
- okCount: 8,
221
- exceededCount: 0,
222
- errorCount: 2,
223
- avgDuration: 1000,
224
- maxDuration: 2000,
225
- minDuration: 500,
226
- p95Duration: 1800,
227
- p99Duration: 1900,
228
- okRate: 0.8,
229
- exceededRate: 0,
230
- errorRate: 0.2, // 超过阈值 0.1
231
- recentTrend: 'stable',
232
- }];
233
-
234
- const anomalies = analyzer.detectAnomalies(summaries);
235
-
236
- expect(anomalies.some(a => a.type === 'high_error_rate')).toBe(true);
237
- });
238
-
239
- it('应该检测趋势上升异常', () => {
240
- const summaries: PerformanceSummary[] = [{
241
- operation: 'rising-op',
242
- timeRange: { start: 1000, end: 2000 },
243
- totalCalls: 10,
244
- okCount: 10,
245
- exceededCount: 0,
246
- errorCount: 0,
247
- avgDuration: 1000,
248
- maxDuration: 2000,
249
- minDuration: 500,
250
- p95Duration: 1800,
251
- p99Duration: 1900,
252
- okRate: 1,
253
- exceededRate: 0,
254
- errorRate: 0,
255
- recentTrend: 'rising',
256
- }];
257
-
258
- const anomalies = analyzer.detectAnomalies(summaries);
259
-
260
- expect(anomalies.some(a => a.type === 'rising_duration')).toBe(true);
261
- });
262
-
263
- it('应该返回空数组(无异常)', () => {
264
- const summaries: PerformanceSummary[] = [{
265
- operation: 'healthy-op',
266
- timeRange: { start: 1000, end: 2000 },
267
- totalCalls: 10,
268
- okCount: 10,
269
- exceededCount: 0,
270
- errorCount: 0,
271
- avgDuration: 100, // 低于阈值
272
- maxDuration: 200,
273
- minDuration: 50,
274
- p95Duration: 180,
275
- p99Duration: 190,
276
- okRate: 1,
277
- exceededRate: 0,
278
- errorRate: 0,
279
- recentTrend: 'stable',
280
- }];
281
-
282
- const anomalies = analyzer.detectAnomalies(summaries);
283
-
284
- expect(anomalies.length).toBe(0);
285
- });
286
- });
287
-
288
- describe('compareWithPrevious', () => {
289
- it('应该计算环比变化', () => {
290
- const current: PerformanceSummary[] = [{
291
- operation: 'test',
292
- timeRange: { start: 2000, end: 3000 },
293
- totalCalls: 10,
294
- okCount: 10,
295
- exceededCount: 0,
296
- errorCount: 0,
297
- avgDuration: 150, // +50
298
- maxDuration: 200,
299
- minDuration: 100,
300
- p95Duration: 180,
301
- p99Duration: 190,
302
- okRate: 1,
303
- exceededRate: 0.05, // +5%
304
- errorRate: 0,
305
- recentTrend: 'stable',
306
- }];
307
-
308
- const previous: PerformanceSummary[] = [{
309
- operation: 'test',
310
- timeRange: { start: 1000, end: 2000 },
311
- totalCalls: 10,
312
- okCount: 10,
313
- exceededCount: 0,
314
- errorCount: 0,
315
- avgDuration: 100,
316
- maxDuration: 150,
317
- minDuration: 50,
318
- p95Duration: 140,
319
- p99Duration: 145,
320
- okRate: 1,
321
- exceededRate: 0,
322
- errorRate: 0,
323
- recentTrend: 'stable',
324
- }];
325
-
326
- const result = analyzer.compareWithPrevious(current, previous);
327
-
328
- expect(result[0]?.changeFromLastPeriod?.avgDurationDelta).toBe(50);
329
- expect(result[0]?.changeFromLastPeriod?.exceededRateDelta).toBe(0.05);
330
- });
331
-
332
- it('应该处理无历史数据的情况', () => {
333
- const current: PerformanceSummary[] = [{
334
- operation: 'new-op',
335
- timeRange: { start: 1000, end: 2000 },
336
- totalCalls: 10,
337
- okCount: 10,
338
- exceededCount: 0,
339
- errorCount: 0,
340
- avgDuration: 100,
341
- maxDuration: 200,
342
- minDuration: 50,
343
- p95Duration: 180,
344
- p99Duration: 190,
345
- okRate: 1,
346
- exceededRate: 0,
347
- errorRate: 0,
348
- recentTrend: 'stable',
349
- }];
350
-
351
- const result = analyzer.compareWithPrevious(current, []);
352
-
353
- expect(result[0]?.changeFromLastPeriod).toBeUndefined();
354
- });
355
- });
356
-
357
- describe('analyzeRecent', () => {
358
- it('应该调用 collector.readRecent', () => {
359
- mockCollector.readRecent.mockReturnValue([]);
360
-
361
- analyzer.analyzeRecent(1);
362
-
363
- expect(mockCollector.readRecent).toHaveBeenCalledWith(1);
364
- });
365
- });
366
-
367
- describe('analyzeOperation', () => {
368
- it('应该调用 collector.readByOperation', () => {
369
- mockCollector.readByOperation.mockReturnValue([]);
370
-
371
- analyzer.analyzeOperation('test-op');
372
-
373
- expect(mockCollector.readByOperation).toHaveBeenCalledWith('test-op');
374
- });
375
- });
376
-
377
- describe('saveSummary / loadSummary', () => {
378
- it('应该保存汇总结果', () => {
379
- mockFs.existsSync.mockReturnValue(true);
380
- mockFs.mkdirSync.mockReturnValue(undefined);
381
-
382
- analyzer.saveSummary([]);
383
-
384
- expect(mockFs.writeFileSync).toHaveBeenCalled();
385
- });
386
-
387
- it('应该加载汇总结果', () => {
388
- mockFs.existsSync.mockReturnValue(true);
389
- mockFs.readFileSync.mockReturnValue('[]');
390
-
391
- const result = analyzer.loadSummary();
392
-
393
- expect(result).toEqual([]);
394
- });
395
-
396
- it('应该返回 null(文件不存在)', () => {
397
- mockFs.existsSync.mockReturnValue(false);
398
-
399
- const result = analyzer.loadSummary();
400
-
401
- expect(result).toBeNull();
402
- });
403
- });
404
-
405
- describe('runHourlySummary', () => {
406
- it('应该执行小时汇总', () => {
407
- mockCollector.readRecent.mockReturnValue([]);
408
- mockFs.existsSync.mockReturnValue(false);
409
-
410
- const result = analyzer.runHourlySummary();
411
-
412
- expect(mockCollector.readRecent).toHaveBeenCalledWith(1);
413
- expect(result).toBeDefined();
414
- });
415
-
416
- it('应该对比上次汇总', () => {
417
- mockCollector.readRecent.mockReturnValue([]);
418
- mockFs.existsSync.mockReturnValue(true);
419
- mockFs.readFileSync.mockReturnValue('[]');
420
-
421
- analyzer.runHourlySummary();
422
-
423
- expect(mockFs.readFileSync).toHaveBeenCalled();
424
- });
425
- });
426
-
427
- describe('runDailyAnomalyCheck', () => {
428
- it('应该执行每日异常检测', () => {
429
- mockCollector.readRecent.mockReturnValue([]);
430
-
431
- const anomalies = analyzer.runDailyAnomalyCheck();
432
-
433
- expect(mockCollector.readRecent).toHaveBeenCalledWith(24);
434
- expect(Array.isArray(anomalies)).toBe(true);
435
- });
436
- });
437
-
438
- describe('generateReport', () => {
439
- it('应该生成报告文本', () => {
440
- const summaries: PerformanceSummary[] = [{
441
- operation: 'test',
442
- timeRange: { start: 1000, end: 2000 },
443
- totalCalls: 10,
444
- okCount: 10,
445
- exceededCount: 0,
446
- errorCount: 0,
447
- avgDuration: 100,
448
- maxDuration: 200,
449
- minDuration: 50,
450
- p95Duration: 180,
451
- p99Duration: 190,
452
- okRate: 1,
453
- exceededRate: 0,
454
- errorRate: 0,
455
- recentTrend: 'stable',
456
- }];
457
-
458
- const report = analyzer.generateReport(summaries, []);
459
-
460
- expect(report).toContain('Performance Report');
461
- expect(report).toContain('test');
462
- expect(report).toContain('Calls: 10');
463
- expect(report).toContain('No Anomalies Detected');
464
- });
465
-
466
- it('应该包含异常信息', () => {
467
- const summaries: PerformanceSummary[] = [{
468
- operation: 'slow-op',
469
- timeRange: { start: 1000, end: 2000 },
470
- totalCalls: 10,
471
- okCount: 10,
472
- exceededCount: 0,
473
- errorCount: 0,
474
- avgDuration: 6000,
475
- maxDuration: 8000,
476
- minDuration: 5000,
477
- p95Duration: 7000,
478
- p99Duration: 7500,
479
- okRate: 1,
480
- exceededRate: 0,
481
- errorRate: 0,
482
- recentTrend: 'stable',
483
- }];
484
-
485
- const anomalies = analyzer.detectAnomalies(summaries);
486
- const report = analyzer.generateReport(summaries, anomalies);
487
-
488
- expect(report).toContain('Anomalies Detected');
489
- expect(report).toContain('high_avg_duration');
490
- });
491
- });
492
-
493
- describe('createPerformanceAnalyzer', () => {
494
- it('应该创建分析器实例', () => {
495
- const instance = createPerformanceAnalyzer();
496
- expect(instance).toBeInstanceOf(PerformanceAnalyzer);
497
- });
498
- });
499
- });