@opensip-cli/simulation 0.1.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/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/internal-surface.test.d.ts +9 -0
  5. package/dist/__tests__/internal-surface.test.d.ts.map +1 -0
  6. package/dist/__tests__/internal-surface.test.js +38 -0
  7. package/dist/__tests__/internal-surface.test.js.map +1 -0
  8. package/dist/__tests__/plugin-loader.test.d.ts +2 -0
  9. package/dist/__tests__/plugin-loader.test.d.ts.map +1 -0
  10. package/dist/__tests__/plugin-loader.test.js +64 -0
  11. package/dist/__tests__/plugin-loader.test.js.map +1 -0
  12. package/dist/__tests__/public-api.test.d.ts +15 -0
  13. package/dist/__tests__/public-api.test.d.ts.map +1 -0
  14. package/dist/__tests__/public-api.test.js +73 -0
  15. package/dist/__tests__/public-api.test.js.map +1 -0
  16. package/dist/__tests__/registry-cross-kind.test.d.ts +6 -0
  17. package/dist/__tests__/registry-cross-kind.test.d.ts.map +1 -0
  18. package/dist/__tests__/registry-cross-kind.test.js +86 -0
  19. package/dist/__tests__/registry-cross-kind.test.js.map +1 -0
  20. package/dist/__tests__/scenario-execution.test.d.ts +10 -0
  21. package/dist/__tests__/scenario-execution.test.d.ts.map +1 -0
  22. package/dist/__tests__/scenario-execution.test.js +92 -0
  23. package/dist/__tests__/scenario-execution.test.js.map +1 -0
  24. package/dist/__tests__/sim-capability-contract.test.d.ts +10 -0
  25. package/dist/__tests__/sim-capability-contract.test.d.ts.map +1 -0
  26. package/dist/__tests__/sim-capability-contract.test.js +131 -0
  27. package/dist/__tests__/sim-capability-contract.test.js.map +1 -0
  28. package/dist/__tests__/sim-config-schema.test.d.ts +5 -0
  29. package/dist/__tests__/sim-config-schema.test.d.ts.map +1 -0
  30. package/dist/__tests__/sim-config-schema.test.js +23 -0
  31. package/dist/__tests__/sim-config-schema.test.js.map +1 -0
  32. package/dist/__tests__/sim-failure-signal.test.d.ts +10 -0
  33. package/dist/__tests__/sim-failure-signal.test.d.ts.map +1 -0
  34. package/dist/__tests__/sim-failure-signal.test.js +86 -0
  35. package/dist/__tests__/sim-failure-signal.test.js.map +1 -0
  36. package/dist/__tests__/surviving-surface-edges.test.d.ts +10 -0
  37. package/dist/__tests__/surviving-surface-edges.test.d.ts.map +1 -0
  38. package/dist/__tests__/surviving-surface-edges.test.js +122 -0
  39. package/dist/__tests__/surviving-surface-edges.test.js.map +1 -0
  40. package/dist/__tests__/test-utils/targets.d.ts +26 -0
  41. package/dist/__tests__/test-utils/targets.d.ts.map +1 -0
  42. package/dist/__tests__/test-utils/targets.js +38 -0
  43. package/dist/__tests__/test-utils/targets.js.map +1 -0
  44. package/dist/__tests__/test-utils/with-sim-scope.d.ts +12 -0
  45. package/dist/__tests__/test-utils/with-sim-scope.d.ts.map +1 -0
  46. package/dist/__tests__/test-utils/with-sim-scope.js +22 -0
  47. package/dist/__tests__/test-utils/with-sim-scope.js.map +1 -0
  48. package/dist/__tests__/tool-live-view.test.d.ts +20 -0
  49. package/dist/__tests__/tool-live-view.test.d.ts.map +1 -0
  50. package/dist/__tests__/tool-live-view.test.js +146 -0
  51. package/dist/__tests__/tool-live-view.test.js.map +1 -0
  52. package/dist/__tests__/tool-show-mode.test.d.ts +10 -0
  53. package/dist/__tests__/tool-show-mode.test.d.ts.map +1 -0
  54. package/dist/__tests__/tool-show-mode.test.js +156 -0
  55. package/dist/__tests__/tool-show-mode.test.js.map +1 -0
  56. package/dist/__tests__/tool.test.d.ts +15 -0
  57. package/dist/__tests__/tool.test.d.ts.map +1 -0
  58. package/dist/__tests__/tool.test.js +250 -0
  59. package/dist/__tests__/tool.test.js.map +1 -0
  60. package/dist/cli/__tests__/sim-config.test.d.ts +2 -0
  61. package/dist/cli/__tests__/sim-config.test.d.ts.map +1 -0
  62. package/dist/cli/__tests__/sim-config.test.js +94 -0
  63. package/dist/cli/__tests__/sim-config.test.js.map +1 -0
  64. package/dist/cli/__tests__/sim-runner.test.d.ts +23 -0
  65. package/dist/cli/__tests__/sim-runner.test.d.ts.map +1 -0
  66. package/dist/cli/__tests__/sim-runner.test.js +188 -0
  67. package/dist/cli/__tests__/sim-runner.test.js.map +1 -0
  68. package/dist/cli/__tests__/sim-worker.test.d.ts +12 -0
  69. package/dist/cli/__tests__/sim-worker.test.d.ts.map +1 -0
  70. package/dist/cli/__tests__/sim-worker.test.js +69 -0
  71. package/dist/cli/__tests__/sim-worker.test.js.map +1 -0
  72. package/dist/cli/__tests__/sim.test.d.ts +2 -0
  73. package/dist/cli/__tests__/sim.test.d.ts.map +1 -0
  74. package/dist/cli/__tests__/sim.test.js +232 -0
  75. package/dist/cli/__tests__/sim.test.js.map +1 -0
  76. package/dist/cli/sim-config-schema.d.ts +30 -0
  77. package/dist/cli/sim-config-schema.d.ts.map +1 -0
  78. package/dist/cli/sim-config-schema.js +33 -0
  79. package/dist/cli/sim-config-schema.js.map +1 -0
  80. package/dist/cli/sim-config.d.ts +22 -0
  81. package/dist/cli/sim-config.d.ts.map +1 -0
  82. package/dist/cli/sim-config.js +73 -0
  83. package/dist/cli/sim-config.js.map +1 -0
  84. package/dist/cli/sim-runner.d.ts +60 -0
  85. package/dist/cli/sim-runner.d.ts.map +1 -0
  86. package/dist/cli/sim-runner.js +175 -0
  87. package/dist/cli/sim-runner.js.map +1 -0
  88. package/dist/cli/sim-worker.d.ts +24 -0
  89. package/dist/cli/sim-worker.d.ts.map +1 -0
  90. package/dist/cli/sim-worker.js +65 -0
  91. package/dist/cli/sim-worker.js.map +1 -0
  92. package/dist/cli/sim.d.ts +56 -0
  93. package/dist/cli/sim.d.ts.map +1 -0
  94. package/dist/cli/sim.js +265 -0
  95. package/dist/cli/sim.js.map +1 -0
  96. package/dist/framework/__tests__/assertions.test.d.ts +2 -0
  97. package/dist/framework/__tests__/assertions.test.d.ts.map +1 -0
  98. package/dist/framework/__tests__/assertions.test.js +122 -0
  99. package/dist/framework/__tests__/assertions.test.js.map +1 -0
  100. package/dist/framework/__tests__/misc-coverage.test.d.ts +18 -0
  101. package/dist/framework/__tests__/misc-coverage.test.d.ts.map +1 -0
  102. package/dist/framework/__tests__/misc-coverage.test.js +142 -0
  103. package/dist/framework/__tests__/misc-coverage.test.js.map +1 -0
  104. package/dist/framework/__tests__/resolve-metric.test.d.ts +12 -0
  105. package/dist/framework/__tests__/resolve-metric.test.d.ts.map +1 -0
  106. package/dist/framework/__tests__/resolve-metric.test.js +124 -0
  107. package/dist/framework/__tests__/resolve-metric.test.js.map +1 -0
  108. package/dist/framework/__tests__/result-builder.test.d.ts +2 -0
  109. package/dist/framework/__tests__/result-builder.test.d.ts.map +1 -0
  110. package/dist/framework/__tests__/result-builder.test.js +180 -0
  111. package/dist/framework/__tests__/result-builder.test.js.map +1 -0
  112. package/dist/framework/__tests__/scenario-logger.test.d.ts +9 -0
  113. package/dist/framework/__tests__/scenario-logger.test.d.ts.map +1 -0
  114. package/dist/framework/__tests__/scenario-logger.test.js +110 -0
  115. package/dist/framework/__tests__/scenario-logger.test.js.map +1 -0
  116. package/dist/framework/__tests__/validation.test.d.ts +9 -0
  117. package/dist/framework/__tests__/validation.test.d.ts.map +1 -0
  118. package/dist/framework/__tests__/validation.test.js +126 -0
  119. package/dist/framework/__tests__/validation.test.js.map +1 -0
  120. package/dist/framework/assertions.d.ts +106 -0
  121. package/dist/framework/assertions.d.ts.map +1 -0
  122. package/dist/framework/assertions.js +256 -0
  123. package/dist/framework/assertions.js.map +1 -0
  124. package/dist/framework/execution/__tests__/execution-engine.test.d.ts +9 -0
  125. package/dist/framework/execution/__tests__/execution-engine.test.d.ts.map +1 -0
  126. package/dist/framework/execution/__tests__/execution-engine.test.js +138 -0
  127. package/dist/framework/execution/__tests__/execution-engine.test.js.map +1 -0
  128. package/dist/framework/execution/__tests__/fault-builders.test.d.ts +5 -0
  129. package/dist/framework/execution/__tests__/fault-builders.test.d.ts.map +1 -0
  130. package/dist/framework/execution/__tests__/fault-builders.test.js +23 -0
  131. package/dist/framework/execution/__tests__/fault-builders.test.js.map +1 -0
  132. package/dist/framework/execution/__tests__/fault-model.test.d.ts +6 -0
  133. package/dist/framework/execution/__tests__/fault-model.test.d.ts.map +1 -0
  134. package/dist/framework/execution/__tests__/fault-model.test.js +64 -0
  135. package/dist/framework/execution/__tests__/fault-model.test.js.map +1 -0
  136. package/dist/framework/execution/__tests__/http-target.test.d.ts +5 -0
  137. package/dist/framework/execution/__tests__/http-target.test.d.ts.map +1 -0
  138. package/dist/framework/execution/__tests__/http-target.test.js +36 -0
  139. package/dist/framework/execution/__tests__/http-target.test.js.map +1 -0
  140. package/dist/framework/execution/__tests__/run-load-window.test.d.ts +7 -0
  141. package/dist/framework/execution/__tests__/run-load-window.test.d.ts.map +1 -0
  142. package/dist/framework/execution/__tests__/run-load-window.test.js +89 -0
  143. package/dist/framework/execution/__tests__/run-load-window.test.js.map +1 -0
  144. package/dist/framework/execution/execution-engine.d.ts +55 -0
  145. package/dist/framework/execution/execution-engine.d.ts.map +1 -0
  146. package/dist/framework/execution/execution-engine.js +111 -0
  147. package/dist/framework/execution/execution-engine.js.map +1 -0
  148. package/dist/framework/execution/fault-builders.d.ts +26 -0
  149. package/dist/framework/execution/fault-builders.d.ts.map +1 -0
  150. package/dist/framework/execution/fault-builders.js +24 -0
  151. package/dist/framework/execution/fault-builders.js.map +1 -0
  152. package/dist/framework/execution/fault-model.d.ts +49 -0
  153. package/dist/framework/execution/fault-model.d.ts.map +1 -0
  154. package/dist/framework/execution/fault-model.js +108 -0
  155. package/dist/framework/execution/fault-model.js.map +1 -0
  156. package/dist/framework/execution/fault-spec.d.ts +40 -0
  157. package/dist/framework/execution/fault-spec.d.ts.map +1 -0
  158. package/dist/framework/execution/fault-spec.js +23 -0
  159. package/dist/framework/execution/fault-spec.js.map +1 -0
  160. package/dist/framework/execution/http-target.d.ts +34 -0
  161. package/dist/framework/execution/http-target.d.ts.map +1 -0
  162. package/dist/framework/execution/http-target.js +41 -0
  163. package/dist/framework/execution/http-target.js.map +1 -0
  164. package/dist/framework/execution/latency-tracker.d.ts +44 -0
  165. package/dist/framework/execution/latency-tracker.d.ts.map +1 -0
  166. package/dist/framework/execution/latency-tracker.js +76 -0
  167. package/dist/framework/execution/latency-tracker.js.map +1 -0
  168. package/dist/framework/execution/run-load-window.d.ts +45 -0
  169. package/dist/framework/execution/run-load-window.d.ts.map +1 -0
  170. package/dist/framework/execution/run-load-window.js +136 -0
  171. package/dist/framework/execution/run-load-window.js.map +1 -0
  172. package/dist/framework/execution/scenario-aborted-error.d.ts +14 -0
  173. package/dist/framework/execution/scenario-aborted-error.d.ts.map +1 -0
  174. package/dist/framework/execution/scenario-aborted-error.js +24 -0
  175. package/dist/framework/execution/scenario-aborted-error.js.map +1 -0
  176. package/dist/framework/execution/target.d.ts +35 -0
  177. package/dist/framework/execution/target.d.ts.map +1 -0
  178. package/dist/framework/execution/target.js +21 -0
  179. package/dist/framework/execution/target.js.map +1 -0
  180. package/dist/framework/registry.d.ts +67 -0
  181. package/dist/framework/registry.d.ts.map +1 -0
  182. package/dist/framework/registry.js +113 -0
  183. package/dist/framework/registry.js.map +1 -0
  184. package/dist/framework/resolve-metric.d.ts +79 -0
  185. package/dist/framework/resolve-metric.d.ts.map +1 -0
  186. package/dist/framework/resolve-metric.js +135 -0
  187. package/dist/framework/resolve-metric.js.map +1 -0
  188. package/dist/framework/result-builder.d.ts +72 -0
  189. package/dist/framework/result-builder.d.ts.map +1 -0
  190. package/dist/framework/result-builder.js +214 -0
  191. package/dist/framework/result-builder.js.map +1 -0
  192. package/dist/framework/result-renderers.d.ts +37 -0
  193. package/dist/framework/result-renderers.d.ts.map +1 -0
  194. package/dist/framework/result-renderers.js +62 -0
  195. package/dist/framework/result-renderers.js.map +1 -0
  196. package/dist/framework/runnable-scenario.d.ts +37 -0
  197. package/dist/framework/runnable-scenario.d.ts.map +1 -0
  198. package/dist/framework/runnable-scenario.js +9 -0
  199. package/dist/framework/runnable-scenario.js.map +1 -0
  200. package/dist/framework/scenario-executor-result.d.ts +44 -0
  201. package/dist/framework/scenario-executor-result.d.ts.map +1 -0
  202. package/dist/framework/scenario-executor-result.js +13 -0
  203. package/dist/framework/scenario-executor-result.js.map +1 -0
  204. package/dist/framework/scenario-logger.d.ts +18 -0
  205. package/dist/framework/scenario-logger.d.ts.map +1 -0
  206. package/dist/framework/scenario-logger.js +39 -0
  207. package/dist/framework/scenario-logger.js.map +1 -0
  208. package/dist/framework/scenario-metric-key.d.ts +24 -0
  209. package/dist/framework/scenario-metric-key.d.ts.map +1 -0
  210. package/dist/framework/scenario-metric-key.js +17 -0
  211. package/dist/framework/scenario-metric-key.js.map +1 -0
  212. package/dist/framework/validation.d.ts +83 -0
  213. package/dist/framework/validation.d.ts.map +1 -0
  214. package/dist/framework/validation.js +93 -0
  215. package/dist/framework/validation.js.map +1 -0
  216. package/dist/index.d.ts +35 -0
  217. package/dist/index.d.ts.map +1 -0
  218. package/dist/index.js +53 -0
  219. package/dist/index.js.map +1 -0
  220. package/dist/internal.d.ts +19 -0
  221. package/dist/internal.d.ts.map +1 -0
  222. package/dist/internal.js +16 -0
  223. package/dist/internal.js.map +1 -0
  224. package/dist/kinds/chaos/__tests__/executor.test.d.ts +6 -0
  225. package/dist/kinds/chaos/__tests__/executor.test.d.ts.map +1 -0
  226. package/dist/kinds/chaos/__tests__/executor.test.js +117 -0
  227. package/dist/kinds/chaos/__tests__/executor.test.js.map +1 -0
  228. package/dist/kinds/chaos/config.d.ts +48 -0
  229. package/dist/kinds/chaos/config.d.ts.map +1 -0
  230. package/dist/kinds/chaos/config.js +15 -0
  231. package/dist/kinds/chaos/config.js.map +1 -0
  232. package/dist/kinds/chaos/define.d.ts +32 -0
  233. package/dist/kinds/chaos/define.d.ts.map +1 -0
  234. package/dist/kinds/chaos/define.js +111 -0
  235. package/dist/kinds/chaos/define.js.map +1 -0
  236. package/dist/kinds/chaos/executor.d.ts +21 -0
  237. package/dist/kinds/chaos/executor.d.ts.map +1 -0
  238. package/dist/kinds/chaos/executor.js +107 -0
  239. package/dist/kinds/chaos/executor.js.map +1 -0
  240. package/dist/kinds/chaos/result.d.ts +43 -0
  241. package/dist/kinds/chaos/result.d.ts.map +1 -0
  242. package/dist/kinds/chaos/result.js +12 -0
  243. package/dist/kinds/chaos/result.js.map +1 -0
  244. package/dist/kinds/load/__tests__/executor.test.d.ts +6 -0
  245. package/dist/kinds/load/__tests__/executor.test.d.ts.map +1 -0
  246. package/dist/kinds/load/__tests__/executor.test.js +75 -0
  247. package/dist/kinds/load/__tests__/executor.test.js.map +1 -0
  248. package/dist/kinds/load/config.d.ts +30 -0
  249. package/dist/kinds/load/config.d.ts.map +1 -0
  250. package/dist/kinds/load/config.js +9 -0
  251. package/dist/kinds/load/config.js.map +1 -0
  252. package/dist/kinds/load/define.d.ts +47 -0
  253. package/dist/kinds/load/define.d.ts.map +1 -0
  254. package/dist/kinds/load/define.js +76 -0
  255. package/dist/kinds/load/define.js.map +1 -0
  256. package/dist/kinds/load/executor.d.ts +16 -0
  257. package/dist/kinds/load/executor.d.ts.map +1 -0
  258. package/dist/kinds/load/executor.js +90 -0
  259. package/dist/kinds/load/executor.js.map +1 -0
  260. package/dist/kinds/load/result.d.ts +21 -0
  261. package/dist/kinds/load/result.d.ts.map +1 -0
  262. package/dist/kinds/load/result.js +10 -0
  263. package/dist/kinds/load/result.js.map +1 -0
  264. package/dist/persistence/session-payload.d.ts +32 -0
  265. package/dist/persistence/session-payload.d.ts.map +1 -0
  266. package/dist/persistence/session-payload.js +46 -0
  267. package/dist/persistence/session-payload.js.map +1 -0
  268. package/dist/persistence/session-replay.d.ts +13 -0
  269. package/dist/persistence/session-replay.d.ts.map +1 -0
  270. package/dist/persistence/session-replay.js +76 -0
  271. package/dist/persistence/session-replay.js.map +1 -0
  272. package/dist/persistence/session-replay.test.d.ts +10 -0
  273. package/dist/persistence/session-replay.test.d.ts.map +1 -0
  274. package/dist/persistence/session-replay.test.js +169 -0
  275. package/dist/persistence/session-replay.test.js.map +1 -0
  276. package/dist/plugins/__tests__/loader-scenarios.test.d.ts +12 -0
  277. package/dist/plugins/__tests__/loader-scenarios.test.d.ts.map +1 -0
  278. package/dist/plugins/__tests__/loader-scenarios.test.js +61 -0
  279. package/dist/plugins/__tests__/loader-scenarios.test.js.map +1 -0
  280. package/dist/plugins/__tests__/scenario-package-discovery.test.d.ts +2 -0
  281. package/dist/plugins/__tests__/scenario-package-discovery.test.d.ts.map +1 -0
  282. package/dist/plugins/__tests__/scenario-package-discovery.test.js +43 -0
  283. package/dist/plugins/__tests__/scenario-package-discovery.test.js.map +1 -0
  284. package/dist/plugins/loader.d.ts +32 -0
  285. package/dist/plugins/loader.d.ts.map +1 -0
  286. package/dist/plugins/loader.js +119 -0
  287. package/dist/plugins/loader.js.map +1 -0
  288. package/dist/plugins/scenario-package-discovery.d.ts +23 -0
  289. package/dist/plugins/scenario-package-discovery.d.ts.map +1 -0
  290. package/dist/plugins/scenario-package-discovery.js +42 -0
  291. package/dist/plugins/scenario-package-discovery.js.map +1 -0
  292. package/dist/plugins/types.d.ts +24 -0
  293. package/dist/plugins/types.d.ts.map +1 -0
  294. package/dist/plugins/types.js +18 -0
  295. package/dist/plugins/types.js.map +1 -0
  296. package/dist/recipes/__tests__/recipes.test.d.ts +2 -0
  297. package/dist/recipes/__tests__/recipes.test.d.ts.map +1 -0
  298. package/dist/recipes/__tests__/recipes.test.js +515 -0
  299. package/dist/recipes/__tests__/recipes.test.js.map +1 -0
  300. package/dist/recipes/built-in-recipes.d.ts +16 -0
  301. package/dist/recipes/built-in-recipes.d.ts.map +1 -0
  302. package/dist/recipes/built-in-recipes.js +37 -0
  303. package/dist/recipes/built-in-recipes.js.map +1 -0
  304. package/dist/recipes/define-recipe.d.ts +29 -0
  305. package/dist/recipes/define-recipe.d.ts.map +1 -0
  306. package/dist/recipes/define-recipe.js +68 -0
  307. package/dist/recipes/define-recipe.js.map +1 -0
  308. package/dist/recipes/registry.d.ts +54 -0
  309. package/dist/recipes/registry.d.ts.map +1 -0
  310. package/dist/recipes/registry.js +89 -0
  311. package/dist/recipes/registry.js.map +1 -0
  312. package/dist/recipes/service.d.ts +61 -0
  313. package/dist/recipes/service.d.ts.map +1 -0
  314. package/dist/recipes/service.js +205 -0
  315. package/dist/recipes/service.js.map +1 -0
  316. package/dist/recipes/types.d.ts +62 -0
  317. package/dist/recipes/types.d.ts.map +1 -0
  318. package/dist/recipes/types.js +10 -0
  319. package/dist/recipes/types.js.map +1 -0
  320. package/dist/scaffold/examples.d.ts +22 -0
  321. package/dist/scaffold/examples.d.ts.map +1 -0
  322. package/dist/scaffold/examples.js +91 -0
  323. package/dist/scaffold/examples.js.map +1 -0
  324. package/dist/scope-augmentation.d.ts +70 -0
  325. package/dist/scope-augmentation.d.ts.map +1 -0
  326. package/dist/scope-augmentation.js +28 -0
  327. package/dist/scope-augmentation.js.map +1 -0
  328. package/dist/tool.d.ts +21 -0
  329. package/dist/tool.d.ts.map +1 -0
  330. package/dist/tool.js +347 -0
  331. package/dist/tool.js.map +1 -0
  332. package/dist/types/base-types.d.ts +35 -0
  333. package/dist/types/base-types.d.ts.map +1 -0
  334. package/dist/types/base-types.js +8 -0
  335. package/dist/types/base-types.js.map +1 -0
  336. package/dist/types/framework-types.d.ts +62 -0
  337. package/dist/types/framework-types.d.ts.map +1 -0
  338. package/dist/types/framework-types.js +15 -0
  339. package/dist/types/framework-types.js.map +1 -0
  340. package/dist/types/kind-types.d.ts +24 -0
  341. package/dist/types/kind-types.d.ts.map +1 -0
  342. package/dist/types/kind-types.js +22 -0
  343. package/dist/types/kind-types.js.map +1 -0
  344. package/dist/types/workload.d.ts +30 -0
  345. package/dist/types/workload.d.ts.map +1 -0
  346. package/dist/types/workload.js +20 -0
  347. package/dist/types/workload.js.map +1 -0
  348. package/package.json +120 -0
@@ -0,0 +1,122 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ASSERTIONS, evaluateAssertion, evaluateOperator, getOperatorDescription, } from '../assertions.js';
3
+ describe('ASSERTIONS factories', () => {
4
+ it.each([
5
+ ['lowErrorRate', () => ASSERTIONS.lowErrorRate(), 'error_rate', 'lt', 0.05],
6
+ ['lowErrorRate(custom)', () => ASSERTIONS.lowErrorRate(0.01), 'error_rate', 'lt', 0.01],
7
+ ['zeroErrors', () => ASSERTIONS.zeroErrors(), 'error_rate', 'eq', 0],
8
+ ['lowLatency(default)', () => ASSERTIONS.lowLatency(), 'p95_latency_ms', 'lt', 500],
9
+ [
10
+ 'lowLatency(p99,1000)',
11
+ () => ASSERTIONS.lowLatency('p99', 1000),
12
+ 'p99_latency_ms',
13
+ 'lt',
14
+ 1000,
15
+ ],
16
+ ['avgLatency', () => ASSERTIONS.avgLatency(), 'avg_latency_ms', 'lt', 200],
17
+ ['avgLatency(custom)', () => ASSERTIONS.avgLatency(50), 'avg_latency_ms', 'lt', 50],
18
+ ['maxLatency', () => ASSERTIONS.maxLatency(), 'max_latency_ms', 'lt', 2000],
19
+ ['maxLatency(custom)', () => ASSERTIONS.maxLatency(5000), 'max_latency_ms', 'lt', 5000],
20
+ ['minThroughput', () => ASSERTIONS.minThroughput(100), 'requests_per_second', 'gte', 100],
21
+ ['maxThroughput', () => ASSERTIONS.maxThroughput(50), 'requests_per_second', 'lte', 50],
22
+ ['highSuccessRate(default)', () => ASSERTIONS.highSuccessRate(), 'success_rate', 'gte', 0.95],
23
+ [
24
+ 'highSuccessRate(custom)',
25
+ () => ASSERTIONS.highSuccessRate(0.99),
26
+ 'success_rate',
27
+ 'gte',
28
+ 0.99,
29
+ ],
30
+ ['perfectSuccessRate', () => ASSERTIONS.perfectSuccessRate(), 'success_rate', 'eq', 1],
31
+ ['memoryUsage', () => ASSERTIONS.memoryUsage(512), 'memory_mb', 'lt', 512],
32
+ ['cpuUsage', () => ASSERTIONS.cpuUsage(80), 'cpu_percent', 'lt', 80],
33
+ ])('%s produces expected ScenarioAssertion', (_name, factory, metric, operator, value) => {
34
+ const a = factory();
35
+ expect(a.metric).toBe(metric);
36
+ expect(a.operator).toBe(operator);
37
+ expect(a.value).toBe(value);
38
+ expect(typeof a.message).toBe('string');
39
+ expect((a.message ?? '').length).toBeGreaterThan(0);
40
+ });
41
+ it('custom() builds an assertion with a user-supplied metric', () => {
42
+ const a = ASSERTIONS.custom('total_requests', 'gt', 42, 'total_requests must be > 42');
43
+ expect(a.metric).toBe('total_requests');
44
+ expect(a.operator).toBe('gt');
45
+ expect(a.value).toBe(42);
46
+ expect(a.message).toBe('total_requests must be > 42');
47
+ });
48
+ it('custom() defaults the message when omitted', () => {
49
+ const a = ASSERTIONS.custom('p50_latency_ms', 'lt', 100);
50
+ expect(a.message).toBe('p50_latency_ms lt 100');
51
+ });
52
+ });
53
+ describe('evaluateOperator', () => {
54
+ it.each([
55
+ [1, 'lt', 2, true],
56
+ [2, 'lt', 2, false],
57
+ [2, 'lte', 2, true],
58
+ [3, 'lte', 2, false],
59
+ [3, 'gt', 2, true],
60
+ [2, 'gt', 2, false],
61
+ [2, 'gte', 2, true],
62
+ [1, 'gte', 2, false],
63
+ [5, 'eq', 5, true],
64
+ [5, 'eq', 6, false],
65
+ [5, 'neq', 6, true],
66
+ [5, 'neq', 5, false],
67
+ ])('evaluateOperator(%d, %s, %d) === %s', (a, op, b, expected) => {
68
+ expect(evaluateOperator(a, op, b)).toBe(expected);
69
+ });
70
+ it('returns false for unknown operators', () => {
71
+ expect(evaluateOperator(1, 'unknown', 2)).toBe(false);
72
+ });
73
+ });
74
+ describe('evaluateAssertion', () => {
75
+ const make = (operator, value) => ({
76
+ metric: 'error_rate',
77
+ operator,
78
+ value,
79
+ message: 'x',
80
+ });
81
+ it.each([
82
+ ['lt', 5, 3, true],
83
+ ['lt', 5, 5, false],
84
+ ['lte', 5, 5, true],
85
+ ['lte', 5, 6, false],
86
+ ['gt', 5, 6, true],
87
+ ['gt', 5, 5, false],
88
+ ['gte', 5, 5, true],
89
+ ['gte', 5, 4, false],
90
+ ['eq', 5, 5, true],
91
+ ['eq', 5, 6, false],
92
+ ['neq', 5, 6, true],
93
+ ['neq', 5, 5, false],
94
+ ])('evaluateAssertion(op=%s, expected=%d, actual=%d) === %s', (op, expected, actual, want) => {
95
+ expect(evaluateAssertion(make(op, expected), actual)).toBe(want);
96
+ });
97
+ it('returns false for unknown operator on the assertion', () => {
98
+ const bad = {
99
+ metric: 'error_rate',
100
+ operator: 'unknown',
101
+ value: 0,
102
+ message: 'x',
103
+ };
104
+ expect(evaluateAssertion(bad, 0)).toBe(false);
105
+ });
106
+ });
107
+ describe('getOperatorDescription', () => {
108
+ it.each([
109
+ ['lt', 'less than'],
110
+ ['lte', 'at most'],
111
+ ['gt', 'greater than'],
112
+ ['gte', 'at least'],
113
+ ['eq', 'equal to'],
114
+ ['neq', 'not equal to'],
115
+ ])('getOperatorDescription(%s) === %s', (op, want) => {
116
+ expect(getOperatorDescription(op)).toBe(want);
117
+ });
118
+ it('returns the operator string for unknown operators', () => {
119
+ expect(getOperatorDescription('unknown')).toBe('unknown');
120
+ });
121
+ });
122
+ //# sourceMappingURL=assertions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertions.test.js","sourceRoot":"","sources":["../../../src/framework/__tests__/assertions.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @fileoverview Coverage gap-fillers for small utility surfaces.
3
+ *
4
+ * Each test here targets a real-world failure or behavior, not just
5
+ * raw line coverage. Concretely:
6
+ * - core's Registry<T> name-collision guard (with nameCollisionMode:
7
+ * 'throw') prevents inconsistent dual-key state when two different
8
+ * ids share a name — without the throw, the last writer wins on
9
+ * `byName` while both ids remain in `byId`. This is the contract
10
+ * the simulation scenario registry depends on.
11
+ * - LatencyTracker's reset() must clear the running sum, otherwise a
12
+ * subsequent record() would carry stale state.
13
+ * - renderScenarioResultView's exhaustiveness branch fires when an
14
+ * unknown `kind` reaches the renderer; tests force this with a
15
+ * hand-rolled cast to verify the runtime guard, not just the types.
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=misc-coverage.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc-coverage.test.d.ts","sourceRoot":"","sources":["../../../src/framework/__tests__/misc-coverage.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @fileoverview Coverage gap-fillers for small utility surfaces.
3
+ *
4
+ * Each test here targets a real-world failure or behavior, not just
5
+ * raw line coverage. Concretely:
6
+ * - core's Registry<T> name-collision guard (with nameCollisionMode:
7
+ * 'throw') prevents inconsistent dual-key state when two different
8
+ * ids share a name — without the throw, the last writer wins on
9
+ * `byName` while both ids remain in `byId`. This is the contract
10
+ * the simulation scenario registry depends on.
11
+ * - LatencyTracker's reset() must clear the running sum, otherwise a
12
+ * subsequent record() would carry stale state.
13
+ * - renderScenarioResultView's exhaustiveness branch fires when an
14
+ * unknown `kind` reaches the renderer; tests force this with a
15
+ * hand-rolled cast to verify the runtime guard, not just the types.
16
+ */
17
+ import { Registry, ValidationError } from '@opensip-cli/core';
18
+ import { describe, expect, it } from 'vitest';
19
+ import { LatencyTracker } from '../execution/latency-tracker.js';
20
+ import { renderScenarioResultView } from '../result-renderers.js';
21
+ function makeScenarioRegistry() {
22
+ return new Registry({
23
+ module: 'test',
24
+ duplicatePolicy: 'silent-skip',
25
+ evtPrefix: 'test.registry',
26
+ nameCollisionMode: 'throw',
27
+ });
28
+ }
29
+ describe('Registry<T> with silent-skip + nameCollisionMode=throw — coverage edges', () => {
30
+ it('throws ValidationError on a name collision (two different ids, same name)', () => {
31
+ const reg = makeScenarioRegistry();
32
+ reg.register({ id: 'a', name: 'shared' });
33
+ expect(() => reg.register({ id: 'b', name: 'shared' })).toThrow(ValidationError);
34
+ });
35
+ it('skips silent duplicate when same id is registered twice', () => {
36
+ const reg = makeScenarioRegistry();
37
+ reg.register({ id: 'a', name: 'one' });
38
+ reg.register({ id: 'a', name: 'one' }); // skipped silently
39
+ expect(reg.size).toBe(1);
40
+ });
41
+ it('size() reflects current entries', () => {
42
+ const reg = makeScenarioRegistry();
43
+ expect(reg.size).toBe(0);
44
+ reg.register({ id: 'a', name: 'one' });
45
+ reg.register({ id: 'b', name: 'two' });
46
+ expect(reg.size).toBe(2);
47
+ });
48
+ it('clear() empties both byId and byName indices', () => {
49
+ const reg = makeScenarioRegistry();
50
+ reg.register({ id: 'a', name: 'one' });
51
+ reg.register({ id: 'b', name: 'two', tags: ['x'] });
52
+ reg.clear();
53
+ expect(reg.size).toBe(0);
54
+ expect(reg.get('a')).toBeUndefined();
55
+ expect(reg.get('one')).toBeUndefined();
56
+ expect(reg.getByTag('x')).toEqual([]);
57
+ });
58
+ it('getByTag returns matching items', () => {
59
+ const reg = makeScenarioRegistry();
60
+ reg.register({ id: 'a', name: 'one', tags: ['x', 'shared'] });
61
+ reg.register({ id: 'b', name: 'two', tags: ['shared'] });
62
+ reg.register({ id: 'c', name: 'three' });
63
+ const shared = reg.getByTag('shared');
64
+ expect(shared.map((i) => i.id).sort()).toEqual(['a', 'b']);
65
+ });
66
+ });
67
+ // ---------------------------------------------------------------------------
68
+ // LatencyTracker — reset() and average() with no samples
69
+ // ---------------------------------------------------------------------------
70
+ describe('LatencyTracker — reset and zero-sample edges', () => {
71
+ it('reset() clears samples, sum, and the sorted cache', () => {
72
+ const t = new LatencyTracker();
73
+ t.record(10);
74
+ t.record(20);
75
+ t.record(30);
76
+ expect(t.average).toBeCloseTo(20);
77
+ expect(t.count).toBe(3);
78
+ t.reset();
79
+ expect(t.count).toBe(0);
80
+ expect(t.average).toBe(0);
81
+ expect(t.getPercentile(50)).toBe(0);
82
+ // After reset, new samples behave as if fresh.
83
+ t.record(100);
84
+ expect(t.average).toBe(100);
85
+ expect(t.count).toBe(1);
86
+ });
87
+ it('average() returns 0 with no samples', () => {
88
+ const t = new LatencyTracker();
89
+ expect(t.average).toBe(0);
90
+ });
91
+ it('getPercentile returns the single sample with one record', () => {
92
+ const t = new LatencyTracker();
93
+ t.record(42);
94
+ expect(t.getPercentile(50)).toBe(42);
95
+ expect(t.getPercentile(99)).toBe(42);
96
+ });
97
+ it('getPercentile interpolates linearly between bracketing samples', () => {
98
+ const t = new LatencyTracker();
99
+ // 4 samples → index for p50 = 0.5 * 3 = 1.5 → interpolate between
100
+ // sorted[1]=20 and sorted[2]=30 with fraction 0.5 → 25.
101
+ t.record(40);
102
+ t.record(20);
103
+ t.record(10);
104
+ t.record(30);
105
+ expect(t.getPercentile(50)).toBeCloseTo(25);
106
+ // p0 and p100 land exactly on the endpoints (lower === upper path).
107
+ expect(t.getPercentile(0)).toBe(10);
108
+ expect(t.getPercentile(100)).toBe(40);
109
+ });
110
+ it('getLatencySnapshot reports avg + percentiles together', () => {
111
+ const t = new LatencyTracker();
112
+ t.record(10);
113
+ t.record(20);
114
+ t.record(30);
115
+ const snap = t.getLatencySnapshot();
116
+ expect(snap.avgLatencyMs).toBeCloseTo(20);
117
+ expect(snap.p50LatencyMs).toBeCloseTo(20);
118
+ expect(snap.p95LatencyMs).toBeGreaterThanOrEqual(snap.p50LatencyMs);
119
+ expect(snap.p99LatencyMs).toBeGreaterThanOrEqual(snap.p95LatencyMs);
120
+ });
121
+ });
122
+ // ---------------------------------------------------------------------------
123
+ // renderScenarioResultView — exhaustiveness guard
124
+ // ---------------------------------------------------------------------------
125
+ describe('renderScenarioResultView — exhaustiveness guard', () => {
126
+ it('throws when called with an unknown kind (runtime safety net)', () => {
127
+ // Hand-rolled cast — the union doesn't permit "future-kind" at compile
128
+ // time, but the runtime exhaustiveness probe is what protects callers
129
+ // when a future variant slips past the type system (e.g., crossing a
130
+ // serialization boundary).
131
+ const future = {
132
+ kind: 'future-kind',
133
+ scenarioId: 's1',
134
+ passed: true,
135
+ durationMs: 1,
136
+ signals: [],
137
+ outcome: {},
138
+ };
139
+ expect(() => renderScenarioResultView(future)).toThrow(/exhaustiveness/);
140
+ });
141
+ });
142
+ //# sourceMappingURL=misc-coverage.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc-coverage.test.js","sourceRoot":"","sources":["../../../src/framework/__tests__/misc-coverage.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @fileoverview Tests pinning the canonical metric resolver.
3
+ *
4
+ * Includes the symmetry regression: both `validateAssertions` (used by the
5
+ * execution-engine path) and `ScenarioResultBuilder.evaluateAssertions`
6
+ * (used by the kind executors) MUST produce the same actual value via
7
+ * `resolveMetric`. Before the unification, the two paths returned
8
+ * different values for `success_rate` on `totalRequests === 0` and
9
+ * disagreed on which keys were resolvable.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=resolve-metric.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-metric.test.d.ts","sourceRoot":"","sources":["../../../src/framework/__tests__/resolve-metric.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * @fileoverview Tests pinning the canonical metric resolver.
3
+ *
4
+ * Includes the symmetry regression: both `validateAssertions` (used by the
5
+ * execution-engine path) and `ScenarioResultBuilder.evaluateAssertions`
6
+ * (used by the kind executors) MUST produce the same actual value via
7
+ * `resolveMetric`. Before the unification, the two paths returned
8
+ * different values for `success_rate` on `totalRequests === 0` and
9
+ * disagreed on which keys were resolvable.
10
+ */
11
+ import { describe, expect, it } from 'vitest';
12
+ import { validateAssertions } from '../execution/execution-engine.js';
13
+ import { resolveMetric } from '../resolve-metric.js';
14
+ import { ScenarioResultBuilder, createEmptyMetrics } from '../result-builder.js';
15
+ const baseMetrics = (overrides = {}) => ({
16
+ ...createEmptyMetrics(),
17
+ totalRequests: 100,
18
+ successfulRequests: 95,
19
+ failedRequests: 5,
20
+ avgLatencyMs: 40,
21
+ p50LatencyMs: 30,
22
+ p95LatencyMs: 70,
23
+ p99LatencyMs: 100,
24
+ errorsGenerated: 5,
25
+ ...overrides,
26
+ });
27
+ /**
28
+ * Run an assertion through both metric-resolution paths and compare. The
29
+ * `eq` operator with the resolver's value as `expected` lets us read the
30
+ * canonical actual back out of the validateAssertions path's `failed[].actual`
31
+ * (we treat any failure with the same `actual` as success for the symmetry
32
+ * check).
33
+ */
34
+ function actualFromValidateAssertions(metrics, metric) {
35
+ const a = {
36
+ metric,
37
+ operator: 'eq',
38
+ // Force a failure so we can read `failed[0].actual`.
39
+ value: Number.NaN,
40
+ message: 'symmetry probe',
41
+ };
42
+ const out = validateAssertions(metrics, [a]);
43
+ // NaN !== NaN ⇒ failed list always populated for this probe.
44
+ return out.failed[0]?.actual ?? Number.NaN;
45
+ }
46
+ function actualFromResultBuilder(metrics, metric, durationSeconds) {
47
+ const a = {
48
+ metric,
49
+ operator: 'eq',
50
+ value: Number.NaN,
51
+ message: 'symmetry probe',
52
+ };
53
+ const builder = ScenarioResultBuilder.create('probe').withMetrics(metrics);
54
+ const built = (durationSeconds === undefined ? builder : builder.withDuration(durationSeconds))
55
+ .evaluateAssertions([a])
56
+ .build();
57
+ return built.assertions.failed[0]?.actual ?? Number.NaN;
58
+ }
59
+ describe('resolveMetric symmetry', () => {
60
+ it('chaos recovery_rate produces the same value via both paths', () => {
61
+ const m = baseMetrics({ errorsGenerated: 10, failedRequests: 2 });
62
+ const expected = resolveMetric('recovery_rate', m);
63
+ expect(actualFromValidateAssertions(m, 'recovery_rate')).toBeCloseTo(expected);
64
+ expect(actualFromResultBuilder(m, 'recovery_rate')).toBeCloseTo(expected);
65
+ // And the value is the documented one (1 - 2/10 = 0.8).
66
+ expect(expected).toBeCloseTo(0.8);
67
+ });
68
+ it('recovery_rate is 1 when no errors generated, both paths agree', () => {
69
+ const m = baseMetrics({ errorsGenerated: 0, failedRequests: 0 });
70
+ expect(actualFromValidateAssertions(m, 'recovery_rate')).toBe(1);
71
+ expect(actualFromResultBuilder(m, 'recovery_rate')).toBe(1);
72
+ });
73
+ it('success_rate is 0 with zero requests, both paths agree (tightening)', () => {
74
+ const m = baseMetrics({ totalRequests: 0, successfulRequests: 0 });
75
+ expect(actualFromValidateAssertions(m, 'success_rate')).toBe(0);
76
+ expect(actualFromResultBuilder(m, 'success_rate')).toBe(0);
77
+ });
78
+ it.each([
79
+ ['error_rate', { totalRequests: 200, failedRequests: 50 }, 0.25],
80
+ ['success_rate', { totalRequests: 200, successfulRequests: 180 }, 0.9],
81
+ ['p50_latency_ms', { p50LatencyMs: 33 }, 33],
82
+ ['p95_latency_ms', { p95LatencyMs: 88 }, 88],
83
+ ['p99_latency_ms', { p99LatencyMs: 200 }, 200],
84
+ ['avg_latency_ms', { avgLatencyMs: 45 }, 45],
85
+ ['total_requests', { totalRequests: 7 }, 7],
86
+ ['failed_requests', { failedRequests: 4 }, 4],
87
+ ])('%s resolves to %d via both paths', (metric, overrides, expected) => {
88
+ const m = baseMetrics(overrides);
89
+ expect(actualFromValidateAssertions(m, metric)).toBeCloseTo(expected);
90
+ expect(actualFromResultBuilder(m, metric)).toBeCloseTo(expected);
91
+ });
92
+ it('requests_per_second resolves via the result-builder path with duration', () => {
93
+ const m = baseMetrics({ totalRequests: 100 });
94
+ expect(actualFromResultBuilder(m, 'requests_per_second', 10)).toBeCloseTo(10);
95
+ // Without duration in the validate-assertions path, the value is 0
96
+ // (no duration plumbed through). Documented behaviour.
97
+ expect(actualFromValidateAssertions(m, 'requests_per_second')).toBe(0);
98
+ });
99
+ it('reserved keys (cpu_percent, memory_mb, max_latency_ms) resolve to 0', () => {
100
+ const m = baseMetrics();
101
+ expect(resolveMetric('cpu_percent', m)).toBe(0);
102
+ expect(resolveMetric('memory_mb', m)).toBe(0);
103
+ expect(resolveMetric('max_latency_ms', m)).toBe(0);
104
+ });
105
+ it('resolves the raw count metric keys directly off SimulationMetrics', () => {
106
+ const m = baseMetrics({
107
+ successfulRequests: 95,
108
+ failedRequests: 5,
109
+ errorsGenerated: 7,
110
+ totalRequests: 100,
111
+ });
112
+ expect(resolveMetric('successful_requests', m)).toBe(95);
113
+ expect(resolveMetric('failed_requests', m)).toBe(5);
114
+ expect(resolveMetric('errors_generated', m)).toBe(7);
115
+ expect(resolveMetric('total_requests', m)).toBe(100);
116
+ });
117
+ it('falls through to 0 for a key outside the supported set (type-bypass guard)', () => {
118
+ const m = baseMetrics();
119
+ // A caller that deliberately bypasses the compile-time narrowing hits the
120
+ // exhaustive default arm, which returns 0.
121
+ expect(resolveMetric('not-a-real-metric', m)).toBe(0);
122
+ });
123
+ });
124
+ //# sourceMappingURL=resolve-metric.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-metric.test.js","sourceRoot":"","sources":["../../../src/framework/__tests__/resolve-metric.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=result-builder.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-builder.test.d.ts","sourceRoot":"","sources":["../../../src/framework/__tests__/result-builder.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,180 @@
1
+ import { ValidationError, createSignal } from '@opensip-cli/core';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { ASSERTIONS } from '../assertions.js';
4
+ import { ScenarioResultBuilder, createEmptyMetrics, mergeMetrics } from '../result-builder.js';
5
+ const baseMetrics = (overrides = {}) => ({
6
+ ...createEmptyMetrics(),
7
+ totalRequests: 100,
8
+ successfulRequests: 99,
9
+ failedRequests: 1,
10
+ avgLatencyMs: 50,
11
+ p50LatencyMs: 40,
12
+ p95LatencyMs: 80,
13
+ p99LatencyMs: 120,
14
+ errorsGenerated: 0,
15
+ ...overrides,
16
+ });
17
+ const sig = (overrides = {}) => createSignal({
18
+ source: 'simulation',
19
+ provider: 'opensip',
20
+ severity: 'medium',
21
+ category: 'warning',
22
+ ruleId: 'sim:test',
23
+ message: 'note',
24
+ ...overrides,
25
+ });
26
+ describe('ScenarioResultBuilder', () => {
27
+ it('returns scenario id', () => {
28
+ expect(ScenarioResultBuilder.create('s1').getScenarioId()).toBe('s1');
29
+ });
30
+ it('builds a passed payload when all assertions hold', () => {
31
+ const out = ScenarioResultBuilder.create('s1')
32
+ .withMetrics(baseMetrics())
33
+ .withDuration(10)
34
+ .evaluateAssertions([ASSERTIONS.lowErrorRate(), ASSERTIONS.highSuccessRate(0.9)])
35
+ .build();
36
+ expect(out.passed).toBe(true);
37
+ expect(out.assertions.passed).toHaveLength(2);
38
+ expect(out.assertions.failed).toEqual([]);
39
+ });
40
+ it('records failed assertion with the actual value', () => {
41
+ const out = ScenarioResultBuilder.create('s1')
42
+ .withMetrics(baseMetrics({ failedRequests: 50 }))
43
+ .evaluateAssertions([ASSERTIONS.lowErrorRate()])
44
+ .build();
45
+ expect(out.passed).toBe(false);
46
+ expect(out.assertions.failed).toHaveLength(1);
47
+ expect(out.assertions.failed[0]?.actual).toBeCloseTo(0.5);
48
+ });
49
+ it('throws when evaluating assertions before metrics are set', () => {
50
+ expect(() => ScenarioResultBuilder.create('s1').evaluateAssertions([ASSERTIONS.lowErrorRate()])).toThrow(ValidationError);
51
+ });
52
+ it('throws on build() when metrics are not set', () => {
53
+ expect(() => ScenarioResultBuilder.create('s1').build()).toThrow(ValidationError);
54
+ });
55
+ it('addSignal / addSignals propagate to the payload', () => {
56
+ const out = ScenarioResultBuilder.create('s1')
57
+ .withMetrics(baseMetrics())
58
+ .addSignal(sig({ ruleId: 'sim:a' }))
59
+ .addSignals([sig({ ruleId: 'sim:b' }), sig({ ruleId: 'sim:c' })])
60
+ .build();
61
+ expect(out.signals.map((s) => s.ruleId)).toEqual(['sim:a', 'sim:b', 'sim:c']);
62
+ });
63
+ it('assertionPassed / assertionFailed allow manual record-keeping', () => {
64
+ const a = ASSERTIONS.lowErrorRate();
65
+ const out = ScenarioResultBuilder.create('s1')
66
+ .withMetrics(baseMetrics())
67
+ .assertionPassed(a)
68
+ .assertionFailed(a, 0.99)
69
+ .build();
70
+ expect(out.assertions.passed).toHaveLength(1);
71
+ expect(out.assertions.failed).toHaveLength(1);
72
+ });
73
+ describe('metric resolution', () => {
74
+ it('resolves error_rate from totalRequests / failedRequests', () => {
75
+ const out = ScenarioResultBuilder.create('s1')
76
+ .withMetrics(baseMetrics({ totalRequests: 200, failedRequests: 10 }))
77
+ .evaluateAssertions([ASSERTIONS.lowErrorRate(0.1)])
78
+ .build();
79
+ expect(out.passed).toBe(true);
80
+ });
81
+ it('resolves error_rate to 0 when totalRequests is 0', () => {
82
+ const out = ScenarioResultBuilder.create('s1')
83
+ .withMetrics(baseMetrics({ totalRequests: 0, failedRequests: 0 }))
84
+ .evaluateAssertions([ASSERTIONS.lowErrorRate()])
85
+ .build();
86
+ expect(out.passed).toBe(true);
87
+ });
88
+ it('resolves success_rate from successful / total', () => {
89
+ const out = ScenarioResultBuilder.create('s1')
90
+ .withMetrics(baseMetrics({ totalRequests: 100, successfulRequests: 100 }))
91
+ .evaluateAssertions([ASSERTIONS.perfectSuccessRate()])
92
+ .build();
93
+ expect(out.passed).toBe(true);
94
+ });
95
+ it('success_rate is 0 when no requests', () => {
96
+ const out = ScenarioResultBuilder.create('s1')
97
+ .withMetrics(baseMetrics({ totalRequests: 0 }))
98
+ .evaluateAssertions([ASSERTIONS.highSuccessRate(0.5)])
99
+ .build();
100
+ expect(out.passed).toBe(false);
101
+ });
102
+ it('resolves requests_per_second from totalRequests / duration', () => {
103
+ const out = ScenarioResultBuilder.create('s1')
104
+ .withMetrics(baseMetrics({ totalRequests: 100 }))
105
+ .withDuration(10)
106
+ .evaluateAssertions([ASSERTIONS.minThroughput(5)])
107
+ .build();
108
+ expect(out.passed).toBe(true); // 10 RPS >= 5
109
+ });
110
+ it('requests_per_second is 0 without duration', () => {
111
+ const out = ScenarioResultBuilder.create('s1')
112
+ .withMetrics(baseMetrics())
113
+ .evaluateAssertions([ASSERTIONS.minThroughput(1)])
114
+ .build();
115
+ expect(out.passed).toBe(false);
116
+ });
117
+ it('resolves direct latency fields from metrics', () => {
118
+ const out = ScenarioResultBuilder.create('s1')
119
+ .withMetrics(baseMetrics({ p95LatencyMs: 200 }))
120
+ .evaluateAssertions([ASSERTIONS.lowLatency('p95', 300)])
121
+ .build();
122
+ expect(out.passed).toBe(true);
123
+ });
124
+ it('returns 0 for unknown metrics', () => {
125
+ const out = ScenarioResultBuilder.create('s1')
126
+ .withMetrics(baseMetrics())
127
+ .evaluateAssertions([ASSERTIONS.custom('cpu_percent', 'lt', 100)])
128
+ .build();
129
+ expect(out.passed).toBe(true); // 0 < 100
130
+ });
131
+ });
132
+ });
133
+ describe('createEmptyMetrics', () => {
134
+ it('returns a zero-valued metrics object', () => {
135
+ const m = createEmptyMetrics();
136
+ expect(m.totalRequests).toBe(0);
137
+ expect(m.successfulRequests).toBe(0);
138
+ expect(m.failedRequests).toBe(0);
139
+ expect(m.avgLatencyMs).toBe(0);
140
+ });
141
+ });
142
+ describe('mergeMetrics', () => {
143
+ it('returns empty metrics for an empty list', () => {
144
+ expect(mergeMetrics([])).toEqual(createEmptyMetrics());
145
+ });
146
+ it('returns the single entry directly', () => {
147
+ const only = baseMetrics();
148
+ expect(mergeMetrics([only])).toBe(only);
149
+ });
150
+ it('sums totals and weights average latency', () => {
151
+ const a = baseMetrics({
152
+ totalRequests: 100,
153
+ successfulRequests: 100,
154
+ failedRequests: 0,
155
+ avgLatencyMs: 50,
156
+ });
157
+ const b = baseMetrics({
158
+ totalRequests: 100,
159
+ successfulRequests: 50,
160
+ failedRequests: 50,
161
+ avgLatencyMs: 150,
162
+ });
163
+ const merged = mergeMetrics([a, b]);
164
+ expect(merged.totalRequests).toBe(200);
165
+ expect(merged.successfulRequests).toBe(150);
166
+ expect(merged.failedRequests).toBe(50);
167
+ expect(merged.avgLatencyMs).toBeCloseTo(100); // weighted by totalRequests
168
+ });
169
+ it('takes the max for percentile latencies', () => {
170
+ const a = baseMetrics({ p99LatencyMs: 100 });
171
+ const b = baseMetrics({ p99LatencyMs: 250 });
172
+ expect(mergeMetrics([a, b]).p99LatencyMs).toBe(250);
173
+ });
174
+ it('returns 0 average latency when totalRequests is 0', () => {
175
+ const a = baseMetrics({ totalRequests: 0, avgLatencyMs: 100 });
176
+ const b = baseMetrics({ totalRequests: 0, avgLatencyMs: 200 });
177
+ expect(mergeMetrics([a, b]).avgLatencyMs).toBe(0);
178
+ });
179
+ });
180
+ //# sourceMappingURL=result-builder.test.js.map