@gate-forge/pack-playwright 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/bin/gateforge-witness.js +40 -0
- package/dist/attestation/proxy.d.ts +40 -0
- package/dist/attestation/proxy.d.ts.map +1 -0
- package/dist/attestation/proxy.js +78 -0
- package/dist/attestation/proxy.js.map +1 -0
- package/dist/constants.d.ts +130 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +138 -0
- package/dist/constants.js.map +1 -0
- package/dist/discovery/adapters.d.ts +167 -0
- package/dist/discovery/adapters.d.ts.map +1 -0
- package/dist/discovery/adapters.js +276 -0
- package/dist/discovery/adapters.js.map +1 -0
- package/dist/discovery/discover.d.ts +57 -0
- package/dist/discovery/discover.d.ts.map +1 -0
- package/dist/discovery/discover.js +544 -0
- package/dist/discovery/discover.js.map +1 -0
- package/dist/discovery/index.d.ts +15 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +15 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/inference.d.ts +63 -0
- package/dist/discovery/inference.d.ts.map +1 -0
- package/dist/discovery/inference.js +173 -0
- package/dist/discovery/inference.js.map +1 -0
- package/dist/discovery/pytest-adapter.d.ts +205 -0
- package/dist/discovery/pytest-adapter.d.ts.map +1 -0
- package/dist/discovery/pytest-adapter.js +548 -0
- package/dist/discovery/pytest-adapter.js.map +1 -0
- package/dist/discovery/reconcile.d.ts +106 -0
- package/dist/discovery/reconcile.d.ts.map +1 -0
- package/dist/discovery/reconcile.js +268 -0
- package/dist/discovery/reconcile.js.map +1 -0
- package/dist/discovery/runner-env.d.ts +80 -0
- package/dist/discovery/runner-env.d.ts.map +1 -0
- package/dist/discovery/runner-env.js +139 -0
- package/dist/discovery/runner-env.js.map +1 -0
- package/dist/discovery/static-discovery.d.ts +121 -0
- package/dist/discovery/static-discovery.d.ts.map +1 -0
- package/dist/discovery/static-discovery.js +1028 -0
- package/dist/discovery/static-discovery.js.map +1 -0
- package/dist/discovery/supervised-run.d.ts +110 -0
- package/dist/discovery/supervised-run.d.ts.map +1 -0
- package/dist/discovery/supervised-run.js +328 -0
- package/dist/discovery/supervised-run.js.map +1 -0
- package/dist/discovery/trusted-config.d.ts +103 -0
- package/dist/discovery/trusted-config.d.ts.map +1 -0
- package/dist/discovery/trusted-config.js +117 -0
- package/dist/discovery/trusted-config.js.map +1 -0
- package/dist/fixture/evidence.d.ts +191 -0
- package/dist/fixture/evidence.d.ts.map +1 -0
- package/dist/fixture/evidence.js +366 -0
- package/dist/fixture/evidence.js.map +1 -0
- package/dist/fixture/fixture.d.ts +37 -0
- package/dist/fixture/fixture.d.ts.map +1 -0
- package/dist/fixture/fixture.js +38 -0
- package/dist/fixture/fixture.js.map +1 -0
- package/dist/fixture/witness-client.d.ts +164 -0
- package/dist/fixture/witness-client.d.ts.map +1 -0
- package/dist/fixture/witness-client.js +253 -0
- package/dist/fixture/witness-client.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +16 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +21 -0
- package/dist/json.js.map +1 -0
- package/dist/reporter/ledger.d.ts +105 -0
- package/dist/reporter/ledger.d.ts.map +1 -0
- package/dist/reporter/ledger.js +197 -0
- package/dist/reporter/ledger.js.map +1 -0
- package/dist/reporter/reporter.cjs +105 -0
- package/dist/reporter/reporter.cjs.map +1 -0
- package/dist/reporter/reporter.d.cts +35 -0
- package/dist/reporter/reporter.d.cts.map +1 -0
- package/dist/reporter/reporter.d.ts +167 -0
- package/dist/reporter/reporter.d.ts.map +1 -0
- package/dist/reporter/reporter.js +673 -0
- package/dist/reporter/reporter.js.map +1 -0
- package/dist/setup.d.ts +49 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +167 -0
- package/dist/setup.js.map +1 -0
- package/dist/supervisor/client.d.ts +73 -0
- package/dist/supervisor/client.d.ts.map +1 -0
- package/dist/supervisor/client.js +164 -0
- package/dist/supervisor/client.js.map +1 -0
- package/dist/supervisor/drain.d.ts +45 -0
- package/dist/supervisor/drain.d.ts.map +1 -0
- package/dist/supervisor/drain.js +235 -0
- package/dist/supervisor/drain.js.map +1 -0
- package/dist/supervisor/index.d.ts +16 -0
- package/dist/supervisor/index.d.ts.map +1 -0
- package/dist/supervisor/index.js +13 -0
- package/dist/supervisor/index.js.map +1 -0
- package/dist/supervisor/spool.d.ts +137 -0
- package/dist/supervisor/spool.d.ts.map +1 -0
- package/dist/supervisor/spool.js +263 -0
- package/dist/supervisor/spool.js.map +1 -0
- package/dist/surface.d.ts +134 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +139 -0
- package/dist/surface.js.map +1 -0
- package/dist/witness/adapter-registry.d.ts +38 -0
- package/dist/witness/adapter-registry.d.ts.map +1 -0
- package/dist/witness/adapter-registry.js +158 -0
- package/dist/witness/adapter-registry.js.map +1 -0
- package/dist/witness/bin.d.ts +21 -0
- package/dist/witness/bin.d.ts.map +1 -0
- package/dist/witness/bin.js +172 -0
- package/dist/witness/bin.js.map +1 -0
- package/dist/witness/browser.d.ts +173 -0
- package/dist/witness/browser.d.ts.map +1 -0
- package/dist/witness/browser.js +580 -0
- package/dist/witness/browser.js.map +1 -0
- package/dist/witness/classifications.d.ts +42 -0
- package/dist/witness/classifications.d.ts.map +1 -0
- package/dist/witness/classifications.js +87 -0
- package/dist/witness/classifications.js.map +1 -0
- package/dist/witness/env-attestation.d.ts +98 -0
- package/dist/witness/env-attestation.d.ts.map +1 -0
- package/dist/witness/env-attestation.js +202 -0
- package/dist/witness/env-attestation.js.map +1 -0
- package/dist/witness/loopback-pins.d.ts +79 -0
- package/dist/witness/loopback-pins.d.ts.map +1 -0
- package/dist/witness/loopback-pins.js +244 -0
- package/dist/witness/loopback-pins.js.map +1 -0
- package/dist/witness/server.d.ts +34 -0
- package/dist/witness/server.d.ts.map +1 -0
- package/dist/witness/server.js +2539 -0
- package/dist/witness/server.js.map +1 -0
- package/dist/witness/types.d.ts +643 -0
- package/dist/witness/types.d.ts.map +1 -0
- package/dist/witness/types.js +2 -0
- package/dist/witness/types.js.map +1 -0
- package/package.json +64 -0
- package/python/gateforge_persistence_intents.py +100 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded pytest diagnostic adapter (plan 2026-09-13 §3.5, phase 2 item
|
|
3
|
+
* 8 + Phase 4 item 9). pytest is a runner, not a test category: its
|
|
4
|
+
* suites power the advisory "red means inspect this" alarm and NEVER
|
|
5
|
+
* supply E2E proof.
|
|
6
|
+
*
|
|
7
|
+
* Hard bounds, all fail-closed:
|
|
8
|
+
* - The adapter only ever composes the CONFIGURED argv (interpreter +
|
|
9
|
+
* args from `diagnostics.suites[]`), appending collection/report
|
|
10
|
+
* flags. It never scans directories for executables and never runs a
|
|
11
|
+
* command it did not compose from config.
|
|
12
|
+
* - Every invocation carries a finite timeout (`timeoutMs` from the
|
|
13
|
+
* suite config); on expiry the child is killed and a typed timeout is
|
|
14
|
+
* reported — an incomplete/unavailable run, never a passing one.
|
|
15
|
+
* - Collection prefers structured output: `--collect-only -q` node ids;
|
|
16
|
+
* execution outcomes come from native junit XML ({@link parseJunitXml})
|
|
17
|
+
* written into the EXCLUDED run-state dir, never tracked inputs.
|
|
18
|
+
* - Diagnostic execution (Phase 4) runs each suite ONCE in an isolated
|
|
19
|
+
* process with every `GATEFORGE_*` variable stripped, and the result
|
|
20
|
+
* is DIAGNOSTIC data: it is never fed into claims, witness records,
|
|
21
|
+
* baselines, waivers, or E2E satisfaction (§3.5).
|
|
22
|
+
*/
|
|
23
|
+
import { spawn } from 'node:child_process';
|
|
24
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
25
|
+
import { isAbsolute, join, relative } from 'node:path';
|
|
26
|
+
import { TestDiscoveryError, untrustedEnv } from './reconcile.js';
|
|
27
|
+
/**
|
|
28
|
+
* Composes the collection argv for a configured suite: the configured
|
|
29
|
+
* interpreter/args verbatim, then `--collect-only -q`, then the
|
|
30
|
+
* configured testPaths. Nothing else — no directory guessing, no extra
|
|
31
|
+
* commands beyond the configured argv + collection flags.
|
|
32
|
+
*
|
|
33
|
+
* Args:
|
|
34
|
+
* suite: the configured diagnostic suite.
|
|
35
|
+
*
|
|
36
|
+
* Returns:
|
|
37
|
+
* string[]: argv to spawn with cwd = repo root (the adapter passes the
|
|
38
|
+
* suite's own testPaths, which are repo-root-relative and resolved by
|
|
39
|
+
* the caller's cwd choice).
|
|
40
|
+
*/
|
|
41
|
+
export function pytestCollectArgv(suite) {
|
|
42
|
+
return [...suite.argv, '--collect-only', '-q', ...suite.testPaths];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Composes the Phase 4 diagnostic EXECUTION argv (junit XML into the
|
|
46
|
+
* EXCLUDED run-state dir). Exported now so the composition is tested;
|
|
47
|
+
* invoking it is Phase 4 work.
|
|
48
|
+
*
|
|
49
|
+
* Args:
|
|
50
|
+
* suite: the configured diagnostic suite.
|
|
51
|
+
* stateDir: absolute run-state directory (excluded from inputs).
|
|
52
|
+
*
|
|
53
|
+
* Returns:
|
|
54
|
+
* string[]: argv running the suite with a junitxml report at
|
|
55
|
+
* `<stateDir>/diagnostics/<suite.name>.xml`.
|
|
56
|
+
*/
|
|
57
|
+
export function pytestExecutionArgv(suite, stateDir) {
|
|
58
|
+
const reportPath = join(stateDir, 'diagnostics', `${suite.name}.xml`);
|
|
59
|
+
return [...suite.argv, `--junitxml=${reportPath}`, ...suite.testPaths];
|
|
60
|
+
}
|
|
61
|
+
/** Matches a `--collect-only -q` output line that is a pytest node id. */
|
|
62
|
+
function isNodeIdLine(line) {
|
|
63
|
+
return line.includes('::') && !line.startsWith('=') && !line.startsWith(' ') && !line.startsWith('\t');
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Runs one bounded collection for a configured suite. The child runs as
|
|
67
|
+
* UNTRUSTED consumer code (all `GATEFORGE_*` env stripped — same trust
|
|
68
|
+
* boundary as playwright enumeration) with the suite's finite timeout.
|
|
69
|
+
*
|
|
70
|
+
* Args:
|
|
71
|
+
* suite: the configured suite (argv, testPaths, timeoutMs).
|
|
72
|
+
* cwd: absolute repo root the repo-relative testPaths resolve against.
|
|
73
|
+
*
|
|
74
|
+
* Returns:
|
|
75
|
+
* Promise<PytestCollectionResult>: collected node ids or an
|
|
76
|
+
* unavailable verdict — collection failure is data (§3.5: show
|
|
77
|
+
* incomplete status), never a fabricated empty success.
|
|
78
|
+
*/
|
|
79
|
+
export async function collectPytestSuite(suite, cwd) {
|
|
80
|
+
const argv = pytestCollectArgv(suite);
|
|
81
|
+
const child = spawn(argv[0] ?? '', argv.slice(1), {
|
|
82
|
+
cwd,
|
|
83
|
+
env: untrustedEnv(process.env),
|
|
84
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
85
|
+
});
|
|
86
|
+
const outcome = await new Promise((settle) => {
|
|
87
|
+
let stdout = '';
|
|
88
|
+
let stderr = '';
|
|
89
|
+
let timedOut = false;
|
|
90
|
+
const timer = setTimeout(() => {
|
|
91
|
+
timedOut = true;
|
|
92
|
+
child.kill('SIGKILL');
|
|
93
|
+
}, suite.timeoutMs);
|
|
94
|
+
child.stdout?.on('data', (chunk) => {
|
|
95
|
+
stdout += chunk.toString('utf8');
|
|
96
|
+
});
|
|
97
|
+
child.stderr?.on('data', (chunk) => {
|
|
98
|
+
stderr += chunk.toString('utf8');
|
|
99
|
+
});
|
|
100
|
+
child.once('error', (error) => {
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
settle({ code: null, stdout, stderr, timedOut: false, error });
|
|
103
|
+
});
|
|
104
|
+
child.once('exit', (code) => {
|
|
105
|
+
clearTimeout(timer);
|
|
106
|
+
settle({ code, stdout, stderr, timedOut, error: null });
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
if (outcome.timedOut) {
|
|
110
|
+
return {
|
|
111
|
+
status: 'unavailable',
|
|
112
|
+
detail: `suite '${suite.name}' collection exceeded its ${String(suite.timeoutMs)}ms timeout and was killed`,
|
|
113
|
+
cases: [],
|
|
114
|
+
collectionErrors: [],
|
|
115
|
+
exitCode: null,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
if (outcome.error !== null) {
|
|
119
|
+
return {
|
|
120
|
+
status: 'unavailable',
|
|
121
|
+
detail: `suite '${suite.name}' collection failed to start (${suite.argv[0] ?? ''}): ${outcome.error.message}`,
|
|
122
|
+
cases: [],
|
|
123
|
+
collectionErrors: [],
|
|
124
|
+
exitCode: null,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const nodeIds = [...new Set(outcome.stdout
|
|
128
|
+
.split('\n')
|
|
129
|
+
.map((line) => line.trim())
|
|
130
|
+
.filter((line) => isNodeIdLine(line)))].sort();
|
|
131
|
+
const collectionErrors = outcome.code !== 0
|
|
132
|
+
? [...new Set((outcome.stderr + '\n' + outcome.stdout)
|
|
133
|
+
.split('\n')
|
|
134
|
+
.filter((line) => /ERROR|error/i.test(line))
|
|
135
|
+
.map((line) => line.trim().slice(0, 300)))].sort()
|
|
136
|
+
: [];
|
|
137
|
+
if (nodeIds.length === 0 && (outcome.code !== 0 || collectionErrors.length > 0)) {
|
|
138
|
+
const firstError = collectionErrors[0];
|
|
139
|
+
return {
|
|
140
|
+
status: 'unavailable',
|
|
141
|
+
detail: `suite '${suite.name}' collected no tests (exit ${String(outcome.code)}): ` +
|
|
142
|
+
(firstError !== undefined ? `first error: ${firstError}` : 'no structured output'),
|
|
143
|
+
cases: [],
|
|
144
|
+
collectionErrors,
|
|
145
|
+
exitCode: outcome.code,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
status: 'discovered',
|
|
150
|
+
detail: `suite '${suite.name}' collection enumerated ${String(nodeIds.length)} case(s) via configured argv`,
|
|
151
|
+
cases: nodeIds.map((nodeId) => {
|
|
152
|
+
const segments = nodeId.split('::');
|
|
153
|
+
return {
|
|
154
|
+
nodeId,
|
|
155
|
+
file: (segments[0] ?? nodeId).split('\\').join('/'),
|
|
156
|
+
titlePath: segments.slice(1),
|
|
157
|
+
};
|
|
158
|
+
}),
|
|
159
|
+
collectionErrors,
|
|
160
|
+
exitCode: outcome.code,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/** Typed parser failure for malformed junit XML (fail closed). */
|
|
164
|
+
export class JunitParseError extends Error {
|
|
165
|
+
constructor(message) {
|
|
166
|
+
super(message);
|
|
167
|
+
this.name = 'JunitParseError';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Parses one attr="value" group into a record, tolerating the
|
|
172
|
+
* whitespace separators between attributes. Anything else (unterminated
|
|
173
|
+
* or malformed attributes) throws.
|
|
174
|
+
*/
|
|
175
|
+
function parseAttributes(text, tagName) {
|
|
176
|
+
const attributes = {};
|
|
177
|
+
const pattern = /([A-Za-z_:][A-Za-z0-9_:.-]*)="([^"]*)"/g;
|
|
178
|
+
const whitespace = /\s*/gy;
|
|
179
|
+
let consumed = 0;
|
|
180
|
+
whitespace.lastIndex = consumed;
|
|
181
|
+
const spaceMatch = whitespace.exec(text);
|
|
182
|
+
if (spaceMatch !== null)
|
|
183
|
+
consumed = whitespace.lastIndex;
|
|
184
|
+
let match;
|
|
185
|
+
while ((match = pattern.exec(text)) !== null) {
|
|
186
|
+
if (match.index !== consumed) {
|
|
187
|
+
throw new JunitParseError(`malformed attribute text in <${tagName}>: '${text.slice(consumed, match.index)}'`);
|
|
188
|
+
}
|
|
189
|
+
attributes[match[1] ?? ''] = match[2] ?? '';
|
|
190
|
+
consumed = pattern.lastIndex;
|
|
191
|
+
whitespace.lastIndex = consumed;
|
|
192
|
+
const trailing = whitespace.exec(text);
|
|
193
|
+
if (trailing !== null)
|
|
194
|
+
consumed = whitespace.lastIndex;
|
|
195
|
+
}
|
|
196
|
+
if (consumed !== text.length) {
|
|
197
|
+
throw new JunitParseError(`malformed attribute text in <${tagName}>: '${text.slice(consumed)}'`);
|
|
198
|
+
}
|
|
199
|
+
return attributes;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Extracts the inner text of an element body up to the given end tag.
|
|
203
|
+
*/
|
|
204
|
+
function innerText(xml, from, endTag) {
|
|
205
|
+
const end = xml.indexOf(endTag, from);
|
|
206
|
+
if (end < 0)
|
|
207
|
+
throw new JunitParseError(`missing ${endTag}`);
|
|
208
|
+
return xml.slice(from, end);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Parses a pytest junit-XML document into structured outcomes (plan
|
|
212
|
+
* phase 2 item 8: prefer structured results over parsing terminal
|
|
213
|
+
* colors). Bounded and strict: the parser understands the exact subset
|
|
214
|
+
* pytest emits (`<testsuite>` with `<testcase>` children carrying
|
|
215
|
+
* `<failure>`, `<error>`, or `<skipped type="...">` children) and THROWS
|
|
216
|
+
* (`JunitParseError`) on anything else — a malformed report is never
|
|
217
|
+
* silently read as a green run. xfail appears as `skipped` with
|
|
218
|
+
* `type="pytest.xfail"`; collection errors appear as testcases named
|
|
219
|
+
* `pytest_collection` with an `<error>` child.
|
|
220
|
+
*
|
|
221
|
+
* Args:
|
|
222
|
+
* xml: the junit-XML document text.
|
|
223
|
+
*
|
|
224
|
+
* Returns:
|
|
225
|
+
* JunitDocument: suite counters + one row per testcase.
|
|
226
|
+
*
|
|
227
|
+
* Throws:
|
|
228
|
+
* JunitParseError: on missing/malformed structure (fail closed).
|
|
229
|
+
*/
|
|
230
|
+
export function parseJunitXml(xml) {
|
|
231
|
+
// The `<testsuite` literal must not match the `<testsuites>` wrapper
|
|
232
|
+
// pytest emits (the `(?![a-zA-Z])` boundary rejects the `s`), or every
|
|
233
|
+
// real document would fail attribute parsing and look "unparsable".
|
|
234
|
+
// Self-closing empty suite (zero tests) first — the open-tag pattern
|
|
235
|
+
// would otherwise swallow the closing slash into its attribute text.
|
|
236
|
+
const emptyMatch = /<testsuite(?![a-zA-Z])[^>]*?\/>/.exec(xml);
|
|
237
|
+
if (emptyMatch !== null) {
|
|
238
|
+
const attributes = parseAttributes((/<testsuite(?![a-zA-Z])([^>]*?)\/>/.exec(xml)?.[1]) ?? '', 'testsuite');
|
|
239
|
+
return {
|
|
240
|
+
suiteName: attributes['name'] ?? '',
|
|
241
|
+
tests: Number(attributes['tests'] ?? '0'),
|
|
242
|
+
failures: Number(attributes['failures'] ?? '0'),
|
|
243
|
+
errors: Number(attributes['errors'] ?? '0'),
|
|
244
|
+
skipped: Number(attributes['skipped'] ?? '0'),
|
|
245
|
+
cases: [],
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const suiteMatch = /<testsuite(?![a-zA-Z])([^>]*)>/.exec(xml);
|
|
249
|
+
if (suiteMatch === null) {
|
|
250
|
+
throw new JunitParseError('no <testsuite> element found');
|
|
251
|
+
}
|
|
252
|
+
const suiteAttributes = parseAttributes(suiteMatch[1] ?? '', 'testsuite');
|
|
253
|
+
const bodyStart = (suiteMatch.index ?? 0) + suiteMatch[0].length;
|
|
254
|
+
const body = innerText(xml, bodyStart, '</testsuite>');
|
|
255
|
+
const cases = [];
|
|
256
|
+
const casePattern = /<testcase([^>]*?)(\/>|>([\s\S]*?)<\/testcase>)/g;
|
|
257
|
+
let match;
|
|
258
|
+
while ((match = casePattern.exec(body)) !== null) {
|
|
259
|
+
const attributes = parseAttributes(match[1] ?? '', 'testcase');
|
|
260
|
+
const childXml = match[3];
|
|
261
|
+
let outcome = 'passed';
|
|
262
|
+
let skipType;
|
|
263
|
+
let message;
|
|
264
|
+
if (childXml !== undefined) {
|
|
265
|
+
if (/<failure/.test(childXml)) {
|
|
266
|
+
outcome = 'failed';
|
|
267
|
+
message = firstLineOf(childXml, '<failure');
|
|
268
|
+
}
|
|
269
|
+
else if (/<error/.test(childXml)) {
|
|
270
|
+
outcome = 'error';
|
|
271
|
+
message = firstLineOf(childXml, '<error');
|
|
272
|
+
}
|
|
273
|
+
else if (/<skipped/.test(childXml)) {
|
|
274
|
+
outcome = 'skipped';
|
|
275
|
+
// Lazy capture + optional slash: pytest emits self-closing
|
|
276
|
+
// `<skipped type="..." message="" />`; a greedy `[^>]*` would
|
|
277
|
+
// swallow the trailing `/' and break attribute parsing (which
|
|
278
|
+
// would mark every xfail-bearing report unparsable).
|
|
279
|
+
const skipMatch = /<skipped\b([^>]*?)\/?>/.exec(childXml);
|
|
280
|
+
const skipAttributes = skipMatch === null ? {} : parseAttributes(skipMatch[1] ?? '', 'skipped');
|
|
281
|
+
skipType = skipAttributes['type'];
|
|
282
|
+
message = skipAttributes['message'];
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
throw new JunitParseError(`unsupported <testcase> child content for '${attributes['name'] ?? ''}'`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
cases.push({
|
|
289
|
+
classname: attributes['classname'] ?? '',
|
|
290
|
+
name: attributes['name'] ?? '',
|
|
291
|
+
outcome,
|
|
292
|
+
...(skipType !== undefined ? { skipType } : {}),
|
|
293
|
+
...(message !== undefined ? { message } : {}),
|
|
294
|
+
...(attributes['file'] !== undefined && attributes['file'] !== '' ? { file: attributes['file'] } : {}),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
suiteName: suiteAttributes['name'] ?? '',
|
|
299
|
+
tests: Number(suiteAttributes['tests'] ?? String(cases.length)),
|
|
300
|
+
failures: Number(suiteAttributes['failures'] ?? '0'),
|
|
301
|
+
errors: Number(suiteAttributes['errors'] ?? '0'),
|
|
302
|
+
skipped: Number(suiteAttributes['skipped'] ?? '0'),
|
|
303
|
+
cases,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/** First-line message of a failure/error child, tag attribute first. */
|
|
307
|
+
function firstLineOf(childXml, tag) {
|
|
308
|
+
const match = new RegExp(`${tag}([^>]*)>([\\s\\S]*?)<`).exec(childXml);
|
|
309
|
+
if (match === null)
|
|
310
|
+
return undefined;
|
|
311
|
+
const attributes = parseAttributes(match[1] ?? '', tag.slice(1));
|
|
312
|
+
const text = (attributes['message'] ?? match[2] ?? '').trim();
|
|
313
|
+
return text.length === 0 ? undefined : text.split('\n')[0];
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Repo-relative form of `path` against `cwd` (absolute inputs only by
|
|
317
|
+
* contract; relative pass through normalized).
|
|
318
|
+
*/
|
|
319
|
+
export function repoRelative(cwd, path) {
|
|
320
|
+
return (isAbsolute(path) ? relative(cwd, path) : path).split('\\').join('/');
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Executes one configured diagnostic suite ONCE (plan Phase 4 item 9, §3.5):
|
|
324
|
+
* an isolated process (every `GATEFORGE_*` variable stripped), the
|
|
325
|
+
* configured argv + a junit-XML report into the EXCLUDED run-state dir,
|
|
326
|
+
* and a finite timeout. The result is advisory diagnostic data — it is
|
|
327
|
+
* never witness evidence and never satisfies an E2E obligation.
|
|
328
|
+
*
|
|
329
|
+
* Exit semantics (plan §3.5 / pytest exit codes):
|
|
330
|
+
* - `completed`: run finished, ≥1 passed, no unexpected failures;
|
|
331
|
+
* - `failures`: the run finished with test failures;
|
|
332
|
+
* - `incomplete`: collection/setup error, timeout, missing interpreter,
|
|
333
|
+
* interruption, zero tests, or a run of ONLY skipped/xfail cases —
|
|
334
|
+
* never displayed as a passing diagnostic run.
|
|
335
|
+
*
|
|
336
|
+
* Args:
|
|
337
|
+
* suite: the configured suite (argv, testPaths, timeoutMs).
|
|
338
|
+
* repoRoot: absolute repo root (suite.cwd resolves against it).
|
|
339
|
+
* stateDir: absolute run-state directory (excluded from inputs); the
|
|
340
|
+
* junit report lands at `<stateDir>/diagnostics/<suite.name>.xml`.
|
|
341
|
+
*
|
|
342
|
+
* Returns:
|
|
343
|
+
* Promise<DiagnosticRunResult>: the structured diagnostic result.
|
|
344
|
+
*/
|
|
345
|
+
export async function executePytestSuite(suite, repoRoot, stateDir) {
|
|
346
|
+
const reportPath = join(stateDir, 'diagnostics', `${suite.name}.xml`);
|
|
347
|
+
const argv = pytestExecutionArgv(suite, stateDir);
|
|
348
|
+
const base = {
|
|
349
|
+
suite: suite.name,
|
|
350
|
+
status: 'incomplete',
|
|
351
|
+
exitCode: null,
|
|
352
|
+
timedOut: false,
|
|
353
|
+
spawnError: null,
|
|
354
|
+
collectionErrors: [],
|
|
355
|
+
selectedScope: [...suite.testPaths],
|
|
356
|
+
nodeIds: [],
|
|
357
|
+
cases: [],
|
|
358
|
+
counts: { passed: 0, failed: 0, errors: 0, skipped: 0, xfailed: 0 },
|
|
359
|
+
complete: false,
|
|
360
|
+
incompleteDetail: null,
|
|
361
|
+
causes: [],
|
|
362
|
+
reportPath,
|
|
363
|
+
reportExists: existsSync(reportPath),
|
|
364
|
+
reportUnparsable: false,
|
|
365
|
+
};
|
|
366
|
+
const child = spawn(argv[0] ?? '', argv.slice(1), {
|
|
367
|
+
cwd: join(repoRoot, suite.cwd),
|
|
368
|
+
env: untrustedEnv(process.env),
|
|
369
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
370
|
+
});
|
|
371
|
+
const outcome = await new Promise((settle) => {
|
|
372
|
+
let stdout = '';
|
|
373
|
+
let stderr = '';
|
|
374
|
+
let timedOut = false;
|
|
375
|
+
const timer = setTimeout(() => {
|
|
376
|
+
timedOut = true;
|
|
377
|
+
child.kill('SIGKILL');
|
|
378
|
+
}, suite.timeoutMs);
|
|
379
|
+
child.stdout?.on('data', (chunk) => {
|
|
380
|
+
stdout += chunk.toString('utf8');
|
|
381
|
+
});
|
|
382
|
+
child.stderr?.on('data', (chunk) => {
|
|
383
|
+
stderr += chunk.toString('utf8');
|
|
384
|
+
});
|
|
385
|
+
child.once('error', (error) => {
|
|
386
|
+
clearTimeout(timer);
|
|
387
|
+
settle({ code: null, signal: null, stdout, stderr, timedOut: false, error });
|
|
388
|
+
});
|
|
389
|
+
child.once('exit', (code, signal) => {
|
|
390
|
+
clearTimeout(timer);
|
|
391
|
+
settle({ code, signal, stdout, stderr, timedOut, error: null });
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
if (outcome.timedOut) {
|
|
395
|
+
return {
|
|
396
|
+
...base,
|
|
397
|
+
timedOut: true,
|
|
398
|
+
incompleteDetail: `suite '${suite.name}' exceeded its ${String(suite.timeoutMs)}ms timeout and was killed — ` +
|
|
399
|
+
'an incomplete diagnostic run never displays as passing',
|
|
400
|
+
causes: ['DIAGNOSTIC_RUN_INCOMPLETE'],
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
if (outcome.error !== null) {
|
|
404
|
+
return {
|
|
405
|
+
...base,
|
|
406
|
+
spawnError: outcome.error.message,
|
|
407
|
+
incompleteDetail: `suite '${suite.name}' could not start (${suite.argv[0] ?? ''}): ${outcome.error.message} — ` +
|
|
408
|
+
'repair the interpreter/configured argv',
|
|
409
|
+
causes: ['DIAGNOSTIC_RUN_INCOMPLETE'],
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
const collectionErrors = [...new Set((outcome.stderr + '\n' + outcome.stdout)
|
|
413
|
+
.split('\n')
|
|
414
|
+
.filter((line) => /ERROR|error/i.test(line))
|
|
415
|
+
.map((line) => line.trim().slice(0, 300)))].sort();
|
|
416
|
+
const reportExists = existsSync(reportPath);
|
|
417
|
+
let document = null;
|
|
418
|
+
let reportUnparsable = false;
|
|
419
|
+
if (reportExists) {
|
|
420
|
+
try {
|
|
421
|
+
document = parseJunitXml(readFileSync(reportPath, 'utf8'));
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
reportUnparsable = true; // fail closed: a malformed report is never a green run
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
const cases = [];
|
|
428
|
+
const counts = { passed: 0, failed: 0, errors: 0, skipped: 0, xfailed: 0 };
|
|
429
|
+
const nodeIds = [];
|
|
430
|
+
if (document !== null) {
|
|
431
|
+
for (const testCase of document.cases) {
|
|
432
|
+
const file = caseFileOf(testCase);
|
|
433
|
+
const nodeId = `${file}::${testCase.name}`;
|
|
434
|
+
nodeIds.push(nodeId);
|
|
435
|
+
if (testCase.outcome === 'passed')
|
|
436
|
+
counts.passed += 1;
|
|
437
|
+
else if (testCase.outcome === 'failed')
|
|
438
|
+
counts.failed += 1;
|
|
439
|
+
else if (testCase.outcome === 'error')
|
|
440
|
+
counts.errors += 1;
|
|
441
|
+
else {
|
|
442
|
+
counts.skipped += 1;
|
|
443
|
+
if (testCase.skipType === 'pytest.xfail' || testCase.skipType === 'xfail')
|
|
444
|
+
counts.xfailed += 1;
|
|
445
|
+
}
|
|
446
|
+
cases.push({
|
|
447
|
+
nodeId,
|
|
448
|
+
outcome: testCase.outcome,
|
|
449
|
+
...(testCase.skipType !== undefined ? { skipType: testCase.skipType } : {}),
|
|
450
|
+
...(testCase.message !== undefined ? { message: testCase.message } : {}),
|
|
451
|
+
// pytest junit: collection errors are testcases named
|
|
452
|
+
// `pytest_collection` with an <error> child.
|
|
453
|
+
phase: testCase.name === 'pytest_collection'
|
|
454
|
+
? 'collection'
|
|
455
|
+
: testCase.outcome === 'error'
|
|
456
|
+
? 'setup'
|
|
457
|
+
: testCase.outcome === 'failed'
|
|
458
|
+
? 'call'
|
|
459
|
+
: 'unknown',
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
const incompleteDetail = diagnoseIncomplete({
|
|
464
|
+
suiteName: suite.name,
|
|
465
|
+
exitCode: outcome.code,
|
|
466
|
+
signal: outcome.signal,
|
|
467
|
+
document,
|
|
468
|
+
reportExists,
|
|
469
|
+
reportUnparsable,
|
|
470
|
+
collectionErrors,
|
|
471
|
+
});
|
|
472
|
+
const complete = incompleteDetail === null;
|
|
473
|
+
let status;
|
|
474
|
+
let causes = [];
|
|
475
|
+
if (!complete) {
|
|
476
|
+
status = 'incomplete';
|
|
477
|
+
causes = ['DIAGNOSTIC_RUN_INCOMPLETE'];
|
|
478
|
+
}
|
|
479
|
+
else if (counts.failed > 0 || counts.errors > 0) {
|
|
480
|
+
status = 'failures';
|
|
481
|
+
causes = ['DIAGNOSTIC_TEST_FAILURE'];
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
status = 'completed';
|
|
485
|
+
}
|
|
486
|
+
return {
|
|
487
|
+
...base,
|
|
488
|
+
exitCode: outcome.code,
|
|
489
|
+
collectionErrors,
|
|
490
|
+
nodeIds: [...new Set(nodeIds)].sort(),
|
|
491
|
+
cases,
|
|
492
|
+
counts,
|
|
493
|
+
complete,
|
|
494
|
+
incompleteDetail,
|
|
495
|
+
causes,
|
|
496
|
+
reportExists,
|
|
497
|
+
reportUnparsable,
|
|
498
|
+
status,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Decides whether a finished diagnostic run is INCOMPLETE (fail closed):
|
|
503
|
+
* unparsable/missing report, nonzero pytest status codes (2 interrupted,
|
|
504
|
+
* 3 internal, 4 usage), exit 5 (no tests collected), zero reported
|
|
505
|
+
* tests, or a run whose cases are ALL skipped/xfail. Returns null when
|
|
506
|
+
* the run honestly completed.
|
|
507
|
+
*/
|
|
508
|
+
function diagnoseIncomplete(input) {
|
|
509
|
+
if (input.signal !== null) {
|
|
510
|
+
return `suite '${input.suiteName}' was interrupted (${input.signal}) — an unavailable run, never a passing one`;
|
|
511
|
+
}
|
|
512
|
+
if (!input.reportExists) {
|
|
513
|
+
return `suite '${input.suiteName}' produced no junit report — the run cannot be trusted as complete`;
|
|
514
|
+
}
|
|
515
|
+
if (input.reportUnparsable || input.document === null) {
|
|
516
|
+
return `suite '${input.suiteName}' produced an unparsable junit report — fail closed (never read as a green run)`;
|
|
517
|
+
}
|
|
518
|
+
if (input.exitCode === 5) {
|
|
519
|
+
return `suite '${input.suiteName}' collected no tests (pytest exit 5) — a zero-test run is incomplete`;
|
|
520
|
+
}
|
|
521
|
+
if (input.exitCode !== null && input.exitCode >= 2 && input.exitCode !== 5) {
|
|
522
|
+
return `suite '${input.suiteName}' ended with pytest status ${String(input.exitCode)} (interrupted/internal/usage error) — incomplete`;
|
|
523
|
+
}
|
|
524
|
+
if (input.exitCode === null) {
|
|
525
|
+
return `suite '${input.suiteName}' ended without an exit status — incomplete`;
|
|
526
|
+
}
|
|
527
|
+
if (input.document.tests === 0) {
|
|
528
|
+
return `suite '${input.suiteName}' reported zero tests — a zero-test run is incomplete`;
|
|
529
|
+
}
|
|
530
|
+
if (input.document.cases.length > 0 && input.document.cases.every((testCase) => testCase.outcome === 'skipped')) {
|
|
531
|
+
return `suite '${input.suiteName}' ran only skipped/expected-failure cases — nothing executed, so the run is incomplete`;
|
|
532
|
+
}
|
|
533
|
+
if (input.collectionErrors.length > 0 && input.exitCode !== 0 && input.document.cases.length === 0) {
|
|
534
|
+
return `suite '${input.suiteName}' reported collection errors: ${input.collectionErrors[0] ?? ''}`;
|
|
535
|
+
}
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
/** Best-effort file part of a junit testcase (file attr, then classname). */
|
|
539
|
+
function caseFileOf(testCase) {
|
|
540
|
+
if (testCase.file !== undefined && testCase.file.length > 0)
|
|
541
|
+
return testCase.file;
|
|
542
|
+
if (testCase.classname.length > 0)
|
|
543
|
+
return testCase.classname.split('.').join('/');
|
|
544
|
+
return '';
|
|
545
|
+
}
|
|
546
|
+
/** Re-export so the adapter module is the single pytest surface. */
|
|
547
|
+
export { TestDiscoveryError };
|
|
548
|
+
//# sourceMappingURL=pytest-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pytest-adapter.js","sourceRoot":"","sources":["../../src/discovery/pytest-adapter.ts"],"names":[],"mappings":"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"}
|