@onlineapps/conn-orch-validator 2.0.31 → 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.31",
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 || '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) {
@@ -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 || console;
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
@@ -238,8 +241,9 @@ class ServiceReadinessValidator {
238
241
  validateStatus: () => true // Accept any status for validation
239
242
  });
240
243
 
241
- // Check response
242
- const isValid = response.status >= 200 && response.status < 300;
244
+ // Check response: 2xx = success, 4xx = endpoint works but rejected test data (valid)
245
+ // Only 5xx (server error) or connection failure = invalid endpoint
246
+ const isValid = response.status < 500;
243
247
 
244
248
  if (isValid) {
245
249
  results.successful++;
@@ -346,64 +350,44 @@ class ServiceReadinessValidator {
346
350
  }
347
351
 
348
352
  /**
349
- * Generate test input based on operation input schema
350
- * Supports Content Descriptor types (content, file) with proper test values
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
351
360
  */
352
361
  generateTestInput(inputSchema) {
353
362
  const testData = {};
354
363
 
355
364
  for (const [fieldName, fieldSpec] of Object.entries(inputSchema)) {
356
- if (fieldSpec.required) {
357
- // Generate appropriate test value based on type
358
- switch (fieldSpec.type) {
359
- case 'string':
360
- testData[fieldName] = fieldSpec.default || 'Test';
361
- break;
362
- case 'number':
363
- testData[fieldName] = fieldSpec.default || 0;
364
- break;
365
- case 'boolean':
366
- testData[fieldName] = fieldSpec.default || false;
367
- break;
368
- case 'array':
369
- testData[fieldName] = fieldSpec.default || [];
370
- break;
371
- case 'object':
372
- testData[fieldName] = fieldSpec.default || {};
373
- break;
374
- // Content Descriptor types - generate valid test content
375
- case 'content':
376
- // Generate content based on field name hints
377
- if (fieldName.toLowerCase().includes('html')) {
378
- testData[fieldName] = fieldSpec.default || '<html><body><h1>Test Validation</h1><p>Auto-generated test content.</p></body></html>';
379
- } else if (fieldName.toLowerCase().includes('markdown') || fieldName.toLowerCase().includes('md')) {
380
- testData[fieldName] = fieldSpec.default || '# Test Validation\n\nAuto-generated test content.';
381
- } else {
382
- testData[fieldName] = fieldSpec.default || 'Test content for validation';
383
- }
384
- break;
385
- case 'file':
386
- // For file types, generate a VALID Content Descriptor object (type=file)
387
- // This keeps endpoint checks predictable and avoids service-specific file upload flows.
388
- testData[fieldName] = fieldSpec.default || {
389
- _descriptor: true,
390
- type: 'file',
391
- storage_ref: 'minio://test/validation/placeholder.txt',
392
- filename: 'placeholder.txt',
393
- content_type: 'text/plain',
394
- size: 1,
395
- fingerprint: 'test-fingerprint'
396
- };
397
- break;
398
- default:
399
- testData[fieldName] = null;
400
- }
401
- }
365
+ if (!fieldSpec.required) continue;
366
+
367
+ const value = this._resolveTestValue(fieldName, fieldSpec);
368
+ testData[fieldName] = value;
402
369
  }
403
370
 
404
371
  return testData;
405
372
  }
406
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
+
407
391
  /**
408
392
  * Get recommendation based on results
409
393
  */
@@ -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
- this.logger = options.logger || console;
21
- this.integrationConfig = options.integrationConfig || {};
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
- 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/
@@ -34,18 +36,18 @@ class ValidationOrchestrator {
34
36
  const legacyConfigDir = path.join(this.serviceRoot, 'conn-config');
35
37
  this.configPath = fs.existsSync(newConfigDir) ? newConfigDir : legacyConfigDir;
36
38
 
37
- const newRuntimeDir = path.join(this.serviceRoot, 'config', 'runtime');
38
- const legacyRuntimeDir = path.join(this.serviceRoot, 'conn-runtime');
39
- this.runtimePath = fs.existsSync(newRuntimeDir) ? newRuntimeDir : legacyRuntimeDir;
39
+ this.runtimePath = path.join(this.serviceRoot, 'conn-runtime');
40
40
  this.proofPath = path.join(this.runtimePath, 'validation-proof.json');
41
41
 
42
42
  // Validators
43
43
  this.structureValidator = new ServiceStructureValidator(this.serviceRoot);
44
- this.readinessValidator = new ServiceReadinessValidator();
44
+ this.readinessValidator = new ServiceReadinessValidator({ logger: this.logger });
45
45
  this.cookbookRunner = new CookbookTestRunner({
46
46
  servicePath: this.serviceRoot,
47
47
  serviceName: this.serviceName,
48
- serviceUrl: this.serviceUrl // Pass serviceUrl to CookbookTestRunner
48
+ serviceUrl: this.serviceUrl,
49
+ logger: this.logger,
50
+ timeout: 30000
49
51
  });
50
52
  }
51
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,