@onlineapps/conn-base-hub 1.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 +6 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +60 -0
- package/coverage/coverage-final.json +2 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +116 -0
- package/coverage/index.js.html +904 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +116 -0
- package/coverage/lcov-report/index.js.html +904 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +145 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/jest.integration.config.js +9 -0
- package/package.json +36 -0
- package/src/config.js +0 -0
- package/src/index.js +274 -0
- package/test/component/hub-integration.test.js +413 -0
- package/test/unit/hub.test.js +351 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Mock all external dependencies before requiring the module
|
|
4
|
+
jest.mock('@onlineapps/connector-mq-client', () => {
|
|
5
|
+
return jest.fn().mockImplementation(() => ({
|
|
6
|
+
connect: jest.fn().mockResolvedValue(),
|
|
7
|
+
publish: jest.fn().mockResolvedValue(),
|
|
8
|
+
subscribe: jest.fn().mockResolvedValue(),
|
|
9
|
+
close: jest.fn().mockResolvedValue()
|
|
10
|
+
}));
|
|
11
|
+
}, { virtual: true });
|
|
12
|
+
|
|
13
|
+
jest.mock('@onlineapps/connector-registry-client', () => ({
|
|
14
|
+
ServiceRegistryClient: jest.fn().mockImplementation(() => ({
|
|
15
|
+
register: jest.fn().mockResolvedValue(),
|
|
16
|
+
deregister: jest.fn().mockResolvedValue(),
|
|
17
|
+
discover: jest.fn().mockResolvedValue([]),
|
|
18
|
+
emit: jest.fn()
|
|
19
|
+
}))
|
|
20
|
+
}), { virtual: true });
|
|
21
|
+
|
|
22
|
+
jest.mock('@onlineapps/connector-cookbook', () => ({
|
|
23
|
+
validateCookbook: jest.fn(),
|
|
24
|
+
parseCookbook: jest.fn(),
|
|
25
|
+
executeCookbook: jest.fn()
|
|
26
|
+
}), { virtual: true });
|
|
27
|
+
|
|
28
|
+
jest.mock('@onlineapps/connector-storage', () => {
|
|
29
|
+
return jest.fn().mockImplementation(() => ({
|
|
30
|
+
upload: jest.fn().mockResolvedValue({ etag: '123' }),
|
|
31
|
+
download: jest.fn().mockResolvedValue(Buffer.from('test')),
|
|
32
|
+
delete: jest.fn().mockResolvedValue(),
|
|
33
|
+
list: jest.fn().mockResolvedValue([])
|
|
34
|
+
}));
|
|
35
|
+
}, { virtual: true });
|
|
36
|
+
|
|
37
|
+
jest.mock('@onlineapps/connector-logger', () => {
|
|
38
|
+
return jest.fn().mockImplementation((config) => ({
|
|
39
|
+
info: jest.fn(),
|
|
40
|
+
error: jest.fn(),
|
|
41
|
+
warn: jest.fn(),
|
|
42
|
+
debug: jest.fn(),
|
|
43
|
+
api: { info: jest.fn(), error: jest.fn() },
|
|
44
|
+
mq: { info: jest.fn(), error: jest.fn() },
|
|
45
|
+
workflow: { info: jest.fn(), error: jest.fn() },
|
|
46
|
+
registry: { info: jest.fn(), error: jest.fn() },
|
|
47
|
+
close: jest.fn().mockResolvedValue()
|
|
48
|
+
}));
|
|
49
|
+
}, { virtual: true });
|
|
50
|
+
|
|
51
|
+
describe('Hub Connector Component Tests', () => {
|
|
52
|
+
let hub;
|
|
53
|
+
let mockConfig;
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
jest.clearAllMocks();
|
|
57
|
+
|
|
58
|
+
// Clear require cache to get fresh module
|
|
59
|
+
delete require.cache[require.resolve('../../src/index.js')];
|
|
60
|
+
|
|
61
|
+
// Now require the hub
|
|
62
|
+
hub = require('../../src/index.js');
|
|
63
|
+
|
|
64
|
+
mockConfig = {
|
|
65
|
+
serviceName: 'test-service',
|
|
66
|
+
version: '1.0.0',
|
|
67
|
+
amqpUrl: 'amqp://localhost',
|
|
68
|
+
registry: {
|
|
69
|
+
registryUrl: 'http://registry:3000'
|
|
70
|
+
},
|
|
71
|
+
mq: {
|
|
72
|
+
queue: 'test-queue'
|
|
73
|
+
},
|
|
74
|
+
storage: {
|
|
75
|
+
endpoint: 'http://minio:9000',
|
|
76
|
+
accessKey: 'test',
|
|
77
|
+
secretKey: 'test'
|
|
78
|
+
},
|
|
79
|
+
logger: {
|
|
80
|
+
level: 'info'
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
jest.restoreAllMocks();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('Module Exports', () => {
|
|
90
|
+
it('should export all required connectors', () => {
|
|
91
|
+
expect(hub.MQClient).toBeDefined();
|
|
92
|
+
expect(hub.ServiceRegistryClient).toBeDefined();
|
|
93
|
+
expect(hub.StorageConnector).toBeDefined();
|
|
94
|
+
expect(hub.createLogger).toBeDefined();
|
|
95
|
+
expect(hub.createMicroservice).toBeDefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should export cookbook functions', () => {
|
|
99
|
+
expect(hub.validateCookbook).toBeDefined();
|
|
100
|
+
expect(hub.parseCookbook).toBeDefined();
|
|
101
|
+
expect(hub.executeCookbook).toBeDefined();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('createMicroservice Factory', () => {
|
|
106
|
+
it('should create microservice with all components', () => {
|
|
107
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
108
|
+
|
|
109
|
+
expect(microservice).toHaveProperty('logger');
|
|
110
|
+
expect(microservice).toHaveProperty('registry');
|
|
111
|
+
expect(microservice).toHaveProperty('mq');
|
|
112
|
+
expect(microservice).toHaveProperty('storage');
|
|
113
|
+
// Note: cookbook is not a property on microservice, it's exported separately
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should create microservice with partial config', () => {
|
|
117
|
+
const partialConfig = {
|
|
118
|
+
serviceName: 'partial-service',
|
|
119
|
+
version: '1.0.0',
|
|
120
|
+
mq: {
|
|
121
|
+
queue: 'partial-queue'
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const microservice = hub.createMicroservice(partialConfig);
|
|
126
|
+
|
|
127
|
+
expect(microservice.logger).toBeDefined();
|
|
128
|
+
expect(microservice.mq).toBeDefined();
|
|
129
|
+
expect(microservice.registry).toBeNull();
|
|
130
|
+
expect(microservice.storage).toBeNull();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should use environment variables as fallback', () => {
|
|
134
|
+
process.env.RABBITMQ_URL = 'amqp://env-rabbit';
|
|
135
|
+
process.env.MINIO_ENDPOINT = 'http://env-minio:9000';
|
|
136
|
+
process.env.MINIO_ACCESS_KEY = 'env-access';
|
|
137
|
+
process.env.MINIO_SECRET_KEY = 'env-secret';
|
|
138
|
+
|
|
139
|
+
const microservice = hub.createMicroservice({
|
|
140
|
+
serviceName: 'env-service',
|
|
141
|
+
version: '1.0.0',
|
|
142
|
+
mq: {},
|
|
143
|
+
storage: {}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
expect(microservice.mq).toBeDefined();
|
|
147
|
+
expect(microservice.storage).toBeDefined();
|
|
148
|
+
|
|
149
|
+
delete process.env.RABBITMQ_URL;
|
|
150
|
+
delete process.env.MINIO_ENDPOINT;
|
|
151
|
+
delete process.env.MINIO_ACCESS_KEY;
|
|
152
|
+
delete process.env.MINIO_SECRET_KEY;
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should handle initialization errors gracefully', () => {
|
|
156
|
+
const invalidConfig = {
|
|
157
|
+
serviceName: null,
|
|
158
|
+
version: undefined
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
expect(() => {
|
|
162
|
+
hub.createMicroservice(invalidConfig);
|
|
163
|
+
}).not.toThrow();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('Logger Integration', () => {
|
|
168
|
+
it('should create logger with correct configuration', () => {
|
|
169
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
170
|
+
|
|
171
|
+
expect(microservice.logger).toBeDefined();
|
|
172
|
+
expect(microservice.logger.info).toBeDefined();
|
|
173
|
+
expect(microservice.logger.error).toBeDefined();
|
|
174
|
+
expect(microservice.logger.warn).toBeDefined();
|
|
175
|
+
expect(microservice.logger.debug).toBeDefined();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should handle logger operations', () => {
|
|
179
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
180
|
+
|
|
181
|
+
expect(() => {
|
|
182
|
+
microservice.logger.info('Test info');
|
|
183
|
+
microservice.logger.error('Test error');
|
|
184
|
+
microservice.logger.warn('Test warning');
|
|
185
|
+
microservice.logger.debug('Test debug');
|
|
186
|
+
}).not.toThrow();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('MQ Client Integration', () => {
|
|
191
|
+
it('should initialize MQ client with correct config', () => {
|
|
192
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
193
|
+
|
|
194
|
+
expect(microservice.mq).toBeDefined();
|
|
195
|
+
expect(microservice.mq.connect).toBeDefined();
|
|
196
|
+
expect(microservice.mq.publish).toBeDefined();
|
|
197
|
+
expect(microservice.mq.subscribe).toBeDefined();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('should handle MQ operations', async () => {
|
|
201
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
202
|
+
|
|
203
|
+
await expect(microservice.mq.connect()).resolves.not.toThrow();
|
|
204
|
+
await expect(microservice.mq.publish('test-queue', { test: 'message' })).resolves.not.toThrow();
|
|
205
|
+
|
|
206
|
+
const handler = jest.fn();
|
|
207
|
+
await expect(microservice.mq.subscribe('test-queue', handler)).resolves.not.toThrow();
|
|
208
|
+
await expect(microservice.mq.close()).resolves.not.toThrow();
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('Service Registry Integration', () => {
|
|
213
|
+
it('should initialize registry client with correct config', () => {
|
|
214
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
215
|
+
|
|
216
|
+
expect(microservice.registry).toBeDefined();
|
|
217
|
+
expect(microservice.registry.register).toBeDefined();
|
|
218
|
+
expect(microservice.registry.discover).toBeDefined();
|
|
219
|
+
expect(microservice.registry.deregister).toBeDefined();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should handle service registration', async () => {
|
|
223
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
224
|
+
|
|
225
|
+
await expect(
|
|
226
|
+
microservice.registry.register({
|
|
227
|
+
name: 'test-service',
|
|
228
|
+
version: '1.0.0',
|
|
229
|
+
endpoints: ['http://localhost:3000']
|
|
230
|
+
})
|
|
231
|
+
).resolves.not.toThrow();
|
|
232
|
+
|
|
233
|
+
const services = await microservice.registry.discover('test-service');
|
|
234
|
+
expect(services).toBeDefined();
|
|
235
|
+
expect(Array.isArray(services)).toBe(true);
|
|
236
|
+
|
|
237
|
+
await expect(microservice.registry.deregister()).resolves.not.toThrow();
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('Storage Integration', () => {
|
|
242
|
+
it('should initialize storage connector with correct config', () => {
|
|
243
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
244
|
+
|
|
245
|
+
expect(microservice.storage).toBeDefined();
|
|
246
|
+
expect(microservice.storage.upload).toBeDefined();
|
|
247
|
+
expect(microservice.storage.download).toBeDefined();
|
|
248
|
+
expect(microservice.storage.delete).toBeDefined();
|
|
249
|
+
expect(microservice.storage.list).toBeDefined();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should handle storage operations', async () => {
|
|
253
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
254
|
+
|
|
255
|
+
const buffer = Buffer.from('test data');
|
|
256
|
+
const result = await microservice.storage.upload('test-bucket', 'test-file', buffer);
|
|
257
|
+
expect(result).toBeDefined();
|
|
258
|
+
expect(result.etag).toBe('123');
|
|
259
|
+
|
|
260
|
+
const downloaded = await microservice.storage.download('test-bucket', 'test-file');
|
|
261
|
+
expect(downloaded).toBeDefined();
|
|
262
|
+
expect(Buffer.isBuffer(downloaded)).toBe(true);
|
|
263
|
+
|
|
264
|
+
await expect(microservice.storage.delete('test-bucket', 'test-file')).resolves.not.toThrow();
|
|
265
|
+
|
|
266
|
+
const list = await microservice.storage.list('test-bucket');
|
|
267
|
+
expect(Array.isArray(list)).toBe(true);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe('Cookbook Integration', () => {
|
|
272
|
+
it('should provide cookbook functions', () => {
|
|
273
|
+
expect(hub.validateCookbook).toBeDefined();
|
|
274
|
+
expect(hub.parseCookbook).toBeDefined();
|
|
275
|
+
expect(hub.executeCookbook).toBeDefined();
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should handle cookbook operations', () => {
|
|
279
|
+
const cookbook = {
|
|
280
|
+
version: '1.0',
|
|
281
|
+
name: 'test-cookbook',
|
|
282
|
+
steps: []
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
expect(() => hub.validateCookbook(cookbook)).not.toThrow();
|
|
286
|
+
expect(() => hub.parseCookbook('yaml content')).not.toThrow();
|
|
287
|
+
expect(() => hub.executeCookbook(cookbook, {})).not.toThrow();
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
describe('Complete Microservice Lifecycle', () => {
|
|
292
|
+
it('should initialize, operate and cleanup microservice', async () => {
|
|
293
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
294
|
+
|
|
295
|
+
// Initialize
|
|
296
|
+
await microservice.mq.connect();
|
|
297
|
+
await microservice.registry.register({
|
|
298
|
+
name: mockConfig.serviceName,
|
|
299
|
+
version: mockConfig.version
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Operate
|
|
303
|
+
microservice.logger.info('Service started');
|
|
304
|
+
await microservice.mq.publish('events', { type: 'started' });
|
|
305
|
+
|
|
306
|
+
// Cleanup
|
|
307
|
+
await microservice.registry.deregister();
|
|
308
|
+
await microservice.mq.close();
|
|
309
|
+
|
|
310
|
+
if (microservice.logger.close) {
|
|
311
|
+
await microservice.logger.close();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
expect(true).toBe(true); // Test completed without errors
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it('should handle errors during lifecycle', async () => {
|
|
318
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
319
|
+
|
|
320
|
+
// Simulate connection error
|
|
321
|
+
microservice.mq.connect = jest.fn().mockRejectedValue(new Error('Connection failed'));
|
|
322
|
+
|
|
323
|
+
await expect(microservice.mq.connect()).rejects.toThrow('Connection failed');
|
|
324
|
+
|
|
325
|
+
// Should still be able to use logger
|
|
326
|
+
expect(() => {
|
|
327
|
+
microservice.logger.error('Connection failed');
|
|
328
|
+
}).not.toThrow();
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
describe('Environment-specific Configuration', () => {
|
|
333
|
+
it('should adapt to development environment', () => {
|
|
334
|
+
const devConfig = {
|
|
335
|
+
...mockConfig,
|
|
336
|
+
environment: 'development',
|
|
337
|
+
logger: {
|
|
338
|
+
level: 'debug',
|
|
339
|
+
pretty: true
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const microservice = hub.createMicroservice(devConfig);
|
|
344
|
+
|
|
345
|
+
expect(microservice.logger).toBeDefined();
|
|
346
|
+
expect(microservice.logger.debug).toBeDefined();
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it('should adapt to production environment', () => {
|
|
350
|
+
const prodConfig = {
|
|
351
|
+
...mockConfig,
|
|
352
|
+
environment: 'production',
|
|
353
|
+
logger: {
|
|
354
|
+
level: 'error',
|
|
355
|
+
json: true
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const microservice = hub.createMicroservice(prodConfig);
|
|
360
|
+
|
|
361
|
+
expect(microservice.logger).toBeDefined();
|
|
362
|
+
expect(microservice.logger.error).toBeDefined();
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
describe('Error Handling', () => {
|
|
367
|
+
it('should handle missing configuration gracefully', () => {
|
|
368
|
+
const invalidConfig = {
|
|
369
|
+
// Missing serviceName
|
|
370
|
+
version: '1.0.0'
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const microservice = hub.createMicroservice(invalidConfig);
|
|
374
|
+
|
|
375
|
+
// Should still create microservice but with limited functionality
|
|
376
|
+
expect(microservice).toBeDefined();
|
|
377
|
+
expect(microservice.logger).toBeDefined();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('should handle null configuration sections', () => {
|
|
381
|
+
const configWithNulls = {
|
|
382
|
+
serviceName: 'test',
|
|
383
|
+
version: '1.0.0',
|
|
384
|
+
registry: null,
|
|
385
|
+
mq: null,
|
|
386
|
+
storage: null
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
const microservice = hub.createMicroservice(configWithNulls);
|
|
390
|
+
|
|
391
|
+
expect(microservice.logger).toBeDefined();
|
|
392
|
+
expect(microservice.registry).toBeNull();
|
|
393
|
+
expect(microservice.mq).toBeNull();
|
|
394
|
+
expect(microservice.storage).toBeNull();
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
describe('Utility Functions', () => {
|
|
399
|
+
it('should provide convenience methods', async () => {
|
|
400
|
+
const microservice = hub.createMicroservice(mockConfig);
|
|
401
|
+
|
|
402
|
+
// Test start method if available
|
|
403
|
+
if (microservice.start) {
|
|
404
|
+
await expect(microservice.start()).resolves.not.toThrow();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Test stop method if available
|
|
408
|
+
if (microservice.stop) {
|
|
409
|
+
await expect(microservice.stop()).resolves.not.toThrow();
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
});
|