@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,353 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CookbookTestRunner = require('../../src/CookbookTestRunner');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
describe('CookbookTestRunner @unit', () => {
|
|
8
|
+
let runner;
|
|
9
|
+
const testServicePath = path.join(__dirname, '../fixtures/test-service');
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
runner = new CookbookTestRunner({
|
|
13
|
+
serviceName: 'test-service',
|
|
14
|
+
serviceUrl: 'http://localhost:3000',
|
|
15
|
+
servicePath: testServicePath,
|
|
16
|
+
mockInfrastructure: true
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('constructor', () => {
|
|
21
|
+
test('should initialize with default options', () => {
|
|
22
|
+
const defaultRunner = new CookbookTestRunner({
|
|
23
|
+
serviceName: 'test'
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
expect(defaultRunner.serviceName).toBe('test');
|
|
27
|
+
expect(defaultRunner.serviceUrl).toBe('http://localhost:3000');
|
|
28
|
+
expect(defaultRunner.mockInfrastructure).toBe(true);
|
|
29
|
+
expect(defaultRunner.timeout).toBe(30000);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('should accept custom options', () => {
|
|
33
|
+
const customRunner = new CookbookTestRunner({
|
|
34
|
+
serviceName: 'custom',
|
|
35
|
+
serviceUrl: 'http://localhost:5000',
|
|
36
|
+
mockInfrastructure: false,
|
|
37
|
+
timeout: 60000
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(customRunner.serviceName).toBe('custom');
|
|
41
|
+
expect(customRunner.serviceUrl).toBe('http://localhost:5000');
|
|
42
|
+
expect(customRunner.mockInfrastructure).toBe(false);
|
|
43
|
+
expect(customRunner.timeout).toBe(60000);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('validateCookbook()', () => {
|
|
48
|
+
test('should validate valid cookbook', () => {
|
|
49
|
+
const validCookbook = {
|
|
50
|
+
version: '1.0.0',
|
|
51
|
+
steps: [{
|
|
52
|
+
id: 'test-1',
|
|
53
|
+
service: 'test-service',
|
|
54
|
+
operation: 'test-op',
|
|
55
|
+
input: {}
|
|
56
|
+
}]
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
expect(() => runner.validateCookbook(validCookbook)).not.toThrow();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('should reject cookbook without steps', () => {
|
|
63
|
+
const invalidCookbook = {
|
|
64
|
+
version: '1.0.0'
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
expect(() => runner.validateCookbook(invalidCookbook))
|
|
68
|
+
.toThrow('Cookbook must have steps array');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should reject cookbook with empty steps', () => {
|
|
72
|
+
const invalidCookbook = {
|
|
73
|
+
version: '1.0.0',
|
|
74
|
+
steps: []
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
expect(() => runner.validateCookbook(invalidCookbook))
|
|
78
|
+
.toThrow('Cookbook must have at least one step');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('should reject step without service', () => {
|
|
82
|
+
const invalidCookbook = {
|
|
83
|
+
version: '1.0.0',
|
|
84
|
+
steps: [{
|
|
85
|
+
operation: 'test-op'
|
|
86
|
+
}]
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
expect(() => runner.validateCookbook(invalidCookbook))
|
|
90
|
+
.toThrow('Step must have service');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('should reject step without operation', () => {
|
|
94
|
+
const invalidCookbook = {
|
|
95
|
+
version: '1.0.0',
|
|
96
|
+
steps: [{
|
|
97
|
+
service: 'test-service'
|
|
98
|
+
}]
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
expect(() => runner.validateCookbook(invalidCookbook))
|
|
102
|
+
.toThrow('Step must have operation');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('hasExpectClauses()', () => {
|
|
107
|
+
test('should detect cookbook with expect clauses', () => {
|
|
108
|
+
const cookbook = {
|
|
109
|
+
steps: [{
|
|
110
|
+
service: 'test',
|
|
111
|
+
operation: 'op',
|
|
112
|
+
expect: { status: 'success' }
|
|
113
|
+
}]
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
expect(runner.hasExpectClauses(cookbook)).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('should detect cookbook without expect clauses', () => {
|
|
120
|
+
const cookbook = {
|
|
121
|
+
steps: [{
|
|
122
|
+
service: 'test',
|
|
123
|
+
operation: 'op'
|
|
124
|
+
}]
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
expect(runner.hasExpectClauses(cookbook)).toBe(false);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('validateOutput()', () => {
|
|
132
|
+
test('should pass valid type check', () => {
|
|
133
|
+
const expected = {
|
|
134
|
+
message: { type: 'string' }
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const actual = {
|
|
138
|
+
message: 'Hello'
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const errors = runner.validateOutput(expected, actual);
|
|
142
|
+
|
|
143
|
+
expect(errors).toHaveLength(0);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('should fail invalid type check', () => {
|
|
147
|
+
const expected = {
|
|
148
|
+
count: { type: 'number' }
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const actual = {
|
|
152
|
+
count: 'not a number'
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const errors = runner.validateOutput(expected, actual);
|
|
156
|
+
|
|
157
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
158
|
+
expect(errors[0]).toContain('expected type number');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('should pass contains check', () => {
|
|
162
|
+
const expected = {
|
|
163
|
+
message: { contains: 'Hello' }
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const actual = {
|
|
167
|
+
message: 'Hello World'
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const errors = runner.validateOutput(expected, actual);
|
|
171
|
+
|
|
172
|
+
expect(errors).toHaveLength(0);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('should fail contains check', () => {
|
|
176
|
+
const expected = {
|
|
177
|
+
message: { contains: 'Goodbye' }
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const actual = {
|
|
181
|
+
message: 'Hello World'
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const errors = runner.validateOutput(expected, actual);
|
|
185
|
+
|
|
186
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
187
|
+
expect(errors[0]).toContain('expected to contain');
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test('should pass pattern check', () => {
|
|
191
|
+
const expected = {
|
|
192
|
+
timestamp: { pattern: '^\\d{4}-\\d{2}-\\d{2}T' }
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const actual = {
|
|
196
|
+
timestamp: '2025-09-30T12:00:00Z'
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const errors = runner.validateOutput(expected, actual);
|
|
200
|
+
|
|
201
|
+
expect(errors).toHaveLength(0);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('should fail pattern check', () => {
|
|
205
|
+
const expected = {
|
|
206
|
+
code: { pattern: '^[A-Z]{3}$' }
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const actual = {
|
|
210
|
+
code: 'invalid'
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const errors = runner.validateOutput(expected, actual);
|
|
214
|
+
|
|
215
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
216
|
+
expect(errors[0]).toContain('does not match pattern');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test('should pass equals check', () => {
|
|
220
|
+
const expected = {
|
|
221
|
+
status: { equals: 'active' }
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const actual = {
|
|
225
|
+
status: 'active'
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const errors = runner.validateOutput(expected, actual);
|
|
229
|
+
|
|
230
|
+
expect(errors).toHaveLength(0);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test('should fail equals check', () => {
|
|
234
|
+
const expected = {
|
|
235
|
+
status: { equals: 'active' }
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const actual = {
|
|
239
|
+
status: 'inactive'
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const errors = runner.validateOutput(expected, actual);
|
|
243
|
+
|
|
244
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
245
|
+
expect(errors[0]).toContain('expected active');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test('should pass range check', () => {
|
|
249
|
+
const expected = {
|
|
250
|
+
count: { min: 0, max: 100 }
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const actual = {
|
|
254
|
+
count: 50
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
const errors = runner.validateOutput(expected, actual);
|
|
258
|
+
|
|
259
|
+
expect(errors).toHaveLength(0);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test('should fail min check', () => {
|
|
263
|
+
const expected = {
|
|
264
|
+
count: { min: 10 }
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const actual = {
|
|
268
|
+
count: 5
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const errors = runner.validateOutput(expected, actual);
|
|
272
|
+
|
|
273
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
274
|
+
expect(errors[0]).toContain('less than min');
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('should fail max check', () => {
|
|
278
|
+
const expected = {
|
|
279
|
+
count: { max: 100 }
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const actual = {
|
|
283
|
+
count: 150
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const errors = runner.validateOutput(expected, actual);
|
|
287
|
+
|
|
288
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
289
|
+
expect(errors[0]).toContain('exceeds max');
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('should check field existence', () => {
|
|
293
|
+
const expected = {
|
|
294
|
+
optional: { exists: false },
|
|
295
|
+
required: { exists: true }
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const actual = {
|
|
299
|
+
required: 'value'
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const errors = runner.validateOutput(expected, actual);
|
|
303
|
+
|
|
304
|
+
expect(errors).toHaveLength(0);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test('should detect missing required field', () => {
|
|
308
|
+
const expected = {
|
|
309
|
+
required: { exists: true }
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
const actual = {};
|
|
313
|
+
|
|
314
|
+
const errors = runner.validateOutput(expected, actual);
|
|
315
|
+
|
|
316
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
317
|
+
expect(errors[0]).toContain('expected to exist');
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
describe('getResults()', () => {
|
|
322
|
+
test('should return initialized results', () => {
|
|
323
|
+
const results = runner.getResults();
|
|
324
|
+
|
|
325
|
+
expect(results).toEqual({
|
|
326
|
+
total: 0,
|
|
327
|
+
passed: 0,
|
|
328
|
+
failed: 0,
|
|
329
|
+
duration: 0,
|
|
330
|
+
steps: []
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
describe('resetResults()', () => {
|
|
336
|
+
test('should reset results', () => {
|
|
337
|
+
// Simulate some test runs
|
|
338
|
+
runner.results.total = 5;
|
|
339
|
+
runner.results.passed = 3;
|
|
340
|
+
runner.results.failed = 2;
|
|
341
|
+
|
|
342
|
+
runner.resetResults();
|
|
343
|
+
|
|
344
|
+
expect(runner.results).toEqual({
|
|
345
|
+
total: 0,
|
|
346
|
+
passed: 0,
|
|
347
|
+
failed: 0,
|
|
348
|
+
duration: 0,
|
|
349
|
+
steps: []
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
});
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MockMQClient = require('../../src/mocks/MockMQClient');
|
|
4
|
+
|
|
5
|
+
describe('MockMQClient @unit', () => {
|
|
6
|
+
let mqClient;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mqClient = new MockMQClient();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe('Connection Management', () => {
|
|
13
|
+
it('should connect successfully', async () => {
|
|
14
|
+
expect(mqClient.isConnected).toBe(false);
|
|
15
|
+
await mqClient.connect();
|
|
16
|
+
expect(mqClient.isConnected).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should disconnect successfully', async () => {
|
|
20
|
+
await mqClient.connect();
|
|
21
|
+
expect(mqClient.isConnected).toBe(true);
|
|
22
|
+
await mqClient.disconnect();
|
|
23
|
+
expect(mqClient.isConnected).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should clear consumers on disconnect', async () => {
|
|
27
|
+
await mqClient.connect();
|
|
28
|
+
await mqClient.consume('test-queue', jest.fn());
|
|
29
|
+
expect(Object.keys(mqClient.consumers)).toHaveLength(1);
|
|
30
|
+
await mqClient.disconnect();
|
|
31
|
+
expect(Object.keys(mqClient.consumers)).toHaveLength(0);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('Publishing Messages', () => {
|
|
36
|
+
beforeEach(async () => {
|
|
37
|
+
await mqClient.connect();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should publish message to queue', async () => {
|
|
41
|
+
const message = { test: 'data' };
|
|
42
|
+
await mqClient.publish('test-queue', message);
|
|
43
|
+
|
|
44
|
+
const messages = mqClient.getMessages('test-queue');
|
|
45
|
+
expect(messages).toHaveLength(1);
|
|
46
|
+
expect(messages[0]).toEqual(message);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should track published messages', async () => {
|
|
50
|
+
await mqClient.publish('queue1', { msg: 1 });
|
|
51
|
+
await mqClient.publish('queue2', { msg: 2 });
|
|
52
|
+
|
|
53
|
+
const allPublished = mqClient.getPublishedMessages();
|
|
54
|
+
expect(allPublished).toHaveLength(2);
|
|
55
|
+
|
|
56
|
+
const queue1Messages = mqClient.getPublishedMessages('queue1');
|
|
57
|
+
expect(queue1Messages).toHaveLength(1);
|
|
58
|
+
expect(queue1Messages[0].message).toEqual({ msg: 1 });
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should throw error when not connected', async () => {
|
|
62
|
+
await mqClient.disconnect();
|
|
63
|
+
await expect(mqClient.publish('test', {})).rejects.toThrow('Not connected to MQ');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should include message options', async () => {
|
|
67
|
+
const options = { priority: 1, persistent: true };
|
|
68
|
+
await mqClient.publish('test-queue', { test: 'data' }, options);
|
|
69
|
+
|
|
70
|
+
const published = mqClient.getPublishedMessages()[0];
|
|
71
|
+
expect(published.options).toEqual(options);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe('Consuming Messages', () => {
|
|
76
|
+
let callback;
|
|
77
|
+
|
|
78
|
+
beforeEach(async () => {
|
|
79
|
+
callback = jest.fn();
|
|
80
|
+
await mqClient.connect();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should register consumer', async () => {
|
|
84
|
+
await mqClient.consume('test-queue', callback);
|
|
85
|
+
expect(mqClient.consumers['test-queue']).toBeDefined();
|
|
86
|
+
expect(mqClient.consumers['test-queue'].callback).toBe(callback);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should process existing messages when consuming', async () => {
|
|
90
|
+
await mqClient.publish('test-queue', { msg: 1 });
|
|
91
|
+
await mqClient.publish('test-queue', { msg: 2 });
|
|
92
|
+
|
|
93
|
+
await mqClient.consume('test-queue', callback);
|
|
94
|
+
|
|
95
|
+
// Wait for async processing
|
|
96
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
97
|
+
|
|
98
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should trigger consumer on new message', async () => {
|
|
102
|
+
await mqClient.consume('test-queue', callback);
|
|
103
|
+
await mqClient.publish('test-queue', { test: 'data' });
|
|
104
|
+
|
|
105
|
+
// Wait for async processing
|
|
106
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
107
|
+
|
|
108
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
109
|
+
const call = callback.mock.calls[0][0];
|
|
110
|
+
expect(JSON.parse(call.content.toString())).toEqual({ test: 'data' });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should throw error when not connected', async () => {
|
|
114
|
+
await mqClient.disconnect();
|
|
115
|
+
await expect(mqClient.consume('test', jest.fn())).rejects.toThrow('Not connected to MQ');
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('Message Acknowledgement', () => {
|
|
120
|
+
let message;
|
|
121
|
+
|
|
122
|
+
beforeEach(async () => {
|
|
123
|
+
await mqClient.connect();
|
|
124
|
+
message = {
|
|
125
|
+
content: Buffer.from(JSON.stringify({ test: 'data' })),
|
|
126
|
+
fields: { routingKey: 'test-queue' }
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should acknowledge message', async () => {
|
|
131
|
+
await mqClient.ack(message);
|
|
132
|
+
expect(mqClient.acknowledgedMessages).toHaveLength(1);
|
|
133
|
+
expect(mqClient.acknowledgedMessages[0].message).toBe(message);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should reject message without requeue', async () => {
|
|
137
|
+
await mqClient.nack(message, false, false);
|
|
138
|
+
expect(mqClient.rejectedMessages).toHaveLength(1);
|
|
139
|
+
expect(mqClient.rejectedMessages[0].requeue).toBe(false);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should reject and requeue message', async () => {
|
|
143
|
+
await mqClient.nack(message, false, true);
|
|
144
|
+
expect(mqClient.rejectedMessages).toHaveLength(1);
|
|
145
|
+
expect(mqClient.rejectedMessages[0].requeue).toBe(true);
|
|
146
|
+
|
|
147
|
+
const messages = mqClient.getMessages('test-queue');
|
|
148
|
+
expect(messages).toHaveLength(1);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('Statistics and Clearing', () => {
|
|
153
|
+
beforeEach(async () => {
|
|
154
|
+
await mqClient.connect();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should return statistics', async () => {
|
|
158
|
+
await mqClient.publish('queue1', { msg: 1 });
|
|
159
|
+
await mqClient.publish('queue2', { msg: 2 });
|
|
160
|
+
await mqClient.consume('queue1', jest.fn());
|
|
161
|
+
|
|
162
|
+
const stats = mqClient.getStats();
|
|
163
|
+
expect(stats.queues).toEqual(['queue1', 'queue2']);
|
|
164
|
+
expect(stats.messageCount).toBe(2);
|
|
165
|
+
expect(stats.published).toBe(2);
|
|
166
|
+
expect(stats.consumers).toEqual(['queue1']);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should clear all data', async () => {
|
|
170
|
+
await mqClient.publish('test', { msg: 1 });
|
|
171
|
+
await mqClient.ack({ test: 'message' });
|
|
172
|
+
|
|
173
|
+
mqClient.clear();
|
|
174
|
+
|
|
175
|
+
expect(mqClient.getMessages('test')).toHaveLength(0);
|
|
176
|
+
expect(mqClient.publishedMessages).toHaveLength(0);
|
|
177
|
+
expect(mqClient.acknowledgedMessages).toHaveLength(0);
|
|
178
|
+
expect(mqClient.rejectedMessages).toHaveLength(0);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('Delay Simulation', () => {
|
|
183
|
+
it('should simulate delay', async () => {
|
|
184
|
+
const start = Date.now();
|
|
185
|
+
await mqClient.simulateDelay(50);
|
|
186
|
+
const duration = Date.now() - start;
|
|
187
|
+
expect(duration).toBeGreaterThanOrEqual(50);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|