@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.
- package/README.md +30 -1
- package/TESTING_STRATEGY.md +0 -0
- package/docs/DESIGN.md +0 -0
- package/examples/service-wrapper-usage.js +0 -0
- package/examples/three-tier-testing.js +0 -0
- package/jest.config.js +0 -0
- package/onlineapps-conn-e2e-testing-1.0.0.tgz +0 -0
- package/package.json +1 -1
- package/src/CookbookTestRunner.js +4 -4
- package/src/CookbookTestUtils.js +0 -0
- package/src/ServiceReadinessValidator.js +0 -0
- package/src/ServiceTestHarness.js +0 -0
- package/src/ServiceValidator.js +0 -0
- package/src/TestOrchestrator.js +0 -0
- package/src/ValidationOrchestrator.js +29 -22
- package/src/WorkflowTestRunner.js +0 -0
- package/src/helpers/README.md +0 -0
- package/src/helpers/createPreValidationTests.js +0 -0
- package/src/helpers/createServiceReadinessTests.js +0 -0
- package/src/index.js +0 -0
- package/src/mocks/MockMQClient.js +0 -0
- package/src/mocks/MockRegistry.js +0 -0
- package/src/mocks/MockStorage.js +0 -0
- package/src/validators/ServiceStructureValidator.js +0 -0
- package/src/validators/ValidationProofGenerator.js +0 -0
- package/test-mq-flow.js +0 -0
- package/tests/component/testing-framework-integration.test.js +0 -313
- package/tests/integration/ServiceReadiness.test.js +0 -265
- package/tests/monitoring-e2e.test.js +0 -315
- package/tests/run-example.js +0 -257
- package/tests/unit/CookbookTestRunner.test.js +0 -353
- package/tests/unit/MockMQClient.test.js +0 -190
- package/tests/unit/MockRegistry.test.js +0 -233
- package/tests/unit/MockStorage.test.js +0 -257
- package/tests/unit/ServiceValidator.test.js +0 -429
- 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
|
-
});
|