@onlineapps/conn-orch-validator 2.0.32 → 2.0.33
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-orch-validator",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.33",
|
|
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": {
|
|
@@ -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
|
|
27
|
+
this.serviceUrl = options.serviceUrl;
|
|
19
28
|
this.servicePath = options.servicePath;
|
|
20
|
-
this.mockInfrastructure = options.mockInfrastructure !== false;
|
|
21
|
-
this.timeout = options.timeout
|
|
22
|
-
this.
|
|
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) {
|
|
@@ -12,8 +12,11 @@ const { resolveHeaders } = require('./utils/resolveHeaders');
|
|
|
12
12
|
*/
|
|
13
13
|
class ServiceReadinessValidator {
|
|
14
14
|
constructor(options = {}) {
|
|
15
|
+
if (!options.logger || typeof options.logger.warn !== 'function') {
|
|
16
|
+
throw new Error('[ServiceReadinessValidator] Logger is required — Expected object with warn() method');
|
|
17
|
+
}
|
|
15
18
|
this.validator = new ServiceValidator(options);
|
|
16
|
-
this.logger = options.logger
|
|
19
|
+
this.logger = options.logger;
|
|
17
20
|
|
|
18
21
|
// Readiness checks: core (80 points) + optional (20 points) = 100 points max
|
|
19
22
|
// Core checks ALWAYS run, optional checks run if testCookbook/registry provided
|
|
@@ -347,64 +350,44 @@ class ServiceReadinessValidator {
|
|
|
347
350
|
}
|
|
348
351
|
|
|
349
352
|
/**
|
|
350
|
-
* Generate test input based on operation input schema
|
|
351
|
-
*
|
|
353
|
+
* Generate test input based on operation input schema.
|
|
354
|
+
*
|
|
355
|
+
* Resolution order per field: example > default > enum[0]
|
|
356
|
+
* If none found for a required field, throws with actionable message.
|
|
357
|
+
*
|
|
358
|
+
* Contract: every required field in operations.json MUST have 'example' or 'default'.
|
|
359
|
+
* See: docs/standards/validation-probe-contract.md
|
|
352
360
|
*/
|
|
353
361
|
generateTestInput(inputSchema) {
|
|
354
362
|
const testData = {};
|
|
355
363
|
|
|
356
364
|
for (const [fieldName, fieldSpec] of Object.entries(inputSchema)) {
|
|
357
|
-
if (fieldSpec.required)
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
}
|
|
365
|
+
if (!fieldSpec.required) continue;
|
|
366
|
+
|
|
367
|
+
const value = this._resolveTestValue(fieldName, fieldSpec);
|
|
368
|
+
testData[fieldName] = value;
|
|
403
369
|
}
|
|
404
370
|
|
|
405
371
|
return testData;
|
|
406
372
|
}
|
|
407
373
|
|
|
374
|
+
/**
|
|
375
|
+
* Resolve a single test value for a required input field.
|
|
376
|
+
* Throws if no value can be determined — forces service authors to provide examples.
|
|
377
|
+
* @private
|
|
378
|
+
*/
|
|
379
|
+
_resolveTestValue(fieldName, fieldSpec) {
|
|
380
|
+
if (fieldSpec.example !== undefined) return fieldSpec.example;
|
|
381
|
+
if (fieldSpec.default !== undefined) return fieldSpec.default;
|
|
382
|
+
if (Array.isArray(fieldSpec.enum) && fieldSpec.enum.length > 0) return fieldSpec.enum[0];
|
|
383
|
+
|
|
384
|
+
throw new Error(
|
|
385
|
+
`[ServiceReadinessValidator] No test value for required field '${fieldName}' ` +
|
|
386
|
+
`(type: ${fieldSpec.type}) — Add 'example' or 'default' to operations.json input schema. ` +
|
|
387
|
+
`See: docs/standards/validation-probe-contract.md`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
408
391
|
/**
|
|
409
392
|
* Get recommendation based on results
|
|
410
393
|
*/
|
package/src/TestOrchestrator.js
CHANGED
|
@@ -17,8 +17,14 @@ class TestOrchestrator {
|
|
|
17
17
|
this.service = options.service;
|
|
18
18
|
this.serviceName = options.serviceName;
|
|
19
19
|
this.openApiSpec = options.openApiSpec;
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
if (!options.logger || typeof options.logger.warn !== 'function') {
|
|
21
|
+
throw new Error('[TestOrchestrator] Logger is required — Expected object with warn() method');
|
|
22
|
+
}
|
|
23
|
+
this.logger = options.logger;
|
|
24
|
+
if (!options.integrationConfig) {
|
|
25
|
+
throw new Error('[TestOrchestrator] integrationConfig is required');
|
|
26
|
+
}
|
|
27
|
+
this.integrationConfig = options.integrationConfig;
|
|
22
28
|
|
|
23
29
|
// Test configuration
|
|
24
30
|
this.testLevels = {
|
|
@@ -227,7 +233,7 @@ class TestOrchestrator {
|
|
|
227
233
|
const config = this.getIntegrationTestConfig();
|
|
228
234
|
|
|
229
235
|
// Run readiness validator (uses real endpoints)
|
|
230
|
-
const validator = new ServiceReadinessValidator();
|
|
236
|
+
const validator = new ServiceReadinessValidator({ logger: this.logger });
|
|
231
237
|
const readinessTest = await validator.validateReadiness({
|
|
232
238
|
name: this.serviceName,
|
|
233
239
|
url: config.serviceUrl,
|
|
@@ -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
|
-
|
|
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
|
|
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
|
|
48
|
+
serviceUrl: this.serviceUrl,
|
|
49
|
+
logger: this.logger,
|
|
50
|
+
timeout: 30000
|
|
47
51
|
});
|
|
48
52
|
}
|
|
49
53
|
|
|
@@ -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,
|