@1aboveio/skills 1.0.8 → 1.0.10
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/.codex-plugin/plugin.json +13 -0
- package/.codex-plugin/resources.json +1827 -0
- package/README.md +22 -0
- package/package.json +9 -2
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/airflow/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/SKILL.md +1 -1
- package/skills/app-dev/android-foundation/release-check.mjs +3 -1
- package/skills/app-dev/app-debug/SKILL.md +1 -1
- package/skills/app-dev/app-debug/release-check.mjs +3 -1
- package/skills/app-dev/better-auth/SKILL.md +1 -1
- package/skills/app-dev/better-auth/release-check.mjs +3 -1
- package/skills/app-dev/data-catalog/SKILL.md +1 -1
- package/skills/app-dev/data-catalog/release-check.mjs +3 -1
- package/skills/app-dev/data-quality/SKILL.md +1 -1
- package/skills/app-dev/data-quality/release-check.mjs +3 -1
- package/skills/app-dev/ios-foundation/SKILL.md +1 -1
- package/skills/app-dev/ios-foundation/release-check.mjs +3 -1
- package/skills/app-dev/monorepo/SKILL.md +1 -1
- package/skills/app-dev/monorepo/release-check.mjs +3 -1
- package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
- package/skills/app-dev/nextjs-fullstack/release-check.mjs +3 -1
- package/skills/app-dev/prisma-setup/SKILL.md +1 -1
- package/skills/app-dev/prisma-setup/release-check.mjs +3 -1
- package/skills/app-dev/pyspark/SKILL.md +1 -1
- package/skills/app-dev/pyspark/release-check.mjs +3 -1
- package/skills/app-dev/python-backend/SKILL.md +1 -1
- package/skills/app-dev/python-backend/release-check.mjs +3 -1
- package/skills/app-dev/shadcn/SKILL.md +1 -1
- package/skills/app-dev/shadcn/release-check.mjs +3 -1
- package/skills/app-dev/zod-v4/SKILL.md +1 -1
- package/skills/app-dev/zod-v4/release-check.mjs +3 -1
- package/skills/cicd/cloud-build/SKILL.md +1 -1
- package/skills/cicd/cloud-build/release-check.mjs +3 -1
- package/skills/cicd/cloud-debug/SKILL.md +1 -1
- package/skills/cicd/cloud-debug/release-check.mjs +3 -1
- package/skills/cicd/cloud-deploy/SKILL.md +1 -1
- package/skills/cicd/cloud-deploy/release-check.mjs +3 -1
- package/skills/cicd/docker/SKILL.md +1 -1
- package/skills/cicd/docker/release-check.mjs +3 -1
- package/skills/cicd/github-actions/SKILL.md +1 -1
- package/skills/cicd/github-actions/release-check.mjs +3 -1
- package/skills/cicd/github-flow/SKILL.md +1 -1
- package/skills/cicd/github-flow/release-check.mjs +3 -1
- package/skills/cicd/google-cloud/SKILL.md +1 -1
- package/skills/cicd/google-cloud/release-check.mjs +3 -1
- package/skills/cicd/mergify/SKILL.md +1 -1
- package/skills/cicd/mergify/release-check.mjs +3 -1
- package/skills/cicd/podman/SKILL.md +1 -1
- package/skills/cicd/podman/release-check.mjs +3 -1
- package/skills/content/article-review/SKILL.md +1 -1
- package/skills/content/article-review/release-check.mjs +3 -1
- package/skills/content/article-to-image/SKILL.md +1 -1
- package/skills/content/article-to-image/release-check.mjs +3 -1
- package/skills/content/flowchart-svg/SKILL.md +1 -1
- package/skills/content/flowchart-svg/release-check.mjs +3 -1
- package/skills/content/image-gen/SKILL.md +1 -1
- package/skills/content/image-gen/release-check.mjs +3 -1
- package/skills/content/mermaid/SKILL.md +1 -1
- package/skills/content/mermaid/release-check.mjs +3 -1
- package/skills/content/wechat-article-writer/SKILL.md +1 -1
- package/skills/content/wechat-article-writer/release-check.mjs +3 -1
- package/skills/content/wechat-publisher/SKILL.md +1 -1
- package/skills/content/wechat-publisher/release-check.mjs +3 -1
- package/skills/content/wechat-search/SKILL.md +1 -1
- package/skills/content/wechat-search/release-check.mjs +3 -1
- package/skills/content/xai-search/SKILL.md +88 -13
- package/skills/content/xai-search/release-check.mjs +3 -1
- package/skills/content/xai-search/scripts/xai_search.sh +125 -149
- package/skills/core/distill-writing/SKILL.md +1 -1
- package/skills/core/distill-writing/release-check.mjs +3 -1
- package/skills/core/doc-to-md/SKILL.md +1 -1
- package/skills/core/doc-to-md/release-check.mjs +3 -1
- package/skills/core/editorial-review/SKILL.md +1 -1
- package/skills/core/editorial-review/release-check.mjs +3 -1
- package/skills/core/house-style/SKILL.md +1 -1
- package/skills/core/house-style/release-check.mjs +3 -1
- package/skills/core/plain-language/SKILL.md +1 -1
- package/skills/core/plain-language/release-check.mjs +3 -1
- package/skills/core/polish-cn/SKILL.md +1 -1
- package/skills/core/polish-cn/release-check.mjs +3 -1
- package/skills/core/reg-parser/SKILL.md +1 -1
- package/skills/core/reg-parser/release-check.mjs +3 -1
- package/skills/core/terminology/SKILL.md +1 -1
- package/skills/core/terminology/release-check.mjs +3 -1
- package/skills/core/write-doc/SKILL.md +1 -1
- package/skills/core/write-doc/release-check.mjs +3 -1
- package/skills/engineering/better-review/SKILL.md +1 -1
- package/skills/engineering/better-review/release-check.mjs +3 -1
- package/skills/engineering/contributing/SKILL.md +1 -1
- package/skills/engineering/contributing/release-check.mjs +3 -1
- package/skills/engineering/e2e-test/SKILL.md +1 -1
- package/skills/engineering/e2e-test/release-check.mjs +3 -1
- package/skills/engineering/engineering-runtime/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
- package/skills/engineering/engineering-runtime/release-check.mjs +3 -1
- package/skills/engineering/engineering-runtime/scripts/installation-resolver.mjs +191 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +51 -10
- package/skills/engineering/ensure-coverage/SKILL.md +1 -1
- package/skills/engineering/ensure-coverage/release-check.mjs +3 -1
- package/skills/engineering/golden-path/SKILL.md +1 -1
- package/skills/engineering/golden-path/release-check.mjs +3 -1
- package/skills/engineering/harness-runtime/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/release-check.mjs +3 -1
- package/skills/engineering/resolve-issues/SKILL.md +1 -1
- package/skills/engineering/resolve-issues/references/preflight.md +7 -0
- package/skills/engineering/resolve-issues/references/shared-modules.md +27 -0
- package/skills/engineering/resolve-issues/references/task-plan.md +5 -1
- package/skills/engineering/resolve-issues/release-check.mjs +3 -1
- package/skills/engineering/resolve-issues/scripts/active-installation.mjs +32 -0
- package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +3 -0
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +17 -1
- package/skills/engineering/resolve-release/SKILL.md +1 -1
- package/skills/engineering/resolve-release/release-check.mjs +3 -1
- package/skills/engineering/rush-issues/SKILL.md +1 -1
- package/skills/engineering/rush-issues/release-check.mjs +3 -1
- package/skills/engineering/rush-release/SKILL.md +1 -1
- package/skills/engineering/rush-release/release-check.mjs +3 -1
- package/skills/engineering/test-quality/SKILL.md +1 -1
- package/skills/engineering/test-quality/release-check.mjs +3 -1
- package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
- package/skills/risk-compliance/compliance-audit/release-check.mjs +3 -1
- package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
- package/skills/risk-compliance/contract-compare/release-check.mjs +3 -1
- package/skills/risk-compliance/contract-review/SKILL.md +1 -1
- package/skills/risk-compliance/contract-review/release-check.mjs +3 -1
- package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
- package/skills/risk-compliance/doc-authenticity/release-check.mjs +3 -1
- package/skills/risk-compliance/fraud-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/fraud-analysis/release-check.mjs +3 -1
- package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/payment-analysis/release-check.mjs +3 -1
- package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
- package/skills/risk-compliance/similar-domain/release-check.mjs +3 -1
- package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
- package/skills/risk-compliance/tld-detection/release-check.mjs +3 -1
- package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +0 -436
- package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +0 -36
- package/skills/app-dev/data-quality/scripts/data-quality.test.mjs +0 -12
- package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +0 -637
- package/skills/cicd/github-flow/scripts/flow.test.mjs +0 -114
- package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +0 -108
- package/skills/cicd/mergify/scripts/audit.test.mjs +0 -201
- package/skills/cicd/mergify/scripts/entrypoints.test.mjs +0 -106
- package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +0 -30
- package/skills/cicd/mergify/scripts/stack-push.test.mjs +0 -233
- package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +0 -1826
- package/skills/content/image-gen/scripts/credentials.test.mjs +0 -212
- package/skills/content/image-gen/scripts/options.test.mjs +0 -245
- package/skills/content/xai-search/tests/smoke_test.sh +0 -36
- package/skills/core/polish-cn/scripts/polish-cn.test.mjs +0 -244
- package/skills/core/reg-parser/scripts/reg-parser.test.mjs +0 -165
- package/skills/engineering/better-review/scripts/pr-context.test.mjs +0 -168
- package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +0 -587
- package/skills/engineering/better-review/scripts/scan-diff.test.mjs +0 -414
- package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +0 -96
- package/skills/engineering/contributing/scripts/persist-conventions.test.mjs +0 -118
- package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +0 -106
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +0 -117
- package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +0 -69
- package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +0 -98
- package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +0 -71
- package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +0 -59
- package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +0 -76
- package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +0 -68
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +0 -95
- package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +0 -288
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +0 -96
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +0 -96
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +0 -47
- package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +0 -86
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +0 -447
- package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +0 -552
- package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +0 -289
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +0 -119
- package/skills/engineering/golden-path/scripts/golden-path.test.mjs +0 -1457
- package/skills/engineering/harness-runtime/discover-models.test.mjs +0 -363
- package/skills/engineering/harness-runtime/harness-runtime.test.mjs +0 -967
- package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +0 -829
- package/skills/engineering/harness-runtime/model-catalog.test.mjs +0 -366
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +0 -280
- package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +0 -346
- package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +0 -88
- package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +0 -264
- package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +0 -79
- package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +0 -107
- package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +0 -14
- package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +0 -149
- package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +0 -915
- package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +0 -156
- package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +0 -448
- package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +0 -217
- package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +0 -91
- package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +0 -1060
- package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +0 -458
- package/skills/engineering/resolve-release/scripts/apply.test.mjs +0 -99
- package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +0 -100
- package/skills/engineering/resolve-release/scripts/flow.test.mjs +0 -340
- package/skills/engineering/resolve-release/scripts/green-head.test.mjs +0 -101
- package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +0 -426
- package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +0 -659
- package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +0 -317
- package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +0 -291
- package/skills/engineering/resolve-release/scripts/plan.test.mjs +0 -428
- package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +0 -591
- package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +0 -119
- package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +0 -104
- package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +0 -14
- package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +0 -12
- package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +0 -212
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +0 -14
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +0 -14
- package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +0 -134
- package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +0 -520
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
// Run the real shell lifecycle against fake external executables, never a device
|
|
2
|
-
// or container daemon. Every fixture records its own processes for test cleanup.
|
|
3
|
-
import { test } from 'node:test';
|
|
4
|
-
import assert from 'node:assert/strict';
|
|
5
|
-
import { spawn, spawnSync } from 'node:child_process';
|
|
6
|
-
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync, existsSync, rmSync } from 'node:fs';
|
|
7
|
-
import { createServer } from 'node:net';
|
|
8
|
-
import { tmpdir } from 'node:os';
|
|
9
|
-
import { dirname, join } from 'node:path';
|
|
10
|
-
import { fileURLToPath } from 'node:url';
|
|
11
|
-
import { setTimeout as delay } from 'node:timers/promises';
|
|
12
|
-
|
|
13
|
-
const SCRIPT = process.env.DEVICE_RUN_SCRIPT ?? join(dirname(fileURLToPath(import.meta.url)), 'device-run.sh');
|
|
14
|
-
|
|
15
|
-
function alive(pid) {
|
|
16
|
-
const r = spawnSync('ps', ['-o', 'stat=', '-p', String(pid)], { encoding: 'utf8' });
|
|
17
|
-
return r.status === 0 && r.stdout.trim() !== '' && !r.stdout.trim().startsWith('Z');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function until(check, message, milliseconds = 5000) {
|
|
21
|
-
const end = Date.now() + milliseconds;
|
|
22
|
-
while (!check()) {
|
|
23
|
-
assert.ok(Date.now() < end, message);
|
|
24
|
-
await delay(20);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function fakeHost(t) {
|
|
29
|
-
const root = mkdtempSync(join(tmpdir(), 'device-run-'));
|
|
30
|
-
const bin = join(root, 'bin');
|
|
31
|
-
const sdk = join(root, 'sdk');
|
|
32
|
-
mkdirSync(bin);
|
|
33
|
-
mkdirSync(join(sdk, 'emulator'), { recursive: true });
|
|
34
|
-
const log = join(root, 'calls.log');
|
|
35
|
-
writeFileSync(log, '');
|
|
36
|
-
const pids = () => existsSync(join(root, 'pids'))
|
|
37
|
-
? readFileSync(join(root, 'pids'), 'utf8').trim().split('\n').filter(Boolean).map((line) => Number(line.split(' ')[1])) : [];
|
|
38
|
-
t.after(() => {
|
|
39
|
-
for (const pid of pids()) {
|
|
40
|
-
if (alive(pid)) { try { process.kill(pid, 'SIGKILL'); } catch {} }
|
|
41
|
-
}
|
|
42
|
-
rmSync(root, { recursive: true, force: true });
|
|
43
|
-
});
|
|
44
|
-
const tool = (path, body) => {
|
|
45
|
-
writeFileSync(path, `#!/usr/bin/env bash\necho "$(basename "$0") $*" >> "$FAKE_LOG"\n${body}\n`);
|
|
46
|
-
chmodSync(path, 0o755);
|
|
47
|
-
};
|
|
48
|
-
writeFileSync(join(bin, 'worker'), `#!/usr/bin/env python3
|
|
49
|
-
import os, signal, sys, time
|
|
50
|
-
label = sys.argv[1]
|
|
51
|
-
root = os.environ['FAKE_ROOT']
|
|
52
|
-
def record(name):
|
|
53
|
-
with open(root + '/pids', 'a') as f: f.write('%s %s\\n' % (name, os.getpid()))
|
|
54
|
-
record(label)
|
|
55
|
-
if label in ('startup', 'journey', 'emulator-tree'):
|
|
56
|
-
pid = os.fork()
|
|
57
|
-
if pid == 0:
|
|
58
|
-
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
|
59
|
-
record(label + '-child')
|
|
60
|
-
open(root + '/' + label + '-child-ready', 'w').close()
|
|
61
|
-
while True: time.sleep(1)
|
|
62
|
-
while not os.path.exists(root + '/' + label + '-child-ready'): time.sleep(0.01)
|
|
63
|
-
if label == 'emulator-tree':
|
|
64
|
-
open(root + '/emulator-ready', 'w').close()
|
|
65
|
-
while not os.path.exists(root + '/release-emulator'): time.sleep(0.01)
|
|
66
|
-
sys.exit(0)
|
|
67
|
-
if os.environ.get('FAKE_EMULATOR_IGNORES_TERM') and label == 'emulator':
|
|
68
|
-
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
|
69
|
-
open(root + '/' + label + '-ready', 'w').close()
|
|
70
|
-
while True: time.sleep(1)
|
|
71
|
-
`);
|
|
72
|
-
chmodSync(join(bin, 'worker'), 0o755);
|
|
73
|
-
tool(join(sdk, 'emulator', 'emulator'), `
|
|
74
|
-
if test -n "\${FAKE_EMULATOR_TREE:-}"; then exec worker emulator-tree; fi
|
|
75
|
-
exec worker emulator`);
|
|
76
|
-
tool(join(bin, 'adb'), `
|
|
77
|
-
printf 'adb-env %s %s\\n' "\${ADB_SERVER_SOCKET:-}" "\${ANDROID_SERIAL:-}" >> "$FAKE_LOG"
|
|
78
|
-
case "$*" in
|
|
79
|
-
start-server)
|
|
80
|
-
if test -n "\${FAKE_ADB_START_HANG:-}"; then exec worker startup; fi
|
|
81
|
-
if test -n "\${FAKE_ADB_START_SIGNAL:-}"; then kill -TERM $$; fi
|
|
82
|
-
exit 0 ;;
|
|
83
|
-
*getprop*) if test -n "\${FAKE_ADB_HANG:-}"; then exec worker probe; fi; echo 1 ;;
|
|
84
|
-
esac`);
|
|
85
|
-
tool(join(bin, 'docker'), `
|
|
86
|
-
case "$1" in
|
|
87
|
-
run)
|
|
88
|
-
while test $# -gt 0; do
|
|
89
|
-
if test "$1" = --cidfile && test -z "\${FAKE_NO_CID:-}"; then echo fakecid42 > "$2"; fi
|
|
90
|
-
shift
|
|
91
|
-
done
|
|
92
|
-
if test -n "\${FAKE_DOCKER_RUN_HANG:-}"; then exec worker startup; fi
|
|
93
|
-
echo fakecid42 ;;
|
|
94
|
-
port) echo 127.0.0.1:55432 ;;
|
|
95
|
-
exec) exit 0 ;;
|
|
96
|
-
rm) if test -n "\${FAKE_RM_HANG:-}"; then exec worker remove; fi; exit 0 ;;
|
|
97
|
-
ps) if test -n "\${FAKE_CONTAINER_REMAINS:-}"; then echo fakecid42; fi; exit 0 ;;
|
|
98
|
-
esac`);
|
|
99
|
-
return { root, bin, sdk, log, pids, ports: await hostPorts() };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function listen(port) {
|
|
103
|
-
return new Promise((resolve, reject) => {
|
|
104
|
-
const server = createServer();
|
|
105
|
-
server.once('error', reject);
|
|
106
|
-
server.listen(port, '127.0.0.1', () => resolve(server));
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function freePort() {
|
|
111
|
-
const server = await listen(0);
|
|
112
|
-
const { port } = server.address();
|
|
113
|
-
await new Promise((resolve) => server.close(resolve));
|
|
114
|
-
return port;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async function freeEmulatorPort() {
|
|
118
|
-
for (let port = 5554; port <= 5584; port += 2) {
|
|
119
|
-
const held = [];
|
|
120
|
-
try {
|
|
121
|
-
held.push(await listen(port));
|
|
122
|
-
held.push(await listen(port + 1));
|
|
123
|
-
return port;
|
|
124
|
-
} catch {
|
|
125
|
-
// taken; try the next pair
|
|
126
|
-
} finally {
|
|
127
|
-
await Promise.all(held.map((server) => new Promise((resolve) => server.close(resolve))));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
throw new Error('no free emulator port pair in 5554-5584');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
async function hostPorts() {
|
|
134
|
-
return {
|
|
135
|
-
EMULATOR_PORT: String(await freeEmulatorPort()),
|
|
136
|
-
ANDROID_BACKEND_PORT: String(await freePort()),
|
|
137
|
-
ANDROID_METRO_PORT: String(await freePort()),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async function run(host, { journey = ['bash', '-c', 'exit 0'], drop, env = {}, signalAt, input = '' } = {}) {
|
|
142
|
-
drop ??= ['bash', '-c', 'echo "drop $SHARD_DB_NAME $SHARD_ADMIN_URL" >> "$FAKE_LOG"'];
|
|
143
|
-
const child = spawn('bash', [SCRIPT, '--drop', ...drop, '--', ...journey], {
|
|
144
|
-
cwd: host.root,
|
|
145
|
-
detached: true,
|
|
146
|
-
env: {
|
|
147
|
-
PATH: `${host.bin}:${process.env.PATH}`,
|
|
148
|
-
TMPDIR: host.root,
|
|
149
|
-
FAKE_LOG: host.log,
|
|
150
|
-
FAKE_ROOT: host.root,
|
|
151
|
-
ANDROID_HOME: host.sdk,
|
|
152
|
-
SETUP_AVD: 'Test_Phone',
|
|
153
|
-
...host.ports,
|
|
154
|
-
DB_NAME_PREFIX: 'app_e2e_',
|
|
155
|
-
KILL_GRACE_SECONDS: '1',
|
|
156
|
-
BOUNDED_SECONDS: '2',
|
|
157
|
-
...env,
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
child.stdin.end(input);
|
|
161
|
-
let stdout = '', stderr = '';
|
|
162
|
-
child.stdout.on('data', (chunk) => { stdout += chunk; });
|
|
163
|
-
child.stderr.on('data', (chunk) => { stderr += chunk; });
|
|
164
|
-
let expired = false;
|
|
165
|
-
const timer = setTimeout(() => {
|
|
166
|
-
expired = true;
|
|
167
|
-
try { process.kill(-child.pid, 'SIGKILL'); } catch {}
|
|
168
|
-
for (const pid of host.pids()) { try { process.kill(pid, 'SIGKILL'); } catch {} }
|
|
169
|
-
}, 12_000);
|
|
170
|
-
const closed = new Promise((resolve) => child.once('close', (status, signal) => resolve({ status, signal })));
|
|
171
|
-
try {
|
|
172
|
-
if (signalAt) {
|
|
173
|
-
await until(() => existsSync(join(host.root, signalAt)), `never reached ${signalAt}`);
|
|
174
|
-
child.kill('SIGTERM'); // Signal only the launcher, as an external caller does.
|
|
175
|
-
}
|
|
176
|
-
const result = await closed;
|
|
177
|
-
const emulatorLog = join(host.root, '.cache/logs/emulator.log');
|
|
178
|
-
return { ...result, stdout, stderr: stderr + (existsSync(emulatorLog) ? readFileSync(emulatorLog, 'utf8') : ''), expired, calls: readFileSync(host.log, 'utf8') };
|
|
179
|
-
} finally {
|
|
180
|
-
clearTimeout(timer);
|
|
181
|
-
if (child.exitCode === null && child.signalCode === null) {
|
|
182
|
-
try { process.kill(-child.pid, 'SIGKILL'); } catch {}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async function stopped(host) {
|
|
188
|
-
await until(() => host.pids().every((pid) => !alive(pid)), 'owned descendants survived cleanup', 1500);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function outcome(r, original, cleanup) {
|
|
192
|
-
assert.equal(r.expired, false, `test safety deadline fired: ${r.stderr}`);
|
|
193
|
-
assert.equal(r.status, original || cleanup, r.stderr);
|
|
194
|
-
assert.match(r.stdout, new RegExp(`original_stage_exit=${original} cleanup_exit=${cleanup}\\n$`), r.stderr);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
test('a passing journey cleans up everything it started and exits 0', async (t) => {
|
|
198
|
-
const host = await fakeHost(t);
|
|
199
|
-
const marker = join(host.root, 'journey ran.txt');
|
|
200
|
-
const r = await run(host, { journey: ['bash', '-c', 'echo "$ANDROID_EMULATOR_SERIAL $SHARD_DB_NAME" > "$1"', 'journey', marker] });
|
|
201
|
-
outcome(r, 0, 0);
|
|
202
|
-
const port = host.ports.EMULATOR_PORT;
|
|
203
|
-
assert.match(readFileSync(marker, 'utf8'), new RegExp(`^emulator-${port} app_e2e_\\d+_\\d+\\n$`));
|
|
204
|
-
assert.ok(r.calls.indexOf('adb start-server') < r.calls.indexOf(`emulator -avd Test_Phone -port ${port}`));
|
|
205
|
-
assert.match(r.calls, new RegExp(`^emulator -avd Test_Phone -port ${port} -memory 4096 `, 'm'));
|
|
206
|
-
assert.match(r.calls, /^drop app_e2e_\d+_\d+ postgresql:\/\/postgres:postgres@127\.0\.0\.1:55432\/postgres$/m);
|
|
207
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
208
|
-
await stopped(host);
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
test('a failing journey keeps its status and still cleans up', async (t) => {
|
|
212
|
-
const host = await fakeHost(t);
|
|
213
|
-
const r = await run(host, { journey: ['bash', '-c', 'exit 42'] });
|
|
214
|
-
outcome(r, 42, 0);
|
|
215
|
-
assert.match(r.calls, /^drop app_e2e_/m);
|
|
216
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
test('an emulator that ignores TERM is killed and reported as a cleanup failure', async (t) => {
|
|
220
|
-
const host = await fakeHost(t);
|
|
221
|
-
// Wait for the fake to install its handler, not an assumed startup delay.
|
|
222
|
-
const r = await run(host, { env: { FAKE_EMULATOR_IGNORES_TERM: '1' }, journey: ['bash', '-c', 'while ! test -e "$FAKE_ROOT/emulator-ready"; do sleep 0.02; done'] });
|
|
223
|
-
outcome(r, 0, 1);
|
|
224
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
225
|
-
await stopped(host);
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
test('a stalled readiness probe ends the run with 124 and no journey', async (t) => {
|
|
229
|
-
const host = await fakeHost(t);
|
|
230
|
-
const marker = join(host.root, 'journey-ran');
|
|
231
|
-
const r = await run(host, { journey: ['touch', marker], env: { FAKE_ADB_HANG: '1', BOUNDED_SECONDS: '0.5' } });
|
|
232
|
-
outcome(r, 124, 0);
|
|
233
|
-
assert.equal(existsSync(marker), false);
|
|
234
|
-
assert.doesNotMatch(r.calls, /^drop /m);
|
|
235
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
236
|
-
await stopped(host);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
test('a busy port stops the run before anything starts', async (t) => {
|
|
240
|
-
const host = await fakeHost(t);
|
|
241
|
-
const server = await listen(Number(host.ports.ANDROID_BACKEND_PORT));
|
|
242
|
-
try {
|
|
243
|
-
const r = await run(host);
|
|
244
|
-
assert.notEqual(r.status, 0);
|
|
245
|
-
assert.match(r.stdout, /cleanup_exit=0/);
|
|
246
|
-
assert.equal(r.calls, '');
|
|
247
|
-
} finally {
|
|
248
|
-
await new Promise((resolve) => server.close(resolve));
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test('an emulator port outside the range adb scans is refused', async (t) => {
|
|
253
|
-
const host = await fakeHost(t);
|
|
254
|
-
const r = await run(host, { env: { EMULATOR_PORT: '5588' } });
|
|
255
|
-
assert.equal(r.status, 2);
|
|
256
|
-
assert.match(r.stderr, /even port in 5554-5584/);
|
|
257
|
-
assert.equal(r.calls, '');
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
test('a timed out docker startup removes its recorded CID and kills descendants', async (t) => {
|
|
261
|
-
const host = await fakeHost(t);
|
|
262
|
-
const r = await run(host, { env: { FAKE_DOCKER_RUN_HANG: '1', BOUNDED_SECONDS: '0.5' } });
|
|
263
|
-
outcome(r, 124, 0);
|
|
264
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
265
|
-
assert.doesNotMatch(r.calls, /^drop /m);
|
|
266
|
-
await stopped(host);
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
for (const stage of ['startup', 'journey']) {
|
|
270
|
-
test(`SIGTERM during ${stage} stops descendants and preserves 143`, async (t) => {
|
|
271
|
-
const host = await fakeHost(t);
|
|
272
|
-
const r = await run(host, {
|
|
273
|
-
signalAt: `${stage}-ready`,
|
|
274
|
-
journey: ['worker', 'journey'],
|
|
275
|
-
env: stage === 'startup' ? { FAKE_DOCKER_RUN_HANG: '1', BOUNDED_SECONDS: '8' } : {},
|
|
276
|
-
});
|
|
277
|
-
outcome(r, 143, 0);
|
|
278
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
279
|
-
if (stage === 'journey') assert.match(r.calls, /^drop /m);
|
|
280
|
-
else assert.doesNotMatch(r.calls, /^drop /m);
|
|
281
|
-
await stopped(host);
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
test('a journey deadline kills its whole process group and still drops the database', async (t) => {
|
|
286
|
-
const host = await fakeHost(t);
|
|
287
|
-
const r = await run(host, { journey: ['worker', 'journey'], env: { JOURNEY_SECONDS: '0.5' } });
|
|
288
|
-
outcome(r, 124, 0);
|
|
289
|
-
assert.match(r.calls, /^drop /m);
|
|
290
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
291
|
-
await stopped(host);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
test('an emulator descendant is removed even after the emulator leader exits', async (t) => {
|
|
295
|
-
const host = await fakeHost(t);
|
|
296
|
-
const r = await run(host, {
|
|
297
|
-
env: { FAKE_EMULATOR_TREE: '1' },
|
|
298
|
-
journey: ['bash', '-c', 'while ! test -e "$FAKE_ROOT/emulator-ready"; do sleep 0.02; done; touch "$FAKE_ROOT/release-emulator"'],
|
|
299
|
-
});
|
|
300
|
-
assert.equal(r.expired, false);
|
|
301
|
-
await stopped(host);
|
|
302
|
-
outcome(r, 0, 1); // A descendant that requires KILL is a cleanup failure.
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
test('cleanup timeouts do not replace an original failure or skip remaining cleanup', async (t) => {
|
|
306
|
-
const host = await fakeHost(t);
|
|
307
|
-
const r = await run(host, {
|
|
308
|
-
journey: ['bash', '-c', 'exit 42'], drop: ['worker', 'drop'],
|
|
309
|
-
env: { FAKE_RM_HANG: '1', BOUNDED_SECONDS: '0.5' },
|
|
310
|
-
});
|
|
311
|
-
outcome(r, 42, 1);
|
|
312
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
313
|
-
assert.match(r.calls, /^docker ps /m);
|
|
314
|
-
await stopped(host);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
test('a command killed by a signal keeps the shell signal status', async (t) => {
|
|
318
|
-
const host = await fakeHost(t);
|
|
319
|
-
const r = await run(host, { journey: ['bash', '-c', 'kill -TERM $$'] });
|
|
320
|
-
outcome(r, 143, 0);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
test('a missing journey executable keeps shell status 127', async (t) => {
|
|
324
|
-
const host = await fakeHost(t);
|
|
325
|
-
const r = await run(host, { journey: [join(host.root, 'missing')] });
|
|
326
|
-
outcome(r, 127, 0);
|
|
327
|
-
assert.match(r.calls, /^drop /m);
|
|
328
|
-
assert.match(r.calls, /^docker rm --force fakecid42$/m);
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
test('a non-executable journey keeps shell status 126', async (t) => {
|
|
332
|
-
const host = await fakeHost(t);
|
|
333
|
-
const path = join(host.root, 'not executable');
|
|
334
|
-
writeFileSync(path, '#!/bin/sh\nexit 0\n');
|
|
335
|
-
const r = await run(host, { journey: [path] });
|
|
336
|
-
outcome(r, 126, 0);
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
test('a signal-ended startup command preserves shell status 143', async (t) => {
|
|
340
|
-
const host = await fakeHost(t);
|
|
341
|
-
const r = await run(host, { env: { FAKE_ADB_START_SIGNAL: '1' } });
|
|
342
|
-
outcome(r, 143, 0);
|
|
343
|
-
assert.doesNotMatch(r.calls, /emulator -avd|docker run/);
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
test('an unacknowledged docker startup reports uncertain cleanup without guessing an ID', async (t) => {
|
|
347
|
-
const host = await fakeHost(t);
|
|
348
|
-
const r = await run(host, { env: { FAKE_DOCKER_RUN_HANG: '1', FAKE_NO_CID: '1', BOUNDED_SECONDS: '0.5' } });
|
|
349
|
-
outcome(r, 124, 1);
|
|
350
|
-
assert.doesNotMatch(r.calls, /^docker rm |^drop /m);
|
|
351
|
-
await stopped(host);
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
test('a container still listed after removal is a cleanup failure', async (t) => {
|
|
355
|
-
const host = await fakeHost(t);
|
|
356
|
-
const r = await run(host, { env: { FAKE_CONTAINER_REMAINS: '1' } });
|
|
357
|
-
outcome(r, 0, 1);
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
test('journey stdin and literal argument boundaries are preserved', async (t) => {
|
|
361
|
-
const host = await fakeHost(t);
|
|
362
|
-
const r = await run(host, {
|
|
363
|
-
input: 'input line\n',
|
|
364
|
-
journey: ['bash', '-c', 'IFS= read -r line; printf "received <%s> <%s> <%s>\\n" "$line" "$1" "$2"', 'journey', 'a b', '--'],
|
|
365
|
-
});
|
|
366
|
-
outcome(r, 0, 0);
|
|
367
|
-
assert.match(r.stdout, /^received <input line> <a b> <-->$/m);
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
test('cleanup leaves an unrelated process running', async (t) => {
|
|
371
|
-
const host = await fakeHost(t);
|
|
372
|
-
const peer = spawn(join(host.bin, 'worker'), ['peer'], {
|
|
373
|
-
detached: true, stdio: 'ignore', env: { ...process.env, FAKE_ROOT: host.root },
|
|
374
|
-
});
|
|
375
|
-
const exited = new Promise((resolve) => peer.once('close', resolve));
|
|
376
|
-
t.after(async () => { peer.kill('SIGKILL'); await exited; });
|
|
377
|
-
await until(() => existsSync(join(host.root, 'peer-ready')), 'peer did not start');
|
|
378
|
-
const r = await run(host);
|
|
379
|
-
outcome(r, 0, 0);
|
|
380
|
-
assert.equal(alive(peer.pid), true);
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
for (const env of [
|
|
384
|
-
{ BOUNDED_SECONDS: '0' }, { BOUNDED_SECONDS: 'NaN' },
|
|
385
|
-
{ JOURNEY_SECONDS: '-1' }, { KILL_GRACE_SECONDS: 'infinity' },
|
|
386
|
-
{ BOOT_ATTEMPTS: '0' }, { DB_URL_VAR: 'bad-name' }, { DB_NAME_VAR: 'SHARD_ADMIN_URL' },
|
|
387
|
-
]) {
|
|
388
|
-
test(`invalid settings are refused before startup: ${JSON.stringify(env)}`, async (t) => {
|
|
389
|
-
const host = await fakeHost(t);
|
|
390
|
-
const r = await run(host, { env });
|
|
391
|
-
assert.equal(r.status, 2, r.stderr);
|
|
392
|
-
assert.equal(r.calls, '');
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
for (const assignment of ['active_pid=$!', 'emulator_pid=$!']) {
|
|
397
|
-
test(`TERM between spawn and recording ${assignment} retains ownership`, async (t) => {
|
|
398
|
-
const host = await fakeHost(t);
|
|
399
|
-
const hook = join(host.root, 'launch-race.bash');
|
|
400
|
-
const ready = assignment.startsWith('active') ? 'startup-ready' : 'emulator-ready';
|
|
401
|
-
writeFileSync(hook, `
|
|
402
|
-
set -T
|
|
403
|
-
trap 'if [[ "$BASH_SUBSHELL" = "0" && "$BASH_COMMAND" = "$RACE_ASSIGNMENT" && ! -e "$FAKE_ROOT/race-fired" ]]; then
|
|
404
|
-
printf "supervisor %s\\n" "$!" >> "$FAKE_ROOT/pids"
|
|
405
|
-
touch "$FAKE_ROOT/race-fired"
|
|
406
|
-
while ! test -e "$FAKE_ROOT/$RACE_READY"; do sleep 0.02; done
|
|
407
|
-
kill -TERM "$$"
|
|
408
|
-
fi' DEBUG
|
|
409
|
-
`);
|
|
410
|
-
const r = await run(host, { env: {
|
|
411
|
-
BASH_ENV: hook, RACE_ASSIGNMENT: assignment, RACE_READY: ready,
|
|
412
|
-
...(assignment.startsWith('active') ? { FAKE_ADB_START_HANG: '1', BOUNDED_SECONDS: '60' } : {}),
|
|
413
|
-
} });
|
|
414
|
-
assert.equal(existsSync(join(host.root, 'race-fired')), true, r.stderr);
|
|
415
|
-
outcome(r, 143, 0);
|
|
416
|
-
assert.doesNotMatch(r.calls, /^docker run/m);
|
|
417
|
-
await stopped(host);
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// The default commands intentionally use the original environment-variable contract.
|
|
422
|
-
test('caller-selected adb endpoint and custom database names reach both commands', async (t) => {
|
|
423
|
-
const host = await fakeHost(t);
|
|
424
|
-
const command = ['bash', '-c', 'printf "contract %s %s %s %s\\n" "$ADB_SERVER_SOCKET" "$ANDROID_EMULATOR_SERIAL" "$TEST_ADMIN_URL" "$TEST_DB" >> "$FAKE_LOG"'];
|
|
425
|
-
const r = await run(host, {
|
|
426
|
-
journey: command, drop: command,
|
|
427
|
-
env: { ADB_SERVER_SOCKET: 'tcp:127.0.0.1:15037', DB_URL_VAR: 'TEST_ADMIN_URL', DB_NAME_VAR: 'TEST_DB' },
|
|
428
|
-
});
|
|
429
|
-
outcome(r, 0, 0);
|
|
430
|
-
assert.match(r.calls, /^adb-env tcp:127\.0\.0\.1:15037 /m);
|
|
431
|
-
const lines = r.calls.split('\n').filter((line) => line.startsWith('contract '));
|
|
432
|
-
assert.equal(lines.length, 2);
|
|
433
|
-
assert.equal(lines[0], lines[1]);
|
|
434
|
-
assert.match(lines[0], new RegExp(`^contract tcp:127\\.0\\.0\\.1:15037 emulator-${host.ports.EMULATOR_PORT} postgresql://postgres:postgres@127\\.0\\.0\\.1:55432/postgres app_e2e_`));
|
|
435
|
-
assert.doesNotMatch(r.calls, /kill-server|emu kill|system prune/);
|
|
436
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
4
|
-
import { tmpdir } from 'node:os';
|
|
5
|
-
import { dirname, join } from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import test from 'node:test';
|
|
8
|
-
|
|
9
|
-
const scriptsDir = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
const conventions = readFileSync(join(scriptsDir, '../references/data-catalog-conventions.md'), 'utf8');
|
|
11
|
-
|
|
12
|
-
test('data-catalog test_data_catalog.py', () => {
|
|
13
|
-
const result = spawnSync('python3', [join(scriptsDir, 'test_data_catalog.py')], { encoding: 'utf8' });
|
|
14
|
-
assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('persist-conventions writes the Data catalog section only with --write', () => {
|
|
18
|
-
const dir = mkdtempSync(join(tmpdir(), 'data-catalog-conventions-'));
|
|
19
|
-
try {
|
|
20
|
-
const cli = join(scriptsDir, 'persist-conventions.mjs');
|
|
21
|
-
const preview = spawnSync(process.execPath, [cli, '--repo-root', dir], { encoding: 'utf8' });
|
|
22
|
-
assert.match(preview.stdout, /preview only, 3 file\(s\) would change/);
|
|
23
|
-
assert.equal(spawnSync(process.execPath, [cli, '--repo-root', dir, '--write'], { encoding: 'utf8' }).status, 0);
|
|
24
|
-
const text = readFileSync(join(dir, 'CONTRIBUTING.md'), 'utf8');
|
|
25
|
-
assert.match(text, /<!-- conventions:data-catalog:start -->[\s\S]*## Data catalog conventions[\s\S]*<!-- conventions:data-catalog:end -->/);
|
|
26
|
-
} finally {
|
|
27
|
-
rmSync(dir, { recursive: true, force: true });
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('every engine command the conventions tell people to run exists', () => {
|
|
32
|
-
const cited = [...conventions.matchAll(/data_catalog\.py (\w+)/g)].map((m) => m[1]);
|
|
33
|
-
assert.deepEqual([...new Set(cited)].sort(), ['audit', 'drift', 'generate']);
|
|
34
|
-
const help = spawnSync('python3', [join(scriptsDir, 'data_catalog.py'), '--help'], { encoding: 'utf8' }).stdout;
|
|
35
|
-
for (const command of cited) assert.match(help, new RegExp(`\\b${command}\\b`), `${command} missing from the engine`);
|
|
36
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import test from 'node:test';
|
|
6
|
-
|
|
7
|
-
const scriptsDir = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
|
|
9
|
-
test('data-quality test_data_quality.py', () => {
|
|
10
|
-
const result = spawnSync('python3', [join(scriptsDir, 'test_data_quality.py')], { encoding: 'utf8' });
|
|
11
|
-
assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
|
|
12
|
-
});
|