@onlineapps/conn-orch-validator 2.0.6 → 2.0.9

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 +29 -22
  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,265 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Integration test for complete service readiness validation
5
- * Uses existing connector tests, doesn't duplicate them
6
- */
7
-
8
- const { ServiceTestHarness, ServiceValidator, WorkflowTestRunner } = require('../../src');
9
- const express = require('express');
10
-
11
- describe('Service Readiness Integration @integration', () => {
12
- let harness;
13
- let app;
14
- let openApiSpec;
15
-
16
- beforeEach(() => {
17
- // Create minimal test service
18
- app = express();
19
- app.use(express.json());
20
-
21
- app.get('/health', (req, res) => {
22
- res.json({ status: 'healthy' });
23
- });
24
-
25
- app.post('/process', (req, res) => {
26
- res.json({ processed: true, data: req.body });
27
- });
28
-
29
- openApiSpec = {
30
- openapi: '3.0.0',
31
- info: { title: 'Test Service', version: '1.0.0' },
32
- paths: {
33
- '/health': {
34
- get: {
35
- operationId: 'healthCheck',
36
- responses: {
37
- '200': {
38
- content: {
39
- 'application/json': {
40
- schema: {
41
- type: 'object',
42
- properties: {
43
- status: { type: 'string' }
44
- }
45
- }
46
- }
47
- }
48
- }
49
- }
50
- }
51
- },
52
- '/process': {
53
- post: {
54
- operationId: 'processData',
55
- requestBody: {
56
- content: {
57
- 'application/json': {
58
- schema: { type: 'object' }
59
- }
60
- }
61
- },
62
- responses: {
63
- '200': {
64
- content: {
65
- 'application/json': {
66
- schema: { type: 'object' }
67
- }
68
- }
69
- }
70
- }
71
- }
72
- }
73
- }
74
- };
75
- });
76
-
77
- afterEach(async () => {
78
- if (harness) {
79
- await harness.stop();
80
- }
81
- });
82
-
83
- describe('Complete Service Validation', () => {
84
- it('should validate service is ready for production', async () => {
85
- harness = new ServiceTestHarness({
86
- service: app,
87
- serviceName: 'test-service',
88
- openApiSpec,
89
- mockInfrastructure: true
90
- });
91
-
92
- await harness.start();
93
-
94
- // 1. Verify service is registered
95
- const registration = harness.getServiceRegistration();
96
- expect(registration).toBeDefined();
97
- expect(registration.name).toBe('test-service');
98
- expect(registration.status).toBe('active');
99
-
100
- // 2. Validate OpenAPI compliance
101
- const validator = new ServiceValidator();
102
- const validation = await validator.validateService(
103
- harness.baseUrl,
104
- openApiSpec
105
- );
106
- expect(validation.valid).toBe(true);
107
- expect(validation.coverage).toBe(100);
108
-
109
- // 3. Test workflow execution
110
- const workflow = await harness.simulateWorkflow({
111
- steps: [
112
- {
113
- id: 'step1',
114
- type: 'task',
115
- service: 'test-service',
116
- operation: 'processData',
117
- input: { test: 'data' }
118
- }
119
- ]
120
- });
121
- expect(workflow.completed).toBe(true);
122
-
123
- // 4. Verify message queue integration
124
- const messages = harness.getPublishedMessages('workflow.completed');
125
- expect(messages.length).toBeGreaterThan(0);
126
- });
127
-
128
- it('should detect service not ready - missing endpoints', async () => {
129
- // Remove an endpoint
130
- delete openApiSpec.paths['/process'];
131
-
132
- harness = new ServiceTestHarness({
133
- service: app,
134
- serviceName: 'test-service',
135
- openApiSpec,
136
- mockInfrastructure: true
137
- });
138
-
139
- await harness.start();
140
-
141
- const validator = new ServiceValidator();
142
- const validation = await validator.validateService(
143
- harness.baseUrl,
144
- openApiSpec
145
- );
146
-
147
- // Service still works but coverage is reduced
148
- expect(validation.valid).toBe(true);
149
- expect(validation.coverage).toBeLessThan(100);
150
- });
151
- });
152
-
153
- describe('Cookbook Validation for Production', () => {
154
- it('should validate cookbook can execute in environment', async () => {
155
- harness = new ServiceTestHarness({
156
- service: app,
157
- serviceName: 'test-service',
158
- openApiSpec,
159
- mockInfrastructure: true
160
- });
161
-
162
- await harness.start();
163
-
164
- const cookbook = {
165
- version: '1.0.0',
166
- steps: [
167
- {
168
- id: 'validate',
169
- type: 'task',
170
- service: 'test-service',
171
- operation: 'healthCheck'
172
- },
173
- {
174
- id: 'process',
175
- type: 'task',
176
- service: 'test-service',
177
- operation: 'processData',
178
- input: { data: '$steps.validate' }
179
- }
180
- ]
181
- };
182
-
183
- // Validate cookbook structure
184
- const validator = new ServiceValidator();
185
- const cookbookValidation = await validator.validateCookbook(
186
- cookbook,
187
- harness.registry
188
- );
189
- expect(cookbookValidation.valid).toBe(true);
190
-
191
- // Execute cookbook
192
- const runner = new WorkflowTestRunner({
193
- mqClient: harness.mqClient,
194
- registry: harness.registry,
195
- storage: harness.storage
196
- });
197
-
198
- const workflow = await runner.runWorkflow(cookbook);
199
- expect(workflow.status).toBe('completed');
200
- expect(workflow.results).toHaveLength(2);
201
- });
202
- });
203
-
204
- describe('Production Deployment Readiness', () => {
205
- it('should verify all production requirements', async () => {
206
- harness = new ServiceTestHarness({
207
- service: app,
208
- serviceName: 'test-service',
209
- openApiSpec,
210
- mockInfrastructure: true
211
- });
212
-
213
- await harness.start();
214
-
215
- const readinessChecks = {
216
- serviceRunning: false,
217
- apiAccessible: false,
218
- registryConnected: false,
219
- mqConnected: false,
220
- openApiValid: false,
221
- healthCheckPassing: false
222
- };
223
-
224
- // Check service is running
225
- readinessChecks.serviceRunning = harness.isRunning;
226
-
227
- // Check API is accessible
228
- try {
229
- const response = await harness.callApi('GET', '/health');
230
- readinessChecks.apiAccessible = true;
231
- readinessChecks.healthCheckPassing = response.status === 'healthy';
232
- } catch (e) {
233
- // API not accessible
234
- }
235
-
236
- // Check registry connection
237
- readinessChecks.registryConnected = !!harness.getServiceRegistration();
238
-
239
- // Check MQ connection
240
- readinessChecks.mqConnected = harness.mqClient.isConnected;
241
-
242
- // Validate OpenAPI
243
- const validator = new ServiceValidator();
244
- const validation = await validator.validateService(
245
- harness.baseUrl,
246
- openApiSpec
247
- );
248
- readinessChecks.openApiValid = validation.valid;
249
-
250
- // All checks should pass
251
- expect(readinessChecks).toEqual({
252
- serviceRunning: true,
253
- apiAccessible: true,
254
- registryConnected: true,
255
- mqConnected: true,
256
- openApiValid: true,
257
- healthCheckPassing: true
258
- });
259
-
260
- // Get statistics
261
- const stats = harness.getStats();
262
- expect(stats).toBeDefined();
263
- });
264
- });
265
- });
@@ -1,315 +0,0 @@
1
- /**
2
- * End-to-End tests for monitoring infrastructure
3
- * Tests the complete flow from service through monitoring to telemetry
4
- */
5
-
6
- const amqp = require('amqplib');
7
- const axios = require('axios');
8
-
9
- describe('Monitoring E2E Tests @e2e', () => {
10
- let connection;
11
- let channel;
12
- const RABBITMQ_URL = process.env.AMQP_URL || 'amqp://localhost:5672';
13
- const HELLO_SERVICE_URL = 'http://localhost:33199';
14
-
15
- beforeAll(async () => {
16
- try {
17
- connection = await amqp.connect(RABBITMQ_URL);
18
- channel = await connection.createChannel();
19
-
20
- // Setup test exchange and queue
21
- await channel.assertExchange('test.exchange', 'topic', { durable: false });
22
- await channel.assertQueue('test.monitoring', { durable: false });
23
- await channel.bindQueue('test.monitoring', 'test.exchange', 'monitoring.#');
24
- } catch (error) {
25
- console.error('Failed to connect to RabbitMQ:', error);
26
- }
27
- });
28
-
29
- afterAll(async () => {
30
- if (channel) await channel.close();
31
- if (connection) await connection.close();
32
- });
33
-
34
- describe('Service to Monitoring Flow', () => {
35
- test('should generate monitoring data from service call', async () => {
36
- // Skip if services not available
37
- if (!connection) {
38
- console.log('Skipping - RabbitMQ not available');
39
- return;
40
- }
41
-
42
- // Send cookbook message to service
43
- const cookbook = {
44
- id: 'e2e-test-1',
45
- type: 'hello',
46
- name: 'good-day',
47
- version: '1.0.0',
48
- metadata: {
49
- workflowId: 'e2e-wf-1',
50
- timestamp: new Date().toISOString()
51
- }
52
- };
53
-
54
- // Send to service via MQ
55
- const replyQueue = await channel.assertQueue('', { exclusive: true });
56
- const correlationId = 'e2e-corr-1';
57
-
58
- await channel.sendToQueue(
59
- 'hello-service',
60
- Buffer.from(JSON.stringify(cookbook)),
61
- {
62
- correlationId,
63
- replyTo: replyQueue.queue
64
- }
65
- );
66
-
67
- // Wait for response
68
- const response = await new Promise((resolve, reject) => {
69
- const timeout = setTimeout(() => {
70
- reject(new Error('Timeout waiting for response'));
71
- }, 5000);
72
-
73
- channel.consume(replyQueue.queue, (msg) => {
74
- if (msg.properties.correlationId === correlationId) {
75
- clearTimeout(timeout);
76
- resolve(JSON.parse(msg.content.toString()));
77
- }
78
- }, { noAck: true });
79
- });
80
-
81
- expect(response).toBeDefined();
82
- expect(response.status).toBeDefined();
83
- });
84
-
85
- test('should track workflow through monitoring', async () => {
86
- // Direct HTTP call to service
87
- try {
88
- const response = await axios.post(`${HELLO_SERVICE_URL}/api/workflow`, {
89
- workflowId: 'e2e-wf-2',
90
- operation: 'good-day',
91
- data: {
92
- message: 'E2E test'
93
- }
94
- });
95
-
96
- expect(response.status).toBe(200);
97
- expect(response.data).toBeDefined();
98
- } catch (error) {
99
- // Service might not be running
100
- console.log('Service not available, skipping HTTP test');
101
- }
102
- });
103
- });
104
-
105
- describe('Monitoring Data Collection', () => {
106
- test('should collect logs from monitoring', async () => {
107
- if (!channel) {
108
- console.log('Skipping - no channel available');
109
- return;
110
- }
111
-
112
- // Setup consumer for monitoring messages
113
- const messages = [];
114
-
115
- await channel.consume('test.monitoring', (msg) => {
116
- if (msg) {
117
- messages.push(JSON.parse(msg.content.toString()));
118
- channel.ack(msg);
119
- }
120
- });
121
-
122
- // Trigger some monitoring events
123
- const testCookbook = {
124
- id: 'monitor-test-1',
125
- type: 'hello',
126
- name: 'test-monitoring',
127
- version: '1.0.0'
128
- };
129
-
130
- await channel.sendToQueue(
131
- 'hello-service',
132
- Buffer.from(JSON.stringify(testCookbook))
133
- );
134
-
135
- // Wait for messages
136
- await new Promise(resolve => setTimeout(resolve, 1000));
137
-
138
- // Check if we received monitoring data
139
- if (messages.length > 0) {
140
- expect(messages[0]).toHaveProperty('timestamp');
141
- expect(messages[0]).toHaveProperty('level');
142
- }
143
- });
144
-
145
- test('should collect metrics from monitoring', async () => {
146
- // This would connect to metrics endpoint if available
147
- // For now, we just verify the structure
148
-
149
- const metricsData = {
150
- timestamp: new Date().toISOString(),
151
- metric: 'requests.total',
152
- value: 1,
153
- labels: {
154
- service: 'hello-service',
155
- endpoint: '/good-day',
156
- status: 'success'
157
- }
158
- };
159
-
160
- expect(metricsData).toHaveProperty('timestamp');
161
- expect(metricsData).toHaveProperty('metric');
162
- expect(metricsData).toHaveProperty('value');
163
- expect(metricsData.labels).toHaveProperty('service');
164
- });
165
- });
166
-
167
- describe('Error Tracking E2E', () => {
168
- test('should track errors through monitoring system', async () => {
169
- if (!channel) {
170
- console.log('Skipping - no channel available');
171
- return;
172
- }
173
-
174
- // Send invalid cookbook to trigger error
175
- const invalidCookbook = {
176
- // Missing required fields
177
- type: 'invalid'
178
- };
179
-
180
- const errorQueue = await channel.assertQueue('', { exclusive: true });
181
- const correlationId = 'error-test-1';
182
-
183
- await channel.sendToQueue(
184
- 'hello-service',
185
- Buffer.from(JSON.stringify(invalidCookbook)),
186
- {
187
- correlationId,
188
- replyTo: errorQueue.queue
189
- }
190
- );
191
-
192
- // Wait for error response
193
- const errorResponse = await new Promise((resolve) => {
194
- const timeout = setTimeout(() => {
195
- resolve({ error: 'timeout' });
196
- }, 2000);
197
-
198
- channel.consume(errorQueue.queue, (msg) => {
199
- if (msg && msg.properties.correlationId === correlationId) {
200
- clearTimeout(timeout);
201
- resolve(JSON.parse(msg.content.toString()));
202
- }
203
- }, { noAck: true });
204
- });
205
-
206
- // Should receive error response or timeout
207
- expect(errorResponse).toBeDefined();
208
- });
209
- });
210
-
211
- describe('Performance Monitoring E2E', () => {
212
- test('should measure end-to-end latency', async () => {
213
- if (!channel) {
214
- console.log('Skipping - no channel available');
215
- return;
216
- }
217
-
218
- const startTime = Date.now();
219
-
220
- const cookbook = {
221
- id: 'perf-test-1',
222
- type: 'hello',
223
- name: 'good-day',
224
- version: '1.0.0'
225
- };
226
-
227
- const perfQueue = await channel.assertQueue('', { exclusive: true });
228
- const correlationId = 'perf-corr-1';
229
-
230
- await channel.sendToQueue(
231
- 'hello-service',
232
- Buffer.from(JSON.stringify(cookbook)),
233
- {
234
- correlationId,
235
- replyTo: perfQueue.queue
236
- }
237
- );
238
-
239
- await new Promise((resolve) => {
240
- const timeout = setTimeout(resolve, 2000);
241
-
242
- channel.consume(perfQueue.queue, (msg) => {
243
- if (msg && msg.properties.correlationId === correlationId) {
244
- clearTimeout(timeout);
245
- resolve();
246
- }
247
- }, { noAck: true });
248
- });
249
-
250
- const latency = Date.now() - startTime;
251
-
252
- // E2E latency should be reasonable
253
- expect(latency).toBeLessThan(5000);
254
-
255
- console.log(`E2E latency: ${latency}ms`);
256
- });
257
-
258
- test('should handle concurrent requests', async () => {
259
- if (!channel) {
260
- console.log('Skipping - no channel available');
261
- return;
262
- }
263
-
264
- const concurrentCount = 10;
265
- const promises = [];
266
-
267
- for (let i = 0; i < concurrentCount; i++) {
268
- const cookbook = {
269
- id: `concurrent-${i}`,
270
- type: 'hello',
271
- name: 'good-day',
272
- version: '1.0.0'
273
- };
274
-
275
- const promise = channel.sendToQueue(
276
- 'hello-service',
277
- Buffer.from(JSON.stringify(cookbook))
278
- );
279
-
280
- promises.push(promise);
281
- }
282
-
283
- await Promise.all(promises);
284
-
285
- // All messages should be sent successfully
286
- expect(promises.length).toBe(concurrentCount);
287
- });
288
- });
289
-
290
- describe('Monitoring Health Check', () => {
291
- test('should verify monitoring infrastructure is healthy', async () => {
292
- // Check RabbitMQ connection
293
- expect(connection).toBeDefined();
294
-
295
- // Check if monitoring exchanges exist
296
- if (channel) {
297
- try {
298
- await channel.checkExchange('telemetry.exchange');
299
- console.log('Telemetry exchange exists');
300
- } catch (error) {
301
- console.log('Telemetry exchange not found (expected in test env)');
302
- }
303
- }
304
-
305
- // Check service health endpoint if available
306
- try {
307
- const health = await axios.get(`${HELLO_SERVICE_URL}/health`);
308
- expect(health.status).toBe(200);
309
- expect(health.data.status).toBe('ok');
310
- } catch (error) {
311
- console.log('Service health check not available');
312
- }
313
- });
314
- });
315
- });