@memberjunction/testing-integration 0.0.0 → 5.49.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/IntegrationTestDriver.d.ts +63 -0
- package/dist/IntegrationTestDriver.d.ts.map +1 -0
- package/dist/IntegrationTestDriver.js +412 -0
- package/dist/IntegrationTestDriver.js.map +1 -0
- package/dist/ai-verify.d.ts +27 -0
- package/dist/ai-verify.d.ts.map +1 -0
- package/dist/ai-verify.js +120 -0
- package/dist/ai-verify.js.map +1 -0
- package/dist/bootstrap-client.d.ts +11 -0
- package/dist/bootstrap-client.d.ts.map +1 -0
- package/dist/bootstrap-client.js +68 -0
- package/dist/bootstrap-client.js.map +1 -0
- package/dist/bootstrap-shared.d.ts +94 -0
- package/dist/bootstrap-shared.d.ts.map +1 -0
- package/dist/bootstrap-shared.js +94 -0
- package/dist/bootstrap-shared.js.map +1 -0
- package/dist/bootstrap.d.ts +14 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +133 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/check-registry.d.ts +39 -0
- package/dist/check-registry.d.ts.map +1 -0
- package/dist/check-registry.js +61 -0
- package/dist/check-registry.js.map +1 -0
- package/dist/check.d.ts +531 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +2 -0
- package/dist/check.js.map +1 -0
- package/dist/checks/self-test.check.d.ts +2 -0
- package/dist/checks/self-test.check.d.ts.map +1 -0
- package/dist/checks/self-test.check.js +35 -0
- package/dist/checks/self-test.check.js.map +1 -0
- package/dist/config.d.ts +35 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +81 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumented-cache.d.ts +47 -0
- package/dist/instrumented-cache.d.ts.map +1 -0
- package/dist/instrumented-cache.js +81 -0
- package/dist/instrumented-cache.js.map +1 -0
- package/dist/registry.d.ts +33 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +37 -0
- package/dist/registry.js.map +1 -0
- package/dist/rls-fixture.d.ts +37 -0
- package/dist/rls-fixture.d.ts.map +1 -0
- package/dist/rls-fixture.js +91 -0
- package/dist/rls-fixture.js.map +1 -0
- package/dist/test-runner.d.ts +55 -0
- package/dist/test-runner.d.ts.map +1 -0
- package/dist/test-runner.js +128 -0
- package/dist/test-runner.js.map +1 -0
- package/dist/tiers.d.ts +28 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +41 -0
- package/dist/tiers.js.map +1 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -8
- package/README.md +0 -45
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { BaseTestDriver, DriverExecutionContext, DriverExecutionResult, SuiteFixtureContext } from '@memberjunction/testing-engine';
|
|
2
|
+
import type { UserInfo } from '@memberjunction/core';
|
|
3
|
+
export declare class IntegrationTestDriver extends BaseTestDriver {
|
|
4
|
+
/** The driver arms its own timeout and breaks the check loop when it fires. */
|
|
5
|
+
supportsCancellation(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Suite-scoped setup (D6). Discovers the two-user RLS fixture ONCE per suite run and
|
|
8
|
+
* stashes it on the shared SuiteFixtureContext so every test of the suite (and the
|
|
9
|
+
* `rls-isolation` bundle's checks) reads the same pair. Best-effort: discovery has
|
|
10
|
+
* nothing to delete, so failures are non-fatal — Execute lazily re-discovers when the
|
|
11
|
+
* fixture is absent (e.g. the `mj test run` path has no suite). Only meaningful on the
|
|
12
|
+
* server transport (the user cache is a SQLServerDataProvider concept).
|
|
13
|
+
*/
|
|
14
|
+
SetupSuite(context: SuiteFixtureContext, _contextUser: UserInfo): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Suite-scoped teardown (D6). No-op: the RLS fixture is DISCOVERED (not created), so
|
|
17
|
+
* there is nothing to delete — the safest possible teardown. Present so the engine's
|
|
18
|
+
* suite-hook lifecycle is exercised end-to-end by this driver.
|
|
19
|
+
*/
|
|
20
|
+
TeardownSuite(_context: SuiteFixtureContext, _contextUser: UserInfo): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* The two-user RLS fixture for the current run: the one discovered in SetupSuite when
|
|
23
|
+
* available, otherwise discovered lazily here (the no-suite `mj test run` path) and
|
|
24
|
+
* cached back onto the suite context for sibling tests.
|
|
25
|
+
*/
|
|
26
|
+
private ensureRlsFixture;
|
|
27
|
+
Execute(context: DriverExecutionContext): Promise<DriverExecutionResult>;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a bundle and run its ordered checks. A bundle that registers a BundleLifecycle
|
|
30
|
+
* (runquery-cache, field-rules-bulk-update, …) has its Setup + Teardown wrapped in ONE
|
|
31
|
+
* try/finally so Teardown is guaranteed even on a mid-Setup crash (R4). Mutation-gated
|
|
32
|
+
* checks run only when `runMutation` is set.
|
|
33
|
+
*/
|
|
34
|
+
private runBundle;
|
|
35
|
+
/**
|
|
36
|
+
* C6: run a single check but bound it by the remaining run budget. The between-checks `timedOut`
|
|
37
|
+
* flag can only stop the loop between checks — a check that hangs forever would otherwise run
|
|
38
|
+
* past the deadline unbounded. Racing the check against a per-check timeout makes a hang surface
|
|
39
|
+
* as a failed check with a clear message (caught by runCheck's try/catch) instead of a wedged
|
|
40
|
+
* run. The check's own promise may keep running after we move on, but the process is dedicated
|
|
41
|
+
* and short-lived (D1), so a dangling promise on the timeout path is harmless.
|
|
42
|
+
*/
|
|
43
|
+
private runWithDeadline;
|
|
44
|
+
/** Run one check in try/catch and append one OracleResult + one TestOutcome. */
|
|
45
|
+
private runCheck;
|
|
46
|
+
/** client-cache / rls-isolation-client run on the GraphQL client transport; others on SQL server. */
|
|
47
|
+
private bundleTransport;
|
|
48
|
+
/**
|
|
49
|
+
* Obtain the run-scoped instrumented provider stack for the chosen transport.
|
|
50
|
+
* Prefers a stack already installed first-caller (CLI's installInstrumentedCacheFirst,
|
|
51
|
+
* or a prior bootstrap in this process); falls back to owning the process. Throws
|
|
52
|
+
* (caught upstream) when a client bundle is requested but the cache was already claimed
|
|
53
|
+
* by a SQL provider, or vice-versa.
|
|
54
|
+
*/
|
|
55
|
+
private buildCheckContext;
|
|
56
|
+
/** Map the OracleResult[] to the framework result (one OracleResult per check). */
|
|
57
|
+
private buildResult;
|
|
58
|
+
/** Gated/skipped run: one passing 'gate' OracleResult, never 'Running', never thrown. */
|
|
59
|
+
private buildSkipResult;
|
|
60
|
+
/** Bootstrap/config error: one failing 'error' OracleResult, status 'Error', never thrown. */
|
|
61
|
+
private buildErrorResult;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=IntegrationTestDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntegrationTestDriver.d.ts","sourceRoot":"","sources":["../src/IntegrationTestDriver.ts"],"names":[],"mappings":"AAyBA,OAAO,EACH,cAAc,EACd,sBAAsB,EACtB,qBAAqB,EAErB,mBAAmB,EACtB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,QAAQ,EAAqB,MAAM,sBAAsB,CAAC;AA2BxE,qBACa,qBAAsB,SAAQ,cAAc;IACrD,+EAA+E;IAC/D,oBAAoB,IAAI,OAAO;IAI/C;;;;;;;OAOG;IACmB,UAAU,CAAC,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrG;;;;OAIG;IACmB,aAAa,CAAC,QAAQ,EAAE,mBAAmB,EAAE,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzG;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAYX,OAAO,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA+FrF;;;;;OAKG;YACW,SAAS;IAoFvB;;;;;;;OAOG;YACW,eAAe;IA0B7B,gFAAgF;YAClE,QAAQ;IAgCtB,qGAAqG;IACrG,OAAO,CAAC,eAAe;IAIvB;;;;;;OAMG;YACW,iBAAiB;IAuC/B,mFAAmF;IACnF,OAAO,CAAC,WAAW;IA8BnB,yFAAyF;IACzF,OAAO,CAAC,eAAe;IAcvB,8FAA8F;IAC9F,OAAO,CAAC,gBAAgB;CAe3B"}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* IntegrationTestDriver.ts — the TestType driver for the "Integration Test" type.
|
|
9
|
+
*
|
|
10
|
+
* Resolved by TestEngine.getDriver() from TestType.DriverClass via
|
|
11
|
+
* MJGlobal.ClassFactory.CreateInstance(BaseTestDriver, 'IntegrationTestDriver').
|
|
12
|
+
*
|
|
13
|
+
* Execute():
|
|
14
|
+
* 1) parse Configuration.checks (an ordered list of check BUNDLES) off MJTestEntity;
|
|
15
|
+
* 2) honor an optional env gate (skip-as-Passed with a note);
|
|
16
|
+
* 3) infer the transport (client-cache ⇒ GraphQL client, else SQL server) and obtain
|
|
17
|
+
* the run-scoped instrumented provider stack (installed first-caller by the CLI,
|
|
18
|
+
* or self-bootstrapped in a dedicated process);
|
|
19
|
+
* 4) for each selected bundle, run its registered NamedCheck[] in array order against
|
|
20
|
+
* ONE shared IntegrationCheckContext — skipping RequiresMutation checks unless the
|
|
21
|
+
* selector opts in — converting a thrown check into a failing OracleResult (never
|
|
22
|
+
* re-throwing; a re-throw would leave the TestRun stuck 'Running'). A bundle that
|
|
23
|
+
* registers a BundleLifecycle (e.g. runquery-cache, field-rules-bulk-update) has its
|
|
24
|
+
* Setup run and Teardown GUARANTEED inside one try/finally, so a mid-Setup crash still
|
|
25
|
+
* tears down whatever the Setup accumulated (R4);
|
|
26
|
+
* 5) map the OracleResult[] onto a DriverExecutionResult (counts computed exactly
|
|
27
|
+
* like AgentEvalDriver). The engine persists oracleResults verbatim to
|
|
28
|
+
* TestRun.ResultDetails as a BARE ARRAY. When EMIT_OUTCOMES is set, also write a
|
|
29
|
+
* {name,passed,durationMs,error}[] sidecar for the golden-equivalence diff.
|
|
30
|
+
*/
|
|
31
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
32
|
+
import { BaseTestDriver } from '@memberjunction/testing-engine';
|
|
33
|
+
import { Metadata } from '@memberjunction/core';
|
|
34
|
+
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
35
|
+
import { getActiveIntegrationStorage, getActiveIntegrationBootstrap, getActiveIntegrationClientBootstrap, bootstrapIntegrationServer, serverProcessAlreadyClaimed } from './bootstrap.js';
|
|
36
|
+
import { bootstrapIntegrationClient } from './bootstrap-client.js';
|
|
37
|
+
import { IntegrationCheckRegistry } from './check-registry.js';
|
|
38
|
+
import { TIER_ENV_GATE, IsTierEnabled } from './tiers.js';
|
|
39
|
+
import { writeOutcomesFile } from './test-runner.js';
|
|
40
|
+
import { discoverRlsFixture } from './rls-fixture.js';
|
|
41
|
+
const TARGET_TYPE = 'Integration Check Bundle';
|
|
42
|
+
/** Bundles that run against the GraphQL client transport (everything else: SQL server). */
|
|
43
|
+
const CLIENT_BUNDLES = new Set(['client-cache', 'rls-isolation-client', 'remote-op-wire-progress']);
|
|
44
|
+
/** Bundles that need the discovered two-user RLS fixture threaded into the context. */
|
|
45
|
+
const RLS_BUNDLES = new Set(['rls-isolation', 'rls-isolation-client']);
|
|
46
|
+
/** Key under SuiteFixtureContext.Data where the discovered RLS fixture is stashed. */
|
|
47
|
+
const RLS_FIXTURE_KEY = 'rlsFixture';
|
|
48
|
+
let IntegrationTestDriver = class IntegrationTestDriver extends BaseTestDriver {
|
|
49
|
+
/** The driver arms its own timeout and breaks the check loop when it fires. */
|
|
50
|
+
supportsCancellation() {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Suite-scoped setup (D6). Discovers the two-user RLS fixture ONCE per suite run and
|
|
55
|
+
* stashes it on the shared SuiteFixtureContext so every test of the suite (and the
|
|
56
|
+
* `rls-isolation` bundle's checks) reads the same pair. Best-effort: discovery has
|
|
57
|
+
* nothing to delete, so failures are non-fatal — Execute lazily re-discovers when the
|
|
58
|
+
* fixture is absent (e.g. the `mj test run` path has no suite). Only meaningful on the
|
|
59
|
+
* server transport (the user cache is a SQLServerDataProvider concept).
|
|
60
|
+
*/
|
|
61
|
+
async SetupSuite(context, _contextUser) {
|
|
62
|
+
try {
|
|
63
|
+
const users = UserCache.Instance.Users;
|
|
64
|
+
if (users && users.length > 0) {
|
|
65
|
+
context.Data[RLS_FIXTURE_KEY] = discoverRlsFixture(this.Provider, users);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
this.log(`SetupSuite RLS discovery skipped: ${e.message}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Suite-scoped teardown (D6). No-op: the RLS fixture is DISCOVERED (not created), so
|
|
74
|
+
* there is nothing to delete — the safest possible teardown. Present so the engine's
|
|
75
|
+
* suite-hook lifecycle is exercised end-to-end by this driver.
|
|
76
|
+
*/
|
|
77
|
+
async TeardownSuite(_context, _contextUser) {
|
|
78
|
+
// no-op — discovery-based fixture has nothing to clean up
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The two-user RLS fixture for the current run: the one discovered in SetupSuite when
|
|
82
|
+
* available, otherwise discovered lazily here (the no-suite `mj test run` path) and
|
|
83
|
+
* cached back onto the suite context for sibling tests.
|
|
84
|
+
*/
|
|
85
|
+
ensureRlsFixture(context) {
|
|
86
|
+
const cached = context.fixtures?.Data?.[RLS_FIXTURE_KEY];
|
|
87
|
+
if (cached) {
|
|
88
|
+
return cached;
|
|
89
|
+
}
|
|
90
|
+
const fx = discoverRlsFixture(this.Provider, UserCache.Instance.Users);
|
|
91
|
+
if (context.fixtures) {
|
|
92
|
+
context.fixtures.Data[RLS_FIXTURE_KEY] = fx;
|
|
93
|
+
}
|
|
94
|
+
return fx;
|
|
95
|
+
}
|
|
96
|
+
async Execute(context) {
|
|
97
|
+
const startTime = Date.now();
|
|
98
|
+
this.logToTestRun(context, 'info', 'Starting integration test execution');
|
|
99
|
+
// 1) Parse Configuration. parseConfig throws on missing/bad JSON — convert to a
|
|
100
|
+
// Failed/Error result rather than re-throwing (re-throw would leave TestRun 'Running').
|
|
101
|
+
let config;
|
|
102
|
+
try {
|
|
103
|
+
config = this.parseConfig(context.test);
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
return this.buildErrorResult(context, startTime, err.message);
|
|
107
|
+
}
|
|
108
|
+
// 2) Whole-test tier gate (gated-tier / local-dev safety net). The tier decides the
|
|
109
|
+
// env var via TIER_ENV_GATE; an explicit `requiresEnv` overrides it. When the gate
|
|
110
|
+
// is unmet, skip-as-Passed with a gate note — the driver result enum has no 'Skipped'.
|
|
111
|
+
const tier = config.tier ?? 'deterministic';
|
|
112
|
+
const explicitGate = config.requiresEnv;
|
|
113
|
+
const gated = explicitGate ? process.env[explicitGate] !== '1' : !IsTierEnabled(tier);
|
|
114
|
+
if (gated) {
|
|
115
|
+
const gateVar = explicitGate ?? TIER_ENV_GATE[tier];
|
|
116
|
+
const note = `Skipped: ${gateVar} not set (tier '${tier}')`;
|
|
117
|
+
this.logToTestRun(context, 'warn', note);
|
|
118
|
+
return this.buildSkipResult(context, startTime, note);
|
|
119
|
+
}
|
|
120
|
+
const selectors = Array.isArray(config.checks) ? config.checks : [];
|
|
121
|
+
const transport = config.transport ?? (selectors.some(s => this.bundleTransport(s.type) === 'client') ? 'client' : 'server');
|
|
122
|
+
// 2b) D1 host check. These suites must own their process — install the instrumented
|
|
123
|
+
// cache as the FIRST caller of LocalCacheManager.Initialize. Inside a live MJAPI
|
|
124
|
+
// the cache is already initialized, so they cannot run here. Fail fast with an
|
|
125
|
+
// actionable message (run via the CLI) instead of a confusing bootstrap stack.
|
|
126
|
+
if (transport === 'server' && serverProcessAlreadyClaimed()) {
|
|
127
|
+
return this.buildErrorResult(context, startTime, 'Integration cache suites must run in a dedicated process: run `npm run test:integration`, ' +
|
|
128
|
+
'or `MJ_INTEGRATION_TEST=1 mj test suite --name "<suite>"`. They cannot run inside a live ' +
|
|
129
|
+
'MJAPI — the cache is already initialized, so the instrumented cache cannot be installed ' +
|
|
130
|
+
'first (plan decision D1).');
|
|
131
|
+
}
|
|
132
|
+
// 3) Arm a driver-side timeout (the engine never applies one). The timer flips `timedOut`
|
|
133
|
+
// to abort the loop BETWEEN checks; the `deadline` additionally bounds EACH check via a
|
|
134
|
+
// per-check race (C6), so a single hung check can't run past the budget forever.
|
|
135
|
+
const effectiveTimeout = this.getEffectiveTimeout(context.test);
|
|
136
|
+
const deadline = Date.now() + effectiveTimeout;
|
|
137
|
+
let timedOut = false;
|
|
138
|
+
const timer = setTimeout(() => { timedOut = true; }, effectiveTimeout);
|
|
139
|
+
const oracleResults = [];
|
|
140
|
+
const outcomes = []; // parallel array for the EMIT_OUTCOMES sidecar
|
|
141
|
+
try {
|
|
142
|
+
const checkCtx = await this.buildCheckContext(context, transport);
|
|
143
|
+
// 4) Run each selected bundle's checks IN ORDER against ONE shared context.
|
|
144
|
+
for (const sel of selectors) {
|
|
145
|
+
if (timedOut) {
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
await this.runBundle(context, checkCtx, sel.type, sel.config, oracleResults, outcomes, () => timedOut, deadline);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (bootErr) {
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
const msg = bootErr.message ?? String(bootErr);
|
|
154
|
+
// ENVIRONMENT GAP, not a product defect: client-transport bundles need a live MJAPI.
|
|
155
|
+
// When the preflight says the server is simply absent (CI runs no MJAPI), skip-as-pass
|
|
156
|
+
// loudly — the same contract the old per-bundle tsx dispatchers honored with exit 0.
|
|
157
|
+
// Any OTHER bootstrap failure (bad credentials, cache ownership, config) stays a
|
|
158
|
+
// hard error.
|
|
159
|
+
if (transport === 'client' && /MJAPI is not reachable/i.test(msg)) {
|
|
160
|
+
return this.buildSkipResult(context, startTime, `SKIPPED (environment gap): ${msg} Client-transport checks need a live MJAPI; start it and re-run for full coverage.`);
|
|
161
|
+
}
|
|
162
|
+
return this.buildErrorResult(context, startTime, `Bootstrap failed: ${msg}`);
|
|
163
|
+
}
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
// 5a) Optional golden-diff sidecar — same shape the tsx scripts emit via EmitOutcomes.
|
|
166
|
+
const emitPath = process.env.EMIT_OUTCOMES;
|
|
167
|
+
if (emitPath) {
|
|
168
|
+
try {
|
|
169
|
+
await writeOutcomesFile(emitPath, outcomes);
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
this.logToTestRun(context, 'warn', `EMIT_OUTCOMES write failed: ${e.message}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// 5b) Assemble the DriverExecutionResult (counts mirror AgentEvalDriver).
|
|
176
|
+
return this.buildResult(context, startTime, oracleResults, timedOut);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Resolve a bundle and run its ordered checks. A bundle that registers a BundleLifecycle
|
|
180
|
+
* (runquery-cache, field-rules-bulk-update, …) has its Setup + Teardown wrapped in ONE
|
|
181
|
+
* try/finally so Teardown is guaranteed even on a mid-Setup crash (R4). Mutation-gated
|
|
182
|
+
* checks run only when `runMutation` is set.
|
|
183
|
+
*/
|
|
184
|
+
async runBundle(context, checkCtx, bundleType, selConfig, oracleResults, outcomes, isTimedOut, deadline) {
|
|
185
|
+
const bundle = IntegrationCheckRegistry.Instance.GetBundle(bundleType);
|
|
186
|
+
if (bundle.length === 0) {
|
|
187
|
+
const message = `Unknown integration check bundle '${bundleType}'. ` +
|
|
188
|
+
`Check bundles register via import side effects — MJ's own bundles live in the private ` +
|
|
189
|
+
`@memberjunction/integration-test-suite package, loaded through mj.config.cjs ` +
|
|
190
|
+
`\`testing.checkModules\` (or the --checks-module flag). If this bundle should exist, ` +
|
|
191
|
+
`verify that config key is present, the module is built, and the bundle name matches.`;
|
|
192
|
+
oracleResults.push({ oracleType: bundleType, passed: false, score: 0, message, details: { DurationMs: 0 } });
|
|
193
|
+
outcomes.push({ Name: bundleType, Passed: false, DurationMs: 0, Error: message });
|
|
194
|
+
this.logToTestRun(context, 'error', `✗ ${message}`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
// Expose the selector's opaque config bag to the bundle's checks (e.g. dataset-cache
|
|
198
|
+
// reads `datasetName`, aggregates-cache reads `entityName`). Set per-bundle since the
|
|
199
|
+
// check context is shared and reused across bundles within one Execute.
|
|
200
|
+
checkCtx.Config = selConfig;
|
|
201
|
+
// The rls-isolation bundles need the discovered two-user fixture (suite-scoped via
|
|
202
|
+
// SetupSuite, or lazily discovered for the no-suite `mj test run` path).
|
|
203
|
+
if (RLS_BUNDLES.has(bundleType)) {
|
|
204
|
+
checkCtx.RlsFixture = this.ensureRlsFixture(context);
|
|
205
|
+
}
|
|
206
|
+
const runMutation = selConfig?.runMutationTests === true;
|
|
207
|
+
// Per-check tier gating routed through the shared IsTierEnabled predicate (the same
|
|
208
|
+
// one the tsx scripts use) so the env gate is honored identically. A selector may also
|
|
209
|
+
// opt mutation checks in explicitly via config.runMutationTests, independent of env.
|
|
210
|
+
const mutationEnabled = IsTierEnabled('mutation') || runMutation;
|
|
211
|
+
const liveModelEnabled = IsTierEnabled('live-model');
|
|
212
|
+
// A mutating bundle registers a lifecycle (setup creates a shared fixture on the context,
|
|
213
|
+
// teardown removes it). R4: run Setup INSIDE the same try whose finally guarantees Teardown,
|
|
214
|
+
// so a mid-Setup crash still runs Teardown against whatever the Setup accumulated onto the
|
|
215
|
+
// context so far (lifecycle Setups publish their fixture handle up-front and append created
|
|
216
|
+
// IDs as they go). A Setup failure short-circuits the bundle with one failing 'fixtures'
|
|
217
|
+
// oracle and skips the checks — but never re-throws and never leaves the fixture orphaned.
|
|
218
|
+
const lifecycle = IntegrationCheckRegistry.Instance.GetLifecycle(bundleType);
|
|
219
|
+
try {
|
|
220
|
+
if (lifecycle) {
|
|
221
|
+
await lifecycle.Setup(checkCtx);
|
|
222
|
+
}
|
|
223
|
+
for (const check of bundle) {
|
|
224
|
+
if (isTimedOut()) {
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
if (check.RequiresMutation && !mutationEnabled) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (check.RequiresLiveModel && !liveModelEnabled) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
await this.runCheck(context, checkCtx, check.Id, check.Name, check.Fn, oracleResults, outcomes, deadline);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (fxErr) {
|
|
237
|
+
// The only throw reachable here is from lifecycle.Setup — runCheck swallows per-check
|
|
238
|
+
// errors into results. Record it as a failing 'fixtures' oracle (never re-thrown).
|
|
239
|
+
const message = `${bundleType} fixture setup failed: ${fxErr.message}`;
|
|
240
|
+
oracleResults.push({ oracleType: `${bundleType}.fixtures`, passed: false, score: 0, message, details: { DurationMs: 0 } });
|
|
241
|
+
outcomes.push({ Name: `${bundleType}.fixtures`, Passed: false, DurationMs: 0, Error: message });
|
|
242
|
+
this.logToTestRun(context, 'error', message);
|
|
243
|
+
}
|
|
244
|
+
finally {
|
|
245
|
+
if (lifecycle) {
|
|
246
|
+
// Best-effort — a teardown failure must never mask a check result or leave TestRun 'Running'.
|
|
247
|
+
try {
|
|
248
|
+
await lifecycle.Teardown(checkCtx);
|
|
249
|
+
}
|
|
250
|
+
catch (tdErr) {
|
|
251
|
+
this.logToTestRun(context, 'warn', `${bundleType} teardown warning: ${tdErr.message}`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* C6: run a single check but bound it by the remaining run budget. The between-checks `timedOut`
|
|
258
|
+
* flag can only stop the loop between checks — a check that hangs forever would otherwise run
|
|
259
|
+
* past the deadline unbounded. Racing the check against a per-check timeout makes a hang surface
|
|
260
|
+
* as a failed check with a clear message (caught by runCheck's try/catch) instead of a wedged
|
|
261
|
+
* run. The check's own promise may keep running after we move on, but the process is dedicated
|
|
262
|
+
* and short-lived (D1), so a dangling promise on the timeout path is harmless.
|
|
263
|
+
*/
|
|
264
|
+
async runWithDeadline(id, fn, checkCtx, deadline) {
|
|
265
|
+
const remaining = deadline - Date.now();
|
|
266
|
+
if (remaining <= 0) {
|
|
267
|
+
throw new Error(`integration run budget exhausted before check '${id}' started`);
|
|
268
|
+
}
|
|
269
|
+
let timer;
|
|
270
|
+
const timeout = new Promise((_, reject) => {
|
|
271
|
+
timer = setTimeout(() => reject(new Error(`check '${id}' exceeded the ${remaining}ms remaining run budget (hung check)`)), remaining);
|
|
272
|
+
});
|
|
273
|
+
try {
|
|
274
|
+
await Promise.race([fn(checkCtx), timeout]);
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
if (timer) {
|
|
278
|
+
clearTimeout(timer);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/** Run one check in try/catch and append one OracleResult + one TestOutcome. */
|
|
283
|
+
async runCheck(context, checkCtx, id, name, fn, oracleResults, outcomes, deadline) {
|
|
284
|
+
const checkStart = Date.now();
|
|
285
|
+
try {
|
|
286
|
+
await this.runWithDeadline(id, fn, checkCtx, deadline);
|
|
287
|
+
const durationMs = Date.now() - checkStart;
|
|
288
|
+
oracleResults.push({
|
|
289
|
+
oracleType: id,
|
|
290
|
+
passed: true,
|
|
291
|
+
score: 1,
|
|
292
|
+
message: name,
|
|
293
|
+
details: { DurationMs: durationMs, runViewCacheSets: checkCtx.Storage.SetCount('RunViewCache') }
|
|
294
|
+
});
|
|
295
|
+
outcomes.push({ Name: name, Passed: true, DurationMs: durationMs });
|
|
296
|
+
this.logToTestRun(context, 'info', `✓ ${id}`);
|
|
297
|
+
}
|
|
298
|
+
catch (checkErr) {
|
|
299
|
+
const durationMs = Date.now() - checkStart;
|
|
300
|
+
const message = checkErr.message;
|
|
301
|
+
oracleResults.push({ oracleType: id, passed: false, score: 0, message, details: { DurationMs: durationMs } });
|
|
302
|
+
outcomes.push({ Name: name, Passed: false, DurationMs: durationMs, Error: message });
|
|
303
|
+
this.logToTestRun(context, 'error', `✗ ${id}: ${message}`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/** client-cache / rls-isolation-client run on the GraphQL client transport; others on SQL server. */
|
|
307
|
+
bundleTransport(bundleType) {
|
|
308
|
+
return CLIENT_BUNDLES.has(bundleType) ? 'client' : 'server';
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Obtain the run-scoped instrumented provider stack for the chosen transport.
|
|
312
|
+
* Prefers a stack already installed first-caller (CLI's installInstrumentedCacheFirst,
|
|
313
|
+
* or a prior bootstrap in this process); falls back to owning the process. Throws
|
|
314
|
+
* (caught upstream) when a client bundle is requested but the cache was already claimed
|
|
315
|
+
* by a SQL provider, or vice-versa.
|
|
316
|
+
*/
|
|
317
|
+
async buildCheckContext(context, transport) {
|
|
318
|
+
if (transport === 'client') {
|
|
319
|
+
const client = getActiveIntegrationClientBootstrap() ?? await bootstrapIntegrationClient();
|
|
320
|
+
return {
|
|
321
|
+
User: context.contextUser,
|
|
322
|
+
Provider: this.Provider,
|
|
323
|
+
Storage: client.Storage,
|
|
324
|
+
Pool: undefined,
|
|
325
|
+
Schema: process.env.MJ_CORE_SCHEMA ?? '__mj'
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
let storage = getActiveIntegrationStorage();
|
|
329
|
+
const activeBootstrap = getActiveIntegrationBootstrap();
|
|
330
|
+
let pool = activeBootstrap?.Pool;
|
|
331
|
+
let schema = activeBootstrap?.Db.Schema;
|
|
332
|
+
// The REAL database provider (a DatabaseProviderBase): the bootstrap's own provider when a
|
|
333
|
+
// bootstrap ran in-process, else the global one installed by the CLI's initializeMJProvider.
|
|
334
|
+
// NOT `this.Provider` — its getter returns a `new Metadata()` FACADE when the engine injected
|
|
335
|
+
// no provider, and the facade lacks IRemoteOperationProvider.RouteOperation (so remote-op
|
|
336
|
+
// checks would fail with "No remote-operation-capable provider"). Dedicated single-provider
|
|
337
|
+
// process (D1), so the global is unambiguous and matches what the tsx dispatcher passes.
|
|
338
|
+
let provider = activeBootstrap?.Provider ?? Metadata.Provider;
|
|
339
|
+
if (!storage) {
|
|
340
|
+
const ic = await bootstrapIntegrationServer();
|
|
341
|
+
storage = ic.Storage;
|
|
342
|
+
pool = ic.Pool;
|
|
343
|
+
schema = ic.Db.Schema;
|
|
344
|
+
provider = ic.Provider;
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
User: context.contextUser,
|
|
348
|
+
Provider: provider,
|
|
349
|
+
Storage: storage,
|
|
350
|
+
Pool: pool,
|
|
351
|
+
Schema: schema ?? (process.env.MJ_CORE_SCHEMA ?? '__mj')
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/** Map the OracleResult[] to the framework result (one OracleResult per check). */
|
|
355
|
+
buildResult(context, startTime, oracleResults, timedOut) {
|
|
356
|
+
const passedChecks = oracleResults.filter(r => r.passed).length;
|
|
357
|
+
const totalChecks = oracleResults.length;
|
|
358
|
+
const failedChecks = totalChecks - passedChecks;
|
|
359
|
+
const status = timedOut ? 'Timeout' : (failedChecks === 0 ? 'Passed' : 'Failed');
|
|
360
|
+
const result = {
|
|
361
|
+
targetType: TARGET_TYPE,
|
|
362
|
+
// No external MJ log entity to link; point TargetLogID at the TestRun itself.
|
|
363
|
+
targetLogId: context.testRun.ID,
|
|
364
|
+
status,
|
|
365
|
+
score: totalChecks === 0 ? 0 : passedChecks / totalChecks,
|
|
366
|
+
oracleResults,
|
|
367
|
+
passedChecks,
|
|
368
|
+
failedChecks,
|
|
369
|
+
totalChecks,
|
|
370
|
+
durationMs: Date.now() - startTime
|
|
371
|
+
};
|
|
372
|
+
if (timedOut) {
|
|
373
|
+
result.errorMessage = `Integration run timed out after ${this.getEffectiveTimeout(context.test)}ms`;
|
|
374
|
+
}
|
|
375
|
+
return result;
|
|
376
|
+
}
|
|
377
|
+
/** Gated/skipped run: one passing 'gate' OracleResult, never 'Running', never thrown. */
|
|
378
|
+
buildSkipResult(context, startTime, note) {
|
|
379
|
+
return {
|
|
380
|
+
targetType: TARGET_TYPE,
|
|
381
|
+
targetLogId: context.testRun.ID,
|
|
382
|
+
status: 'Passed',
|
|
383
|
+
score: 1,
|
|
384
|
+
oracleResults: [{ oracleType: 'gate', passed: true, score: 1, message: note, details: { DurationMs: 0 } }],
|
|
385
|
+
passedChecks: 1,
|
|
386
|
+
failedChecks: 0,
|
|
387
|
+
totalChecks: 1,
|
|
388
|
+
durationMs: Date.now() - startTime
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
/** Bootstrap/config error: one failing 'error' OracleResult, status 'Error', never thrown. */
|
|
392
|
+
buildErrorResult(context, startTime, message) {
|
|
393
|
+
this.logToTestRun(context, 'error', message);
|
|
394
|
+
return {
|
|
395
|
+
targetType: TARGET_TYPE,
|
|
396
|
+
targetLogId: context.testRun.ID,
|
|
397
|
+
status: 'Error',
|
|
398
|
+
score: 0,
|
|
399
|
+
oracleResults: [{ oracleType: 'error', passed: false, score: 0, message, details: { DurationMs: 0 } }],
|
|
400
|
+
passedChecks: 0,
|
|
401
|
+
failedChecks: 1,
|
|
402
|
+
totalChecks: 1,
|
|
403
|
+
durationMs: Date.now() - startTime,
|
|
404
|
+
errorMessage: message
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
IntegrationTestDriver = __decorate([
|
|
409
|
+
RegisterClass(BaseTestDriver, 'IntegrationTestDriver')
|
|
410
|
+
], IntegrationTestDriver);
|
|
411
|
+
export { IntegrationTestDriver };
|
|
412
|
+
//# sourceMappingURL=IntegrationTestDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IntegrationTestDriver.js","sourceRoot":"","sources":["../src/IntegrationTestDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { UserInfo } from '@memberjunction/core';
|
|
2
|
+
type Row = Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* Verifies an `MJ: AI Prompt Runs` row finalized correctly: terminal Status, **CompletedAt set** (the
|
|
5
|
+
* "stuck at Running" guard the save queue prevents), and on success a non-empty Result + recorded timing.
|
|
6
|
+
*/
|
|
7
|
+
export declare function verifyPromptRun(promptRunID: string, user: UserInfo): Promise<Row>;
|
|
8
|
+
/** Verifies an `MJ: Action Execution Logs` row finalized: **EndedAt set** + a ResultCode recorded. */
|
|
9
|
+
export declare function verifyActionLog(logID: string, user: UserInfo): Promise<Row>;
|
|
10
|
+
export interface AgentRunVerification {
|
|
11
|
+
run: Row;
|
|
12
|
+
stepCount: number;
|
|
13
|
+
promptRunsVerified: number;
|
|
14
|
+
actionLogsVerified: number;
|
|
15
|
+
subAgentRunsVerified: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Deep-verifies an agent run end to end: the `MJ: AI Agent Runs` header, every `MJ: AI Agent Run Steps`
|
|
19
|
+
* row (each terminal + CompletedAt set — never stuck at Running), and the records each step points at via
|
|
20
|
+
* TargetLogID — Prompt steps → AI Prompt Runs, Actions/Tool steps → Action Execution Logs, Sub-Agent steps
|
|
21
|
+
* → child AI Agent Runs (recursively). `expectSuccess` asserts the run reached 'Completed'.
|
|
22
|
+
*/
|
|
23
|
+
export declare function verifyAgentRun(agentRunID: string, user: UserInfo, expectSuccess?: boolean, opts?: {
|
|
24
|
+
skipActionLogs?: boolean;
|
|
25
|
+
}): Promise<AgentRunVerification>;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=ai-verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-verify.d.ts","sourceRoot":"","sources":["../src/ai-verify.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGrD,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA2BnC;;;GAGG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CASvF;AAED,sGAAsG;AACtG,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAKjF;AAED,MAAM,WAAW,oBAAoB;IACjC,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;CAChC;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,aAAa,UAAO,EAAE,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqDrK"}
|