@onlineapps/conn-orch-validator 2.0.0
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/README.md +78 -0
- package/TESTING_STRATEGY.md +92 -0
- package/docs/DESIGN.md +134 -0
- package/examples/service-wrapper-usage.js +250 -0
- package/examples/three-tier-testing.js +144 -0
- package/jest.config.js +23 -0
- package/onlineapps-conn-e2e-testing-1.0.0.tgz +0 -0
- package/package.json +43 -0
- package/src/CookbookTestRunner.js +434 -0
- package/src/CookbookTestUtils.js +237 -0
- package/src/ServiceReadinessValidator.js +430 -0
- package/src/ServiceTestHarness.js +256 -0
- package/src/ServiceValidator.js +387 -0
- package/src/TestOrchestrator.js +727 -0
- package/src/ValidationOrchestrator.js +506 -0
- package/src/WorkflowTestRunner.js +396 -0
- package/src/helpers/README.md +235 -0
- package/src/helpers/createPreValidationTests.js +321 -0
- package/src/helpers/createServiceReadinessTests.js +245 -0
- package/src/index.js +62 -0
- package/src/mocks/MockMQClient.js +176 -0
- package/src/mocks/MockRegistry.js +164 -0
- package/src/mocks/MockStorage.js +186 -0
- package/src/validators/ServiceStructureValidator.js +487 -0
- package/src/validators/ValidationProofGenerator.js +79 -0
- package/test-mq-flow.js +72 -0
- package/test-orchestrator.js +95 -0
- package/tests/component/testing-framework-integration.test.js +313 -0
- package/tests/integration/ServiceReadiness.test.js +265 -0
- package/tests/monitoring-e2e.test.js +315 -0
- package/tests/run-example.js +257 -0
- package/tests/unit/CookbookTestRunner.test.js +353 -0
- package/tests/unit/MockMQClient.test.js +190 -0
- package/tests/unit/MockRegistry.test.js +233 -0
- package/tests/unit/MockStorage.test.js +257 -0
- package/tests/unit/ServiceValidator.test.js +429 -0
- package/tests/unit/WorkflowTestRunner.test.js +546 -0
|
@@ -0,0 +1,315 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simple test runner to demonstrate connector-testing functionality
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { TestOrchestrator, ServiceTestHarness, ServiceReadinessValidator } = require('../src');
|
|
8
|
+
const express = require('express');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
// Create a minimal test service
|
|
12
|
+
function createTestService() {
|
|
13
|
+
const app = express();
|
|
14
|
+
app.use(express.json());
|
|
15
|
+
|
|
16
|
+
app.get('/health', (req, res) => {
|
|
17
|
+
res.json({
|
|
18
|
+
status: 'healthy',
|
|
19
|
+
service: 'test-service',
|
|
20
|
+
timestamp: new Date().toISOString()
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
app.get('/good-day', (req, res) => {
|
|
25
|
+
const name = req.query.name || 'World';
|
|
26
|
+
res.json({
|
|
27
|
+
message: `Good day, ${name}!`,
|
|
28
|
+
timestamp: new Date().toISOString()
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
app.post('/process', (req, res) => {
|
|
33
|
+
res.json({
|
|
34
|
+
processed: true,
|
|
35
|
+
input: req.body,
|
|
36
|
+
output: { transformed: true }
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return app;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Create OpenAPI spec
|
|
44
|
+
function createOpenApiSpec() {
|
|
45
|
+
return {
|
|
46
|
+
openapi: '3.0.0',
|
|
47
|
+
info: {
|
|
48
|
+
title: 'Test Service',
|
|
49
|
+
version: '1.0.0',
|
|
50
|
+
description: 'Service for testing connector-testing'
|
|
51
|
+
},
|
|
52
|
+
paths: {
|
|
53
|
+
'/health': {
|
|
54
|
+
get: {
|
|
55
|
+
operationId: 'healthCheck',
|
|
56
|
+
summary: 'Health check endpoint',
|
|
57
|
+
responses: {
|
|
58
|
+
'200': {
|
|
59
|
+
description: 'Service is healthy',
|
|
60
|
+
content: {
|
|
61
|
+
'application/json': {
|
|
62
|
+
schema: {
|
|
63
|
+
type: 'object',
|
|
64
|
+
properties: {
|
|
65
|
+
status: { type: 'string' },
|
|
66
|
+
service: { type: 'string' },
|
|
67
|
+
timestamp: { type: 'string' }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
'/good-day': {
|
|
77
|
+
get: {
|
|
78
|
+
operationId: 'goodDay',
|
|
79
|
+
summary: 'Greeting endpoint',
|
|
80
|
+
parameters: [
|
|
81
|
+
{
|
|
82
|
+
name: 'name',
|
|
83
|
+
in: 'query',
|
|
84
|
+
required: false,
|
|
85
|
+
schema: { type: 'string' }
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
responses: {
|
|
89
|
+
'200': {
|
|
90
|
+
description: 'Greeting response',
|
|
91
|
+
content: {
|
|
92
|
+
'application/json': {
|
|
93
|
+
schema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
message: { type: 'string' },
|
|
97
|
+
timestamp: { type: 'string' }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
'/process': {
|
|
107
|
+
post: {
|
|
108
|
+
operationId: 'processData',
|
|
109
|
+
summary: 'Process data',
|
|
110
|
+
requestBody: {
|
|
111
|
+
content: {
|
|
112
|
+
'application/json': {
|
|
113
|
+
schema: {
|
|
114
|
+
type: 'object'
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
responses: {
|
|
120
|
+
'200': {
|
|
121
|
+
description: 'Processing result',
|
|
122
|
+
content: {
|
|
123
|
+
'application/json': {
|
|
124
|
+
schema: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
processed: { type: 'boolean' },
|
|
128
|
+
input: { type: 'object' },
|
|
129
|
+
output: { type: 'object' }
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function runTests() {
|
|
143
|
+
console.log('=== Connector-Testing Demo ===\n');
|
|
144
|
+
|
|
145
|
+
const app = createTestService();
|
|
146
|
+
const openApiSpec = createOpenApiSpec();
|
|
147
|
+
|
|
148
|
+
// Test 1: Service Test Harness
|
|
149
|
+
console.log('1. Testing with ServiceTestHarness (with mocks)...\n');
|
|
150
|
+
|
|
151
|
+
const harness = new ServiceTestHarness({
|
|
152
|
+
service: app,
|
|
153
|
+
serviceName: 'test-service',
|
|
154
|
+
openApiSpec,
|
|
155
|
+
mockInfrastructure: true
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await harness.start();
|
|
159
|
+
console.log(` ✓ Service started at: ${harness.baseUrl}`);
|
|
160
|
+
|
|
161
|
+
// Test API calls
|
|
162
|
+
const healthResponse = await harness.callApi('GET', '/health');
|
|
163
|
+
console.log(` ✓ Health check: ${healthResponse.status}`);
|
|
164
|
+
|
|
165
|
+
const greetingResponse = await harness.callApi('GET', '/good-day', null, {});
|
|
166
|
+
console.log(` ✓ Greeting: ${greetingResponse.message}`);
|
|
167
|
+
|
|
168
|
+
// Test workflow simulation
|
|
169
|
+
const workflow = await harness.simulateWorkflow({
|
|
170
|
+
steps: [
|
|
171
|
+
{
|
|
172
|
+
id: 'step1',
|
|
173
|
+
type: 'task',
|
|
174
|
+
service: 'test-service',
|
|
175
|
+
operation: 'healthCheck'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: 'step2',
|
|
179
|
+
type: 'task',
|
|
180
|
+
service: 'test-service',
|
|
181
|
+
operation: 'processData',
|
|
182
|
+
input: { test: 'data' }
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
});
|
|
186
|
+
console.log(` ✓ Workflow completed: ${workflow.completed}`);
|
|
187
|
+
|
|
188
|
+
// Check mock infrastructure
|
|
189
|
+
const messages = harness.getPublishedMessages();
|
|
190
|
+
console.log(` ✓ Messages published: ${messages.length}`);
|
|
191
|
+
|
|
192
|
+
const registration = harness.getServiceRegistration();
|
|
193
|
+
console.log(` ✓ Service registered: ${registration.name}`);
|
|
194
|
+
|
|
195
|
+
await harness.stop();
|
|
196
|
+
console.log(' ✓ Harness stopped\n');
|
|
197
|
+
|
|
198
|
+
// Test 2: Service Readiness Validator
|
|
199
|
+
console.log('2. Testing with ServiceReadinessValidator...\n');
|
|
200
|
+
|
|
201
|
+
// Start service for validation
|
|
202
|
+
const server = app.listen(4444);
|
|
203
|
+
|
|
204
|
+
const validator = new ServiceReadinessValidator();
|
|
205
|
+
const readiness = await validator.validateReadiness({
|
|
206
|
+
name: 'test-service',
|
|
207
|
+
url: 'http://localhost:4444',
|
|
208
|
+
openApiSpec,
|
|
209
|
+
healthEndpoint: '/health'
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
console.log(` ✓ Readiness score: ${readiness.score}/${readiness.maxScore}`);
|
|
213
|
+
console.log(` ✓ Service ready: ${readiness.ready}`);
|
|
214
|
+
console.log(` ✓ Recommendation: ${readiness.recommendation}`);
|
|
215
|
+
|
|
216
|
+
// Show check results
|
|
217
|
+
console.log('\n Check results:');
|
|
218
|
+
for (const [name, check] of Object.entries(readiness.checks)) {
|
|
219
|
+
const status = check.passed ? '✓' : '✗';
|
|
220
|
+
console.log(` ${status} ${name}: ${check.passed ? 'Passed' : 'Failed'}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
server.close();
|
|
224
|
+
console.log('\n ✓ Validator test completed\n');
|
|
225
|
+
|
|
226
|
+
// Test 3: Test Orchestrator (Three-tier testing)
|
|
227
|
+
console.log('3. Testing with TestOrchestrator (three-tier)...\n');
|
|
228
|
+
|
|
229
|
+
const orchestrator = new TestOrchestrator({
|
|
230
|
+
service: app,
|
|
231
|
+
serviceName: 'test-service',
|
|
232
|
+
openApiSpec
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Run only unit tests for speed
|
|
236
|
+
console.log(' Running unit tests with full mocks...');
|
|
237
|
+
const unitResults = await orchestrator.runUnitTests();
|
|
238
|
+
|
|
239
|
+
console.log(` ✓ Unit tests passed: ${unitResults.passed}`);
|
|
240
|
+
console.log(` ✓ Coverage: ${unitResults.coverage}%`);
|
|
241
|
+
console.log(` ✓ Tests run: ${unitResults.tests.length}`);
|
|
242
|
+
|
|
243
|
+
// Show individual test results
|
|
244
|
+
console.log('\n Test results:');
|
|
245
|
+
unitResults.tests.forEach(test => {
|
|
246
|
+
const status = test.passed ? '✓' : '✗';
|
|
247
|
+
console.log(` ${status} ${test.name}`);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
console.log('\n=== All tests completed successfully! ===\n');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Run the tests
|
|
254
|
+
runTests().catch(error => {
|
|
255
|
+
console.error('Test failed:', error);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
});
|