@glubean/sdk 0.7.0 → 0.8.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/dist/contract-http/adapter.d.ts.map +1 -1
- package/dist/contract-http/adapter.js +9 -0
- package/dist/contract-http/adapter.js.map +1 -1
- package/dist/data-path.d.ts.map +1 -1
- package/dist/data-path.js +10 -2
- package/dist/data-path.js.map +1 -1
- package/dist/load/artifact.d.ts +376 -0
- package/dist/load/artifact.d.ts.map +1 -0
- package/dist/load/artifact.js +14 -0
- package/dist/load/artifact.js.map +1 -0
- package/dist/load/builder.d.ts +80 -0
- package/dist/load/builder.d.ts.map +1 -0
- package/dist/load/builder.js +262 -0
- package/dist/load/builder.js.map +1 -0
- package/dist/load/context.d.ts +81 -0
- package/dist/load/context.d.ts.map +1 -0
- package/dist/load/context.js +2 -0
- package/dist/load/context.js.map +1 -0
- package/dist/load/duration.d.ts +9 -0
- package/dist/load/duration.d.ts.map +1 -0
- package/dist/load/duration.js +22 -0
- package/dist/load/duration.js.map +1 -0
- package/dist/load/events.d.ts +132 -0
- package/dist/load/events.d.ts.map +1 -0
- package/dist/load/events.js +2 -0
- package/dist/load/events.js.map +1 -0
- package/dist/load/feeder.d.ts +118 -0
- package/dist/load/feeder.d.ts.map +1 -0
- package/dist/load/feeder.js +170 -0
- package/dist/load/feeder.js.map +1 -0
- package/dist/load/index.d.ts +32 -0
- package/dist/load/index.d.ts.map +1 -0
- package/dist/load/index.js +7 -0
- package/dist/load/index.js.map +1 -0
- package/dist/load/progress.d.ts +56 -0
- package/dist/load/progress.d.ts.map +1 -0
- package/dist/load/progress.js +2 -0
- package/dist/load/progress.js.map +1 -0
- package/dist/load/projection.d.ts +36 -0
- package/dist/load/projection.d.ts.map +1 -0
- package/dist/load/projection.js +47 -0
- package/dist/load/projection.js.map +1 -0
- package/dist/load/runner.d.ts +201 -0
- package/dist/load/runner.d.ts.map +1 -0
- package/dist/load/runner.js +78 -0
- package/dist/load/runner.js.map +1 -0
- package/dist/load/scenario.d.ts +130 -0
- package/dist/load/scenario.d.ts.map +1 -0
- package/dist/load/scenario.js +9 -0
- package/dist/load/scenario.js.map +1 -0
- package/dist/load/step.d.ts +42 -0
- package/dist/load/step.d.ts.map +1 -0
- package/dist/load/step.js +2 -0
- package/dist/load/step.js.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* loadRunner(): the pressure model + report model over a loadScenario.
|
|
3
|
+
*
|
|
4
|
+
* `loadRunner()` is the runnable: it references one `loadScenario()` (or a
|
|
5
|
+
* traffic mix of several) and says how much pressure to apply. Discovery
|
|
6
|
+
* (M2) surfaces only `loadRunner()` exports as runnable; the referenced
|
|
7
|
+
* scenarios are workloads, not independently scheduled.
|
|
8
|
+
*
|
|
9
|
+
* M1 is the static authoring surface: `loadRunner()` returns a `LoadPlan`
|
|
10
|
+
* holding the resolved config. Actual execution lives in @glubean/runner.
|
|
11
|
+
*/
|
|
12
|
+
import type { LoadBuilder } from "./builder.js";
|
|
13
|
+
import type { FeederBinding } from "./feeder.js";
|
|
14
|
+
import type { LoadProjection } from "./projection.js";
|
|
15
|
+
import type { LoadScenario } from "./scenario.js";
|
|
16
|
+
import type { LoadAssertionFailureMode } from "./step.js";
|
|
17
|
+
/** A duration as milliseconds (number) or a human string like `"60s"` / `"2m"`. */
|
|
18
|
+
export type LoadDuration = number | string;
|
|
19
|
+
export interface LoadProducerSlotInfo {
|
|
20
|
+
id: string;
|
|
21
|
+
index: number;
|
|
22
|
+
}
|
|
23
|
+
export interface LoadIterationInfo {
|
|
24
|
+
id: string;
|
|
25
|
+
index: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Arguments passed to a function-form `input`. `TRow` is the `loadRunner.each()`
|
|
29
|
+
* row type that produced this plan (typed and present for each variants);
|
|
30
|
+
* `undefined` for non-each plans.
|
|
31
|
+
*/
|
|
32
|
+
export interface LoadInputArgs<TRow = undefined> {
|
|
33
|
+
row: TRow;
|
|
34
|
+
/** Feeder-allocated rows for this iteration, keyed by feeder name. */
|
|
35
|
+
feed: Record<string, any>;
|
|
36
|
+
producerSlot: LoadProducerSlotInfo;
|
|
37
|
+
iteration: LoadIterationInfo;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Per-iteration scenario input. Object form is a static input (same for every
|
|
41
|
+
* iteration); function form is the canonical form when feeders / producer-slot /
|
|
42
|
+
* iteration / `.each()` row participate. There is no hidden merge.
|
|
43
|
+
*/
|
|
44
|
+
export type LoadInputOption<TInput, TRow = undefined> = TInput | ((args: LoadInputArgs<TRow>) => TInput);
|
|
45
|
+
/** Safety valve for `ctx.report.primaryComplete(... releaseProducerSlot: true)`. */
|
|
46
|
+
export interface LoadContinuationConfig {
|
|
47
|
+
maxOutstanding?: number;
|
|
48
|
+
maxConcurrent?: number;
|
|
49
|
+
minPollInterval?: LoadDuration;
|
|
50
|
+
drainTimeout?: LoadDuration;
|
|
51
|
+
onBacklogFull?: "block-producer" | "fail-iteration";
|
|
52
|
+
}
|
|
53
|
+
/** Optional pacing / think-time (MVP may leave unimplemented → back-to-back). */
|
|
54
|
+
export interface LoadPacingConfig {
|
|
55
|
+
thinkTime?: LoadDuration | {
|
|
56
|
+
min: LoadDuration;
|
|
57
|
+
max: LoadDuration;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Threshold expressions for one scope (e.g. `errorRate: "<1%"`, `p95: "<800ms"`). */
|
|
61
|
+
export interface LoadThresholdScope {
|
|
62
|
+
errorRate?: string;
|
|
63
|
+
p50?: string;
|
|
64
|
+
p90?: string;
|
|
65
|
+
p95?: string;
|
|
66
|
+
p99?: string;
|
|
67
|
+
throughputPerSec?: string;
|
|
68
|
+
backlog?: string;
|
|
69
|
+
backpressureMs?: string;
|
|
70
|
+
}
|
|
71
|
+
/** Structured thresholds. `endpoints` / `steps` are keyed by routeKey / stepId. */
|
|
72
|
+
export interface LoadThresholds {
|
|
73
|
+
transaction?: LoadThresholdScope;
|
|
74
|
+
primary?: LoadThresholdScope;
|
|
75
|
+
endToEnd?: LoadThresholdScope;
|
|
76
|
+
continuation?: LoadThresholdScope;
|
|
77
|
+
endpoints?: Record<string, LoadThresholdScope>;
|
|
78
|
+
steps?: Record<string, LoadThresholdScope>;
|
|
79
|
+
}
|
|
80
|
+
/** Bounded report sampling caps. */
|
|
81
|
+
export interface LoadReportConfig {
|
|
82
|
+
failureTraces?: number;
|
|
83
|
+
slowTransactionSummaries?: number;
|
|
84
|
+
}
|
|
85
|
+
/** A scenario reference: a built `LoadScenario` or an un-built `LoadBuilder`. */
|
|
86
|
+
export type LoadScenarioRef<Input = unknown> = LoadScenario<Input, any> | LoadBuilder<Input, any>;
|
|
87
|
+
type Feeders = Record<string, FeederBinding>;
|
|
88
|
+
interface LoadRunnerCommon {
|
|
89
|
+
concurrency: number;
|
|
90
|
+
duration?: LoadDuration;
|
|
91
|
+
iterations?: number;
|
|
92
|
+
rampUp?: LoadDuration;
|
|
93
|
+
pacing?: LoadPacingConfig;
|
|
94
|
+
continuation?: LoadContinuationConfig;
|
|
95
|
+
assertions?: {
|
|
96
|
+
onFailure?: LoadAssertionFailureMode;
|
|
97
|
+
};
|
|
98
|
+
thresholds?: LoadThresholds;
|
|
99
|
+
report?: LoadReportConfig;
|
|
100
|
+
/** How a run-level abort (stop / duration deadline / SIGINT) reaches in-flight
|
|
101
|
+
* requests.
|
|
102
|
+
* - `"precise"` (default): cancel in-flight HTTP at once. Uses a leak-free
|
|
103
|
+
* per-iteration abort bridge — no per-request listener accumulation.
|
|
104
|
+
* - `"coarse"`: don't wire the abort signal into each request; stop between steps
|
|
105
|
+
* instead. A few % more throughput for high-RPS runs where requests are short,
|
|
106
|
+
* at the cost of letting an already-sent request finish before the run stops. */
|
|
107
|
+
abort?: "precise" | "coarse";
|
|
108
|
+
}
|
|
109
|
+
/** Single-scenario load runner config. `TRow` is the `.each()` row, if any. */
|
|
110
|
+
export interface LoadRunnerConfig<Input = unknown, TRow = undefined> extends LoadRunnerCommon {
|
|
111
|
+
scenario: LoadScenarioRef<Input>;
|
|
112
|
+
feeders?: Feeders;
|
|
113
|
+
input?: LoadInputOption<Input, TRow>;
|
|
114
|
+
}
|
|
115
|
+
/** One entry in a traffic mix. */
|
|
116
|
+
export interface LoadMixEntry<Input = unknown, TRow = undefined> {
|
|
117
|
+
id: string;
|
|
118
|
+
scenario: LoadScenarioRef<Input>;
|
|
119
|
+
weight: number;
|
|
120
|
+
feeders?: Feeders;
|
|
121
|
+
input?: LoadInputOption<Input, TRow>;
|
|
122
|
+
}
|
|
123
|
+
/** Multi-scenario (traffic mix) config. Each entry may have its own input/feeders. */
|
|
124
|
+
export interface LoadMixConfig<TRow = undefined> extends LoadRunnerCommon {
|
|
125
|
+
scenarios: LoadMixEntry<any, TRow>[];
|
|
126
|
+
/** Shared feeders (no Input coupling). Per-entry feeders override these. */
|
|
127
|
+
feeders?: Feeders;
|
|
128
|
+
}
|
|
129
|
+
export type AnyLoadRunnerConfig = LoadRunnerConfig<any, any> | LoadMixConfig<any>;
|
|
130
|
+
/** A runnable load plan (output of `loadRunner()`). */
|
|
131
|
+
export interface LoadPlan {
|
|
132
|
+
readonly __glubean_type: "load-runner";
|
|
133
|
+
id: string;
|
|
134
|
+
config: AnyLoadRunnerConfig;
|
|
135
|
+
/**
|
|
136
|
+
* For `loadRunner.each()` variants: the table row that produced this plan.
|
|
137
|
+
* The load runtime surfaces it to function-form `input` as `args.row`.
|
|
138
|
+
* Absent for non-each plans.
|
|
139
|
+
*/
|
|
140
|
+
row?: Record<string, unknown>;
|
|
141
|
+
/**
|
|
142
|
+
* Plain-data projection of this plan (runnerId / scenarios / steps /
|
|
143
|
+
* normalized durations / threshold scopes), exposed as a lazily-recomputed
|
|
144
|
+
* getter so it always reflects the current config / scenario builders — no
|
|
145
|
+
* stale snapshot if a scenario gains steps after `loadRunner()`. Discovery
|
|
146
|
+
* (scanner / CLI) reads it by duck-typing the exported value: no SDK import
|
|
147
|
+
* and no global registry needed.
|
|
148
|
+
*/
|
|
149
|
+
readonly projection: LoadProjection;
|
|
150
|
+
}
|
|
151
|
+
interface LoadRunnerFn {
|
|
152
|
+
/** Single-scenario load plan. */
|
|
153
|
+
<Input, TRow = undefined>(id: string, config: LoadRunnerConfig<Input, TRow>): LoadPlan;
|
|
154
|
+
/** Traffic-mix load plan. */
|
|
155
|
+
(id: string, config: LoadMixConfig): LoadPlan;
|
|
156
|
+
/**
|
|
157
|
+
* Scenario-level inventory expansion: one load plan per row (e.g. by plan,
|
|
158
|
+
* region, tenant). Each variant has its own id / thresholds / report, and the
|
|
159
|
+
* factory may return a single scenario or a traffic mix. Function-form `input`
|
|
160
|
+
* receives the producing row as a typed `args.row`.
|
|
161
|
+
*/
|
|
162
|
+
each<TRow extends object>(table: readonly TRow[]): <Input>(idTemplate: string, factory: (row: TRow, index: number) => LoadRunnerConfig<Input, TRow> | LoadMixConfig<TRow>) => LoadPlan[];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Define a pressure plan over one or more load scenarios.
|
|
166
|
+
*
|
|
167
|
+
* @example single scenario
|
|
168
|
+
* ```ts
|
|
169
|
+
* export const checkoutLoad = loadRunner("checkout-300", {
|
|
170
|
+
* scenario: checkoutScenario,
|
|
171
|
+
* concurrency: 300,
|
|
172
|
+
* duration: "60s",
|
|
173
|
+
* input: ({ feed, producerSlot, iteration }) => ({
|
|
174
|
+
* user: feed.user,
|
|
175
|
+
* clientRequestId: `${producerSlot.id}-${iteration.id}`,
|
|
176
|
+
* }),
|
|
177
|
+
* thresholds: { transaction: { errorRate: "<1%", p95: "<2000ms" } },
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export declare const loadRunner: LoadRunnerFn;
|
|
182
|
+
/**
|
|
183
|
+
* Type-safe constructor for a traffic-mix entry: it binds `input` to the
|
|
184
|
+
* scenario's `Input`, so a mismatched input shape is rejected at author time.
|
|
185
|
+
*
|
|
186
|
+
* Use it inside `scenarios: [...]`. A bare object literal in the array is only
|
|
187
|
+
* checked against `LoadMixEntry<any>` (TypeScript can't infer a distinct `Input`
|
|
188
|
+
* per array element), so wrap each entry with `loadMixEntry()` for per-entry
|
|
189
|
+
* type checking of heterogeneous typed scenarios.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```ts
|
|
193
|
+
* scenarios: [
|
|
194
|
+
* loadMixEntry({ id: "checkout", scenario: checkout, weight: 70, input: () => ({ sku: "s" }) }),
|
|
195
|
+
* loadMixEntry({ id: "refund", scenario: refund, weight: 30, input: () => ({ orderId: "o" }) }),
|
|
196
|
+
* ]
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export declare function loadMixEntry<Input, TRow = undefined>(entry: LoadMixEntry<Input, TRow>): LoadMixEntry<any, TRow>;
|
|
200
|
+
export {};
|
|
201
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/load/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { projectLoadPlan } from "./projection.js";
|
|
2
|
+
/** Interpolate `$index` and `$field` placeholders in an `.each()` id template. */
|
|
3
|
+
function interpolateId(template, row, index) {
|
|
4
|
+
// Token-aware: match a whole `$identifier` placeholder, so a field name that
|
|
5
|
+
// prefixes another (possibly missing) longer placeholder can't corrupt it
|
|
6
|
+
// (e.g. `$plan` must not eat the `$plan` inside a missing `$planId`).
|
|
7
|
+
return template.replace(/\$(\w+)/g, (match, name) => {
|
|
8
|
+
if (name === "index")
|
|
9
|
+
return String(index);
|
|
10
|
+
if (Object.prototype.hasOwnProperty.call(row, name))
|
|
11
|
+
return String(row[name]);
|
|
12
|
+
return match; // unknown placeholder — leave intact rather than silently corrupt
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Build a LoadPlan whose `projection` is a lazily-recomputed getter, so it
|
|
17
|
+
* always reflects the current config / scenario builders (no stale snapshot if
|
|
18
|
+
* a scenario gains steps after `loadRunner()` is called).
|
|
19
|
+
*/
|
|
20
|
+
function makeLoadPlan(id, config, row) {
|
|
21
|
+
const plan = {
|
|
22
|
+
__glubean_type: "load-runner",
|
|
23
|
+
id,
|
|
24
|
+
config,
|
|
25
|
+
...(row !== undefined ? { row } : {}),
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(plan, "projection", {
|
|
28
|
+
get: () => projectLoadPlan(plan),
|
|
29
|
+
enumerable: true,
|
|
30
|
+
});
|
|
31
|
+
return plan;
|
|
32
|
+
}
|
|
33
|
+
const loadRunnerImpl = (id, config) => makeLoadPlan(id, config);
|
|
34
|
+
loadRunnerImpl.each = (table) => {
|
|
35
|
+
return (idTemplate, factory) => table.map((row, index) => {
|
|
36
|
+
const rowRecord = row;
|
|
37
|
+
return makeLoadPlan(interpolateId(idTemplate, rowRecord, index), factory(row, index), rowRecord);
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Define a pressure plan over one or more load scenarios.
|
|
42
|
+
*
|
|
43
|
+
* @example single scenario
|
|
44
|
+
* ```ts
|
|
45
|
+
* export const checkoutLoad = loadRunner("checkout-300", {
|
|
46
|
+
* scenario: checkoutScenario,
|
|
47
|
+
* concurrency: 300,
|
|
48
|
+
* duration: "60s",
|
|
49
|
+
* input: ({ feed, producerSlot, iteration }) => ({
|
|
50
|
+
* user: feed.user,
|
|
51
|
+
* clientRequestId: `${producerSlot.id}-${iteration.id}`,
|
|
52
|
+
* }),
|
|
53
|
+
* thresholds: { transaction: { errorRate: "<1%", p95: "<2000ms" } },
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export const loadRunner = loadRunnerImpl;
|
|
58
|
+
/**
|
|
59
|
+
* Type-safe constructor for a traffic-mix entry: it binds `input` to the
|
|
60
|
+
* scenario's `Input`, so a mismatched input shape is rejected at author time.
|
|
61
|
+
*
|
|
62
|
+
* Use it inside `scenarios: [...]`. A bare object literal in the array is only
|
|
63
|
+
* checked against `LoadMixEntry<any>` (TypeScript can't infer a distinct `Input`
|
|
64
|
+
* per array element), so wrap each entry with `loadMixEntry()` for per-entry
|
|
65
|
+
* type checking of heterogeneous typed scenarios.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* scenarios: [
|
|
70
|
+
* loadMixEntry({ id: "checkout", scenario: checkout, weight: 70, input: () => ({ sku: "s" }) }),
|
|
71
|
+
* loadMixEntry({ id: "refund", scenario: refund, weight: 30, input: () => ({ orderId: "o" }) }),
|
|
72
|
+
* ]
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function loadMixEntry(entry) {
|
|
76
|
+
return entry;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/load/runner.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAmKlD,kFAAkF;AAClF,SAAS,aAAa,CACpB,QAAgB,EAChB,GAA4B,EAC5B,KAAa;IAEb,6EAA6E;IAC7E,0EAA0E;IAC1E,sEAAsE;IACtE,OAAO,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC1D,IAAI,IAAI,KAAK,OAAO;YAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9E,OAAO,KAAK,CAAC,CAAC,kEAAkE;IAClF,CAAC,CAAC,CAAC;AACL,CAAC;AAwBD;;;;GAIG;AACH,SAAS,YAAY,CACnB,EAAU,EACV,MAA2B,EAC3B,GAA6B;IAE7B,MAAM,IAAI,GAAG;QACX,cAAc,EAAE,aAAsB;QACtC,EAAE;QACF,MAAM;QACN,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtC,CAAC;IACF,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE;QACxC,GAAG,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC;QAChC,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IACH,OAAO,IAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,cAAc,GAAG,CAAC,EAAU,EAAE,MAA2B,EAAY,EAAE,CAC3E,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;AAE3B,cAAc,CAAC,IAAI,GAAG,CAAsB,KAAsB,EAAE,EAAE;IACpE,OAAO,CACL,UAAkB,EAClB,OAGwD,EAC5C,EAAE,CACd,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACvB,MAAM,SAAS,GAAG,GAA8B,CAAC;QACjD,OAAO,YAAY,CACjB,aAAa,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAC3C,OAAO,CAAC,GAAG,EAAE,KAAK,CAAwB,EAC1C,SAAS,CACV,CAAC;IACJ,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,cAA8B,CAAC;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAgC;IAEhC,OAAO,KAAgC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* loadScenario definition shape + branch/poll runtime data.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the test() step / branch / poll runtime structures, but bind to
|
|
5
|
+
* `LoadContext` and carry a load-specific per-step assertion policy. The load
|
|
6
|
+
* orchestrator (later milestones) executes these. They are intentionally
|
|
7
|
+
* independent of `Test` / `TestEvent` structures so load's bounded-aggregation
|
|
8
|
+
* model never inherits ordinary test timeline semantics.
|
|
9
|
+
*/
|
|
10
|
+
import type { StepJsonScalar, StepMeta, StepNoExtraKeys } from "../types.js";
|
|
11
|
+
import type { LoadContext } from "./context.js";
|
|
12
|
+
import type { LoadAssertionFailureMode, LoadStepOptions } from "./step.js";
|
|
13
|
+
/** Step metadata for a load scenario step: StepMeta plus a load assertion policy. */
|
|
14
|
+
export interface LoadStepMeta extends StepMeta {
|
|
15
|
+
assertions?: {
|
|
16
|
+
onFailure?: LoadAssertionFailureMode;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A scenario step's runtime structure. A normal step has a callable `fn`; a
|
|
21
|
+
* branch step (condition/switch) additionally carries `branch`, and a poll step
|
|
22
|
+
* carries `poll` — for both, `fn` is a throwing stub and the orchestrator
|
|
23
|
+
* dispatches on the extra field.
|
|
24
|
+
*/
|
|
25
|
+
export interface LoadStepDefinition<Input = unknown, S = unknown> {
|
|
26
|
+
meta: LoadStepMeta;
|
|
27
|
+
fn: (ctx: LoadContext<Input>, state: S) => Promise<S | void>;
|
|
28
|
+
branch?: LoadBranchData<Input, S>;
|
|
29
|
+
poll?: LoadPollData<Input, S>;
|
|
30
|
+
}
|
|
31
|
+
/** Runtime branch data (condition / switchOn / switchCond) bound to LoadContext. */
|
|
32
|
+
export interface LoadBranchData<Input = unknown, S = unknown> {
|
|
33
|
+
mode: "predicate" | "value";
|
|
34
|
+
message?: string;
|
|
35
|
+
/** value-mode only: subject lens evaluated once against committed state. */
|
|
36
|
+
subject?: (ctx: LoadContext<Input>, state: S) => unknown;
|
|
37
|
+
cases: Array<{
|
|
38
|
+
predicate?: (ctx: LoadContext<Input>, state: S) => boolean | Promise<boolean>;
|
|
39
|
+
value?: StepJsonScalar;
|
|
40
|
+
message?: string;
|
|
41
|
+
steps: LoadStepDefinition<Input, S>[];
|
|
42
|
+
}>;
|
|
43
|
+
default: LoadStepDefinition<Input, S>[];
|
|
44
|
+
}
|
|
45
|
+
/** Runtime poll data (bounded poll-until) bound to LoadContext. */
|
|
46
|
+
export interface LoadPollData<Input = unknown, S = unknown> {
|
|
47
|
+
fn: (ctx: LoadContext<Input>, state: S) => Promise<unknown>;
|
|
48
|
+
until: (ctx: LoadContext<Input>, res: unknown, state: S) => boolean | Promise<boolean>;
|
|
49
|
+
out?: (state: S, res: unknown) => unknown;
|
|
50
|
+
every?: number;
|
|
51
|
+
backoff?: number;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
perAttemptTimeout?: number;
|
|
54
|
+
maxAttempts?: number;
|
|
55
|
+
}
|
|
56
|
+
/** Narrow a LoadStepDefinition to a branch step. */
|
|
57
|
+
export declare function isLoadBranchStep<Input, S>(step: LoadStepDefinition<Input, S>): step is LoadStepDefinition<Input, S> & {
|
|
58
|
+
branch: LoadBranchData<Input, S>;
|
|
59
|
+
};
|
|
60
|
+
/** Narrow a LoadStepDefinition to a poll step. */
|
|
61
|
+
export declare function isLoadPollStep<Input, S>(step: LoadStepDefinition<Input, S>): step is LoadStepDefinition<Input, S> & {
|
|
62
|
+
poll: LoadPollData<Input, S>;
|
|
63
|
+
};
|
|
64
|
+
/** `loadScenario().condition` spec — arbitrary runtime predicate. */
|
|
65
|
+
export interface LoadConditionSpec<Input = unknown, S = unknown> {
|
|
66
|
+
predicate: (ctx: LoadContext<Input>, state: S) => boolean | Promise<boolean>;
|
|
67
|
+
message?: string;
|
|
68
|
+
}
|
|
69
|
+
/** `loadScenario().poll` options. `Res` is inferred from the attempt `fn`'s return. */
|
|
70
|
+
export interface LoadPollOpts<Input, S, Res, NewS> {
|
|
71
|
+
until: (ctx: LoadContext<Input>, res: Res, state: S) => boolean | Promise<boolean>;
|
|
72
|
+
every?: number;
|
|
73
|
+
backoff?: number;
|
|
74
|
+
timeout?: number;
|
|
75
|
+
perAttemptTimeout?: number;
|
|
76
|
+
maxAttempts?: number;
|
|
77
|
+
out?: (state: S, res: Res) => NewS;
|
|
78
|
+
}
|
|
79
|
+
/** Module-private phantom brand making LoadFragmentBuilder invariant in State. */
|
|
80
|
+
declare const LOAD_FRAGMENT_STATE: unique symbol;
|
|
81
|
+
/**
|
|
82
|
+
* Restricted builder for a `loadScenario()` branch body (condition then/else,
|
|
83
|
+
* switch case/default). Exposes step / use / condition / switchOn / switchCond /
|
|
84
|
+
* poll and accumulates them into the branch node; it deliberately does NOT
|
|
85
|
+
* expose setup / teardown / meta / build. Invariant in `State` via the phantom
|
|
86
|
+
* brand (same convergence guarantee as TestFragmentBuilder).
|
|
87
|
+
*/
|
|
88
|
+
export interface LoadFragmentBuilder<Input = unknown, S = unknown> {
|
|
89
|
+
readonly [LOAD_FRAGMENT_STATE]: (s: S) => S;
|
|
90
|
+
step(name: string, fn: (ctx: LoadContext<Input>, state: S) => Promise<void>): LoadFragmentBuilder<Input, S>;
|
|
91
|
+
step<NewS>(name: string, fn: (ctx: LoadContext<Input>, state: S) => Promise<NewS>): LoadFragmentBuilder<Input, NewS>;
|
|
92
|
+
step(name: string, options: LoadStepOptions, fn: (ctx: LoadContext<Input>, state: S) => Promise<void>): LoadFragmentBuilder<Input, S>;
|
|
93
|
+
step<NewS>(name: string, options: LoadStepOptions, fn: (ctx: LoadContext<Input>, state: S) => Promise<NewS>): LoadFragmentBuilder<Input, NewS>;
|
|
94
|
+
use<NewS>(fn: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, NewS>): LoadFragmentBuilder<Input, NewS>;
|
|
95
|
+
condition<R extends S = S>(spec: LoadConditionSpec<Input, S>, thenBranch: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, R & StepNoExtraKeys<R, S>>): LoadFragmentBuilder<Input, S>;
|
|
96
|
+
condition<T>(spec: LoadConditionSpec<Input, S>, thenBranch: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, T>, elseBranch: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, NoInfer<T>>): LoadFragmentBuilder<Input, T>;
|
|
97
|
+
switchOn<V>(lens: (ctx: LoadContext<Input>, state: S) => V): <T>(cases: ReadonlyArray<{
|
|
98
|
+
value: [Exclude<Awaited<V>, undefined>] extends [StepJsonScalar] ? Exclude<Awaited<V>, undefined> : never;
|
|
99
|
+
then: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, NoInfer<T>>;
|
|
100
|
+
}>, deflt: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, T>) => LoadFragmentBuilder<Input, T>;
|
|
101
|
+
switchCond<T>(cases: ReadonlyArray<{
|
|
102
|
+
when: (ctx: LoadContext<Input>, state: S) => boolean | Promise<boolean>;
|
|
103
|
+
then: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, NoInfer<T>>;
|
|
104
|
+
}>, deflt: (b: LoadFragmentBuilder<Input, S>) => LoadFragmentBuilder<Input, T>): LoadFragmentBuilder<Input, T>;
|
|
105
|
+
poll<Res, NewS = S>(name: string, fn: (ctx: LoadContext<Input>, state: S) => Promise<Res>, opts: LoadPollOpts<Input, S, Res, NewS>): LoadFragmentBuilder<Input, NewS>;
|
|
106
|
+
}
|
|
107
|
+
/** Scenario-level metadata. */
|
|
108
|
+
export interface LoadScenarioMeta {
|
|
109
|
+
id: string;
|
|
110
|
+
description?: string;
|
|
111
|
+
/** Scenario-level default for guard/assertion failures. */
|
|
112
|
+
assertions?: {
|
|
113
|
+
onFailure?: LoadAssertionFailureMode;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* A complete loadScenario definition (output of `LoadBuilder.build()`).
|
|
118
|
+
*
|
|
119
|
+
* This is the performance-transaction workload that a `loadRunner()` executes.
|
|
120
|
+
* It is NOT independently runnable — only `loadRunner()` exports are scheduled.
|
|
121
|
+
*/
|
|
122
|
+
export interface LoadScenario<Input = unknown, S = unknown> {
|
|
123
|
+
readonly __glubean_type: "load-scenario";
|
|
124
|
+
meta: LoadScenarioMeta;
|
|
125
|
+
setup?: (ctx: LoadContext<Input>) => Promise<unknown>;
|
|
126
|
+
steps: LoadStepDefinition<Input, unknown>[];
|
|
127
|
+
teardown?: (ctx: LoadContext<Input>, state: S) => Promise<void>;
|
|
128
|
+
}
|
|
129
|
+
export {};
|
|
130
|
+
//# sourceMappingURL=scenario.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../src/load/scenario.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Narrow a LoadStepDefinition to a branch step. */
|
|
2
|
+
export function isLoadBranchStep(step) {
|
|
3
|
+
return step.branch !== undefined;
|
|
4
|
+
}
|
|
5
|
+
/** Narrow a LoadStepDefinition to a poll step. */
|
|
6
|
+
export function isLoadPollStep(step) {
|
|
7
|
+
return step.poll !== undefined;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=scenario.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario.js","sourceRoot":"","sources":["../../src/load/scenario.ts"],"names":[],"mappings":"AA4DA,oDAAoD;AACpD,MAAM,UAAU,gBAAgB,CAC9B,IAAkC;IAElC,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;AACnC,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,cAAc,CAC5B,IAAkC;IAElC,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load scenario step authoring types.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the `test().builder()` step model (return-state threading:
|
|
5
|
+
* a step returns the next state, or `void`/`undefined` to keep the current
|
|
6
|
+
* state) but bind to `LoadContext` and add a load-specific assertion policy.
|
|
7
|
+
*/
|
|
8
|
+
import type { StepMeta } from "../types.js";
|
|
9
|
+
import type { LoadContext } from "./context.js";
|
|
10
|
+
/**
|
|
11
|
+
* What happens when a guard/assertion fails inside a load step.
|
|
12
|
+
*
|
|
13
|
+
* Resolution order (most specific wins):
|
|
14
|
+
* per-assertion `.orFail()` / thrown error
|
|
15
|
+
* > step-level `assertions.onFailure`
|
|
16
|
+
* > scenario-level `assertions.onFailure`
|
|
17
|
+
* > loadRunner `assertions.onFailure`
|
|
18
|
+
* > default `"continue"`
|
|
19
|
+
*/
|
|
20
|
+
export type LoadAssertionFailureMode =
|
|
21
|
+
/** Default: record + count the failure, keep running the scenario. */
|
|
22
|
+
"continue"
|
|
23
|
+
/** Current step completes; remaining steps are skipped. */
|
|
24
|
+
| "skipRemainingSteps"
|
|
25
|
+
/** Fail-fast the current iteration. */
|
|
26
|
+
| "abortIteration";
|
|
27
|
+
/** Per-step options for `loadScenario` steps (`StepMeta` minus `name`, plus load policy). */
|
|
28
|
+
export type LoadStepOptions = Omit<StepMeta, "name"> & {
|
|
29
|
+
assertions?: {
|
|
30
|
+
onFailure?: LoadAssertionFailureMode;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
/** A scenario `setup` producing the initial state from the context. */
|
|
34
|
+
export type LoadSetupFunction<Input, NewState> = (ctx: LoadContext<Input>) => Promise<NewState>;
|
|
35
|
+
/**
|
|
36
|
+
* A scenario step. Returns the next state, or `void`/`undefined` to keep the
|
|
37
|
+
* current state (matching `test().builder()` semantics).
|
|
38
|
+
*/
|
|
39
|
+
export type LoadStepFunction<Input, State, NewState = State> = (ctx: LoadContext<Input>, state: State) => Promise<NewState | void>;
|
|
40
|
+
/** A scenario `teardown`, always run with the last committed state. */
|
|
41
|
+
export type LoadTeardownFunction<Input, State> = (ctx: LoadContext<Input>, state: State) => Promise<void>;
|
|
42
|
+
//# sourceMappingURL=step.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/load/step.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;;;;;;;;GASG;AACH,MAAM,MAAM,wBAAwB;AAClC,sEAAsE;AACpE,UAAU;AACZ,2DAA2D;GACzD,oBAAoB;AACtB,uCAAuC;GACrC,gBAAgB,CAAC;AAErB,6FAA6F;AAC7F,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG;IACrD,UAAU,CAAC,EAAE;QACX,SAAS,CAAC,EAAE,wBAAwB,CAAC;KACtC,CAAC;CACH,CAAC;AAEF,uEAAuE;AACvE,MAAM,MAAM,iBAAiB,CAAC,KAAK,EAAE,QAAQ,IAAI,CAC/C,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,KACpB,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEvB;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAG,KAAK,IAAI,CAC7D,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,EACvB,KAAK,EAAE,KAAK,KACT,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;AAE9B,uEAAuE;AACvE,MAAM,MAAM,oBAAoB,CAAC,KAAK,EAAE,KAAK,IAAI,CAC/C,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,EACvB,KAAK,EAAE,KAAK,KACT,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step.js","sourceRoot":"","sources":["../../src/load/step.ts"],"names":[],"mappings":""}
|
package/dist/types.d.ts
CHANGED
|
@@ -1332,6 +1332,16 @@ export interface HttpRequestOptions {
|
|
|
1332
1332
|
* ```
|
|
1333
1333
|
*/
|
|
1334
1334
|
schema?: HttpSchemaOptions;
|
|
1335
|
+
/**
|
|
1336
|
+
* Per-request context — a non-wire object shared across this request's hooks (never
|
|
1337
|
+
* sent to the server). The runtime reads `context.glubeanRoute` (an exact route
|
|
1338
|
+
* template like `"GET /runs/:runId"`) to attribute the load runner's endpoint stats
|
|
1339
|
+
* exactly instead of heuristically normalizing the URL; a `contract.http()` client
|
|
1340
|
+
* sets it automatically. A custom `HttpClient` may ignore this option.
|
|
1341
|
+
*/
|
|
1342
|
+
context?: {
|
|
1343
|
+
glubeanRoute?: string;
|
|
1344
|
+
} & Record<string, unknown>;
|
|
1335
1345
|
}
|
|
1336
1346
|
/**
|
|
1337
1347
|
* Hooks for intercepting HTTP request/response lifecycle.
|
|
@@ -1713,6 +1723,12 @@ export interface Trace {
|
|
|
1713
1723
|
name?: string;
|
|
1714
1724
|
/** Optional detailed description */
|
|
1715
1725
|
description?: string;
|
|
1726
|
+
/** Optional EXACT route template, e.g. "GET /runs/:runId". Carried via the request's
|
|
1727
|
+
* non-wire `context.glubeanRoute` option (set by a `contract.http()` client from its
|
|
1728
|
+
* `endpoint`, or by a caller) — NEVER a request header, so it can't leak to the server.
|
|
1729
|
+
* The load runner uses it for an exact endpoint routeKey instead of the heuristic
|
|
1730
|
+
* URL-normalization fallback. Absent → fall back. */
|
|
1731
|
+
routeKey?: string;
|
|
1716
1732
|
/** @deprecated Use `target` and `metadata` instead. HTTP method. */
|
|
1717
1733
|
method?: string;
|
|
1718
1734
|
/** @deprecated Use `target` and `metadata` instead. Request URL. */
|