@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.
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/internal-surface.test.d.ts +9 -0
- package/dist/__tests__/internal-surface.test.d.ts.map +1 -0
- package/dist/__tests__/internal-surface.test.js +38 -0
- package/dist/__tests__/internal-surface.test.js.map +1 -0
- package/dist/__tests__/plugin-loader.test.d.ts +2 -0
- package/dist/__tests__/plugin-loader.test.d.ts.map +1 -0
- package/dist/__tests__/plugin-loader.test.js +64 -0
- package/dist/__tests__/plugin-loader.test.js.map +1 -0
- package/dist/__tests__/public-api.test.d.ts +15 -0
- package/dist/__tests__/public-api.test.d.ts.map +1 -0
- package/dist/__tests__/public-api.test.js +73 -0
- package/dist/__tests__/public-api.test.js.map +1 -0
- package/dist/__tests__/registry-cross-kind.test.d.ts +6 -0
- package/dist/__tests__/registry-cross-kind.test.d.ts.map +1 -0
- package/dist/__tests__/registry-cross-kind.test.js +86 -0
- package/dist/__tests__/registry-cross-kind.test.js.map +1 -0
- package/dist/__tests__/scenario-execution.test.d.ts +10 -0
- package/dist/__tests__/scenario-execution.test.d.ts.map +1 -0
- package/dist/__tests__/scenario-execution.test.js +92 -0
- package/dist/__tests__/scenario-execution.test.js.map +1 -0
- package/dist/__tests__/sim-capability-contract.test.d.ts +10 -0
- package/dist/__tests__/sim-capability-contract.test.d.ts.map +1 -0
- package/dist/__tests__/sim-capability-contract.test.js +131 -0
- package/dist/__tests__/sim-capability-contract.test.js.map +1 -0
- package/dist/__tests__/sim-config-schema.test.d.ts +5 -0
- package/dist/__tests__/sim-config-schema.test.d.ts.map +1 -0
- package/dist/__tests__/sim-config-schema.test.js +23 -0
- package/dist/__tests__/sim-config-schema.test.js.map +1 -0
- package/dist/__tests__/sim-failure-signal.test.d.ts +10 -0
- package/dist/__tests__/sim-failure-signal.test.d.ts.map +1 -0
- package/dist/__tests__/sim-failure-signal.test.js +86 -0
- package/dist/__tests__/sim-failure-signal.test.js.map +1 -0
- package/dist/__tests__/surviving-surface-edges.test.d.ts +10 -0
- package/dist/__tests__/surviving-surface-edges.test.d.ts.map +1 -0
- package/dist/__tests__/surviving-surface-edges.test.js +122 -0
- package/dist/__tests__/surviving-surface-edges.test.js.map +1 -0
- package/dist/__tests__/test-utils/targets.d.ts +26 -0
- package/dist/__tests__/test-utils/targets.d.ts.map +1 -0
- package/dist/__tests__/test-utils/targets.js +38 -0
- package/dist/__tests__/test-utils/targets.js.map +1 -0
- package/dist/__tests__/test-utils/with-sim-scope.d.ts +12 -0
- package/dist/__tests__/test-utils/with-sim-scope.d.ts.map +1 -0
- package/dist/__tests__/test-utils/with-sim-scope.js +22 -0
- package/dist/__tests__/test-utils/with-sim-scope.js.map +1 -0
- package/dist/__tests__/tool-live-view.test.d.ts +20 -0
- package/dist/__tests__/tool-live-view.test.d.ts.map +1 -0
- package/dist/__tests__/tool-live-view.test.js +146 -0
- package/dist/__tests__/tool-live-view.test.js.map +1 -0
- package/dist/__tests__/tool-show-mode.test.d.ts +10 -0
- package/dist/__tests__/tool-show-mode.test.d.ts.map +1 -0
- package/dist/__tests__/tool-show-mode.test.js +156 -0
- package/dist/__tests__/tool-show-mode.test.js.map +1 -0
- package/dist/__tests__/tool.test.d.ts +15 -0
- package/dist/__tests__/tool.test.d.ts.map +1 -0
- package/dist/__tests__/tool.test.js +250 -0
- package/dist/__tests__/tool.test.js.map +1 -0
- package/dist/cli/__tests__/sim-config.test.d.ts +2 -0
- package/dist/cli/__tests__/sim-config.test.d.ts.map +1 -0
- package/dist/cli/__tests__/sim-config.test.js +94 -0
- package/dist/cli/__tests__/sim-config.test.js.map +1 -0
- package/dist/cli/__tests__/sim-runner.test.d.ts +23 -0
- package/dist/cli/__tests__/sim-runner.test.d.ts.map +1 -0
- package/dist/cli/__tests__/sim-runner.test.js +188 -0
- package/dist/cli/__tests__/sim-runner.test.js.map +1 -0
- package/dist/cli/__tests__/sim-worker.test.d.ts +12 -0
- package/dist/cli/__tests__/sim-worker.test.d.ts.map +1 -0
- package/dist/cli/__tests__/sim-worker.test.js +69 -0
- package/dist/cli/__tests__/sim-worker.test.js.map +1 -0
- package/dist/cli/__tests__/sim.test.d.ts +2 -0
- package/dist/cli/__tests__/sim.test.d.ts.map +1 -0
- package/dist/cli/__tests__/sim.test.js +232 -0
- package/dist/cli/__tests__/sim.test.js.map +1 -0
- package/dist/cli/sim-config-schema.d.ts +30 -0
- package/dist/cli/sim-config-schema.d.ts.map +1 -0
- package/dist/cli/sim-config-schema.js +33 -0
- package/dist/cli/sim-config-schema.js.map +1 -0
- package/dist/cli/sim-config.d.ts +22 -0
- package/dist/cli/sim-config.d.ts.map +1 -0
- package/dist/cli/sim-config.js +73 -0
- package/dist/cli/sim-config.js.map +1 -0
- package/dist/cli/sim-runner.d.ts +60 -0
- package/dist/cli/sim-runner.d.ts.map +1 -0
- package/dist/cli/sim-runner.js +175 -0
- package/dist/cli/sim-runner.js.map +1 -0
- package/dist/cli/sim-worker.d.ts +24 -0
- package/dist/cli/sim-worker.d.ts.map +1 -0
- package/dist/cli/sim-worker.js +65 -0
- package/dist/cli/sim-worker.js.map +1 -0
- package/dist/cli/sim.d.ts +56 -0
- package/dist/cli/sim.d.ts.map +1 -0
- package/dist/cli/sim.js +265 -0
- package/dist/cli/sim.js.map +1 -0
- package/dist/framework/__tests__/assertions.test.d.ts +2 -0
- package/dist/framework/__tests__/assertions.test.d.ts.map +1 -0
- package/dist/framework/__tests__/assertions.test.js +122 -0
- package/dist/framework/__tests__/assertions.test.js.map +1 -0
- package/dist/framework/__tests__/misc-coverage.test.d.ts +18 -0
- package/dist/framework/__tests__/misc-coverage.test.d.ts.map +1 -0
- package/dist/framework/__tests__/misc-coverage.test.js +142 -0
- package/dist/framework/__tests__/misc-coverage.test.js.map +1 -0
- package/dist/framework/__tests__/resolve-metric.test.d.ts +12 -0
- package/dist/framework/__tests__/resolve-metric.test.d.ts.map +1 -0
- package/dist/framework/__tests__/resolve-metric.test.js +124 -0
- package/dist/framework/__tests__/resolve-metric.test.js.map +1 -0
- package/dist/framework/__tests__/result-builder.test.d.ts +2 -0
- package/dist/framework/__tests__/result-builder.test.d.ts.map +1 -0
- package/dist/framework/__tests__/result-builder.test.js +180 -0
- package/dist/framework/__tests__/result-builder.test.js.map +1 -0
- package/dist/framework/__tests__/scenario-logger.test.d.ts +9 -0
- package/dist/framework/__tests__/scenario-logger.test.d.ts.map +1 -0
- package/dist/framework/__tests__/scenario-logger.test.js +110 -0
- package/dist/framework/__tests__/scenario-logger.test.js.map +1 -0
- package/dist/framework/__tests__/validation.test.d.ts +9 -0
- package/dist/framework/__tests__/validation.test.d.ts.map +1 -0
- package/dist/framework/__tests__/validation.test.js +126 -0
- package/dist/framework/__tests__/validation.test.js.map +1 -0
- package/dist/framework/assertions.d.ts +106 -0
- package/dist/framework/assertions.d.ts.map +1 -0
- package/dist/framework/assertions.js +256 -0
- package/dist/framework/assertions.js.map +1 -0
- package/dist/framework/execution/__tests__/execution-engine.test.d.ts +9 -0
- package/dist/framework/execution/__tests__/execution-engine.test.d.ts.map +1 -0
- package/dist/framework/execution/__tests__/execution-engine.test.js +138 -0
- package/dist/framework/execution/__tests__/execution-engine.test.js.map +1 -0
- package/dist/framework/execution/__tests__/fault-builders.test.d.ts +5 -0
- package/dist/framework/execution/__tests__/fault-builders.test.d.ts.map +1 -0
- package/dist/framework/execution/__tests__/fault-builders.test.js +23 -0
- package/dist/framework/execution/__tests__/fault-builders.test.js.map +1 -0
- package/dist/framework/execution/__tests__/fault-model.test.d.ts +6 -0
- package/dist/framework/execution/__tests__/fault-model.test.d.ts.map +1 -0
- package/dist/framework/execution/__tests__/fault-model.test.js +64 -0
- package/dist/framework/execution/__tests__/fault-model.test.js.map +1 -0
- package/dist/framework/execution/__tests__/http-target.test.d.ts +5 -0
- package/dist/framework/execution/__tests__/http-target.test.d.ts.map +1 -0
- package/dist/framework/execution/__tests__/http-target.test.js +36 -0
- package/dist/framework/execution/__tests__/http-target.test.js.map +1 -0
- package/dist/framework/execution/__tests__/run-load-window.test.d.ts +7 -0
- package/dist/framework/execution/__tests__/run-load-window.test.d.ts.map +1 -0
- package/dist/framework/execution/__tests__/run-load-window.test.js +89 -0
- package/dist/framework/execution/__tests__/run-load-window.test.js.map +1 -0
- package/dist/framework/execution/execution-engine.d.ts +55 -0
- package/dist/framework/execution/execution-engine.d.ts.map +1 -0
- package/dist/framework/execution/execution-engine.js +111 -0
- package/dist/framework/execution/execution-engine.js.map +1 -0
- package/dist/framework/execution/fault-builders.d.ts +26 -0
- package/dist/framework/execution/fault-builders.d.ts.map +1 -0
- package/dist/framework/execution/fault-builders.js +24 -0
- package/dist/framework/execution/fault-builders.js.map +1 -0
- package/dist/framework/execution/fault-model.d.ts +49 -0
- package/dist/framework/execution/fault-model.d.ts.map +1 -0
- package/dist/framework/execution/fault-model.js +108 -0
- package/dist/framework/execution/fault-model.js.map +1 -0
- package/dist/framework/execution/fault-spec.d.ts +40 -0
- package/dist/framework/execution/fault-spec.d.ts.map +1 -0
- package/dist/framework/execution/fault-spec.js +23 -0
- package/dist/framework/execution/fault-spec.js.map +1 -0
- package/dist/framework/execution/http-target.d.ts +34 -0
- package/dist/framework/execution/http-target.d.ts.map +1 -0
- package/dist/framework/execution/http-target.js +41 -0
- package/dist/framework/execution/http-target.js.map +1 -0
- package/dist/framework/execution/latency-tracker.d.ts +44 -0
- package/dist/framework/execution/latency-tracker.d.ts.map +1 -0
- package/dist/framework/execution/latency-tracker.js +76 -0
- package/dist/framework/execution/latency-tracker.js.map +1 -0
- package/dist/framework/execution/run-load-window.d.ts +45 -0
- package/dist/framework/execution/run-load-window.d.ts.map +1 -0
- package/dist/framework/execution/run-load-window.js +136 -0
- package/dist/framework/execution/run-load-window.js.map +1 -0
- package/dist/framework/execution/scenario-aborted-error.d.ts +14 -0
- package/dist/framework/execution/scenario-aborted-error.d.ts.map +1 -0
- package/dist/framework/execution/scenario-aborted-error.js +24 -0
- package/dist/framework/execution/scenario-aborted-error.js.map +1 -0
- package/dist/framework/execution/target.d.ts +35 -0
- package/dist/framework/execution/target.d.ts.map +1 -0
- package/dist/framework/execution/target.js +21 -0
- package/dist/framework/execution/target.js.map +1 -0
- package/dist/framework/registry.d.ts +67 -0
- package/dist/framework/registry.d.ts.map +1 -0
- package/dist/framework/registry.js +113 -0
- package/dist/framework/registry.js.map +1 -0
- package/dist/framework/resolve-metric.d.ts +79 -0
- package/dist/framework/resolve-metric.d.ts.map +1 -0
- package/dist/framework/resolve-metric.js +135 -0
- package/dist/framework/resolve-metric.js.map +1 -0
- package/dist/framework/result-builder.d.ts +72 -0
- package/dist/framework/result-builder.d.ts.map +1 -0
- package/dist/framework/result-builder.js +214 -0
- package/dist/framework/result-builder.js.map +1 -0
- package/dist/framework/result-renderers.d.ts +37 -0
- package/dist/framework/result-renderers.d.ts.map +1 -0
- package/dist/framework/result-renderers.js +62 -0
- package/dist/framework/result-renderers.js.map +1 -0
- package/dist/framework/runnable-scenario.d.ts +37 -0
- package/dist/framework/runnable-scenario.d.ts.map +1 -0
- package/dist/framework/runnable-scenario.js +9 -0
- package/dist/framework/runnable-scenario.js.map +1 -0
- package/dist/framework/scenario-executor-result.d.ts +44 -0
- package/dist/framework/scenario-executor-result.d.ts.map +1 -0
- package/dist/framework/scenario-executor-result.js +13 -0
- package/dist/framework/scenario-executor-result.js.map +1 -0
- package/dist/framework/scenario-logger.d.ts +18 -0
- package/dist/framework/scenario-logger.d.ts.map +1 -0
- package/dist/framework/scenario-logger.js +39 -0
- package/dist/framework/scenario-logger.js.map +1 -0
- package/dist/framework/scenario-metric-key.d.ts +24 -0
- package/dist/framework/scenario-metric-key.d.ts.map +1 -0
- package/dist/framework/scenario-metric-key.js +17 -0
- package/dist/framework/scenario-metric-key.js.map +1 -0
- package/dist/framework/validation.d.ts +83 -0
- package/dist/framework/validation.d.ts.map +1 -0
- package/dist/framework/validation.js +93 -0
- package/dist/framework/validation.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +19 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +16 -0
- package/dist/internal.js.map +1 -0
- package/dist/kinds/chaos/__tests__/executor.test.d.ts +6 -0
- package/dist/kinds/chaos/__tests__/executor.test.d.ts.map +1 -0
- package/dist/kinds/chaos/__tests__/executor.test.js +117 -0
- package/dist/kinds/chaos/__tests__/executor.test.js.map +1 -0
- package/dist/kinds/chaos/config.d.ts +48 -0
- package/dist/kinds/chaos/config.d.ts.map +1 -0
- package/dist/kinds/chaos/config.js +15 -0
- package/dist/kinds/chaos/config.js.map +1 -0
- package/dist/kinds/chaos/define.d.ts +32 -0
- package/dist/kinds/chaos/define.d.ts.map +1 -0
- package/dist/kinds/chaos/define.js +111 -0
- package/dist/kinds/chaos/define.js.map +1 -0
- package/dist/kinds/chaos/executor.d.ts +21 -0
- package/dist/kinds/chaos/executor.d.ts.map +1 -0
- package/dist/kinds/chaos/executor.js +107 -0
- package/dist/kinds/chaos/executor.js.map +1 -0
- package/dist/kinds/chaos/result.d.ts +43 -0
- package/dist/kinds/chaos/result.d.ts.map +1 -0
- package/dist/kinds/chaos/result.js +12 -0
- package/dist/kinds/chaos/result.js.map +1 -0
- package/dist/kinds/load/__tests__/executor.test.d.ts +6 -0
- package/dist/kinds/load/__tests__/executor.test.d.ts.map +1 -0
- package/dist/kinds/load/__tests__/executor.test.js +75 -0
- package/dist/kinds/load/__tests__/executor.test.js.map +1 -0
- package/dist/kinds/load/config.d.ts +30 -0
- package/dist/kinds/load/config.d.ts.map +1 -0
- package/dist/kinds/load/config.js +9 -0
- package/dist/kinds/load/config.js.map +1 -0
- package/dist/kinds/load/define.d.ts +47 -0
- package/dist/kinds/load/define.d.ts.map +1 -0
- package/dist/kinds/load/define.js +76 -0
- package/dist/kinds/load/define.js.map +1 -0
- package/dist/kinds/load/executor.d.ts +16 -0
- package/dist/kinds/load/executor.d.ts.map +1 -0
- package/dist/kinds/load/executor.js +90 -0
- package/dist/kinds/load/executor.js.map +1 -0
- package/dist/kinds/load/result.d.ts +21 -0
- package/dist/kinds/load/result.d.ts.map +1 -0
- package/dist/kinds/load/result.js +10 -0
- package/dist/kinds/load/result.js.map +1 -0
- package/dist/persistence/session-payload.d.ts +32 -0
- package/dist/persistence/session-payload.d.ts.map +1 -0
- package/dist/persistence/session-payload.js +46 -0
- package/dist/persistence/session-payload.js.map +1 -0
- package/dist/persistence/session-replay.d.ts +13 -0
- package/dist/persistence/session-replay.d.ts.map +1 -0
- package/dist/persistence/session-replay.js +76 -0
- package/dist/persistence/session-replay.js.map +1 -0
- package/dist/persistence/session-replay.test.d.ts +10 -0
- package/dist/persistence/session-replay.test.d.ts.map +1 -0
- package/dist/persistence/session-replay.test.js +169 -0
- package/dist/persistence/session-replay.test.js.map +1 -0
- package/dist/plugins/__tests__/loader-scenarios.test.d.ts +12 -0
- package/dist/plugins/__tests__/loader-scenarios.test.d.ts.map +1 -0
- package/dist/plugins/__tests__/loader-scenarios.test.js +61 -0
- package/dist/plugins/__tests__/loader-scenarios.test.js.map +1 -0
- package/dist/plugins/__tests__/scenario-package-discovery.test.d.ts +2 -0
- package/dist/plugins/__tests__/scenario-package-discovery.test.d.ts.map +1 -0
- package/dist/plugins/__tests__/scenario-package-discovery.test.js +43 -0
- package/dist/plugins/__tests__/scenario-package-discovery.test.js.map +1 -0
- package/dist/plugins/loader.d.ts +32 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +119 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/scenario-package-discovery.d.ts +23 -0
- package/dist/plugins/scenario-package-discovery.d.ts.map +1 -0
- package/dist/plugins/scenario-package-discovery.js +42 -0
- package/dist/plugins/scenario-package-discovery.js.map +1 -0
- package/dist/plugins/types.d.ts +24 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +18 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/recipes/__tests__/recipes.test.d.ts +2 -0
- package/dist/recipes/__tests__/recipes.test.d.ts.map +1 -0
- package/dist/recipes/__tests__/recipes.test.js +515 -0
- package/dist/recipes/__tests__/recipes.test.js.map +1 -0
- package/dist/recipes/built-in-recipes.d.ts +16 -0
- package/dist/recipes/built-in-recipes.d.ts.map +1 -0
- package/dist/recipes/built-in-recipes.js +37 -0
- package/dist/recipes/built-in-recipes.js.map +1 -0
- package/dist/recipes/define-recipe.d.ts +29 -0
- package/dist/recipes/define-recipe.d.ts.map +1 -0
- package/dist/recipes/define-recipe.js +68 -0
- package/dist/recipes/define-recipe.js.map +1 -0
- package/dist/recipes/registry.d.ts +54 -0
- package/dist/recipes/registry.d.ts.map +1 -0
- package/dist/recipes/registry.js +89 -0
- package/dist/recipes/registry.js.map +1 -0
- package/dist/recipes/service.d.ts +61 -0
- package/dist/recipes/service.d.ts.map +1 -0
- package/dist/recipes/service.js +205 -0
- package/dist/recipes/service.js.map +1 -0
- package/dist/recipes/types.d.ts +62 -0
- package/dist/recipes/types.d.ts.map +1 -0
- package/dist/recipes/types.js +10 -0
- package/dist/recipes/types.js.map +1 -0
- package/dist/scaffold/examples.d.ts +22 -0
- package/dist/scaffold/examples.d.ts.map +1 -0
- package/dist/scaffold/examples.js +91 -0
- package/dist/scaffold/examples.js.map +1 -0
- package/dist/scope-augmentation.d.ts +70 -0
- package/dist/scope-augmentation.d.ts.map +1 -0
- package/dist/scope-augmentation.js +28 -0
- package/dist/scope-augmentation.js.map +1 -0
- package/dist/tool.d.ts +21 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +347 -0
- package/dist/tool.js.map +1 -0
- package/dist/types/base-types.d.ts +35 -0
- package/dist/types/base-types.d.ts.map +1 -0
- package/dist/types/base-types.js +8 -0
- package/dist/types/base-types.js.map +1 -0
- package/dist/types/framework-types.d.ts +62 -0
- package/dist/types/framework-types.d.ts.map +1 -0
- package/dist/types/framework-types.js +15 -0
- package/dist/types/framework-types.js.map +1 -0
- package/dist/types/kind-types.d.ts +24 -0
- package/dist/types/kind-types.d.ts.map +1 -0
- package/dist/types/kind-types.js +22 -0
- package/dist/types/kind-types.js.map +1 -0
- package/dist/types/workload.d.ts +30 -0
- package/dist/types/workload.d.ts.map +1 -0
- package/dist/types/workload.js +20 -0
- package/dist/types/workload.js.map +1 -0
- package/package.json +120 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pre-built assertions for simulation scenarios
|
|
3
|
+
*
|
|
4
|
+
* All assertion functions are pure (no side effects).
|
|
5
|
+
* Default thresholds are production-safe.
|
|
6
|
+
* Custom assertions allow escape hatch.
|
|
7
|
+
*/
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// ASSERTION BUILDERS
|
|
10
|
+
// =============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Pre-built assertions for common metrics.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* export const myScenario = defineLoadScenario({
|
|
17
|
+
* // ...
|
|
18
|
+
* assertions: [
|
|
19
|
+
* ASSERTIONS.lowErrorRate(),
|
|
20
|
+
* ASSERTIONS.lowLatency('p95', 500),
|
|
21
|
+
* ASSERTIONS.minThroughput(100),
|
|
22
|
+
* ],
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export const ASSERTIONS = {
|
|
27
|
+
// ===========================================================================
|
|
28
|
+
// ERROR RATE
|
|
29
|
+
// ===========================================================================
|
|
30
|
+
/**
|
|
31
|
+
* Assert that error rate is below threshold.
|
|
32
|
+
* @param threshold - Maximum error rate (0-1). Default: 0.05 (5%)
|
|
33
|
+
*/
|
|
34
|
+
lowErrorRate: (threshold = 0.05) => ({
|
|
35
|
+
metric: 'error_rate',
|
|
36
|
+
operator: 'lt',
|
|
37
|
+
value: threshold,
|
|
38
|
+
message: `Error rate must be < ${(threshold * 100).toFixed(1)}%`,
|
|
39
|
+
}),
|
|
40
|
+
/**
|
|
41
|
+
* Assert zero errors.
|
|
42
|
+
*/
|
|
43
|
+
zeroErrors: () => ({
|
|
44
|
+
metric: 'error_rate',
|
|
45
|
+
operator: 'eq',
|
|
46
|
+
value: 0,
|
|
47
|
+
message: 'Error rate must be 0%',
|
|
48
|
+
}),
|
|
49
|
+
// ===========================================================================
|
|
50
|
+
// LATENCY
|
|
51
|
+
// ===========================================================================
|
|
52
|
+
/**
|
|
53
|
+
* Assert that latency percentile is below threshold.
|
|
54
|
+
* @param percentile - Which percentile to check (p50, p95, p99)
|
|
55
|
+
* @param thresholdMs - Maximum latency in milliseconds
|
|
56
|
+
*/
|
|
57
|
+
lowLatency: (percentile = 'p95', thresholdMs = 500) => ({
|
|
58
|
+
metric: `${percentile}_latency_ms`,
|
|
59
|
+
operator: 'lt',
|
|
60
|
+
value: thresholdMs,
|
|
61
|
+
message: `${percentile.toUpperCase()} latency must be < ${thresholdMs}ms`,
|
|
62
|
+
}),
|
|
63
|
+
/**
|
|
64
|
+
* Assert that average latency is below threshold.
|
|
65
|
+
* @param thresholdMs - Maximum average latency in milliseconds
|
|
66
|
+
*/
|
|
67
|
+
avgLatency: (thresholdMs = 200) => ({
|
|
68
|
+
metric: 'avg_latency_ms',
|
|
69
|
+
operator: 'lt',
|
|
70
|
+
value: thresholdMs,
|
|
71
|
+
message: `Average latency must be < ${thresholdMs}ms`,
|
|
72
|
+
}),
|
|
73
|
+
/**
|
|
74
|
+
* Assert that max latency is below threshold.
|
|
75
|
+
* @param thresholdMs - Maximum latency in milliseconds
|
|
76
|
+
*/
|
|
77
|
+
maxLatency: (thresholdMs = 2000) => ({
|
|
78
|
+
metric: 'max_latency_ms',
|
|
79
|
+
operator: 'lt',
|
|
80
|
+
value: thresholdMs,
|
|
81
|
+
message: `Max latency must be < ${thresholdMs}ms`,
|
|
82
|
+
}),
|
|
83
|
+
// ===========================================================================
|
|
84
|
+
// THROUGHPUT
|
|
85
|
+
// ===========================================================================
|
|
86
|
+
/**
|
|
87
|
+
* Assert minimum throughput.
|
|
88
|
+
* @param rps - Minimum requests per second
|
|
89
|
+
*/
|
|
90
|
+
minThroughput: (rps) => ({
|
|
91
|
+
metric: 'requests_per_second',
|
|
92
|
+
operator: 'gte',
|
|
93
|
+
value: rps,
|
|
94
|
+
message: `Throughput must be >= ${rps} RPS`,
|
|
95
|
+
}),
|
|
96
|
+
/**
|
|
97
|
+
* Assert maximum throughput (useful for rate limiting tests).
|
|
98
|
+
* @param rps - Maximum requests per second
|
|
99
|
+
*/
|
|
100
|
+
maxThroughput: (rps) => ({
|
|
101
|
+
metric: 'requests_per_second',
|
|
102
|
+
operator: 'lte',
|
|
103
|
+
value: rps,
|
|
104
|
+
message: `Throughput must be <= ${rps} RPS`,
|
|
105
|
+
}),
|
|
106
|
+
// ===========================================================================
|
|
107
|
+
// SUCCESS RATE
|
|
108
|
+
// ===========================================================================
|
|
109
|
+
/**
|
|
110
|
+
* Assert high success rate.
|
|
111
|
+
* @param threshold - Minimum success rate (0-1). Default: 0.95 (95%)
|
|
112
|
+
*/
|
|
113
|
+
highSuccessRate: (threshold = 0.95) => ({
|
|
114
|
+
metric: 'success_rate',
|
|
115
|
+
operator: 'gte',
|
|
116
|
+
value: threshold,
|
|
117
|
+
message: `Success rate must be >= ${(threshold * 100).toFixed(1)}%`,
|
|
118
|
+
}),
|
|
119
|
+
/**
|
|
120
|
+
* Assert 100% success rate.
|
|
121
|
+
*/
|
|
122
|
+
perfectSuccessRate: () => ({
|
|
123
|
+
metric: 'success_rate',
|
|
124
|
+
operator: 'eq',
|
|
125
|
+
value: 1,
|
|
126
|
+
message: 'Success rate must be 100%',
|
|
127
|
+
}),
|
|
128
|
+
// ===========================================================================
|
|
129
|
+
// RESOURCE USAGE
|
|
130
|
+
// ===========================================================================
|
|
131
|
+
/**
|
|
132
|
+
* Assert memory usage is below threshold.
|
|
133
|
+
* @param thresholdMb - Maximum memory in megabytes
|
|
134
|
+
*/
|
|
135
|
+
memoryUsage: (thresholdMb) => ({
|
|
136
|
+
metric: 'memory_mb',
|
|
137
|
+
operator: 'lt',
|
|
138
|
+
value: thresholdMb,
|
|
139
|
+
message: `Memory usage must be < ${thresholdMb}MB`,
|
|
140
|
+
}),
|
|
141
|
+
/**
|
|
142
|
+
* Assert CPU usage is below threshold.
|
|
143
|
+
* @param threshold - Maximum CPU percentage (0-100)
|
|
144
|
+
*/
|
|
145
|
+
cpuUsage: (threshold) => ({
|
|
146
|
+
metric: 'cpu_percent',
|
|
147
|
+
operator: 'lt',
|
|
148
|
+
value: threshold,
|
|
149
|
+
message: `CPU usage must be < ${threshold}%`,
|
|
150
|
+
}),
|
|
151
|
+
// ===========================================================================
|
|
152
|
+
// CUSTOM
|
|
153
|
+
// ===========================================================================
|
|
154
|
+
/**
|
|
155
|
+
* Create a custom assertion.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* ASSERTIONS.custom('listing_creation_time_ms', 'lt', 1000, 'Listing creation must be < 1s')
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
custom: (metric, operator, value, message) => ({
|
|
163
|
+
metric,
|
|
164
|
+
operator,
|
|
165
|
+
value,
|
|
166
|
+
message: message ?? `${metric} ${operator} ${value}`,
|
|
167
|
+
}),
|
|
168
|
+
};
|
|
169
|
+
// =============================================================================
|
|
170
|
+
// ASSERTION EVALUATION
|
|
171
|
+
// =============================================================================
|
|
172
|
+
/**
|
|
173
|
+
* Evaluate an operator comparison (low-level).
|
|
174
|
+
*/
|
|
175
|
+
export function evaluateOperator(actual, operator, expected) {
|
|
176
|
+
switch (operator) {
|
|
177
|
+
case 'lt': {
|
|
178
|
+
return actual < expected;
|
|
179
|
+
}
|
|
180
|
+
case 'lte': {
|
|
181
|
+
return actual <= expected;
|
|
182
|
+
}
|
|
183
|
+
case 'gt': {
|
|
184
|
+
return actual > expected;
|
|
185
|
+
}
|
|
186
|
+
case 'gte': {
|
|
187
|
+
return actual >= expected;
|
|
188
|
+
}
|
|
189
|
+
case 'eq': {
|
|
190
|
+
return actual === expected;
|
|
191
|
+
}
|
|
192
|
+
case 'neq': {
|
|
193
|
+
return actual !== expected;
|
|
194
|
+
}
|
|
195
|
+
default: {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Evaluate an assertion against an actual value.
|
|
202
|
+
*/
|
|
203
|
+
export function evaluateAssertion(assertion, actual) {
|
|
204
|
+
switch (assertion.operator) {
|
|
205
|
+
case 'lt': {
|
|
206
|
+
return actual < assertion.value;
|
|
207
|
+
}
|
|
208
|
+
case 'lte': {
|
|
209
|
+
return actual <= assertion.value;
|
|
210
|
+
}
|
|
211
|
+
case 'gt': {
|
|
212
|
+
return actual > assertion.value;
|
|
213
|
+
}
|
|
214
|
+
case 'gte': {
|
|
215
|
+
return actual >= assertion.value;
|
|
216
|
+
}
|
|
217
|
+
case 'eq': {
|
|
218
|
+
return actual === assertion.value;
|
|
219
|
+
}
|
|
220
|
+
case 'neq': {
|
|
221
|
+
return actual !== assertion.value;
|
|
222
|
+
}
|
|
223
|
+
default: {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get a human-readable description of an operator.
|
|
230
|
+
*/
|
|
231
|
+
export function getOperatorDescription(operator) {
|
|
232
|
+
switch (operator) {
|
|
233
|
+
case 'lt': {
|
|
234
|
+
return 'less than';
|
|
235
|
+
}
|
|
236
|
+
case 'lte': {
|
|
237
|
+
return 'at most';
|
|
238
|
+
}
|
|
239
|
+
case 'gt': {
|
|
240
|
+
return 'greater than';
|
|
241
|
+
}
|
|
242
|
+
case 'gte': {
|
|
243
|
+
return 'at least';
|
|
244
|
+
}
|
|
245
|
+
case 'eq': {
|
|
246
|
+
return 'equal to';
|
|
247
|
+
}
|
|
248
|
+
case 'neq': {
|
|
249
|
+
return 'not equal to';
|
|
250
|
+
}
|
|
251
|
+
default: {
|
|
252
|
+
return operator;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=assertions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertions.js","sourceRoot":"","sources":["../../src/framework/assertions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Unit tests for execution-engine utilities.
|
|
3
|
+
*
|
|
4
|
+
* The orchestration loop is exercised by scenario-execution.test.ts;
|
|
5
|
+
* this file targets the helper functions that are exported as the
|
|
6
|
+
* public API of the engine.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=execution-engine.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-engine.test.d.ts","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/execution-engine.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Unit tests for execution-engine utilities.
|
|
3
|
+
*
|
|
4
|
+
* The orchestration loop is exercised by scenario-execution.test.ts;
|
|
5
|
+
* this file targets the helper functions that are exported as the
|
|
6
|
+
* public API of the engine.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, expect, it } from 'vitest';
|
|
9
|
+
import { resolveMetric } from '../../resolve-metric.js';
|
|
10
|
+
import { createEmptyMetrics } from '../../result-builder.js';
|
|
11
|
+
import { ScenarioAbortedError, scenarioAborted, sleepWithAbort, updateLatencyMetrics, validateAssertions, } from '../execution-engine.js';
|
|
12
|
+
const baseMetrics = (overrides = {}) => ({
|
|
13
|
+
...createEmptyMetrics(),
|
|
14
|
+
totalRequests: 100,
|
|
15
|
+
successfulRequests: 99,
|
|
16
|
+
failedRequests: 1,
|
|
17
|
+
avgLatencyMs: 50,
|
|
18
|
+
p50LatencyMs: 40,
|
|
19
|
+
p95LatencyMs: 80,
|
|
20
|
+
p99LatencyMs: 120,
|
|
21
|
+
...overrides,
|
|
22
|
+
});
|
|
23
|
+
describe('validateAssertions', () => {
|
|
24
|
+
it('returns passed=true when every assertion holds', () => {
|
|
25
|
+
const assertions = [
|
|
26
|
+
{ metric: 'error_rate', operator: 'lt', value: 0.5, message: 'low error rate' },
|
|
27
|
+
{ metric: 'success_rate', operator: 'gt', value: 0.5, message: 'high success rate' },
|
|
28
|
+
];
|
|
29
|
+
const out = validateAssertions(baseMetrics(), assertions);
|
|
30
|
+
expect(out.passed).toBe(true);
|
|
31
|
+
expect(out.failed).toEqual([]);
|
|
32
|
+
});
|
|
33
|
+
it('returns failed entries with the actual value', () => {
|
|
34
|
+
const assertions = [
|
|
35
|
+
{ metric: 'error_rate', operator: 'lt', value: 0.001, message: 'extreme low error' },
|
|
36
|
+
];
|
|
37
|
+
const out = validateAssertions(baseMetrics(), assertions);
|
|
38
|
+
expect(out.passed).toBe(false);
|
|
39
|
+
expect(out.failed).toHaveLength(1);
|
|
40
|
+
expect(out.failed[0]?.actual).toBeCloseTo(0.01);
|
|
41
|
+
});
|
|
42
|
+
it('returns passed=false / failed=[] when assertions is not an array', () => {
|
|
43
|
+
const out = validateAssertions(baseMetrics(), undefined);
|
|
44
|
+
expect(out.passed).toBe(false);
|
|
45
|
+
expect(out.failed).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
it('honors an empty assertion list as passing', () => {
|
|
48
|
+
expect(validateAssertions(baseMetrics(), []).passed).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('resolveMetric (via validateAssertions)', () => {
|
|
52
|
+
it.each([
|
|
53
|
+
['error_rate', baseMetrics({ totalRequests: 100, failedRequests: 25 }), 0.25],
|
|
54
|
+
['error_rate', baseMetrics({ totalRequests: 0 }), 0],
|
|
55
|
+
['success_rate', baseMetrics({ totalRequests: 100, successfulRequests: 90 }), 0.9],
|
|
56
|
+
// Per resolve-metric.ts: success_rate is 0 when totalRequests === 0 (tightening choice).
|
|
57
|
+
['success_rate', baseMetrics({ totalRequests: 0 }), 0],
|
|
58
|
+
['recovery_rate', baseMetrics({ errorsGenerated: 10, failedRequests: 2 }), 0.8],
|
|
59
|
+
['recovery_rate', baseMetrics({ errorsGenerated: 0 }), 1],
|
|
60
|
+
['p50_latency', baseMetrics({ p50LatencyMs: 40 }), 40],
|
|
61
|
+
['p50_latency_ms', baseMetrics({ p50LatencyMs: 40 }), 40],
|
|
62
|
+
['p95_latency_ms', baseMetrics({ p95LatencyMs: 80 }), 80],
|
|
63
|
+
['p99_latency_ms', baseMetrics({ p99LatencyMs: 120 }), 120],
|
|
64
|
+
['avg_latency_ms', baseMetrics({ avgLatencyMs: 60 }), 60],
|
|
65
|
+
['total_requests', baseMetrics({ totalRequests: 5 }), 5],
|
|
66
|
+
['failed_requests', baseMetrics({ failedRequests: 3 }), 3],
|
|
67
|
+
])('resolveMetric(%s)', (metric, metrics, expected) => {
|
|
68
|
+
expect(resolveMetric(metric, metrics)).toBeCloseTo(expected);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('updateLatencyMetrics', () => {
|
|
72
|
+
it('seeds all percentile fields on the first sample', () => {
|
|
73
|
+
const m = createEmptyMetrics();
|
|
74
|
+
updateLatencyMetrics(m, 100);
|
|
75
|
+
expect(m.avgLatencyMs).toBe(100);
|
|
76
|
+
expect(m.p50LatencyMs).toBe(100);
|
|
77
|
+
expect(m.p95LatencyMs).toBe(100);
|
|
78
|
+
expect(m.p99LatencyMs).toBe(100);
|
|
79
|
+
});
|
|
80
|
+
it('updates the running average on subsequent samples', () => {
|
|
81
|
+
const m = { ...createEmptyMetrics(), totalRequests: 1, avgLatencyMs: 100 };
|
|
82
|
+
// After: n=1, avg becomes (100*0 + sample)/1 — but the function expects
|
|
83
|
+
// `metrics.totalRequests` to be the count BEFORE incrementing.
|
|
84
|
+
updateLatencyMetrics(m, 200);
|
|
85
|
+
expect(m.avgLatencyMs).toBe(200);
|
|
86
|
+
});
|
|
87
|
+
it('approximates percentiles as multiples of the average for n>=1', () => {
|
|
88
|
+
const m = { ...createEmptyMetrics(), totalRequests: 2, avgLatencyMs: 100 };
|
|
89
|
+
updateLatencyMetrics(m, 200);
|
|
90
|
+
expect(m.p50LatencyMs).toBeCloseTo(m.avgLatencyMs * 0.9);
|
|
91
|
+
expect(m.p95LatencyMs).toBeCloseTo(m.avgLatencyMs * 1.5);
|
|
92
|
+
expect(m.p99LatencyMs).toBeCloseTo(m.avgLatencyMs * 2);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe('sleepWithAbort', () => {
|
|
96
|
+
it('resolves after the specified delay', async () => {
|
|
97
|
+
const ac = new AbortController();
|
|
98
|
+
const start = Date.now();
|
|
99
|
+
await sleepWithAbort(20, ac.signal);
|
|
100
|
+
expect(Date.now() - start).toBeGreaterThanOrEqual(15);
|
|
101
|
+
});
|
|
102
|
+
it('rejects immediately when the signal is already aborted', async () => {
|
|
103
|
+
const ac = new AbortController();
|
|
104
|
+
ac.abort();
|
|
105
|
+
await expect(sleepWithAbort(1000, ac.signal)).rejects.toThrow(ScenarioAbortedError);
|
|
106
|
+
});
|
|
107
|
+
it('rejects when the signal is aborted mid-sleep', async () => {
|
|
108
|
+
const ac = new AbortController();
|
|
109
|
+
const promise = sleepWithAbort(10_000, ac.signal);
|
|
110
|
+
setTimeout(() => ac.abort(), 5);
|
|
111
|
+
await expect(promise).rejects.toThrow(ScenarioAbortedError);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('scenarioAborted', () => {
|
|
115
|
+
it('returns silently when signal is undefined', () => {
|
|
116
|
+
expect(() => scenarioAborted(undefined)).not.toThrow();
|
|
117
|
+
});
|
|
118
|
+
it('returns silently when signal is not aborted', () => {
|
|
119
|
+
const ac = new AbortController();
|
|
120
|
+
expect(() => scenarioAborted(ac.signal)).not.toThrow();
|
|
121
|
+
});
|
|
122
|
+
it('throws ScenarioAbortedError when signal is aborted', () => {
|
|
123
|
+
const ac = new AbortController();
|
|
124
|
+
ac.abort();
|
|
125
|
+
expect(() => scenarioAborted(ac.signal, 'sid')).toThrow(ScenarioAbortedError);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe('ScenarioAbortedError', () => {
|
|
129
|
+
it('carries the scenario id when one is supplied', () => {
|
|
130
|
+
const err = new ScenarioAbortedError('s1');
|
|
131
|
+
expect(err.message).toContain('s1');
|
|
132
|
+
});
|
|
133
|
+
it('uses an unknown placeholder when no id is supplied', () => {
|
|
134
|
+
const err = new ScenarioAbortedError();
|
|
135
|
+
expect(err.message.length).toBeGreaterThan(0);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=execution-engine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-engine.test.js","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/execution-engine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fault-builders.test.d.ts","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/fault-builders.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tests for the fault.* builders.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { fault } from '../fault-builders.js';
|
|
6
|
+
describe('fault builders', () => {
|
|
7
|
+
it('latency', () => {
|
|
8
|
+
expect(fault.latency({ ms: 5 })).toEqual({ kind: 'latency', ms: 5 });
|
|
9
|
+
});
|
|
10
|
+
it('abort', () => {
|
|
11
|
+
expect(fault.abort()).toEqual({ kind: 'abort' });
|
|
12
|
+
});
|
|
13
|
+
it('drop', () => {
|
|
14
|
+
expect(fault.drop()).toEqual({ kind: 'drop' });
|
|
15
|
+
});
|
|
16
|
+
it('of assembles a probability-gated spec', () => {
|
|
17
|
+
expect(fault.of([fault.drop(), fault.abort()], { probability: 0.3 })).toEqual({
|
|
18
|
+
faults: [{ kind: 'drop' }, { kind: 'abort' }],
|
|
19
|
+
probability: 0.3,
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=fault-builders.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fault-builders.test.js","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/fault-builders.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACjB,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACf,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACd,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5E,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC7C,WAAW,EAAE,GAAG;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fault-model.test.d.ts","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/fault-model.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Behaviour tests for the client-side fault model. Determinism
|
|
3
|
+
* comes from an injected RNG sequence so perturbed counts are exact.
|
|
4
|
+
*/
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { countingTarget, noopTarget } from '../../../__tests__/test-utils/targets.js';
|
|
7
|
+
import { fault } from '../fault-builders.js';
|
|
8
|
+
import { createFaultModel } from '../fault-model.js';
|
|
9
|
+
const ctx = { signal: new AbortController().signal, correlationId: 'c' };
|
|
10
|
+
/** RNG that walks a fixed sequence (wraps). */
|
|
11
|
+
const seq = (vals) => {
|
|
12
|
+
let i = 0;
|
|
13
|
+
return () => vals[i++ % vals.length] ?? 0;
|
|
14
|
+
};
|
|
15
|
+
describe('createFaultModel', () => {
|
|
16
|
+
it('perturbs exactly the requests whose draw < probability', async () => {
|
|
17
|
+
const ct = countingTarget();
|
|
18
|
+
const fm = createFaultModel(fault.of([fault.drop()], { probability: 0.5 }), {
|
|
19
|
+
rng: seq([0.4, 0.6, 0.4, 0.6]),
|
|
20
|
+
});
|
|
21
|
+
const wrapped = fm.wrap(ct.target);
|
|
22
|
+
const results = await Promise.allSettled([
|
|
23
|
+
wrapped(ctx),
|
|
24
|
+
wrapped(ctx),
|
|
25
|
+
wrapped(ctx),
|
|
26
|
+
wrapped(ctx),
|
|
27
|
+
]);
|
|
28
|
+
// Draws 0.4 and 0.4 (< 0.5) → dropped (rejected); 0.6 and 0.6 → passed through.
|
|
29
|
+
expect(results.filter((r) => r.status === 'rejected')).toHaveLength(2);
|
|
30
|
+
expect(ct.calls()).toBe(2); // dropped requests never reach the target
|
|
31
|
+
expect(fm.drained()).toHaveLength(2);
|
|
32
|
+
expect(fm.drained().every((f) => f.kind === 'drop')).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it('latency fault delays the real call (target still runs)', async () => {
|
|
35
|
+
const ct = countingTarget();
|
|
36
|
+
const fm = createFaultModel(fault.of([fault.latency({ ms: 50 })], { probability: 1 }), {
|
|
37
|
+
rng: () => 0,
|
|
38
|
+
});
|
|
39
|
+
const start = Date.now();
|
|
40
|
+
await fm.wrap(ct.target)(ctx);
|
|
41
|
+
expect(Date.now() - start).toBeGreaterThanOrEqual(45);
|
|
42
|
+
expect(ct.calls()).toBe(1);
|
|
43
|
+
});
|
|
44
|
+
it('abort fault fails even when the target ignores the signal', async () => {
|
|
45
|
+
const fm = createFaultModel(fault.of([fault.abort()], { probability: 1 }), { rng: () => 0 });
|
|
46
|
+
await expect(fm.wrap(noopTarget)(ctx)).rejects.toThrow();
|
|
47
|
+
expect(fm.drained()).toHaveLength(1);
|
|
48
|
+
expect(fm.drained()[0]?.kind).toBe('abort');
|
|
49
|
+
});
|
|
50
|
+
it('does not perturb when probability is 0', async () => {
|
|
51
|
+
const ct = countingTarget();
|
|
52
|
+
const fm = createFaultModel(fault.of([fault.drop()], { probability: 0 }), { rng: () => 0 });
|
|
53
|
+
await fm.wrap(ct.target)(ctx);
|
|
54
|
+
expect(ct.calls()).toBe(1);
|
|
55
|
+
expect(fm.drained()).toHaveLength(0);
|
|
56
|
+
});
|
|
57
|
+
it('round-robins across multiple fault kinds deterministically', async () => {
|
|
58
|
+
const fm = createFaultModel(fault.of([fault.drop(), fault.latency({ ms: 1 })], { probability: 1 }), { rng: () => 0 });
|
|
59
|
+
const wrapped = fm.wrap(noopTarget);
|
|
60
|
+
await Promise.allSettled([wrapped(ctx), wrapped(ctx), wrapped(ctx)]);
|
|
61
|
+
expect(fm.drained().map((f) => f.kind)).toEqual(['drop', 'latency', 'drop']);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=fault-model.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fault-model.test.js","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/fault-model.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-target.test.d.ts","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/http-target.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tests for the httpTarget helper (fetch stubbed).
|
|
3
|
+
*/
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { httpTarget } from '../http-target.js';
|
|
6
|
+
const ctx = { signal: new AbortController().signal, correlationId: 'c' };
|
|
7
|
+
const respond = (body, status) => () => Promise.resolve(new Response(body, { status }));
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
vi.restoreAllMocks();
|
|
10
|
+
});
|
|
11
|
+
describe('httpTarget', () => {
|
|
12
|
+
it('resolves on a 2xx', async () => {
|
|
13
|
+
vi.stubGlobal('fetch', vi.fn(respond('ok', 200)));
|
|
14
|
+
await expect(httpTarget({ url: 'https://x.test' })(ctx)).resolves.toBeUndefined();
|
|
15
|
+
});
|
|
16
|
+
it('throws on a non-2xx, carrying the status', async () => {
|
|
17
|
+
vi.stubGlobal('fetch', vi.fn(respond('no', 503)));
|
|
18
|
+
await expect(httpTarget({ url: 'https://x.test' })(ctx)).rejects.toThrow(/503/);
|
|
19
|
+
});
|
|
20
|
+
it('forwards method, headers, body, and the abort signal', async () => {
|
|
21
|
+
const f = vi.fn(respond('ok', 200));
|
|
22
|
+
vi.stubGlobal('fetch', f);
|
|
23
|
+
await httpTarget({ url: 'https://x.test', method: 'POST', headers: { a: 'b' }, body: 'p' })(ctx);
|
|
24
|
+
expect(f).toHaveBeenCalledWith('https://x.test', expect.objectContaining({
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: { a: 'b' },
|
|
27
|
+
body: 'p',
|
|
28
|
+
signal: ctx.signal,
|
|
29
|
+
}));
|
|
30
|
+
});
|
|
31
|
+
it('honours a custom okStatus predicate', async () => {
|
|
32
|
+
vi.stubGlobal('fetch', vi.fn(respond('nope', 404)));
|
|
33
|
+
await expect(httpTarget({ url: 'https://x.test', okStatus: (s) => s === 404 })(ctx)).resolves.toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=http-target.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-target.test.js","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/http-target.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE7D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C,MAAM,GAAG,GAAkB,EAAE,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC;AAExF,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE,CAAC,GAAG,EAAE,CACrD,OAAO,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AAElD,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,eAAe,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACxD,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACpC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC1B,MAAM,UAAU,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CACzF,GAAG,CACJ,CAAC;QACF,MAAM,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAC5B,gBAAgB,EAChB,MAAM,CAAC,gBAAgB,CAAC;YACtB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE;YACnB,IAAI,EAAE,GAAG;YACT,MAAM,EAAE,GAAG,CAAC,MAAM;SACnB,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,MAAM,CACV,UAAU,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CACvE,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-load-window.test.d.ts","sourceRoot":"","sources":["../../../../src/framework/execution/__tests__/run-load-window.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|