devcontour-harness 0.1.0-alpha.5 → 0.1.0-alpha.7
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/README.md +42 -2
- package/docs/compatibility-versions.md +56 -0
- package/docs/compatibility.md +2 -2
- package/docs/connectors.md +323 -0
- package/docs/contracts.md +33 -5
- package/docs/integrations/hindsight.md +148 -0
- package/docs/quickstart.md +1 -1
- package/docs/release-notes/0.1.0-alpha.6.md +238 -0
- package/docs/release-notes/0.1.0-alpha.7.md +71 -0
- package/docs/review-probes.md +199 -0
- package/docs/review-protocol.md +251 -0
- package/docs/toolchains.md +167 -0
- package/docs/turbo-starter.md +269 -0
- package/docs/upgrade.md +77 -24
- package/examples/README.md +1 -0
- package/examples/toolchains/README.md +32 -0
- package/examples/toolchains/go/bad/label/label.go +9 -0
- package/examples/toolchains/go/good/label/label.go +9 -0
- package/examples/toolchains/go/policy.json +79 -0
- package/examples/toolchains/go/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/go/repo/_gitignore +1 -0
- package/examples/toolchains/go/repo/go.mod +5 -0
- package/examples/toolchains/go/repo/go.sum +2 -0
- package/examples/toolchains/go/repo/label/label.go +9 -0
- package/examples/toolchains/go/repo/label/label_test.go +27 -0
- package/examples/toolchains/go/repo/label/version.go +9 -0
- package/examples/toolchains/go/task.json +25 -0
- package/examples/toolchains/mixed-go/bad/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/bad/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/good/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/good/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/policy.json +126 -0
- package/examples/toolchains/mixed-go/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/mixed-go/repo/_gitignore +6 -0
- package/examples/toolchains/mixed-go/repo/backend/go.mod +3 -0
- package/examples/toolchains/mixed-go/repo/backend/label/label.go +9 -0
- package/examples/toolchains/mixed-go/repo/backend/label/label_test.go +30 -0
- package/examples/toolchains/mixed-go/repo/contract/check.mjs +17 -0
- package/examples/toolchains/mixed-go/repo/contract/label.json +9 -0
- package/examples/toolchains/mixed-go/repo/frontend/package.json +15 -0
- package/examples/toolchains/mixed-go/repo/frontend/pnpm-lock.yaml +22 -0
- package/examples/toolchains/mixed-go/repo/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-go/repo/frontend/test/label.test.js +11 -0
- package/examples/toolchains/mixed-go/task.json +25 -0
- package/examples/toolchains/mixed-python/bad/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/bad/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/good/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/good/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/policy.json +121 -0
- package/examples/toolchains/mixed-python/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/mixed-python/repo/_gitignore +6 -0
- package/examples/toolchains/mixed-python/repo/backend/.python-version +1 -0
- package/examples/toolchains/mixed-python/repo/backend/pyproject.toml +19 -0
- package/examples/toolchains/mixed-python/repo/backend/src/fx_backend/__init__.py +6 -0
- package/examples/toolchains/mixed-python/repo/backend/tests/test_label.py +11 -0
- package/examples/toolchains/mixed-python/repo/backend/uv.lock +108 -0
- package/examples/toolchains/mixed-python/repo/contract/check.mjs +17 -0
- package/examples/toolchains/mixed-python/repo/contract/label.json +9 -0
- package/examples/toolchains/mixed-python/repo/frontend/package.json +15 -0
- package/examples/toolchains/mixed-python/repo/frontend/pnpm-lock.yaml +22 -0
- package/examples/toolchains/mixed-python/repo/frontend/src/label.js +4 -0
- package/examples/toolchains/mixed-python/repo/frontend/test/label.test.js +11 -0
- package/examples/toolchains/mixed-python/task.json +25 -0
- package/examples/toolchains/npm/bad/src/label.js +4 -0
- package/examples/toolchains/npm/good/src/label.js +4 -0
- package/examples/toolchains/npm/policy.json +82 -0
- package/examples/toolchains/npm/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/npm/repo/_gitignore +4 -0
- package/examples/toolchains/npm/repo/package-lock.json +22 -0
- package/examples/toolchains/npm/repo/package.json +13 -0
- package/examples/toolchains/npm/repo/src/label.js +4 -0
- package/examples/toolchains/npm/repo/test/label.test.js +13 -0
- package/examples/toolchains/npm/task.json +25 -0
- package/examples/toolchains/pnpm/bad/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/good/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/policy.json +85 -0
- package/examples/toolchains/pnpm/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/pnpm/repo/_gitignore +4 -0
- package/examples/toolchains/pnpm/repo/package.json +10 -0
- package/examples/toolchains/pnpm/repo/packages/checker/check.mjs +5 -0
- package/examples/toolchains/pnpm/repo/packages/checker/package.json +9 -0
- package/examples/toolchains/pnpm/repo/packages/label/package.json +14 -0
- package/examples/toolchains/pnpm/repo/packages/label/src/label.js +4 -0
- package/examples/toolchains/pnpm/repo/packages/label/test/label.test.js +13 -0
- package/examples/toolchains/pnpm/repo/pnpm-lock.yaml +29 -0
- package/examples/toolchains/pnpm/repo/pnpm-workspace.yaml +2 -0
- package/examples/toolchains/pnpm/task.json +25 -0
- package/examples/toolchains/python/bad/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/good/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/policy.json +80 -0
- package/examples/toolchains/python/repo/.python-version +1 -0
- package/examples/toolchains/python/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/python/repo/_gitignore +5 -0
- package/examples/toolchains/python/repo/pyproject.toml +19 -0
- package/examples/toolchains/python/repo/src/fx_label/__init__.py +6 -0
- package/examples/toolchains/python/repo/tests/test_label.py +13 -0
- package/examples/toolchains/python/repo/uv.lock +108 -0
- package/examples/toolchains/python/task.json +25 -0
- package/examples/toolchains/turbo/bad/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/good/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/policy.json +110 -0
- package/examples/toolchains/turbo/repo/REQUIREMENTS.md +9 -0
- package/examples/toolchains/turbo/repo/_gitignore +4 -0
- package/examples/toolchains/turbo/repo/package.json +13 -0
- package/examples/toolchains/turbo/repo/packages/checker/check.mjs +5 -0
- package/examples/toolchains/turbo/repo/packages/checker/package.json +9 -0
- package/examples/toolchains/turbo/repo/packages/label/package.json +14 -0
- package/examples/toolchains/turbo/repo/packages/label/src/label.js +4 -0
- package/examples/toolchains/turbo/repo/packages/label/test/label.test.js +13 -0
- package/examples/toolchains/turbo/repo/pnpm-lock.yaml +94 -0
- package/examples/toolchains/turbo/repo/pnpm-workspace.yaml +2 -0
- package/examples/toolchains/turbo/repo/turbo.json +7 -0
- package/examples/toolchains/turbo/task.json +25 -0
- package/examples/turbo-starter/README.md +16 -0
- package/examples/turbo-starter/changes/issued-at-consumer-only.patch +12 -0
- package/examples/turbo-starter/changes/issued-at.patch +130 -0
- package/examples/turbo-starter/cleanup.mjs +58 -0
- package/examples/turbo-starter/graph.json +32 -0
- package/examples/turbo-starter/harness/acceptance/db-isolation.test.mjs +97 -0
- package/examples/turbo-starter/harness/acceptance/env-probe.test.mjs +75 -0
- package/examples/turbo-starter/harness/acceptance/generation.test.mjs +54 -0
- package/examples/turbo-starter/harness/acceptance/issued-at.test.mjs +43 -0
- package/examples/turbo-starter/harness/acceptance/lifecycle-probe.test.mjs +47 -0
- package/examples/turbo-starter/harness/compose-bridge.mjs +593 -0
- package/examples/turbo-starter/harness/compose.acceptance.yml +23 -0
- package/examples/turbo-starter/harness/env/backend.env.template +7 -0
- package/examples/turbo-starter/harness/env/compose.env.template +6 -0
- package/examples/turbo-starter/policy.json +109 -0
- package/examples/turbo-starter/policy.lifecycle.json +114 -0
- package/examples/turbo-starter/setup.mjs +352 -0
- package/lib/agents/cli-adapter.js +10 -1
- package/lib/agents/inspect.d.ts +56 -2
- package/lib/agents/inspect.js +264 -14
- package/lib/agents/review-probe.d.ts +229 -7
- package/lib/agents/review-probe.js +830 -72
- package/lib/agents/schemas.d.ts +3 -1
- package/lib/agents/schemas.js +7 -3
- package/lib/cli.js +167 -7
- package/lib/contracts/cli.d.ts +820 -11
- package/lib/contracts/cli.js +243 -4
- package/lib/contracts/errors.d.ts +3 -1
- package/lib/contracts/errors.js +2 -0
- package/lib/contracts/events.d.ts +37 -5
- package/lib/contracts/events.js +9 -0
- package/lib/contracts/execution.d.ts +389 -15
- package/lib/contracts/execution.js +76 -4
- package/lib/contracts/failure.js +5 -0
- package/lib/contracts/index.d.ts +1 -0
- package/lib/contracts/index.js +1 -0
- package/lib/contracts/policy.d.ts +15 -0
- package/lib/contracts/policy.js +10 -0
- package/lib/contracts/ports.d.ts +50 -0
- package/lib/contracts/profiles.d.ts +14 -0
- package/lib/contracts/profiles.js +4 -0
- package/lib/contracts/published.d.ts +279 -8
- package/lib/contracts/result.d.ts +171 -0
- package/lib/contracts/result.js +39 -1
- package/lib/contracts/review.d.ts +231 -0
- package/lib/contracts/review.js +326 -2
- package/lib/contracts/toolchain.d.ts +96 -0
- package/lib/contracts/toolchain.js +89 -0
- package/lib/control/doctor.d.ts +16 -1
- package/lib/control/doctor.js +45 -3
- package/lib/control/harness.d.ts +52 -6
- package/lib/control/harness.js +28 -1
- package/lib/control/recovery.d.ts +3 -1
- package/lib/control/review.js +23 -11
- package/lib/engine/budget.d.ts +3 -3
- package/lib/engine/classify.js +1 -0
- package/lib/engine/engine.d.ts +67 -17
- package/lib/engine/prompt.d.ts +29 -1
- package/lib/engine/prompt.js +57 -0
- package/lib/engine/property-recovery.js +2 -0
- package/lib/engine/result.js +52 -0
- package/lib/engine/reuse.js +6 -1
- package/lib/engine/runner.d.ts +25 -0
- package/lib/engine/runner.js +500 -123
- package/lib/environment/lifecycle.js +6 -0
- package/lib/environment/live-calls.js +3 -2
- package/lib/environment/os-tools.d.ts +16 -0
- package/lib/environment/os-tools.js +35 -0
- package/lib/environment/process.d.ts +8 -0
- package/lib/environment/process.js +13 -6
- package/lib/integrations/connector/commands.d.ts +358 -0
- package/lib/integrations/connector/commands.js +428 -0
- package/lib/integrations/connector/config.d.ts +215 -0
- package/lib/integrations/connector/config.js +214 -0
- package/lib/integrations/connector/delivery.d.ts +107 -0
- package/lib/integrations/connector/delivery.js +591 -0
- package/lib/integrations/connector/fake.d.ts +291 -0
- package/lib/integrations/connector/fake.js +786 -0
- package/lib/integrations/connector/history.d.ts +124 -0
- package/lib/integrations/connector/history.js +497 -0
- package/lib/integrations/connector/index.d.ts +16 -0
- package/lib/integrations/connector/index.js +16 -0
- package/lib/integrations/connector/redact.d.ts +19 -0
- package/lib/integrations/connector/redact.js +91 -0
- package/lib/integrations/connector/registry.d.ts +15 -0
- package/lib/integrations/connector/registry.js +43 -0
- package/lib/integrations/connector/snapshot.d.ts +131 -0
- package/lib/integrations/connector/snapshot.js +422 -0
- package/lib/integrations/connector/source.d.ts +37 -0
- package/lib/integrations/connector/source.js +73 -0
- package/lib/integrations/connector/steps.d.ts +71 -0
- package/lib/integrations/connector/steps.js +188 -0
- package/lib/integrations/connector/store.d.ts +140 -0
- package/lib/integrations/connector/store.js +277 -0
- package/lib/integrations/connector/summary.d.ts +38 -0
- package/lib/integrations/connector/summary.js +59 -0
- package/lib/integrations/connector/testing-worker.d.ts +1 -0
- package/lib/integrations/connector/testing-worker.js +81 -0
- package/lib/integrations/connector/testing.d.ts +205 -0
- package/lib/integrations/connector/testing.js +1615 -0
- package/lib/integrations/connector/transport.d.ts +240 -0
- package/lib/integrations/connector/transport.js +28 -0
- package/lib/integrations/memory/context.d.ts +120 -0
- package/lib/integrations/memory/context.js +239 -0
- package/lib/integrations/memory/index.d.ts +8 -0
- package/lib/integrations/memory/index.js +8 -0
- package/lib/integrations/memory/provider.d.ts +79 -0
- package/lib/integrations/memory/provider.js +22 -0
- package/lib/integrations/memory/sink.d.ts +56 -0
- package/lib/integrations/memory/sink.js +116 -0
- package/lib/integrations/memory/testing.d.ts +44 -0
- package/lib/integrations/memory/testing.js +61 -0
- package/lib/integrations/relay-v1/index.d.ts +122 -0
- package/lib/integrations/relay-v1/index.js +860 -0
- package/lib/integrations/relay-v2/index.d.ts +145 -0
- package/lib/integrations/relay-v2/index.js +752 -0
- package/lib/integrations/relay-v2/process.d.ts +32 -0
- package/lib/integrations/relay-v2/process.js +112 -0
- package/lib/integrations/relay-v2/protocol.d.ts +172 -0
- package/lib/integrations/relay-v2/protocol.js +142 -0
- package/lib/profiles/resolve.d.ts +5 -1
- package/lib/profiles/resolve.js +31 -0
- package/lib/storage/document.d.ts +116 -16
- package/lib/toolchains/index.d.ts +9 -0
- package/lib/toolchains/index.js +9 -0
- package/lib/toolchains/inspect.d.ts +105 -0
- package/lib/toolchains/inspect.js +831 -0
- package/lib/toolchains/manifests.d.ts +67 -0
- package/lib/toolchains/manifests.js +238 -0
- package/lib/toolchains/probe.d.ts +28 -0
- package/lib/toolchains/probe.js +54 -0
- package/lib/toolchains/recipes.d.ts +33 -0
- package/lib/toolchains/recipes.js +51 -0
- package/lib/verification/acceptance.d.ts +16 -0
- package/lib/verification/acceptance.js +16 -0
- package/lib/verification/gates.d.ts +38 -0
- package/lib/verification/gates.js +108 -26
- package/package.json +22 -1
- package/profiles/go-gotestsum.json +21 -0
- package/profiles/npm-ci.json +22 -0
- package/profiles/pnpm-frozen.json +24 -0
- package/profiles/python-uv.json +26 -0
- package/schemas/execution-document.schema.json +345 -4
- package/schemas/execution-policy.schema.json +48 -0
- package/schemas/result-envelope.schema.json +213 -1
- package/schemas/run-event.schema.json +93 -0
- package/schemas/run-result.schema.json +207 -0
- package/schemas/stack-profile.schema.json +43 -0
- package/templates/controller-mode/AGENTS.controller.md +58 -0
- package/templates/controller-mode/README.md +44 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Gate `sdk-generation` (S02): закоммиченные OpenAPI и SDK равны выходу закреплённого генератора
|
|
2
|
+
// на закоммиченных исходниках. Генератор запускается штатной командой starter; после
|
|
3
|
+
// сравнения рабочее дерево возвращается к проверяемому коммиту, чтобы gate не менял
|
|
4
|
+
// отслеживаемые файлы (harness проверяет это отдельно).
|
|
5
|
+
// node --test --test-reporter=junit --test-reporter-destination=<report> .harness/acceptance/generation.test.mjs
|
|
6
|
+
import { after, before, test } from 'node:test';
|
|
7
|
+
import assert from 'node:assert/strict';
|
|
8
|
+
import { execFileSync, spawnSync } from 'node:child_process';
|
|
9
|
+
|
|
10
|
+
/** Выходы генерации, которые поручение вправе менять только через генератор. */
|
|
11
|
+
export const GENERATED = [
|
|
12
|
+
'apps/nest-backend/openapi',
|
|
13
|
+
'packages/client-rest-api-sdk/src/generated',
|
|
14
|
+
'packages/admin-rest-api-sdk/src/generated',
|
|
15
|
+
];
|
|
16
|
+
/** Штатная команда генерации starter; версия codegen закреплена в package.json SDK (защищён). */
|
|
17
|
+
const GENERATOR = ['pnpm', 'rest-api-sdk:generate'];
|
|
18
|
+
|
|
19
|
+
const root = process.env.FIXTURE_ROOT ?? process.cwd();
|
|
20
|
+
const git = (...args) => execFileSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
21
|
+
let generation;
|
|
22
|
+
|
|
23
|
+
before(() => {
|
|
24
|
+
// Детерминированный вход: без .env файлов starter и без сетевого update-check Prisma.
|
|
25
|
+
generation = spawnSync(GENERATOR[0], GENERATOR.slice(1), {
|
|
26
|
+
cwd: root,
|
|
27
|
+
encoding: 'utf8',
|
|
28
|
+
env: { ...process.env, DOTENV_CONFIG_PATH: '/dev/null', CHECKPOINT_DISABLE: '1' },
|
|
29
|
+
timeout: 540_000,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
after(() => {
|
|
34
|
+
// Вернуть дерево к проверяемому коммиту: только пути генерации.
|
|
35
|
+
git('checkout', '--', ...GENERATED);
|
|
36
|
+
git('clean', '-fdq', '--', ...GENERATED);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('sdk-generation: генератор завершился успешно', () => {
|
|
40
|
+
assert.equal(
|
|
41
|
+
generation.status,
|
|
42
|
+
0,
|
|
43
|
+
`${GENERATOR.join(' ')}: exit ${generation.status}\n${(generation.stderr || generation.stdout).slice(-4000)}`,
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
for (const path of GENERATED)
|
|
48
|
+
test(`sdk-generation: ${path} совпадает с выходом генератора`, () => {
|
|
49
|
+
assert.equal(generation.status, 0, 'генерация не выполнена');
|
|
50
|
+
const diff = git('diff', '--stat', '--', path).trim();
|
|
51
|
+
const untracked = git('ls-files', '--others', '--exclude-standard', '--', path).trim();
|
|
52
|
+
assert.equal(diff, '', `устаревший или изменённый вручную выход генерации:\n${diff}`);
|
|
53
|
+
assert.equal(untracked, '', `генератор создал незакоммиченные файлы:\n${untracked}`);
|
|
54
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Приёмочные проверки поручения `issued-at` (S01): контракт backend → OpenAPI → SDK → потребитель.
|
|
2
|
+
// Поставляются примером devcontour-harness и запускаются gate `acceptance`:
|
|
3
|
+
// node --test --test-reporter=junit --test-reporter-destination=<report> .harness/acceptance/issued-at.test.mjs
|
|
4
|
+
// Только встроенные модули Node: зависимостей проекта не требуется.
|
|
5
|
+
import { test } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { resolve } from 'node:path';
|
|
9
|
+
|
|
10
|
+
const root = process.env.FIXTURE_ROOT ?? process.cwd();
|
|
11
|
+
const read = (path) => readFileSync(resolve(root, path), 'utf8');
|
|
12
|
+
|
|
13
|
+
/** Тело `export interface <name> { ... }` в сгенерированном файле SDK. */
|
|
14
|
+
function interfaceBody(source, name) {
|
|
15
|
+
const start = source.indexOf(`export interface ${name} {`);
|
|
16
|
+
assert.ok(start >= 0, `в SDK нет interface ${name}`);
|
|
17
|
+
return source.slice(start, source.indexOf('\n}', start));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (const realm of ['client', 'admin']) {
|
|
21
|
+
test(`issued-at: ${realm} OpenAPI AccessTokenDto.issuedAt — обязательный date-time`, () => {
|
|
22
|
+
const doc = JSON.parse(read(`apps/nest-backend/openapi/${realm}.openapi.json`));
|
|
23
|
+
const schema = doc.components.schemas.AccessTokenDto;
|
|
24
|
+
assert.equal(schema.properties.issuedAt?.type, 'string');
|
|
25
|
+
assert.equal(schema.properties.issuedAt?.format, 'date-time');
|
|
26
|
+
assert.ok(schema.required.includes('issuedAt'), 'issuedAt должен быть required');
|
|
27
|
+
});
|
|
28
|
+
test(`issued-at: ${realm} SDK AccessTokenDto объявляет issuedAt: string`, () => {
|
|
29
|
+
const body = interfaceBody(
|
|
30
|
+
read(`packages/${realm}-rest-api-sdk/src/generated/data-contracts.ts`),
|
|
31
|
+
'AccessTokenDto',
|
|
32
|
+
);
|
|
33
|
+
assert.match(body, /\n\s+issuedAt: string;/);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
test('issued-at: потребитель web использует AccessTokenDto.issuedAt из SDK', () => {
|
|
38
|
+
const path = 'apps/next-web-app/src/infra/client-api/types/access-token-issued-at.type.ts';
|
|
39
|
+
assert.ok(existsSync(resolve(root, path)), `нет ${path}`);
|
|
40
|
+
const text = read(path);
|
|
41
|
+
assert.match(text, /from '@oim\/client-rest-api-sdk\/data-contracts'/);
|
|
42
|
+
assert.match(text, /AccessTokenDto\['issuedAt'\]/);
|
|
43
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Gate `lifecycle-probe` (S04): отмечает момент старта gate в каталоге окружения фазы
|
|
2
|
+
// и ведёт себя по файлу режима S04_GATE ({"mode":"pass"|"fail"|"block"}):
|
|
3
|
+
// pass — успех; fail — отказ проверки; block — ждать, пока процесс harness не исчезнет
|
|
4
|
+
// (сценарий прерывает его SIGKILL при активном окружении).
|
|
5
|
+
// node --test --test-reporter=junit --test-reporter-destination=.artifacts/junit/lifecycle.xml \
|
|
6
|
+
// .harness/acceptance/lifecycle-probe.test.mjs
|
|
7
|
+
import { test } from 'node:test';
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
|
|
12
|
+
const env = process.env;
|
|
13
|
+
const dir = env.HARNESS_ENVIRONMENT_DIR ?? env.DEVCONTOUR_ENVIRONMENT_DIR;
|
|
14
|
+
const mode =
|
|
15
|
+
env.S04_GATE && existsSync(env.S04_GATE)
|
|
16
|
+
? JSON.parse(readFileSync(env.S04_GATE, 'utf8')).mode
|
|
17
|
+
: 'pass';
|
|
18
|
+
|
|
19
|
+
test('S04 lifecycle-probe: gate стартует только в готовом окружении', async () => {
|
|
20
|
+
assert.ok(dir, 'нет каталога окружения фазы');
|
|
21
|
+
const receipt = JSON.parse(readFileSync(join(dir, 'bridge', 'receipt.json'), 'utf8'));
|
|
22
|
+
writeFileSync(
|
|
23
|
+
join(dir, 'gate-started.json'),
|
|
24
|
+
JSON.stringify({
|
|
25
|
+
at: new Date().toISOString(),
|
|
26
|
+
pid: process.pid,
|
|
27
|
+
bridge: receipt.status,
|
|
28
|
+
mode,
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
assert.equal(receipt.status, 'ready', 'gate до ready');
|
|
32
|
+
if (mode === 'block') {
|
|
33
|
+
// Процесс harness — владелец окружения из его receipt. Его исчезновение и есть сигнал.
|
|
34
|
+
const owner = JSON.parse(readFileSync(join(dir, 'environment.json'), 'utf8')).ownerPid;
|
|
35
|
+
const alive = () => {
|
|
36
|
+
try {
|
|
37
|
+
process.kill(owner, 0);
|
|
38
|
+
return true;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return error.code === 'EPERM';
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
while (alive()) await new Promise((r) => setTimeout(r, 200));
|
|
44
|
+
assert.fail('процесс harness прерван');
|
|
45
|
+
}
|
|
46
|
+
assert.notEqual(mode, 'fail', 'проверка намеренно провалена (S04 gate failure)');
|
|
47
|
+
});
|