@onlineapps/conn-orch-validator 2.0.32 → 2.0.34

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/docs/DESIGN.md CHANGED
@@ -1,134 +1,80 @@
1
- # Connector-Testing Design Document
1
+ # conn-orch-validator Design
2
2
 
3
3
  ## Purpose
4
4
 
5
- The conn-orch-validator package provides a unified testing and validation framework for OA Drive microservices. It serves three critical functions:
5
+ Validation framework for OA Drive microservices. Drives two flows:
6
6
 
7
- 1. **Development Testing** - Mock infrastructure for isolated service testing
8
- 2. **Production Validation** - On-the-fly validation of new services during registration
9
- 3. **Service Readiness** - Complete verification before deployment
7
+ 1. **Pre-validation** (Tier 1) runs during `service-wrapper` startup. Verifies
8
+ structure (config files, package.json), readiness (endpoints respond, health
9
+ works) and produces a signed `validation-proof.json` stored under
10
+ `conn-runtime/`.
11
+ 2. **Readiness checks** — reusable probes (`createServiceReadinessTests`,
12
+ `createPreValidationTests`) consumable from unit/component test suites
13
+ of individual biz services.
10
14
 
11
- ## Key Principles
15
+ The single source of truth for service endpoint metadata is
16
+ [`operations.json`](../../../docs/standards/operations-registry-contract.md).
17
+ OpenAPI iteration (`paths`/`operationId`) is NOT supported — that legacy
18
+ surface was removed together with the now-retired `ServiceValidator` /
19
+ `TestOrchestrator` / `ServiceTestHarness` classes.
12
20
 
13
- ### No Duplication
14
- - Does NOT duplicate tests from individual connectors
15
- - Uses existing connector functionality where available
16
- - Focuses on integration and orchestration
21
+ ## Key Principles
17
22
 
18
- ### Production-Ready
19
- - Same code used in development AND production
20
- - Validates services before they join the ecosystem
21
- - Ensures cookbook compatibility
23
+ - **No duplication** — does not re-test individual connector logic; focuses on
24
+ integration, readiness and proof generation.
25
+ - **Production-ready** the exact same code runs locally, in CI and during
26
+ wrapper startup.
27
+ - **Fail-fast** — missing logger, missing serviceUrl, missing operations.json:
28
+ immediate throw.
22
29
 
23
30
  ## Components
24
31
 
25
- ### 1. Mock Infrastructure (Development)
26
- - `MockMQClient` - In-memory message queue simulation
27
- - `MockRegistry` - Service registry simulation
28
- - `MockStorage` - Object storage simulation
32
+ ### Mock Infrastructure (for unit tests)
33
+
34
+ - `MockMQClient` — in-memory message queue simulation
35
+ - `MockRegistry` service registry simulation
36
+ - `MockStorage` — object storage simulation
29
37
 
30
- ### 2. Validation Tools (Production)
31
- - `ServiceValidator` - OpenAPI compliance and endpoint testing
32
- - `WorkflowTestRunner` - Cookbook execution testing
33
- - `CookbookTestUtils` - Cookbook structure validation
38
+ ### Production Validation
34
39
 
35
- ### 3. Integration Framework
36
- - `ServiceTestHarness` - Complete test environment orchestration
40
+ - `ValidationOrchestrator` 6-step pre-validation pipeline, emits proof
41
+ - `ServiceReadinessValidator` — score-based readiness checks (operations /
42
+ endpoints / health / cookbook / registry)
43
+ - `ServiceStructureValidator` — config layout checks (config/service/*)
44
+ - `ValidationProofGenerator` — fingerprint + codec helpers
45
+ - `CookbookTestRunner` / `WorkflowTestRunner` — cookbook execution probes
46
+ - `CookbookTestUtils` — static cookbook-structure validators
37
47
 
38
- ## Use Cases
48
+ ### Test Suite Helpers
39
49
 
40
- ### Development Workflow
41
- ```javascript
42
- // Developer testing their service
43
- const harness = new ServiceTestHarness({
44
- service: myExpressApp,
45
- serviceName: 'my-service',
46
- openApiSpec: spec,
47
- mockInfrastructure: true // Use mocks
48
- });
50
+ - `createServiceReadinessTests(options)` — Jest suite generator
51
+ - `createPreValidationTests(options)` — Jest suite generator
49
52
 
50
- await harness.start();
51
- // Run tests...
52
- await harness.stop();
53
- ```
53
+ ## Integration Points
54
54
 
55
- ### Production Validation
56
- ```javascript
57
- // Registry validating new service
58
- const validator = new ServiceValidator();
59
- const result = await validator.validateService(
60
- serviceUrl,
61
- openApiSpec
62
- );
63
-
64
- if (!result.valid) {
65
- // Reject registration
66
- }
67
- ```
68
-
69
- ### Service-Wrapper Integration
70
- ```javascript
71
- // Service-wrapper using connector-testing
72
- class ServiceWrapper {
73
- async validateBeforeStart() {
74
- const validator = new ServiceValidator();
75
- const validation = await validator.validateService(
76
- `http://localhost:${this.port}`,
77
- this.openApiSpec
78
- );
79
-
80
- if (!validation.valid) {
81
- throw new Error('Service validation failed');
82
- }
83
- }
84
- }
85
- ```
86
-
87
- ## Testing Strategy
88
-
89
- ### What We Test
90
- 1. **Service Contract** - OpenAPI compliance
91
- 2. **Workflow Capability** - Can process cookbooks
92
- 3. **Infrastructure Integration** - Registry, MQ, Storage connectivity
93
- 4. **Health & Status** - Monitoring endpoints
94
-
95
- ### What We DON'T Test
96
- 1. Individual connector functionality (tested in connector packages)
97
- 2. Business logic correctness (service's responsibility)
98
- 3. Performance metrics (separate concern)
99
-
100
- ## Production Validation Flow
101
-
102
- ```
103
- New Service Registration
104
-
105
- [Registry]
106
-
107
- Uses connector-testing
108
-
109
- 1. Validate OpenAPI
110
- 2. Test all endpoints
111
- 3. Execute test cookbook
112
- 4. Verify health check
113
-
114
- Pass? → Accept : Reject
115
- ```
116
-
117
- ## Integration with Existing System
118
-
119
- ### Uses Existing Connectors
120
- - Leverages real connector implementations where possible
121
- - Only mocks what's necessary for isolation
122
- - Validates against actual connector interfaces
123
-
124
- ### Complements Existing Tests
125
- - Individual connectors have unit tests
126
- - Services have business logic tests
127
- - Connector-testing provides integration validation
128
-
129
- ## Future Enhancements
130
-
131
- 1. **Performance Benchmarking** - Baseline performance requirements
132
- 2. **Security Validation** - Authentication/authorization checks
133
- 3. **Chaos Testing** - Fault injection and recovery
134
- 4. **Compliance Checking** - Regulatory requirement validation
55
+ - `@onlineapps/service-wrapper` instantiates `ValidationOrchestrator` during
56
+ wrapper startup. Proof is cached under `conn-runtime/validation-proof.json`
57
+ (30-day validity, invalidated by config fingerprint change — includes
58
+ operations map, see
59
+ [operations-registry-contract.md §3](../../../docs/standards/operations-registry-contract.md)).
60
+ - Biz-service templates import `createPreValidationTests` /
61
+ `createServiceReadinessTests` from this package for their own test suites.
62
+
63
+ ## What We Test
64
+
65
+ 1. **Service contract** — operations.json structure + endpoint reachability
66
+ 2. **Workflow capability** — can process cookbooks
67
+ 3. **Infrastructure** — registry / MQ / storage connectivity
68
+ 4. **Health** — `/health` returns 200
69
+
70
+ ## What We DO NOT Test
71
+
72
+ 1. Individual connector behavior (tested in connector packages)
73
+ 2. Business logic correctness (service responsibility)
74
+ 3. Performance / load (separate concern)
75
+
76
+ ## Related Documentation
77
+
78
+ - [operations-registry-contract.md](../../../docs/standards/operations-registry-contract.md) — operations.json schema
79
+ - [validation-probe-contract.md](../../../docs/standards/validation-probe-contract.md) — required `example`/`default` fields for probes
80
+ - [validator.md](../../../docs/architecture/validator.md) — architecture overview
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/conn-orch-validator",
3
- "version": "2.0.32",
3
+ "version": "2.0.34",
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
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "author": "OnlineApps",
22
22
  "license": "PROPRIETARY",
23
23
  "dependencies": {
24
- "@onlineapps/service-validator-core": "1.0.12",
24
+ "@onlineapps/service-validator-core": "1.0.13",
25
25
  "@onlineapps/runtime-config": "1.0.2",
26
26
  "ajv": "^8.12.0",
27
27
  "ajv-formats": "^2.1.1",
@@ -14,12 +14,24 @@ const { resolveHeaders } = require('./utils/resolveHeaders');
14
14
  */
15
15
  class CookbookTestRunner {
16
16
  constructor(options = {}) {
17
+ if (!options.serviceName) {
18
+ throw new Error('[CookbookTestRunner] serviceName is required');
19
+ }
20
+ if (!options.serviceUrl) {
21
+ throw new Error('[CookbookTestRunner] serviceUrl is required');
22
+ }
23
+ if (!options.logger || typeof options.logger.warn !== 'function') {
24
+ throw new Error('[CookbookTestRunner] Logger is required — Expected object with warn() method');
25
+ }
17
26
  this.serviceName = options.serviceName;
18
- this.serviceUrl = options.serviceUrl || 'http://127.0.0.1:3000';
27
+ this.serviceUrl = options.serviceUrl;
19
28
  this.servicePath = options.servicePath;
20
- this.mockInfrastructure = options.mockInfrastructure !== false; // default true
21
- this.timeout = options.timeout || 30000;
22
- this.logger = options.logger || console;
29
+ this.mockInfrastructure = options.mockInfrastructure !== false;
30
+ this.timeout = options.timeout;
31
+ if (!this.timeout || typeof this.timeout !== 'number' || this.timeout <= 0) {
32
+ throw new Error('[CookbookTestRunner] timeout is required — Expected positive number (ms)');
33
+ }
34
+ this.logger = options.logger;
23
35
 
24
36
  // Initialize mocked infrastructure
25
37
  if (this.mockInfrastructure) {
@@ -1,19 +1,25 @@
1
1
  'use strict';
2
2
 
3
- const ServiceValidator = require('./ServiceValidator');
4
3
  const CookbookTestUtils = require('./CookbookTestUtils');
5
4
  const { resolveHeaders } = require('./utils/resolveHeaders');
6
5
 
7
6
  /**
8
- * ServiceReadinessValidator - Orchestrates complete service validation
9
- * Used by service-wrapper to verify service is ready for production
7
+ * ServiceReadinessValidator - Orchestrates complete service validation.
10
8
  *
11
- * IMPORTANT: Only supports operations.json format. OpenAPI is deprecated.
9
+ * Used by service-wrapper to verify a service is ready for production.
10
+ * Works exclusively against the operations.json contract — OpenAPI-style
11
+ * `paths` iteration was removed when the contract became the single source
12
+ * of truth for endpoint metadata.
13
+ *
14
+ * @see /api/docs/standards/operations-registry-contract.md §3
15
+ * @see /api/docs/standards/validation-probe-contract.md
12
16
  */
13
17
  class ServiceReadinessValidator {
14
18
  constructor(options = {}) {
15
- this.validator = new ServiceValidator(options);
16
- this.logger = options.logger || console;
19
+ if (!options.logger || typeof options.logger.warn !== 'function') {
20
+ throw new Error('[ServiceReadinessValidator] Logger is required — Expected object with warn() method');
21
+ }
22
+ this.logger = options.logger;
17
23
 
18
24
  // Readiness checks: core (80 points) + optional (20 points) = 100 points max
19
25
  // Core checks ALWAYS run, optional checks run if testCookbook/registry provided
@@ -347,64 +353,44 @@ class ServiceReadinessValidator {
347
353
  }
348
354
 
349
355
  /**
350
- * Generate test input based on operation input schema
351
- * Supports Content Descriptor types (content, file) with proper test values
356
+ * Generate test input based on operation input schema.
357
+ *
358
+ * Resolution order per field: example > default > enum[0]
359
+ * If none found for a required field, throws with actionable message.
360
+ *
361
+ * Contract: every required field in operations.json MUST have 'example' or 'default'.
362
+ * See: docs/standards/validation-probe-contract.md
352
363
  */
353
364
  generateTestInput(inputSchema) {
354
365
  const testData = {};
355
366
 
356
367
  for (const [fieldName, fieldSpec] of Object.entries(inputSchema)) {
357
- if (fieldSpec.required) {
358
- // Generate appropriate test value based on type
359
- switch (fieldSpec.type) {
360
- case 'string':
361
- testData[fieldName] = fieldSpec.default || 'Test';
362
- break;
363
- case 'number':
364
- testData[fieldName] = fieldSpec.default || 0;
365
- break;
366
- case 'boolean':
367
- testData[fieldName] = fieldSpec.default || false;
368
- break;
369
- case 'array':
370
- testData[fieldName] = fieldSpec.default || [];
371
- break;
372
- case 'object':
373
- testData[fieldName] = fieldSpec.default || {};
374
- break;
375
- // Content Descriptor types - generate valid test content
376
- case 'content':
377
- // Generate content based on field name hints
378
- if (fieldName.toLowerCase().includes('html')) {
379
- testData[fieldName] = fieldSpec.default || '<html><body><h1>Test Validation</h1><p>Auto-generated test content.</p></body></html>';
380
- } else if (fieldName.toLowerCase().includes('markdown') || fieldName.toLowerCase().includes('md')) {
381
- testData[fieldName] = fieldSpec.default || '# Test Validation\n\nAuto-generated test content.';
382
- } else {
383
- testData[fieldName] = fieldSpec.default || 'Test content for validation';
384
- }
385
- break;
386
- case 'file':
387
- // For file types, generate a VALID Content Descriptor object (type=file)
388
- // This keeps endpoint checks predictable and avoids service-specific file upload flows.
389
- testData[fieldName] = fieldSpec.default || {
390
- _descriptor: true,
391
- type: 'file',
392
- storage_ref: 'minio://test/validation/placeholder.txt',
393
- filename: 'placeholder.txt',
394
- content_type: 'text/plain',
395
- size: 1,
396
- fingerprint: 'test-fingerprint'
397
- };
398
- break;
399
- default:
400
- testData[fieldName] = null;
401
- }
402
- }
368
+ if (!fieldSpec.required) continue;
369
+
370
+ const value = this._resolveTestValue(fieldName, fieldSpec);
371
+ testData[fieldName] = value;
403
372
  }
404
373
 
405
374
  return testData;
406
375
  }
407
376
 
377
+ /**
378
+ * Resolve a single test value for a required input field.
379
+ * Throws if no value can be determined — forces service authors to provide examples.
380
+ * @private
381
+ */
382
+ _resolveTestValue(fieldName, fieldSpec) {
383
+ if (fieldSpec.example !== undefined) return fieldSpec.example;
384
+ if (fieldSpec.default !== undefined) return fieldSpec.default;
385
+ if (Array.isArray(fieldSpec.enum) && fieldSpec.enum.length > 0) return fieldSpec.enum[0];
386
+
387
+ throw new Error(
388
+ `[ServiceReadinessValidator] No test value for required field '${fieldName}' ` +
389
+ `(type: ${fieldSpec.type}) — Add 'example' or 'default' to operations.json input schema. ` +
390
+ `See: docs/standards/validation-probe-contract.md`
391
+ );
392
+ }
393
+
408
394
  /**
409
395
  * Get recommendation based on results
410
396
  */
@@ -22,11 +22,13 @@ class ValidationOrchestrator {
22
22
  this.serviceName = options.serviceName;
23
23
  this.serviceVersion = options.serviceVersion;
24
24
  this.serviceUrl = options.serviceUrl; // NEW: Service URL for HTTP calls
25
- this.logger = options.logger || console;
25
+ if (!options.logger || typeof options.logger.warn !== 'function') {
26
+ throw new Error('[ValidationOrchestrator] Logger is required — Expected object with warn() method');
27
+ }
28
+ this.logger = options.logger;
26
29
 
27
- // Validate required options
28
30
  if (!this.serviceUrl) {
29
- throw new Error('serviceUrl is required for ValidationOrchestrator');
31
+ throw new Error('[ValidationOrchestrator] serviceUrl is required');
30
32
  }
31
33
 
32
34
  // Paths — prefer new config/service/ layout, fall back to legacy conn-config/
@@ -39,11 +41,13 @@ class ValidationOrchestrator {
39
41
 
40
42
  // Validators
41
43
  this.structureValidator = new ServiceStructureValidator(this.serviceRoot);
42
- this.readinessValidator = new ServiceReadinessValidator();
44
+ this.readinessValidator = new ServiceReadinessValidator({ logger: this.logger });
43
45
  this.cookbookRunner = new CookbookTestRunner({
44
46
  servicePath: this.serviceRoot,
45
47
  serviceName: this.serviceName,
46
- serviceUrl: this.serviceUrl // Pass serviceUrl to CookbookTestRunner
48
+ serviceUrl: this.serviceUrl,
49
+ logger: this.logger,
50
+ timeout: 30000
47
51
  });
48
52
  }
49
53
 
package/src/config.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Runtime configuration schema for @onlineapps/conn-orch-validator.
5
5
  *
6
6
  * Uses @onlineapps/runtime-config for unified priority:
7
- * 1. Explicit config (passed to TestOrchestrator options)
7
+ * 1. Explicit config (passed to ValidationOrchestrator/readiness options)
8
8
  * 2. Environment variable
9
9
  * 3. Module-owned defaults (none for topology)
10
10
  *
@@ -138,7 +138,7 @@ function createServiceReadinessTests(testsDir, options = {}) {
138
138
  }
139
139
 
140
140
  // Run readiness validation
141
- const validator = new ServiceReadinessValidator();
141
+ const validator = new ServiceReadinessValidator({ logger: console });
142
142
  const result = await validator.validateReadiness({
143
143
  name: serviceName,
144
144
  version: serviceVersion,
package/src/index.js CHANGED
@@ -1,17 +1,25 @@
1
1
  'use strict';
2
2
 
3
- // Mock infrastructure components (load first - no dependencies)
3
+ /**
4
+ * @module @onlineapps/conn-orch-validator
5
+ * @description Service validation framework using the operations.json contract.
6
+ *
7
+ * Production entry point: {@link ValidationOrchestrator} (6-step pre-validation
8
+ * driven by operations.json — OpenAPI path iteration is NOT supported).
9
+ *
10
+ * @see /api/docs/standards/operations-registry-contract.md §3 (operations.json)
11
+ * @see /api/docs/standards/validation-probe-contract.md (validation probes)
12
+ * @see /api/docs/architecture/validator.md (validator architecture)
13
+ */
14
+
4
15
  const MockMQClient = require('./mocks/MockMQClient');
5
16
  const MockRegistry = require('./mocks/MockRegistry');
6
17
  const MockStorage = require('./mocks/MockStorage');
7
18
 
8
- // Base test utilities (no circular dependencies)
9
- const ServiceValidator = require('./ServiceValidator');
10
19
  const CookbookTestUtils = require('./CookbookTestUtils');
11
20
  const { ServiceStructureValidator } = require('./validators/ServiceStructureValidator');
12
21
  const ValidationProofGenerator = require('./validators/ValidationProofGenerator');
13
22
 
14
- // Test runners (depend on mocks)
15
23
  let CookbookTestRunner;
16
24
  try {
17
25
  CookbookTestRunner = require('./CookbookTestRunner');
@@ -20,43 +28,29 @@ try {
20
28
  }
21
29
  const WorkflowTestRunner = require('./WorkflowTestRunner');
22
30
 
23
- // Orchestrators (depend on validators and runners)
24
31
  const ServiceReadinessValidator = require('./ServiceReadinessValidator');
25
- const TestOrchestrator = require('./TestOrchestrator');
26
- const ServiceTestHarness = require('./ServiceTestHarness');
27
32
  const ValidationOrchestrator = require('./ValidationOrchestrator');
28
33
 
29
- // Test helpers (generic test suite creators)
30
34
  const { createServiceReadinessTests } = require('./helpers/createServiceReadinessTests');
31
35
  const { createPreValidationTests } = require('./helpers/createPreValidationTests');
32
36
 
33
- // Export all components with getters to avoid circular dependency issues
34
37
  module.exports = {
35
- // Mocks
36
38
  get MockMQClient() { return MockMQClient; },
37
39
  get MockRegistry() { return MockRegistry; },
38
40
  get MockStorage() { return MockStorage; },
39
41
 
40
- // Test utilities
41
- get ServiceTestHarness() { return ServiceTestHarness; },
42
- get ServiceValidator() { return ServiceValidator; },
43
42
  get WorkflowTestRunner() { return WorkflowTestRunner; },
44
43
  get CookbookTestUtils() { return CookbookTestUtils; },
45
44
  get ServiceReadinessValidator() { return ServiceReadinessValidator; },
46
- get TestOrchestrator() { return TestOrchestrator; },
47
45
  get CookbookTestRunner() { return CookbookTestRunner; },
48
46
  get ValidationProofGenerator() { return ValidationProofGenerator; },
49
47
  get ServiceStructureValidator() { return ServiceStructureValidator; },
50
48
  get ValidationOrchestrator() { return ValidationOrchestrator; },
51
49
 
52
- // Test helpers (NEW - generic test suite creators)
53
50
  get createServiceReadinessTests() { return createServiceReadinessTests; },
54
51
  get createPreValidationTests() { return createPreValidationTests; },
55
52
 
56
- // Convenience factory functions
57
- createTestHarness: (options) => new ServiceTestHarness(options),
58
- createValidator: (options) => new ServiceValidator(options),
59
53
  createMockMQ: () => new MockMQClient(),
60
54
  createMockRegistry: () => new MockRegistry(),
61
55
  createMockStorage: () => new MockStorage()
62
- };
56
+ };