@onlineapps/conn-orch-validator 2.0.5 → 2.0.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.
Files changed (36) hide show
  1. package/README.md +30 -1
  2. package/TESTING_STRATEGY.md +0 -0
  3. package/docs/DESIGN.md +0 -0
  4. package/examples/service-wrapper-usage.js +0 -0
  5. package/examples/three-tier-testing.js +0 -0
  6. package/jest.config.js +0 -0
  7. package/onlineapps-conn-e2e-testing-1.0.0.tgz +0 -0
  8. package/package.json +1 -1
  9. package/src/CookbookTestRunner.js +4 -4
  10. package/src/CookbookTestUtils.js +0 -0
  11. package/src/ServiceReadinessValidator.js +0 -0
  12. package/src/ServiceTestHarness.js +0 -0
  13. package/src/ServiceValidator.js +0 -0
  14. package/src/TestOrchestrator.js +0 -0
  15. package/src/ValidationOrchestrator.js +31 -33
  16. package/src/WorkflowTestRunner.js +0 -0
  17. package/src/helpers/README.md +0 -0
  18. package/src/helpers/createPreValidationTests.js +0 -0
  19. package/src/helpers/createServiceReadinessTests.js +0 -0
  20. package/src/index.js +0 -0
  21. package/src/mocks/MockMQClient.js +0 -0
  22. package/src/mocks/MockRegistry.js +0 -0
  23. package/src/mocks/MockStorage.js +0 -0
  24. package/src/validators/ServiceStructureValidator.js +0 -0
  25. package/src/validators/ValidationProofGenerator.js +0 -0
  26. package/test-mq-flow.js +0 -0
  27. package/tests/component/testing-framework-integration.test.js +0 -313
  28. package/tests/integration/ServiceReadiness.test.js +0 -265
  29. package/tests/monitoring-e2e.test.js +0 -315
  30. package/tests/run-example.js +0 -257
  31. package/tests/unit/CookbookTestRunner.test.js +0 -353
  32. package/tests/unit/MockMQClient.test.js +0 -190
  33. package/tests/unit/MockRegistry.test.js +0 -233
  34. package/tests/unit/MockStorage.test.js +0 -257
  35. package/tests/unit/ServiceValidator.test.js +0 -429
  36. package/tests/unit/WorkflowTestRunner.test.js +0 -546
@@ -1,429 +0,0 @@
1
- 'use strict';
2
-
3
- const ServiceValidator = require('../../src/ServiceValidator');
4
- const MockRegistry = require('../../src/mocks/MockRegistry');
5
- const axios = require('axios');
6
-
7
- jest.mock('axios');
8
-
9
- describe('ServiceValidator @unit', () => {
10
- let validator;
11
- let registry;
12
-
13
- beforeEach(() => {
14
- validator = new ServiceValidator();
15
- registry = new MockRegistry();
16
- axios.mockClear();
17
- });
18
-
19
- describe('Test Value Generation', () => {
20
- it('should generate string values', () => {
21
- expect(validator.generateTestValue({ type: 'string' })).toBe('test');
22
- expect(validator.generateTestValue({ type: 'string', example: 'custom' })).toBe('custom');
23
- expect(validator.generateTestValue({ type: 'string', enum: ['opt1', 'opt2'] })).toBe('opt1');
24
- });
25
-
26
- it('should generate formatted strings', () => {
27
- expect(validator.generateTestValue({ type: 'string', format: 'email' })).toBe('test@example.com');
28
- expect(validator.generateTestValue({ type: 'string', format: 'date' })).toBe('2024-01-01');
29
- expect(validator.generateTestValue({ type: 'string', format: 'date-time' })).toBe('2024-01-01T00:00:00Z');
30
- expect(validator.generateTestValue({ type: 'string', format: 'uuid' }))
31
- .toBe('123e4567-e89b-12d3-a456-426614174000');
32
- });
33
-
34
- it('should generate number values', () => {
35
- expect(validator.generateTestValue({ type: 'number' })).toBe(1);
36
- expect(validator.generateTestValue({ type: 'integer' })).toBe(1);
37
- expect(validator.generateTestValue({ type: 'number', minimum: 10 })).toBe(10);
38
- expect(validator.generateTestValue({ type: 'number', maximum: 100 })).toBe(100);
39
- expect(validator.generateTestValue({ type: 'number', example: 42 })).toBe(42);
40
- });
41
-
42
- it('should generate boolean values', () => {
43
- expect(validator.generateTestValue({ type: 'boolean' })).toBe(true);
44
- expect(validator.generateTestValue({ type: 'boolean', example: false })).toBe(false);
45
- });
46
-
47
- it('should generate array values', () => {
48
- const result = validator.generateTestValue({
49
- type: 'array',
50
- items: { type: 'string' }
51
- });
52
- expect(Array.isArray(result)).toBe(true);
53
- expect(result).toEqual(['test']);
54
- });
55
-
56
- it('should generate object values', () => {
57
- const schema = {
58
- type: 'object',
59
- properties: {
60
- name: { type: 'string' },
61
- age: { type: 'number' }
62
- },
63
- required: ['name']
64
- };
65
-
66
- const result = validator.generateTestValue(schema);
67
- expect(result).toHaveProperty('name', 'test');
68
- // Age might or might not be included (random)
69
- });
70
-
71
- it('should handle null schema', () => {
72
- expect(validator.generateTestValue(null)).toBeNull();
73
- expect(validator.generateTestValue(undefined)).toBeNull();
74
- });
75
- });
76
-
77
- describe('Request Building', () => {
78
- const operation = {
79
- parameters: [
80
- { name: 'id', in: 'path', schema: { type: 'string' }, required: true },
81
- { name: 'filter', in: 'query', schema: { type: 'string' } },
82
- { name: 'x-api-key', in: 'header', schema: { type: 'string' } }
83
- ],
84
- requestBody: {
85
- content: {
86
- 'application/json': {
87
- schema: {
88
- type: 'object',
89
- properties: { data: { type: 'string' } }
90
- }
91
- }
92
- }
93
- }
94
- };
95
-
96
- it('should build request with path parameters', () => {
97
- const request = validator.buildTestRequest('/users/{id}', 'get', operation);
98
- expect(request.path).toBe('/users/test');
99
- });
100
-
101
- it('should build request with query parameters', () => {
102
- const request = validator.buildTestRequest('/users', 'get', operation);
103
- // Query params are optional and added randomly
104
- expect(request.query).toBeDefined();
105
- });
106
-
107
- it('should build request with headers', () => {
108
- const request = validator.buildTestRequest('/users', 'get', operation);
109
- expect(request.headers).toBeDefined();
110
- });
111
-
112
- it('should build request with body', () => {
113
- const request = validator.buildTestRequest('/users', 'post', operation);
114
- expect(request.headers['Content-Type']).toBe('application/json');
115
- expect(request.body).toHaveProperty('data');
116
- });
117
-
118
- it('should handle operations without parameters', () => {
119
- const request = validator.buildTestRequest('/users', 'get', {});
120
- expect(request.path).toBe('/users');
121
- expect(request.query).toEqual({});
122
- expect(request.headers).toEqual({});
123
- expect(request.body).toBeNull();
124
- });
125
- });
126
-
127
- describe('Endpoint Testing', () => {
128
- const operation = {
129
- operationId: 'getUser',
130
- responses: {
131
- '200': {
132
- content: {
133
- 'application/json': {
134
- schema: {
135
- type: 'object',
136
- properties: {
137
- id: { type: 'string' },
138
- name: { type: 'string' }
139
- },
140
- required: ['id', 'name']
141
- }
142
- }
143
- }
144
- }
145
- }
146
- };
147
-
148
- it('should test endpoint successfully', async () => {
149
- axios.mockResolvedValue({
150
- status: 200,
151
- headers: {},
152
- data: { id: '123', name: 'Test' }
153
- });
154
-
155
- const result = await validator.testEndpoint(
156
- 'http://localhost:3000',
157
- '/users',
158
- 'get',
159
- operation
160
- );
161
-
162
- expect(result.valid).toBe(true);
163
- expect(result.path).toBe('/users');
164
- expect(result.method).toBe('GET');
165
- expect(result.operationId).toBe('getUser');
166
- expect(result.response.status).toBe(200);
167
- });
168
-
169
- it('should handle endpoint errors', async () => {
170
- axios.mockRejectedValue(new Error('Connection refused'));
171
-
172
- const result = await validator.testEndpoint(
173
- 'http://localhost:3000',
174
- '/users',
175
- 'get',
176
- operation
177
- );
178
-
179
- expect(result.valid).toBe(false);
180
- expect(result.errors).toContain('Failed to call endpoint: Connection refused');
181
- });
182
-
183
- it('should validate response against schema', async () => {
184
- axios.mockResolvedValue({
185
- status: 200,
186
- headers: {},
187
- data: { invalid: 'response' }
188
- });
189
-
190
- const result = await validator.testEndpoint(
191
- 'http://localhost:3000',
192
- '/users',
193
- 'get',
194
- operation
195
- );
196
-
197
- expect(result.valid).toBe(false);
198
- expect(result.errors[0]).toContain('Response validation failed');
199
- });
200
-
201
- it('should handle unexpected status codes', async () => {
202
- axios.mockResolvedValue({
203
- status: 404,
204
- headers: {},
205
- data: { error: 'Not found' }
206
- });
207
-
208
- const result = await validator.testEndpoint(
209
- 'http://localhost:3000',
210
- '/users',
211
- 'get',
212
- operation
213
- );
214
-
215
- expect(result.valid).toBe(false);
216
- expect(result.errors).toContain('Unexpected status code: 404');
217
- });
218
- });
219
-
220
- describe('Service Validation', () => {
221
- const openApiSpec = {
222
- paths: {
223
- '/users': {
224
- get: {
225
- operationId: 'getUsers',
226
- responses: {
227
- '200': {
228
- content: {
229
- 'application/json': {
230
- schema: { type: 'array' }
231
- }
232
- }
233
- }
234
- }
235
- },
236
- post: {
237
- operationId: 'createUser',
238
- responses: {
239
- '201': {
240
- content: {
241
- 'application/json': {
242
- schema: { type: 'object' }
243
- }
244
- }
245
- }
246
- }
247
- }
248
- }
249
- }
250
- };
251
-
252
- it('should validate service with all endpoints passing', async () => {
253
- // Return different responses based on method
254
- axios.mockImplementation((config) => {
255
- if (config.method === 'GET') {
256
- return Promise.resolve({
257
- status: 200,
258
- headers: {},
259
- data: []
260
- });
261
- } else if (config.method === 'POST') {
262
- return Promise.resolve({
263
- status: 201,
264
- headers: {},
265
- data: {}
266
- });
267
- }
268
- });
269
-
270
- const results = await validator.validateService(
271
- 'http://localhost:3000',
272
- openApiSpec
273
- );
274
-
275
- expect(results.valid).toBe(true);
276
- expect(results.errors).toHaveLength(0);
277
- expect(results.testedEndpoints).toHaveLength(2);
278
- expect(results.coverage).toBe(100);
279
- });
280
-
281
- it('should mark service invalid if any endpoint fails', async () => {
282
- axios
283
- .mockResolvedValueOnce({ status: 200, headers: {}, data: [] })
284
- .mockRejectedValueOnce(new Error('Failed'));
285
-
286
- const results = await validator.validateService(
287
- 'http://localhost:3000',
288
- openApiSpec
289
- );
290
-
291
- expect(results.valid).toBe(false);
292
- expect(results.errors.length).toBeGreaterThan(0);
293
- });
294
-
295
- it('should handle spec without paths', async () => {
296
- const results = await validator.validateService(
297
- 'http://localhost:3000',
298
- {}
299
- );
300
-
301
- expect(results.valid).toBe(false);
302
- expect(results.errors).toContain('No paths defined in OpenAPI spec');
303
- });
304
- });
305
-
306
- describe('Cookbook Validation', () => {
307
- beforeEach(async () => {
308
- await registry.register({
309
- name: 'service1',
310
- openapi: {
311
- paths: {
312
- '/test': {
313
- get: { operationId: 'testOp' }
314
- }
315
- }
316
- }
317
- });
318
- });
319
-
320
- it('should validate cookbook with valid steps', async () => {
321
- const cookbook = {
322
- steps: [
323
- {
324
- id: 'step1',
325
- type: 'task',
326
- service: 'service1',
327
- operation: 'testOp'
328
- }
329
- ]
330
- };
331
-
332
- const results = await validator.validateCookbook(cookbook, registry);
333
-
334
- expect(results.valid).toBe(true);
335
- expect(results.errors).toHaveLength(0);
336
- expect(results.validatedSteps).toHaveLength(1);
337
- });
338
-
339
- it('should detect missing step fields', async () => {
340
- const cookbook = {
341
- steps: [
342
- { type: 'task' }, // Missing id and service
343
- { id: 'step2' } // Missing type
344
- ]
345
- };
346
-
347
- const results = await validator.validateCookbook(cookbook, registry);
348
-
349
- expect(results.valid).toBe(false);
350
- expect(results.errors.length).toBeGreaterThan(0);
351
- });
352
-
353
- it('should validate foreach steps', async () => {
354
- const cookbook = {
355
- steps: [
356
- {
357
- id: 'foreach1',
358
- type: 'foreach',
359
- items: '$api_input.items',
360
- body: { id: 'body', type: 'task', service: 'service1' }
361
- }
362
- ]
363
- };
364
-
365
- const results = await validator.validateCookbook(cookbook, registry);
366
- expect(results.valid).toBe(true);
367
- });
368
-
369
- it('should validate switch steps', async () => {
370
- const cookbook = {
371
- steps: [
372
- {
373
- id: 'switch1',
374
- type: 'switch',
375
- condition: '$api_input.type',
376
- cases: [
377
- { value: 'a', step: { id: 's1', type: 'task', service: 'service1' } }
378
- ]
379
- }
380
- ]
381
- };
382
-
383
- const results = await validator.validateCookbook(cookbook, registry);
384
- expect(results.valid).toBe(true);
385
- });
386
-
387
- it('should detect non-existent service', async () => {
388
- const cookbook = {
389
- steps: [
390
- {
391
- id: 'step1',
392
- type: 'task',
393
- service: 'non-existent'
394
- }
395
- ]
396
- };
397
-
398
- const results = await validator.validateCookbook(cookbook, registry);
399
-
400
- expect(results.valid).toBe(false);
401
- expect(results.errors).toContain('Service not found: non-existent');
402
- });
403
-
404
- it('should detect non-existent operation', async () => {
405
- const cookbook = {
406
- steps: [
407
- {
408
- id: 'step1',
409
- type: 'task',
410
- service: 'service1',
411
- operation: 'nonExistentOp'
412
- }
413
- ]
414
- };
415
-
416
- const results = await validator.validateCookbook(cookbook, registry);
417
-
418
- expect(results.valid).toBe(false);
419
- expect(results.errors).toContain('Operation not found: nonExistentOp');
420
- });
421
-
422
- it('should handle cookbook without steps', async () => {
423
- const results = await validator.validateCookbook({}, registry);
424
-
425
- expect(results.valid).toBe(false);
426
- expect(results.errors).toContain('Cookbook must have steps array');
427
- });
428
- });
429
- });