@sanoma-ai/workflows 0.0.0-stage → 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 +105 -0
- package/README.md +493 -2
- package/dist/approvals.d.ts +46 -0
- package/dist/approvals.js +111 -0
- package/dist/approvals.js.map +1 -0
- package/dist/ast.d.ts +57 -0
- package/dist/ast.js +81 -0
- package/dist/ast.js.map +1 -0
- package/dist/call.d.ts +33 -0
- package/dist/call.js +402 -0
- package/dist/call.js.map +1 -0
- package/dist/client.d.ts +167 -0
- package/dist/client.js +400 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +126 -0
- package/dist/config.js +247 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.d.ts +30 -0
- package/dist/credentials.js +193 -0
- package/dist/credentials.js.map +1 -0
- package/dist/cucumber.d.ts +64 -0
- package/dist/cucumber.js +158 -0
- package/dist/cucumber.js.map +1 -0
- package/dist/datafile.d.ts +62 -0
- package/dist/datafile.js +326 -0
- package/dist/datafile.js.map +1 -0
- package/dist/db.d.ts +58 -0
- package/dist/db.js +179 -0
- package/dist/db.js.map +1 -0
- package/dist/define.d.ts +205 -0
- package/dist/define.js +103 -0
- package/dist/define.js.map +1 -0
- package/dist/describe.d.ts +135 -0
- package/dist/describe.js +127 -0
- package/dist/describe.js.map +1 -0
- package/dist/drift.d.ts +75 -0
- package/dist/drift.js +90 -0
- package/dist/drift.js.map +1 -0
- package/dist/env.d.ts +49 -0
- package/dist/env.js +83 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +88 -0
- package/dist/errors.js +148 -0
- package/dist/errors.js.map +1 -0
- package/dist/expectations.d.ts +26 -0
- package/dist/expectations.js +137 -0
- package/dist/expectations.js.map +1 -0
- package/dist/fake.d.ts +55 -0
- package/dist/fake.js +87 -0
- package/dist/fake.js.map +1 -0
- package/dist/fill.d.ts +9 -0
- package/dist/fill.js +17 -0
- package/dist/fill.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger.d.ts +217 -0
- package/dist/ledger.js +251 -0
- package/dist/ledger.js.map +1 -0
- package/dist/lint.d.ts +32 -0
- package/dist/lint.js +168 -0
- package/dist/lint.js.map +1 -0
- package/dist/log.d.ts +24 -0
- package/dist/log.js +83 -0
- package/dist/log.js.map +1 -0
- package/dist/op.d.ts +257 -0
- package/dist/op.js +188 -0
- package/dist/op.js.map +1 -0
- package/dist/outline.d.ts +179 -0
- package/dist/outline.js +506 -0
- package/dist/outline.js.map +1 -0
- package/dist/paths.d.ts +11 -0
- package/dist/paths.js +30 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin.d.ts +28 -0
- package/dist/plugin.js +25 -0
- package/dist/plugin.js.map +1 -0
- package/dist/policy.d.ts +114 -0
- package/dist/policy.js +60 -0
- package/dist/policy.js.map +1 -0
- package/dist/resource.d.ts +212 -0
- package/dist/resource.js +285 -0
- package/dist/resource.js.map +1 -0
- package/dist/resources.d.ts +62 -0
- package/dist/resources.js +197 -0
- package/dist/resources.js.map +1 -0
- package/dist/run.d.ts +87 -0
- package/dist/run.js +2 -0
- package/dist/run.js.map +1 -0
- package/dist/sandbox.d.ts +33 -0
- package/dist/sandbox.js +123 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/scenario.d.ts +212 -0
- package/dist/scenario.js +1079 -0
- package/dist/scenario.js.map +1 -0
- package/dist/scenarios.d.ts +55 -0
- package/dist/scenarios.js +71 -0
- package/dist/scenarios.js.map +1 -0
- package/dist/shared.d.ts +61 -0
- package/dist/shared.js +77 -0
- package/dist/shared.js.map +1 -0
- package/dist/steps.d.ts +76 -0
- package/dist/steps.js +23 -0
- package/dist/steps.js.map +1 -0
- package/dist/version.d.ts +29 -0
- package/dist/version.js +76 -0
- package/dist/version.js.map +1 -0
- package/dist/worker.d.ts +34 -0
- package/dist/worker.js +219 -0
- package/dist/worker.js.map +1 -0
- package/oxlint.json +128 -0
- package/package.json +91 -3
- package/src/approvals.ts +157 -0
- package/src/ast.ts +115 -0
- package/src/call.ts +468 -0
- package/src/client.ts +534 -0
- package/src/config.ts +381 -0
- package/src/credentials.ts +211 -0
- package/src/cucumber.ts +230 -0
- package/src/datafile.ts +409 -0
- package/src/db.ts +197 -0
- package/src/define.ts +285 -0
- package/src/describe.ts +262 -0
- package/src/drift.ts +149 -0
- package/src/env.ts +122 -0
- package/src/errors.ts +202 -0
- package/src/expectations.ts +165 -0
- package/src/fake.ts +156 -0
- package/src/fill.ts +24 -0
- package/src/index.ts +120 -0
- package/src/ledger.ts +419 -0
- package/src/lint.ts +208 -0
- package/src/log.ts +82 -0
- package/src/op.ts +399 -0
- package/src/outline.ts +620 -0
- package/src/paths.ts +32 -0
- package/src/plugin.ts +37 -0
- package/src/policy.ts +139 -0
- package/src/resource.ts +447 -0
- package/src/resources.ts +256 -0
- package/src/run.ts +91 -0
- package/src/sandbox.ts +157 -0
- package/src/scenario.ts +1328 -0
- package/src/scenarios.ts +111 -0
- package/src/shared.ts +116 -0
- package/src/steps.ts +90 -0
- package/src/version.ts +86 -0
- package/src/worker.ts +253 -0
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ApprovalState, Principal, WorkflowDefinition } from "./define.ts";
|
|
2
|
+
import type { Fake } from "./fake.ts";
|
|
3
|
+
import type { LedgerStore } from "./ledger.ts";
|
|
4
|
+
import type { DriverFn, Op } from "./op.ts";
|
|
5
|
+
import type { CallNode } from "./outline.ts";
|
|
6
|
+
import type { Policy } from "./policy.ts";
|
|
7
|
+
import type { Resource } from "./resource.ts";
|
|
8
|
+
import type { Steps } from "./steps.ts";
|
|
9
|
+
/** What the DBOS workflow receives: the workflow's input, who started the run, and for a sandbox run its scenario. */
|
|
10
|
+
export interface RunArgs {
|
|
11
|
+
input: unknown;
|
|
12
|
+
startedBy: Principal;
|
|
13
|
+
/** The scenario a sandbox run is seeded from; the run calls the fakes instead of the drivers. */
|
|
14
|
+
sandbox?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* What one `startWorker` call runs with. DBOS registrations are process-wide and outlive a
|
|
18
|
+
* shutdown, so each run takes the state current when it starts and keeps it: a run left over
|
|
19
|
+
* from a stopped worker never reads a newer worker's drivers or policy.
|
|
20
|
+
*/
|
|
21
|
+
export interface WorkerState {
|
|
22
|
+
/** The config's `appName`, recorded on every ledger record. */
|
|
23
|
+
app: string;
|
|
24
|
+
/** The operations as the config's connectors declare them, by id. */
|
|
25
|
+
ops: Map<string, Op>;
|
|
26
|
+
/** The drivers' functions, by operation id, each guarded by its driver's `env` (`indexDrivers` in config.ts). */
|
|
27
|
+
drivers: Map<string, DriverFn>;
|
|
28
|
+
/** The makers of the config's fake vendors, by vendor id: a sandbox run makes its own of each when it is seeded. */
|
|
29
|
+
fakes: Map<string, () => Fake<any, any>>;
|
|
30
|
+
/** Where sandbox runs' scenarios are, the resource types their steps may name, and the steps the connectors ship. */
|
|
31
|
+
scenarios?: URL;
|
|
32
|
+
types: ReadonlyMap<string, Resource>;
|
|
33
|
+
steps: readonly Steps[];
|
|
34
|
+
/** Its `version`, when it has one, is recorded with each of its decisions. */
|
|
35
|
+
policy: Policy;
|
|
36
|
+
ledger: LedgerStore;
|
|
37
|
+
/**
|
|
38
|
+
* The config's workflows by name, the built-in `drift` among them. A run takes its definition
|
|
39
|
+
* from here, by the name it was registered under: a process registers each name with DBOS once,
|
|
40
|
+
* and each worker's config says what it runs. Scenarios name them too.
|
|
41
|
+
*/
|
|
42
|
+
workflows: Map<string, WorkflowDefinition<any, any>>;
|
|
43
|
+
/** Each workflow's outline, by name: read once when the worker starts, every run is held to it (`call_not_in_outline`). */
|
|
44
|
+
outlines: Map<string, WorkflowOutline>;
|
|
45
|
+
/**
|
|
46
|
+
* Set when the worker stops, before DBOS shuts down. DBOS abandons a stopped worker's run
|
|
47
|
+
* functions, which then fail as their next DBOS call finds the database closed. Such a failure,
|
|
48
|
+
* one with none of our codes, is not recorded: the run recovered on the next worker records
|
|
49
|
+
* how it really ends (see `isInfrastructureError`).
|
|
50
|
+
*/
|
|
51
|
+
stopped: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** What a run keeps in memory. Rebuilt the same way when DBOS replays the run. */
|
|
54
|
+
export interface Run {
|
|
55
|
+
id: string;
|
|
56
|
+
workflow: string;
|
|
57
|
+
actor: Principal;
|
|
58
|
+
/** The scenario a sandbox run is seeded from; unset for a live run. */
|
|
59
|
+
sandbox?: string;
|
|
60
|
+
/** A sandbox run's own fakes' functions, by operation id, from `seedSandbox`; unset for a live run. */
|
|
61
|
+
fakeDrivers?: Map<string, DriverFn>;
|
|
62
|
+
approvals: ApprovalState[];
|
|
63
|
+
/** The next ledger `seq`. Advanced only outside steps, so a replay counts the same way. */
|
|
64
|
+
seq: number;
|
|
65
|
+
/**
|
|
66
|
+
* The last `ctx` call queued. Each call waits for the one before it, so a run's calls run one
|
|
67
|
+
* at a time, in program order, even under `Promise.all`. Never rejects.
|
|
68
|
+
*/
|
|
69
|
+
tail: Promise<unknown>;
|
|
70
|
+
/**
|
|
71
|
+
* Set while a `ctx.all` runs, so a second one started before it settles is refused. The
|
|
72
|
+
* member a call belongs to travels with the call (`currentGroup` in ledger.ts), not here.
|
|
73
|
+
*/
|
|
74
|
+
inAll: boolean;
|
|
75
|
+
/** Set when the workflow body has returned or thrown. A call still queued then is refused. */
|
|
76
|
+
ended: boolean;
|
|
77
|
+
/** The workflow's outline, which every `ctx` call is placed in (`placeCall`). */
|
|
78
|
+
outline: WorkflowOutline;
|
|
79
|
+
state: WorkerState;
|
|
80
|
+
}
|
|
81
|
+
/** What `placeCall` holds a run's `ctx` calls to: the file's lines, so a frame's line and column become an offset, and the outline's call nodes. */
|
|
82
|
+
export interface WorkflowOutline {
|
|
83
|
+
file: string;
|
|
84
|
+
/** `lineStartsOf` the file's text, `\n` line endings. */
|
|
85
|
+
lineStarts: readonly number[];
|
|
86
|
+
calls: readonly CallNode[];
|
|
87
|
+
}
|
package/dist/run.js
ADDED
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SanomaError } from "./errors.ts";
|
|
2
|
+
import type { Fake, ResourceFake } from "./fake.ts";
|
|
3
|
+
import { type LedgerRecord } from "./ledger.ts";
|
|
4
|
+
import type { Run } from "./run.ts";
|
|
5
|
+
import { type Given, type Scenario } from "./scenario.ts";
|
|
6
|
+
/**
|
|
7
|
+
* The error a sandbox run of the scenario fails with when it seeds a resource of a vendor whose
|
|
8
|
+
* fake (one of `fakes`, by vendor) holds none, or whose connector attaches no fake; undefined
|
|
9
|
+
* when every vendor it seeds a resource of has a `ResourceFake`. Pure.
|
|
10
|
+
*/
|
|
11
|
+
export declare function missingResourceFake(scenario: Pick<Scenario, "name" | "given">, fakes: ReadonlyMap<string, Fake<unknown>>): SanomaError | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Seeds one resource into the run's own fake of its vendor: put with its fields, or removed.
|
|
14
|
+
* A seed the fake refuses (a field the provider's shape lacks, say) fails the scenario, naming
|
|
15
|
+
* the step, as the other seed-time refusals do.
|
|
16
|
+
*/
|
|
17
|
+
export declare function seedResource(scenario: string, copy: ResourceFake, given: Extract<Given, {
|
|
18
|
+
resource: string;
|
|
19
|
+
}>): Extract<LedgerRecord, {
|
|
20
|
+
type: "scenario.seeded";
|
|
21
|
+
}>["seeds"][number];
|
|
22
|
+
/**
|
|
23
|
+
* Seeds a sandbox run of the scenario `name`, from the worker, in one step: reads the scenario,
|
|
24
|
+
* checks that it runs this workflow, makes the run's own fakes (each vendor's maker, called once
|
|
25
|
+
* for the run), checks that every operation the workflow uses or the scenario seeds has one and
|
|
26
|
+
* that every resource it seeds has a fake holding resources, calls each `Given` operation
|
|
27
|
+
* through them, puts or removes each `Given` resource in them, injects the faults into them,
|
|
28
|
+
* then puts their functions on the run. The run then calls those only, so sandbox runs share no
|
|
29
|
+
* state when the makers make a new fake each. The step's checkpoint never stands in for them: a
|
|
30
|
+
* run whose seeding is replayed from it has none, and fails, since a sandbox run does not
|
|
31
|
+
* survive a worker restart.
|
|
32
|
+
*/
|
|
33
|
+
export declare function seedSandbox(run: Run, name: string): Promise<void>;
|
package/dist/sandbox.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
2
|
+
import { indexDrivers } from "./config.js";
|
|
3
|
+
import { opIdsOf } from "./define.js";
|
|
4
|
+
import { SanomaError } from "./errors.js";
|
|
5
|
+
import { entry, write } from "./ledger.js";
|
|
6
|
+
import { loadScenarios } from "./scenario.js";
|
|
7
|
+
import { errorMessage } from "./shared.js";
|
|
8
|
+
/*
|
|
9
|
+
* What a worker does for a sandbox run, imported only when it starts one: kept apart from
|
|
10
|
+
* `scenario.ts`, which the app reads too, because it needs DBOS and the ledger.
|
|
11
|
+
*/
|
|
12
|
+
/** True for a fake that holds resources (`ResourceFake`, as `@sanoma-ai/bridge`'s `tfFake` is). */
|
|
13
|
+
const holdsResources = (fake) => "override" in fake && "put" in fake && "remove" in fake;
|
|
14
|
+
/**
|
|
15
|
+
* The error a sandbox run of the scenario fails with when it seeds a resource of a vendor whose
|
|
16
|
+
* fake (one of `fakes`, by vendor) holds none, or whose connector attaches no fake; undefined
|
|
17
|
+
* when every vendor it seeds a resource of has a `ResourceFake`. Pure.
|
|
18
|
+
*/
|
|
19
|
+
export function missingResourceFake(scenario, fakes) {
|
|
20
|
+
const plain = scenario.given.filter((g) => {
|
|
21
|
+
if (!("resource" in g))
|
|
22
|
+
return false;
|
|
23
|
+
const fake = fakes.get(g.vendor);
|
|
24
|
+
return !fake || !holdsResources(fake);
|
|
25
|
+
});
|
|
26
|
+
if (plain.length === 0)
|
|
27
|
+
return undefined;
|
|
28
|
+
const resources = [...new Set(plain.map((g) => g.resource))];
|
|
29
|
+
const vendors = [...new Set(plain.map((g) => g.vendor))];
|
|
30
|
+
const why = vendors.map((v) => fakes.has(v) ? `${v}'s fake holds no resources (it is not a tfFake)` : `${v}'s connector attaches no fake`);
|
|
31
|
+
return new SanomaError("invalid_input", `Scenario "${scenario.name}" seeds ${resources.join(", ")}, but ${why.join("; ")}`, {
|
|
32
|
+
scenario: scenario.name,
|
|
33
|
+
resources,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Seeds one resource into the run's own fake of its vendor: put with its fields, or removed.
|
|
38
|
+
* A seed the fake refuses (a field the provider's shape lacks, say) fails the scenario, naming
|
|
39
|
+
* the step, as the other seed-time refusals do.
|
|
40
|
+
*/
|
|
41
|
+
export function seedResource(scenario, copy, given) {
|
|
42
|
+
const { resource, type, name } = given;
|
|
43
|
+
try {
|
|
44
|
+
if ("gone" in given) {
|
|
45
|
+
copy.remove(type, name);
|
|
46
|
+
return { resource, name, gone: true };
|
|
47
|
+
}
|
|
48
|
+
copy.put(type, name, given.fields);
|
|
49
|
+
return { resource, name, fields: given.fields };
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
throw new SanomaError("invalid_input", `Scenario "${scenario}" cannot seed ${resource} "${name}" ("${given.step}"): ${errorMessage(err)}`, { scenario, step: given.step, resource, name }, { cause: err });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Seeds a sandbox run of the scenario `name`, from the worker, in one step: reads the scenario,
|
|
57
|
+
* checks that it runs this workflow, makes the run's own fakes (each vendor's maker, called once
|
|
58
|
+
* for the run), checks that every operation the workflow uses or the scenario seeds has one and
|
|
59
|
+
* that every resource it seeds has a fake holding resources, calls each `Given` operation
|
|
60
|
+
* through them, puts or removes each `Given` resource in them, injects the faults into them,
|
|
61
|
+
* then puts their functions on the run. The run then calls those only, so sandbox runs share no
|
|
62
|
+
* state when the makers make a new fake each. The step's checkpoint never stands in for them: a
|
|
63
|
+
* run whose seeding is replayed from it has none, and fails, since a sandbox run does not
|
|
64
|
+
* survive a worker restart.
|
|
65
|
+
*/
|
|
66
|
+
export async function seedSandbox(run, name) {
|
|
67
|
+
const { state } = run;
|
|
68
|
+
let copies;
|
|
69
|
+
const { seeds } = await DBOS.runStep(async () => {
|
|
70
|
+
// Read in the step, so a recovered run never reads a feature file edited or renamed since.
|
|
71
|
+
const { scenarios, errors } = await loadScenarios(state);
|
|
72
|
+
const scenario = scenarios.find((s) => s.name === name);
|
|
73
|
+
if (!scenario) {
|
|
74
|
+
const why = errors.length ? `; these files did not load: ${errors.map((e) => e.message).join("; ")}` : "";
|
|
75
|
+
throw new SanomaError("invalid_input", `No scenario named "${name}"${why}`, { scenario: name });
|
|
76
|
+
}
|
|
77
|
+
if (scenario.workflow !== run.workflow) {
|
|
78
|
+
throw new SanomaError("invalid_input", `Scenario "${name}" runs ${scenario.workflow}, not ${run.workflow}`, {
|
|
79
|
+
scenario: name,
|
|
80
|
+
workflow: scenario.workflow,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const fakes = new Map([...state.fakes].map(([vendor, make]) => [vendor, make()]));
|
|
84
|
+
const drivers = indexDrivers([...fakes.values()].map((f) => f.driver), state.ops);
|
|
85
|
+
const uses = opIdsOf(state.workflows.get(run.workflow));
|
|
86
|
+
const seeding = scenario.given.flatMap((g) => ("op" in g ? [g.op] : []));
|
|
87
|
+
const missing = [...new Set([...uses, ...seeding])].filter((id) => !drivers.has(id));
|
|
88
|
+
if (missing.length) {
|
|
89
|
+
throw new SanomaError("invalid_input", `A sandbox run of ${run.workflow} has no fake for ${missing.join(", ")}: no fake its connectors attach implements ${missing.length > 1 ? "them" : "it"}`, { scenario: name, missing });
|
|
90
|
+
}
|
|
91
|
+
const plain = missingResourceFake(scenario, fakes);
|
|
92
|
+
if (plain)
|
|
93
|
+
throw plain;
|
|
94
|
+
const seeded = [];
|
|
95
|
+
for (const [i, given] of scenario.given.entries()) {
|
|
96
|
+
if ("fault" in given)
|
|
97
|
+
continue;
|
|
98
|
+
if ("op" in given) {
|
|
99
|
+
const call = { idempotencyKey: `${run.id}:seed:${i}`, runId: run.id, opId: given.op, attempt: 1 };
|
|
100
|
+
const output = await drivers.get(given.op)(given.input, call);
|
|
101
|
+
seeded.push({ op: given.op, input: given.input, output });
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Checked above: the vendor's fake holds resources.
|
|
105
|
+
seeded.push(seedResource(name, fakes.get(given.vendor), given));
|
|
106
|
+
}
|
|
107
|
+
for (const given of scenario.given) {
|
|
108
|
+
if ("fault" in given)
|
|
109
|
+
fakes.get(state.ops.get(given.op).vendor)[given.fault](given.op);
|
|
110
|
+
}
|
|
111
|
+
copies = drivers;
|
|
112
|
+
return { seeds: seeded };
|
|
113
|
+
}, { name: "sandbox:seed" });
|
|
114
|
+
if (!copies) {
|
|
115
|
+
// Replayed from its checkpoint (after a worker restart, or in a fork), so the run has no fakes.
|
|
116
|
+
// The records written before the restart hold the seqs from here on: the failure goes after them.
|
|
117
|
+
run.seq = Math.max(run.seq, ...(await state.ledger.read(run.id)).map((r) => r.seq + 1));
|
|
118
|
+
throw new SanomaError("invalid_input", `Sandbox run ${run.id} was interrupted by a worker restart and the fakes' state is gone; start the scenario again`, { runId: run.id, scenario: name });
|
|
119
|
+
}
|
|
120
|
+
run.fakeDrivers = copies;
|
|
121
|
+
await write(run, entry(run, { type: "scenario.seeded", scenario: name, seeds }));
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../src/sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { RunSummary, SanomaClient } from "./client.ts";
|
|
2
|
+
import type { ResolvedConfig } from "./config.ts";
|
|
3
|
+
import type { Fake } from "./fake.ts";
|
|
4
|
+
import type { LedgerRecord } from "./ledger.ts";
|
|
5
|
+
import type { Driver } from "./op.ts";
|
|
6
|
+
import type { Seed } from "./steps.ts";
|
|
7
|
+
/** One step of a scenario, as written, for a list and for marking the graph node it is about. */
|
|
8
|
+
export interface ScenarioStep {
|
|
9
|
+
text: string;
|
|
10
|
+
kind: "given" | "when" | "then";
|
|
11
|
+
/** The operation the step is about, when it names one. */
|
|
12
|
+
op?: string;
|
|
13
|
+
/** For a `Then` step about a step by its name (`step "Draft the post" was called`): that name. */
|
|
14
|
+
name?: string;
|
|
15
|
+
/**
|
|
16
|
+
* For a `Then` step about an operation, or a step by its name: true when it expects a call (or
|
|
17
|
+
* a run), false for `was not called` (or `ran 0 times`).
|
|
18
|
+
*/
|
|
19
|
+
called?: boolean;
|
|
20
|
+
/** For a `Then` step about the policy's decision on an operation: `was denied`, or `was held for`. */
|
|
21
|
+
decision?: "denied" | "held";
|
|
22
|
+
/** For a `Given` that injects a fault into the operation's next call (`fails once` and the like), rather than seeding it. */
|
|
23
|
+
fault?: true;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A fake's state to seed through one of its operations (`as` names what the call returns, for
|
|
27
|
+
* an operation's own test), a fault to inject into its next call, or an object a vendor's fake
|
|
28
|
+
* holds: `resource` is its type's id (`github.repository`, its `vendor` and `type`) and `name`
|
|
29
|
+
* its import id, with `fields` to set on it (put, when the vendor has none) or `gone` to remove it.
|
|
30
|
+
*/
|
|
31
|
+
export type Given = {
|
|
32
|
+
step: string;
|
|
33
|
+
op: string;
|
|
34
|
+
input: unknown;
|
|
35
|
+
as?: string;
|
|
36
|
+
} | {
|
|
37
|
+
step: string;
|
|
38
|
+
op: string;
|
|
39
|
+
fault: Fault;
|
|
40
|
+
} | {
|
|
41
|
+
step: string;
|
|
42
|
+
resource: string;
|
|
43
|
+
vendor: string;
|
|
44
|
+
type: string;
|
|
45
|
+
name: string;
|
|
46
|
+
fields: Record<string, unknown>;
|
|
47
|
+
} | {
|
|
48
|
+
step: string;
|
|
49
|
+
resource: string;
|
|
50
|
+
vendor: string;
|
|
51
|
+
type: string;
|
|
52
|
+
name: string;
|
|
53
|
+
gone: true;
|
|
54
|
+
};
|
|
55
|
+
/** How one approval is decided; `approval` is its title or its id. */
|
|
56
|
+
export interface Decision {
|
|
57
|
+
step: string;
|
|
58
|
+
approval: string;
|
|
59
|
+
decision: "approve" | "reject";
|
|
60
|
+
by: string;
|
|
61
|
+
note?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* What the run should do: call an operation (with at least this input) or not, run the step
|
|
65
|
+
* `name`d in the workflow's outline or not, or a number of `times`, have the policy deny an
|
|
66
|
+
* operation (`denied`) or hold one for an approver (`held`), end a certain way, or, for a drift
|
|
67
|
+
* run, report the resource `declared` (`<file>#<export>`) clean, gone, or drifted in a field.
|
|
68
|
+
* A step whose own code checks the run (a connector's or the company's, or an operation's own
|
|
69
|
+
* test's) is `custom`, with what it is about.
|
|
70
|
+
*/
|
|
71
|
+
export type Expectation = {
|
|
72
|
+
step: string;
|
|
73
|
+
op: string;
|
|
74
|
+
input?: unknown;
|
|
75
|
+
called: boolean;
|
|
76
|
+
} | {
|
|
77
|
+
step: string;
|
|
78
|
+
name: string;
|
|
79
|
+
input?: unknown;
|
|
80
|
+
called: boolean;
|
|
81
|
+
} | {
|
|
82
|
+
step: string;
|
|
83
|
+
name: string;
|
|
84
|
+
times: number;
|
|
85
|
+
} | {
|
|
86
|
+
step: string;
|
|
87
|
+
op: string;
|
|
88
|
+
decision: "denied";
|
|
89
|
+
} | {
|
|
90
|
+
step: string;
|
|
91
|
+
op: string;
|
|
92
|
+
decision: "held";
|
|
93
|
+
approver: string;
|
|
94
|
+
} | {
|
|
95
|
+
step: string;
|
|
96
|
+
outcome: "finished" | "failed";
|
|
97
|
+
code?: string;
|
|
98
|
+
} | {
|
|
99
|
+
step: string;
|
|
100
|
+
declared: string;
|
|
101
|
+
status: "clean" | "gone";
|
|
102
|
+
} | {
|
|
103
|
+
step: string;
|
|
104
|
+
declared: string;
|
|
105
|
+
status: "drifted";
|
|
106
|
+
field: string;
|
|
107
|
+
} | {
|
|
108
|
+
step: string;
|
|
109
|
+
custom: true;
|
|
110
|
+
op?: string;
|
|
111
|
+
called?: boolean;
|
|
112
|
+
};
|
|
113
|
+
export interface Scenario {
|
|
114
|
+
name: string;
|
|
115
|
+
/** The feature file, relative to the scenarios directory. */
|
|
116
|
+
file: string;
|
|
117
|
+
/** Its line in the file: its keyword's, or for an outline's row, the row's. */
|
|
118
|
+
line: number;
|
|
119
|
+
workflow: string;
|
|
120
|
+
/**
|
|
121
|
+
* The scenario's own lines of its feature file, for display: from its keyword line to the end
|
|
122
|
+
* of its last step (a step's doc string or table included, and an outline's examples), less
|
|
123
|
+
* the keyword line's indent. An outline's rows share their outline's.
|
|
124
|
+
*/
|
|
125
|
+
text: string;
|
|
126
|
+
/** Every step in order, for a list and for marking graph nodes. */
|
|
127
|
+
steps: ScenarioStep[];
|
|
128
|
+
given: Given[];
|
|
129
|
+
input: unknown;
|
|
130
|
+
decisions: Decision[];
|
|
131
|
+
/**
|
|
132
|
+
* The titles of the approvals the workflow's code asks for, where a title is a string literal
|
|
133
|
+
* (read from its outline), so `drive` can tell a decision for an approval still to come from
|
|
134
|
+
* one meant for whichever comes next.
|
|
135
|
+
*/
|
|
136
|
+
approvals: string[];
|
|
137
|
+
expect: Expectation[];
|
|
138
|
+
}
|
|
139
|
+
/** The result of one expectation against a run's ledger. */
|
|
140
|
+
export interface Check {
|
|
141
|
+
step: string;
|
|
142
|
+
ok: boolean;
|
|
143
|
+
detail?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* What steps can name: the config's operations, workflows and resource types by id, the steps
|
|
147
|
+
* its connectors (and the company) ship, and where the feature files are.
|
|
148
|
+
*/
|
|
149
|
+
export type Scope = Pick<ResolvedConfig, "ops" | "workflows" | "scenarios" | "types" | "steps">;
|
|
150
|
+
type Fault = Extract<Seed, {
|
|
151
|
+
fault: unknown;
|
|
152
|
+
}>["fault"];
|
|
153
|
+
/** Where an operation's own test makes its calls: an operation's driver, live, replayed or a fake's, and the fake. */
|
|
154
|
+
export interface FeatureTarget {
|
|
155
|
+
driver: Driver;
|
|
156
|
+
/** The fake whose driver it is: a scenario's faults need one. */
|
|
157
|
+
fake?: Fake<any, any>;
|
|
158
|
+
}
|
|
159
|
+
/** What `loadScenarios` returns. */
|
|
160
|
+
export interface LoadedScenarios {
|
|
161
|
+
scenarios: Scenario[];
|
|
162
|
+
errors: {
|
|
163
|
+
file: string;
|
|
164
|
+
message: string;
|
|
165
|
+
}[];
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Every scenario in the `.feature` files under `scenarios` (a `file:` URL to a directory),
|
|
169
|
+
* compiled by Cucumber, with an error for each file that does not compile and each name used
|
|
170
|
+
* twice. No directory, or none given, is no scenarios. Rejects when an operation's phrase names
|
|
171
|
+
* a field it lacks. The files are compiled again only once one is added, removed or written
|
|
172
|
+
* (its name, `mtimeMs` or size changes): until then each call returns the same object, which
|
|
173
|
+
* callers must not change.
|
|
174
|
+
*/
|
|
175
|
+
export declare function loadScenarios(scope: Scope): Promise<LoadedScenarios>;
|
|
176
|
+
/**
|
|
177
|
+
* Checks a run's ledger records against the scenario, as its feature file reads now: Cucumber
|
|
178
|
+
* runs the scenario's `Then` steps, each judging the run on its own, and the rest of its steps
|
|
179
|
+
* do nothing. One check per expectation (`scenario.expect`), in order, a step that does not hold
|
|
180
|
+
* with why as its `detail`. Rejects when the scenario no longer compiles as it did (a step the
|
|
181
|
+
* file no longer matches, say): load the scenarios again first, as the app does.
|
|
182
|
+
*/
|
|
183
|
+
export declare function check(scope: Scope, scenario: Scenario, records: readonly LedgerRecord[]): Promise<Check[]>;
|
|
184
|
+
/**
|
|
185
|
+
* The scenarios of the `.feature` files under `dir` (a `file:` URL to a directory), in order,
|
|
186
|
+
* named as `loadScenarios` names them, from a dry run: what a test runner lists before it runs
|
|
187
|
+
* each (`testFeature`). Rejects, naming the file, for one Gherkin cannot parse.
|
|
188
|
+
*/
|
|
189
|
+
export declare function featureScenarios(scope: Scope, dir: URL): Promise<{
|
|
190
|
+
file: string;
|
|
191
|
+
line: number;
|
|
192
|
+
name: string;
|
|
193
|
+
tags: string[];
|
|
194
|
+
}[]>;
|
|
195
|
+
/**
|
|
196
|
+
* Runs the scenario at `line` of the feature file `file` (absolute) as an operation's own test,
|
|
197
|
+
* on the target: its `Given` steps seed through it, its `When` steps call its operations directly
|
|
198
|
+
* (no worker, no policy), and its `Then` steps check those calls. Rejects with its first step
|
|
199
|
+
* that did not pass, at `file:line`.
|
|
200
|
+
*/
|
|
201
|
+
export declare function testFeature(scope: Scope, file: string, line: number, target: FeatureTarget): Promise<void>;
|
|
202
|
+
/**
|
|
203
|
+
* Decides the run's approvals as the scenario says until the run ends, and returns how it
|
|
204
|
+
* ended. Each pending approval takes the decision naming its title (or id), else the next one
|
|
205
|
+
* left that names no approval of the run (one it has asked for, or one its code names). Throws
|
|
206
|
+
* for an approval with no such decision, and `run_running` when the run has not ended within
|
|
207
|
+
* `timeoutMs` or the worker has not read a decision by then.
|
|
208
|
+
*/
|
|
209
|
+
export declare function drive(client: SanomaClient, runId: string, scenario: Scenario, { timeoutMs }?: {
|
|
210
|
+
timeoutMs?: number;
|
|
211
|
+
}): Promise<RunSummary>;
|
|
212
|
+
export {};
|