@onlineapps/conn-orch-validator 3.2.3 → 3.3.1
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/CHANGELOG.md +68 -0
- package/README.md +2 -2
- package/docs/DESIGN.md +4 -4
- package/jest.config.js +2 -2
- package/package.json +1 -1
- package/src/CookbookTestRunner.js +9 -5
- package/src/ServiceReadinessValidator.js +30 -46
- package/src/helpers/README.md +1 -1
- package/src/helpers/createServiceReadinessTests.js +16 -60
- package/src/index.js +2 -2
- package/src/validators/ServiceStructureValidator.js +4 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Changelog — @onlineapps/conn-orch-validator
|
|
2
|
+
|
|
3
|
+
All notable changes to this package. Follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format.
|
|
4
|
+
|
|
5
|
+
## [3.3.1] — 2026-08-17
|
|
6
|
+
|
|
7
|
+
**Tier-1 step 5 refactor: retire HTTP `/health` probe per ADR 0005.**
|
|
8
|
+
|
|
9
|
+
Fáze F5 surfaced this in the live rollout: after service-wrapper 3.4.x removed Express init, every biz Tier-1 validation failed step 5 (`Health check failed`) because `ServiceReadinessValidator.checkHealth()` still called `fetch(url + '/health')`. There is nothing listening under ADR 0005 — biz containers have zero HTTP surface.
|
|
10
|
+
|
|
11
|
+
### BREAKING (behaviour of `validateReadiness()`)
|
|
12
|
+
|
|
13
|
+
- `checkHealth()` method removed.
|
|
14
|
+
- `service.healthEndpoint` option removed (no consumer left).
|
|
15
|
+
- `service.url` still accepted but no longer consumed (kept in results.serviceUrl for report annotation only).
|
|
16
|
+
- Weight rebalance: `operations` 60 → 80 (absorbs the retired `health` 20 pts). `cookbook` and `registry` unchanged. Total remains 100.
|
|
17
|
+
- `results.checks.health` no longer emitted.
|
|
18
|
+
|
|
19
|
+
### Helper API change (`createServiceReadinessTests`)
|
|
20
|
+
|
|
21
|
+
- No longer starts an Express `app.listen(testPort, ...)`.
|
|
22
|
+
- Removed `options.testPort` (no port to bind).
|
|
23
|
+
- Removed the `health endpoint responds correctly` test.
|
|
24
|
+
- Removed `result.checks.health?.passed` assertion.
|
|
25
|
+
- Existing biz-side test files that consume this helper (`api_biz/hello-service`, `api_biz/converter`, `api_biz/ingest` under `tests/bootstrap/`) continue to work unchanged — the helper signature stays `createServiceReadinessTests(testsDir, options)`, only the internal setup shrinks.
|
|
26
|
+
|
|
27
|
+
### Rationale
|
|
28
|
+
|
|
29
|
+
Tier-1 runs in Phase 0.2 (very early — before the wrapper opens any connectors). Under ADR 0005 there is no HTTP listener to probe *ever*, in any phase; runtime liveness is observed by Registry via the MQ heartbeat + Redis projection path (`infrastructureHealthTracker`) *after* Phase 0.10. Tier-1 has no meaningful health signal to check — the honest fix is to drop the check.
|
|
30
|
+
|
|
31
|
+
Structure + config + operations correctness (steps 1-3) plus cookbook execution (step 4) already prove service readiness; `operations` at 80 pts + optional `cookbook` and `registry` cover the remaining 20 pts.
|
|
32
|
+
|
|
33
|
+
### Tests
|
|
34
|
+
|
|
35
|
+
Full unit suite (158 tests, 11 suites) GREEN with the retired HTTP probe removed. No new tests needed — `checkHealth` had no isolated test; behaviour was exercised implicitly.
|
|
36
|
+
|
|
37
|
+
## [3.3.0] — 2026-08-17
|
|
38
|
+
|
|
39
|
+
**Env-var contract rename per env-conventions.md.** Details: `api/docs/biz/60-templates/env-conventions.md`, `api/docs/biz/40-cookbooks/test-env-vars.md`.
|
|
40
|
+
|
|
41
|
+
### BREAKING
|
|
42
|
+
|
|
43
|
+
- **`CookbookTestRunner._dispatchViaHandler`** now reads `TESTING_TENANT_ID` and `TESTING_WORKSPACE_ID` from `process.env`. Old names `OA_VALIDATION_TENANT_ID` / `OA_VALIDATION_WORKSPACE_ID` are no longer recognised.
|
|
44
|
+
- **Missing-var error message** updated: `Missing required environment variables TESTING_TENANT_ID and/or TESTING_WORKSPACE_ID` (was: `OA_VALIDATION_*`).
|
|
45
|
+
- **No backward compatibility.** Per Architecture Principle #11, the runner does NOT fall back to the old names. Deploy pipelines and container env files must ship `TESTING_*`. A biz service that starts with only `OA_VALIDATION_*` in env will fail Tier-1 validation on first cookbook execution.
|
|
46
|
+
|
|
47
|
+
### Migration
|
|
48
|
+
|
|
49
|
+
Every biz-service env-template file under `api_biz/*/config/env-templates/*.env` has been updated in the same session (Fáze B2 in the biz-services alignment). Deployment steps:
|
|
50
|
+
|
|
51
|
+
1. `npm publish @onlineapps/conn-orch-validator@3.3.0`
|
|
52
|
+
2. In each `api_biz/*/package.json`: exact `"@onlineapps/conn-orch-validator": "3.3.0"` + `npm install`
|
|
53
|
+
3. Restart containers; `init.sh` regenerates `config/env-active/*.env` from the updated templates so the new `TESTING_*` names land in the runtime env.
|
|
54
|
+
|
|
55
|
+
### Rationale
|
|
56
|
+
|
|
57
|
+
- The `OA_VALIDATION_` prefix was semantically overloaded (`OA_VALIDATION_*` sounds like it could be a general-purpose "validation" flag, not specifically a cookbook-runner probe).
|
|
58
|
+
- `TESTING_*` is the canonical instance of the `TESTING_*` category defined in `env-conventions.md` — values that legitimately run in dev + CI + production because the Tier-1 cookbook runner fires everywhere.
|
|
59
|
+
- Rename enforced by `api/scripts/lint-env-prefixes.sh` (0 violations across the workspace as of the same-day commits).
|
|
60
|
+
|
|
61
|
+
### Tests
|
|
62
|
+
|
|
63
|
+
- `CookbookTestRunner.testingPrefix.test.js` (3 tests) — GREEN. Asserts source references only the new names, missing-var errors mention `TESTING_*`.
|
|
64
|
+
- Existing `CookbookTestRunner.handlerDispatch.test.js`, `resolveHeaders.test.js`, `CookbookTestRunner.integration.test.js`, and `jest.config.js` all updated to set/reference `TESTING_*`.
|
|
65
|
+
|
|
66
|
+
## [3.2.3] — Pre-3.3.0 baseline
|
|
67
|
+
|
|
68
|
+
Last version reading `OA_VALIDATION_TENANT_ID` / `OA_VALIDATION_WORKSPACE_ID`. Documented in `api/docs/biz/40-cookbooks/test-env-vars.md` Status section as historical.
|
package/README.md
CHANGED
|
@@ -124,13 +124,13 @@ ServiceStructureValidator.getStandardLevels();
|
|
|
124
124
|
// [{ level: 'v1.0', name: 'Base Service Standard', since: '2025-06-01' }, ...]
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
**Related:** [Service
|
|
127
|
+
**Related:** [Biz Service Canonical Shape — Implementation Standard Levels](/docs/biz/00-model/service-shape.md#implementation-standard-levels), [Error Handling Standard](/docs/standards/ERROR_HANDLING.md#business-service-error-standard)
|
|
128
128
|
|
|
129
129
|
## Related Documentation
|
|
130
130
|
|
|
131
131
|
- [SERVICE_REGISTRATION_FLOW.md](/services/hello-service/docs/SERVICE_REGISTRATION_FLOW.md)
|
|
132
132
|
- [/docs/architecture/validator.md](/docs/architecture/validator.md)
|
|
133
|
-
- [/docs/
|
|
133
|
+
- [/docs/biz/30-operations/schema-v3.md](/docs/biz/30-operations/schema-v3.md)
|
|
134
134
|
- [/docs/standards/ERROR_HANDLING.md](/docs/standards/ERROR_HANDLING.md)
|
|
135
135
|
- [@onlineapps/service-validator-core](/shared/service-validator-core/README.md)
|
|
136
136
|
|
package/docs/DESIGN.md
CHANGED
|
@@ -13,7 +13,7 @@ Validation framework for OA Drive microservices. Drives two flows:
|
|
|
13
13
|
of individual biz services.
|
|
14
14
|
|
|
15
15
|
The single source of truth for service endpoint metadata is
|
|
16
|
-
[`operations.json`](../../../docs/
|
|
16
|
+
[`operations.json`](../../../docs/biz/30-operations/registration-wire.md).
|
|
17
17
|
OpenAPI iteration (`paths`/`operationId`) is NOT supported — that legacy
|
|
18
18
|
surface was removed together with the now-retired `ServiceValidator` /
|
|
19
19
|
`TestOrchestrator` / `ServiceTestHarness` classes.
|
|
@@ -56,7 +56,7 @@ surface was removed together with the now-retired `ServiceValidator` /
|
|
|
56
56
|
wrapper startup. Proof is cached under `conn-runtime/validation-proof.json`
|
|
57
57
|
(30-day validity, invalidated by config fingerprint change — includes
|
|
58
58
|
operations map, see
|
|
59
|
-
[operations-registry-contract.md §3](../../../docs/
|
|
59
|
+
[operations-registry-contract.md §3](../../../docs/biz/30-operations/registration-wire.md)).
|
|
60
60
|
- Biz-service templates import `createPreValidationTests` /
|
|
61
61
|
`createServiceReadinessTests` from this package for their own test suites.
|
|
62
62
|
|
|
@@ -75,6 +75,6 @@ surface was removed together with the now-retired `ServiceValidator` /
|
|
|
75
75
|
|
|
76
76
|
## Related Documentation
|
|
77
77
|
|
|
78
|
-
- [operations-registry-contract.md](../../../docs/
|
|
79
|
-
- [
|
|
78
|
+
- [operations-registry-contract.md](../../../docs/biz/30-operations/registration-wire.md) — operations.json schema
|
|
79
|
+
- [test-runner-flow.md](../../../docs/biz/40-cookbooks/test-runner-flow.md) — required `example`/`default` fields for probes + full dispatch mechanics
|
|
80
80
|
- [validator.md](../../../docs/architecture/validator.md) — architecture overview
|
package/jest.config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
process.env.
|
|
4
|
-
process.env.
|
|
3
|
+
process.env.TESTING_TENANT_ID = process.env.TESTING_TENANT_ID || '99';
|
|
4
|
+
process.env.TESTING_WORKSPACE_ID = process.env.TESTING_WORKSPACE_ID || '200';
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
testEnvironment: 'node',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-orch-validator",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "Validation orchestrator for OA Drive microservices - coordinates validation across all layers (base, infra, orch, business)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -21,7 +21,7 @@ const { resolveHeaders } = require('./utils/resolveHeaders');
|
|
|
21
21
|
* matching the shape ServiceWrapper.ContextBuilder produces in production
|
|
22
22
|
* (see api/docs/architecture/biz-service-invocation-model.md §5). Handlers
|
|
23
23
|
* that need DB access import sequelize directly from their own
|
|
24
|
-
* src/config/database.js module (see
|
|
24
|
+
* src/config/database.js module (see biz/60-templates/onboarding-checklist.md §9a);
|
|
25
25
|
* connector slots stay null and the handler surfaces its own failure if
|
|
26
26
|
* something it genuinely needs is missing.
|
|
27
27
|
*
|
|
@@ -185,10 +185,14 @@ class CookbookTestRunner {
|
|
|
185
185
|
// { modulePath, exportName } (v3 handler dispatch is the only mode).
|
|
186
186
|
const spec = await this.resolveOperation(step.service, step.operation);
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
|
|
188
|
+
// Env-var contract (docs/biz/40-cookbooks/test-env-vars.md +
|
|
189
|
+
// docs/biz/60-templates/env-conventions.md): TESTING_* prefix marks
|
|
190
|
+
// values that legitimately ship to production because Tier-1 cookbook
|
|
191
|
+
// runner fires at every service startup, including in prod.
|
|
192
|
+
const rawTenantId = process.env.TESTING_TENANT_ID;
|
|
193
|
+
const rawWorkspaceId = process.env.TESTING_WORKSPACE_ID;
|
|
190
194
|
if (!rawTenantId || !rawWorkspaceId) {
|
|
191
|
-
throw new Error('[CookbookTestRunner] Missing required environment variables
|
|
195
|
+
throw new Error('[CookbookTestRunner] Missing required environment variables TESTING_TENANT_ID and/or TESTING_WORKSPACE_ID');
|
|
192
196
|
}
|
|
193
197
|
// Coerce numeric env vars to integers so ctx matches production
|
|
194
198
|
// ContextBuilder (which receives already-typed values from the MQ envelope).
|
|
@@ -225,7 +229,7 @@ class CookbookTestRunner {
|
|
|
225
229
|
* handler(input, ctx). Mirrors the production ContextBuilder shape
|
|
226
230
|
* (see api/docs/architecture/biz-service-invocation-model.md §5) with
|
|
227
231
|
* all connector slots set to null — handlers that need DB access use
|
|
228
|
-
* direct sequelize import per
|
|
232
|
+
* direct sequelize import per biz/60-templates/onboarding-checklist.md §9a.
|
|
229
233
|
*/
|
|
230
234
|
async _dispatchViaHandler({ step, spec, testConfig, validationTenantId, validationWorkspaceId, result, startTime }) {
|
|
231
235
|
const stepTimeout = testConfig.timeout || this.timeout;
|
|
@@ -11,8 +11,19 @@ const CookbookTestUtils = require('./CookbookTestUtils');
|
|
|
11
11
|
* per-operation endpoints. The HTTP loopback check was removed when v3
|
|
12
12
|
* adopted in-process handler invocation.
|
|
13
13
|
*
|
|
14
|
+
* ADR 0005 (2026-08-17): biz containers have zero HTTP surface. The
|
|
15
|
+
* runtime `health` check (previously `fetch(url + '/health')`) is
|
|
16
|
+
* retired because there is nothing listening. Runtime health is
|
|
17
|
+
* observed by Registry via the MQ heartbeat + Redis projection path
|
|
18
|
+
* (see api_services_registry/src/services/infrastructureHealthTracker)
|
|
19
|
+
* — outside Tier-1's scope, and later in the boot sequence anyway
|
|
20
|
+
* (Tier-1 runs in Phase 0.2, heartbeat in Phase 0.10). The 20 points
|
|
21
|
+
* previously spent on `health` fold into `operations` so total stays
|
|
22
|
+
* at 100.
|
|
23
|
+
*
|
|
14
24
|
* @see /api/docs/architecture/biz-service-invocation-model.md §5.3
|
|
15
|
-
* @see /api/docs/
|
|
25
|
+
* @see /api/docs/biz/40-cookbooks/test-runner-flow.md (input probe contract)
|
|
26
|
+
* @see /api/docs/biz/80-decisions/0005-no-http-in-biz-containers.md
|
|
16
27
|
*/
|
|
17
28
|
class ServiceReadinessValidator {
|
|
18
29
|
constructor(options = {}) {
|
|
@@ -24,14 +35,16 @@ class ServiceReadinessValidator {
|
|
|
24
35
|
// Readiness checks: core (80 points) + optional (20 points) = 100 points max
|
|
25
36
|
// Core checks ALWAYS run, optional checks run if testCookbook/registry provided
|
|
26
37
|
// See: /shared/connector/conn-orch-validator/README.md for usage pattern
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
38
|
+
//
|
|
39
|
+
// Weight allocation post-ADR-0005:
|
|
40
|
+
// operations: 80 — was 60; absorbed the 20 pts from retired `health`.
|
|
41
|
+
// cookbook: 15 — unchanged (optional).
|
|
42
|
+
// registry: 5 — unchanged (optional).
|
|
43
|
+
// The retired `health` HTTP probe is documented in the class JSDoc above.
|
|
30
44
|
this.checks = {
|
|
31
|
-
operations: { weight:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
registry: { weight: 5, required: false } // OPTIONAL - registry compatible (MockRegistry)
|
|
45
|
+
operations: { weight: 80, required: true }, // operations.json v3 structure valid
|
|
46
|
+
cookbook: { weight: 15, required: false }, // OPTIONAL - cookbook valid (with mocks)
|
|
47
|
+
registry: { weight: 5, required: false } // OPTIONAL - registry compatible (MockRegistry)
|
|
35
48
|
};
|
|
36
49
|
}
|
|
37
50
|
|
|
@@ -45,8 +58,7 @@ class ServiceReadinessValidator {
|
|
|
45
58
|
url,
|
|
46
59
|
operations,
|
|
47
60
|
registry,
|
|
48
|
-
testCookbook
|
|
49
|
-
healthEndpoint = '/health'
|
|
61
|
+
testCookbook
|
|
50
62
|
} = service;
|
|
51
63
|
|
|
52
64
|
const results = {
|
|
@@ -77,13 +89,12 @@ class ServiceReadinessValidator {
|
|
|
77
89
|
// 2. (v3) Per-op HTTP endpoint probing retired — operations are dispatched
|
|
78
90
|
// in-process via the handler registry. No network call per operation.
|
|
79
91
|
|
|
80
|
-
// 3.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
92
|
+
// 3. (ADR 0005) Runtime health check retired — biz containers have no HTTP
|
|
93
|
+
// surface. Runtime liveness flows via MQ heartbeat to Registry's
|
|
94
|
+
// infrastructureHealthTracker; consumed by BusinessReadinessChecker
|
|
95
|
+
// (post Fáze A2.3). Tier-1 cannot observe that state because it runs
|
|
96
|
+
// in Phase 0.2, before the heartbeat publisher starts in Phase 0.10.
|
|
97
|
+
// The 20-point weight moved to `operations` above.
|
|
87
98
|
|
|
88
99
|
// 4. Test cookbook execution (if provided)
|
|
89
100
|
if (testCookbook) {
|
|
@@ -196,35 +207,8 @@ class ServiceReadinessValidator {
|
|
|
196
207
|
}
|
|
197
208
|
}
|
|
198
209
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
*/
|
|
202
|
-
async checkHealth(healthUrl) {
|
|
203
|
-
try {
|
|
204
|
-
const response = await fetch(healthUrl, {
|
|
205
|
-
method: 'GET',
|
|
206
|
-
signal: AbortSignal.timeout(5000)
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
let data = null;
|
|
210
|
-
try {
|
|
211
|
-
data = await response.json();
|
|
212
|
-
} catch (_) {
|
|
213
|
-
// health endpoint may return non-JSON; keep data null and rely on status.
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return {
|
|
217
|
-
passed: response.status === 200,
|
|
218
|
-
status: response.status,
|
|
219
|
-
data
|
|
220
|
-
};
|
|
221
|
-
} catch (error) {
|
|
222
|
-
return {
|
|
223
|
-
passed: false,
|
|
224
|
-
error: error.message
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
}
|
|
210
|
+
// checkHealth() removed 2026-08-17 per ADR 0005 (no HTTP surface in
|
|
211
|
+
// biz containers). See class JSDoc header for full rationale.
|
|
228
212
|
|
|
229
213
|
/**
|
|
230
214
|
* Check cookbook structure validity
|
package/src/helpers/README.md
CHANGED
|
@@ -146,7 +146,7 @@ If validation fails, clear error messages are shown:
|
|
|
146
146
|
✗ Service configuration missing: conn-config/config.json
|
|
147
147
|
Type: MISSING_CONFIG
|
|
148
148
|
File: conn-config/config.json
|
|
149
|
-
Fix: Create config.json with service metadata. See: /docs/
|
|
149
|
+
Fix: Create config.json with service metadata. See: /docs/biz/60-templates/service-template.md
|
|
150
150
|
|
|
151
151
|
⚠️ WARNINGS (1):
|
|
152
152
|
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Create Service Readiness Integration Tests
|
|
3
3
|
*
|
|
4
|
-
* Generic test suite that validates service
|
|
5
|
-
* Works for ALL business services
|
|
4
|
+
* Generic test suite that validates service configuration + operations
|
|
5
|
+
* are ready for production. Works for ALL business services — no
|
|
6
|
+
* service-specific code needed.
|
|
7
|
+
*
|
|
8
|
+
* ADR 0005 (2026-08-17): biz containers have zero HTTP surface. This
|
|
9
|
+
* helper NO LONGER starts an Express app, NO LONGER binds a test port,
|
|
10
|
+
* NO LONGER fetches `/health`. What it verifies:
|
|
11
|
+
* - Service structure valid (via ServiceStructureValidator)
|
|
12
|
+
* - operations.json valid v3 shape (handler, bundle_scope, input, output)
|
|
13
|
+
* - Optional: cookbook validation + registry compatibility
|
|
6
14
|
*
|
|
7
15
|
* @module helpers/createServiceReadinessTests
|
|
8
16
|
*
|
|
9
17
|
* Usage:
|
|
10
18
|
* const { createServiceReadinessTests } = require('@onlineapps/conn-orch-validator');
|
|
11
|
-
* createServiceReadinessTests(__dirname); // Pass tests/
|
|
19
|
+
* createServiceReadinessTests(__dirname); // Pass tests/bootstrap directory
|
|
12
20
|
*
|
|
13
21
|
* Related:
|
|
14
|
-
* - /docs/
|
|
15
|
-
* - /
|
|
22
|
+
* - /docs/biz/80-decisions/0005-no-http-in-biz-containers.md
|
|
23
|
+
* - /docs/biz/00-model/service-shape.md (zero-HTTP canonical shape)
|
|
16
24
|
* - /shared/connector/conn-orch-validator/README.md - Package documentation
|
|
17
25
|
*/
|
|
18
26
|
|
|
@@ -27,24 +35,22 @@ const { ServiceStructureValidator } = require('../validators/ServiceStructureVal
|
|
|
27
35
|
/**
|
|
28
36
|
* Create service readiness integration test suite
|
|
29
37
|
*
|
|
30
|
-
* @param {string} testsDir - Path to tests/
|
|
38
|
+
* @param {string} testsDir - Path to tests/bootstrap directory (use __dirname)
|
|
31
39
|
* @param {Object} [options] - Optional configuration
|
|
32
|
-
* @param {number} [options.testPort=5556] - Port for test server
|
|
33
40
|
* @param {boolean} [options.includeOptionalChecks=true] - Include cookbook & registry checks
|
|
34
41
|
* @param {number} [options.timeout=15000] - Test timeout in ms
|
|
35
42
|
*
|
|
36
43
|
* @example
|
|
37
|
-
* // In services/my-service/tests/
|
|
44
|
+
* // In services/my-service/tests/bootstrap/service-readiness.test.js
|
|
38
45
|
* const { createServiceReadinessTests } = require('@onlineapps/conn-orch-validator');
|
|
39
46
|
*
|
|
40
47
|
* createServiceReadinessTests(__dirname);
|
|
41
48
|
*/
|
|
42
49
|
function createServiceReadinessTests(testsDir, options = {}) {
|
|
43
|
-
// Calculate service root (2 levels up from tests/
|
|
50
|
+
// Calculate service root (2 levels up from tests/bootstrap/)
|
|
44
51
|
const serviceRoot = path.resolve(testsDir, '../..');
|
|
45
52
|
|
|
46
53
|
const {
|
|
47
|
-
testPort = 5556,
|
|
48
54
|
includeOptionalChecks = true,
|
|
49
55
|
timeout = 15000
|
|
50
56
|
} = options;
|
|
@@ -72,58 +78,24 @@ function createServiceReadinessTests(testsDir, options = {}) {
|
|
|
72
78
|
};
|
|
73
79
|
const configPath = resolveConfig('config.json');
|
|
74
80
|
const operationsPath = resolveConfig('operations.json');
|
|
75
|
-
const appPath = path.join(serviceRoot, 'src/app.js');
|
|
76
81
|
|
|
77
82
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
78
83
|
const operations = JSON.parse(fs.readFileSync(operationsPath, 'utf-8'));
|
|
79
|
-
const app = require(appPath);
|
|
80
84
|
|
|
81
85
|
// Extract metadata from config
|
|
82
86
|
const serviceName = config.service.name;
|
|
83
87
|
const serviceVersion = config.service.version;
|
|
84
|
-
const healthEndpoint = config.wrapper?.health?.endpoint || '/health';
|
|
85
88
|
|
|
86
|
-
// Create test suite
|
|
87
89
|
describe(`${serviceName} Service Readiness @integration`, () => {
|
|
88
|
-
let server;
|
|
89
|
-
let baseUrl;
|
|
90
|
-
|
|
91
|
-
beforeAll(async () => {
|
|
92
|
-
// Start service for testing
|
|
93
|
-
server = await new Promise((resolve) => {
|
|
94
|
-
const srv = app.listen(testPort, () => {
|
|
95
|
-
baseUrl = `http://127.0.0.1:${testPort}`;
|
|
96
|
-
console.log(`\n✓ Test server started: ${baseUrl}\n`);
|
|
97
|
-
resolve(srv);
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
afterAll(async () => {
|
|
103
|
-
// Stop service
|
|
104
|
-
if (server) {
|
|
105
|
-
await new Promise((resolve) => {
|
|
106
|
-
server.close(() => {
|
|
107
|
-
console.log('\n✓ Test server stopped\n');
|
|
108
|
-
resolve();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
|
|
114
90
|
test('service passes readiness validation', async () => {
|
|
115
91
|
// Validator expects flat operations object
|
|
116
92
|
const operationsFlat = operations.operations || operations;
|
|
117
93
|
|
|
118
|
-
// Prepare optional checks
|
|
119
94
|
let mockRegistry = null;
|
|
120
95
|
let testCookbook = null;
|
|
121
96
|
|
|
122
97
|
if (includeOptionalChecks) {
|
|
123
|
-
// Create MockRegistry for registry compatibility check (+5 points)
|
|
124
98
|
mockRegistry = new MockRegistry();
|
|
125
|
-
|
|
126
|
-
// Auto-generate test cookbook from operations (+15 points)
|
|
127
99
|
testCookbook = {
|
|
128
100
|
version: '1.0.0',
|
|
129
101
|
steps: Object.entries(operationsFlat).map(([name, op]) => ({
|
|
@@ -137,19 +109,15 @@ function createServiceReadinessTests(testsDir, options = {}) {
|
|
|
137
109
|
};
|
|
138
110
|
}
|
|
139
111
|
|
|
140
|
-
// Run readiness validation
|
|
141
112
|
const validator = new ServiceReadinessValidator({ logger: console });
|
|
142
113
|
const result = await validator.validateReadiness({
|
|
143
114
|
name: serviceName,
|
|
144
115
|
version: serviceVersion,
|
|
145
|
-
url: baseUrl,
|
|
146
116
|
operations: operationsFlat,
|
|
147
|
-
healthEndpoint: healthEndpoint,
|
|
148
117
|
testCookbook: testCookbook,
|
|
149
118
|
registry: mockRegistry
|
|
150
119
|
});
|
|
151
120
|
|
|
152
|
-
// Log detailed results
|
|
153
121
|
console.log('\n📊 Readiness Validation Results:');
|
|
154
122
|
console.log(` Score: ${result.score}/100`);
|
|
155
123
|
console.log(` Ready: ${result.ready ? '✅' : '❌'}`);
|
|
@@ -167,7 +135,6 @@ function createServiceReadinessTests(testsDir, options = {}) {
|
|
|
167
135
|
}
|
|
168
136
|
console.log('');
|
|
169
137
|
|
|
170
|
-
// Assertions
|
|
171
138
|
expect(result).toHaveProperty('ready');
|
|
172
139
|
expect(result).toHaveProperty('score');
|
|
173
140
|
expect(result).toHaveProperty('checks');
|
|
@@ -177,26 +144,15 @@ function createServiceReadinessTests(testsDir, options = {}) {
|
|
|
177
144
|
|
|
178
145
|
if (includeOptionalChecks) {
|
|
179
146
|
expect(result.score).toBe(100);
|
|
180
|
-
expect(result.checks.health?.passed).toBe(true);
|
|
181
147
|
expect(result.checks.operations?.passed).toBe(true);
|
|
182
148
|
expect(result.checks.cookbook?.passed).toBe(true);
|
|
183
149
|
expect(result.checks.registry?.passed).toBe(true);
|
|
184
150
|
} else {
|
|
185
151
|
expect(result.score).toBeGreaterThanOrEqual(80);
|
|
186
|
-
expect(result.checks.health?.passed).toBe(true);
|
|
187
152
|
expect(result.checks.operations?.passed).toBe(true);
|
|
188
153
|
}
|
|
189
154
|
}, timeout);
|
|
190
155
|
|
|
191
|
-
test('health endpoint responds correctly', async () => {
|
|
192
|
-
const response = await fetch(`${baseUrl}${healthEndpoint}`);
|
|
193
|
-
const data = await response.json();
|
|
194
|
-
|
|
195
|
-
expect(response.status).toBe(200);
|
|
196
|
-
expect(data).toHaveProperty('status');
|
|
197
|
-
expect(data.status).toBe('healthy');
|
|
198
|
-
});
|
|
199
|
-
|
|
200
156
|
test('service has valid operations specification (v3)', () => {
|
|
201
157
|
expect(operations).toBeDefined();
|
|
202
158
|
expect(operations.operations || operations).toBeDefined();
|
package/src/index.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* Production entry point: {@link ValidationOrchestrator} (6-step pre-validation
|
|
8
8
|
* driven by operations.json — OpenAPI path iteration is NOT supported).
|
|
9
9
|
*
|
|
10
|
-
* @see /api/docs/
|
|
11
|
-
* @see /api/docs/
|
|
10
|
+
* @see /api/docs/biz/30-operations/registration-wire.md §3 (operations.json)
|
|
11
|
+
* @see /api/docs/biz/40-cookbooks/test-runner-flow.md (validation probes)
|
|
12
12
|
* @see /api/docs/architecture/validator.md (validator architecture)
|
|
13
13
|
*/
|
|
14
14
|
|
|
@@ -223,7 +223,7 @@ class ServiceStructureValidator {
|
|
|
223
223
|
level: nextLevel.level,
|
|
224
224
|
check: check.id,
|
|
225
225
|
message: `Standard ${nextLevel.level} (${nextLevel.name}): missing ${check.message}`,
|
|
226
|
-
fix: `Implement ${check.message} to reach standard ${nextLevel.level}. See docs/
|
|
226
|
+
fix: `Implement ${check.message} to reach standard ${nextLevel.level}. See docs/biz/60-templates/service-template.md`
|
|
227
227
|
});
|
|
228
228
|
}
|
|
229
229
|
}
|
|
@@ -305,7 +305,7 @@ class ServiceStructureValidator {
|
|
|
305
305
|
type: 'MISSING_CONFIG',
|
|
306
306
|
path: 'config/service/config.json (or conn-config/config.json)',
|
|
307
307
|
message: 'Service configuration missing: config/service/config.json (or conn-config/config.json)',
|
|
308
|
-
fix: 'Create config.json with service metadata. See: /docs/
|
|
308
|
+
fix: 'Create config.json with service metadata. See: /docs/biz/60-templates/service-template.md'
|
|
309
309
|
});
|
|
310
310
|
} else {
|
|
311
311
|
try {
|
|
@@ -328,7 +328,7 @@ class ServiceStructureValidator {
|
|
|
328
328
|
type: 'MISSING_OPERATIONS',
|
|
329
329
|
path: 'config/service/operations.json (or conn-config/operations.json)',
|
|
330
330
|
message: 'Operations specification missing: config/service/operations.json (or conn-config/operations.json)',
|
|
331
|
-
fix: 'Create operations.json. See: /docs/
|
|
331
|
+
fix: 'Create operations.json. See: /docs/biz/30-operations/schema-v3.md'
|
|
332
332
|
});
|
|
333
333
|
} else {
|
|
334
334
|
try {
|
|
@@ -603,7 +603,7 @@ class ServiceStructureValidator {
|
|
|
603
603
|
type: 'MISSING_APP',
|
|
604
604
|
path: 'src/app.js',
|
|
605
605
|
message: 'Express application missing: src/app.js',
|
|
606
|
-
fix: 'Create src/app.js with Express app. See: /docs/
|
|
606
|
+
fix: 'Create src/app.js with Express app. See: /docs/biz/60-templates/service-template.md'
|
|
607
607
|
});
|
|
608
608
|
} else {
|
|
609
609
|
this.info.push('✓ Found src/app.js');
|