@onlineapps/infrastructure-tools 1.0.0 → 1.0.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/infrastructure-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Infrastructure orchestration utilities for OA Drive infrastructure services (health tracking, queue initialization, service discovery)",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -42,13 +42,24 @@ async function waitForInfrastructureReady(options = {}) {
|
|
|
42
42
|
const checkInterval = options.checkInterval || parseInt(process.env.INFRASTRUCTURE_HEALTH_WAIT_CHECK_INTERVAL) || 5000; // 5 seconds
|
|
43
43
|
const logger = options.logger || console;
|
|
44
44
|
|
|
45
|
+
// Universal logger adapter (supports both console and winston)
|
|
46
|
+
const log = (message) => {
|
|
47
|
+
if (typeof logger.info === 'function') {
|
|
48
|
+
logger.info(message);
|
|
49
|
+
} else if (typeof logger.log === 'function') {
|
|
50
|
+
logger.log(message);
|
|
51
|
+
} else {
|
|
52
|
+
console.log(message);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
45
56
|
const startTime = Date.now();
|
|
46
57
|
let attemptCount = 0;
|
|
47
58
|
let redis = null;
|
|
48
59
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
60
|
+
log('[InfrastructureReady] Waiting for all infrastructure services to be ready...');
|
|
61
|
+
log(`[InfrastructureReady] Redis URL: ${redisUrl}`);
|
|
62
|
+
log(`[InfrastructureReady] Max wait: ${maxWait}ms, Check interval: ${checkInterval}ms`);
|
|
52
63
|
|
|
53
64
|
try {
|
|
54
65
|
// Connect to Redis
|
|
@@ -56,11 +67,11 @@ async function waitForInfrastructureReady(options = {}) {
|
|
|
56
67
|
redis = createClient({ url: redisUrl });
|
|
57
68
|
|
|
58
69
|
redis.on('error', (err) => {
|
|
59
|
-
|
|
70
|
+
log(`[InfrastructureReady] Redis error: ${err.message}`);
|
|
60
71
|
});
|
|
61
72
|
|
|
62
73
|
await redis.connect();
|
|
63
|
-
|
|
74
|
+
log('[InfrastructureReady] Connected to Redis');
|
|
64
75
|
|
|
65
76
|
while (Date.now() - startTime < maxWait) {
|
|
66
77
|
attemptCount++;
|
|
@@ -72,7 +83,7 @@ async function waitForInfrastructureReady(options = {}) {
|
|
|
72
83
|
if (allHealthy === 'true') {
|
|
73
84
|
// All services are UP, we can proceed
|
|
74
85
|
const elapsed = Date.now() - startTime;
|
|
75
|
-
|
|
86
|
+
log(`[InfrastructureReady] ✓ All infrastructure services are ready (took ${elapsed}ms, ${attemptCount} attempts)`);
|
|
76
87
|
|
|
77
88
|
// Optionally log individual service status
|
|
78
89
|
// Note: Service names should match config.infrastructureServices in Registry
|
|
@@ -84,19 +95,19 @@ async function waitForInfrastructureReady(options = {}) {
|
|
|
84
95
|
statuses[serviceName] = JSON.parse(status);
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
|
-
|
|
98
|
+
log(`[InfrastructureReady] Infrastructure status: ${JSON.stringify(statuses, null, 2)}`);
|
|
88
99
|
|
|
89
100
|
return true;
|
|
90
101
|
}
|
|
91
102
|
|
|
92
103
|
// Not all services ready yet
|
|
93
|
-
|
|
94
|
-
|
|
104
|
+
log(`[InfrastructureReady] Attempt ${attemptCount}: Not all services ready (allHealthy: ${allHealthy || 'null'})`);
|
|
105
|
+
log(`[InfrastructureReady] Waiting ${checkInterval}ms before next check...`);
|
|
95
106
|
|
|
96
107
|
} catch (error) {
|
|
97
108
|
// Redis might not be ready yet, or connection issue
|
|
98
|
-
|
|
99
|
-
|
|
109
|
+
log(`[InfrastructureReady] Attempt ${attemptCount}: Redis check failed (${error.message})`);
|
|
110
|
+
log(`[InfrastructureReady] Waiting ${checkInterval}ms before retry...`);
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
// Wait before next check
|
|
@@ -114,7 +125,7 @@ async function waitForInfrastructureReady(options = {}) {
|
|
|
114
125
|
// Clean up Redis connection
|
|
115
126
|
if (redis && redis.isReady) {
|
|
116
127
|
await redis.quit();
|
|
117
|
-
|
|
128
|
+
log('[InfrastructureReady] Redis connection closed');
|
|
118
129
|
}
|
|
119
130
|
}
|
|
120
131
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Integration test for infrastructure-tools
|
|
6
|
+
* Tests all components: healthPublisher, waitForInfrastructureReady, initInfrastructureQueues
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
createHealthPublisher,
|
|
11
|
+
createBaseClientAdapter,
|
|
12
|
+
createAmqplibAdapter,
|
|
13
|
+
waitForInfrastructureReady,
|
|
14
|
+
initInfrastructureQueues
|
|
15
|
+
} = require('./src/index');
|
|
16
|
+
|
|
17
|
+
console.log('🧪 Testing @onlineapps/infrastructure-tools\n');
|
|
18
|
+
|
|
19
|
+
// Test 1: Check exports
|
|
20
|
+
console.log('Test 1: Checking exports...');
|
|
21
|
+
const exportTypes = {
|
|
22
|
+
createHealthPublisher: typeof createHealthPublisher,
|
|
23
|
+
createBaseClientAdapter: typeof createBaseClientAdapter,
|
|
24
|
+
createAmqplibAdapter: typeof createAmqplibAdapter,
|
|
25
|
+
waitForInfrastructureReady: typeof waitForInfrastructureReady,
|
|
26
|
+
initInfrastructureQueues: typeof initInfrastructureQueues
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let allExportsOk = true;
|
|
30
|
+
for (const [name, type] of Object.entries(exportTypes)) {
|
|
31
|
+
if (type !== 'function') {
|
|
32
|
+
console.error(` ✗ ${name} is not a function (got ${type})`);
|
|
33
|
+
allExportsOk = false;
|
|
34
|
+
} else {
|
|
35
|
+
console.log(` ✓ ${name} is a function`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!allExportsOk) {
|
|
40
|
+
console.error('\n❌ Export test failed');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log('✓ All exports are functions\n');
|
|
45
|
+
|
|
46
|
+
// Test 2: Test createHealthPublisher with mock
|
|
47
|
+
async function testHealthPublisher() {
|
|
48
|
+
console.log('Test 2: Testing createHealthPublisher with mock publish function...');
|
|
49
|
+
let publishedMessages = [];
|
|
50
|
+
const mockPublish = async (queueName, data) => {
|
|
51
|
+
publishedMessages.push({ queueName, data, timestamp: new Date().toISOString() });
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const mockGetHealthData = () => ({
|
|
55
|
+
mq: 'healthy',
|
|
56
|
+
redis: 'healthy',
|
|
57
|
+
http: 'healthy'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const publisher = createHealthPublisher({
|
|
62
|
+
serviceName: 'test-service',
|
|
63
|
+
version: '1.0.0',
|
|
64
|
+
publishFunction: mockPublish,
|
|
65
|
+
getHealthData: mockGetHealthData,
|
|
66
|
+
config: {
|
|
67
|
+
queueName: 'test.health.checks',
|
|
68
|
+
publishInterval: 100
|
|
69
|
+
},
|
|
70
|
+
logger: {
|
|
71
|
+
log: () => {},
|
|
72
|
+
warn: () => {},
|
|
73
|
+
error: () => {},
|
|
74
|
+
debug: () => {},
|
|
75
|
+
info: () => {}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Test immediate publish
|
|
80
|
+
await publisher.publishNow();
|
|
81
|
+
if (publishedMessages.length !== 1) {
|
|
82
|
+
throw new Error(`Expected 1 published message, got ${publishedMessages.length}`);
|
|
83
|
+
}
|
|
84
|
+
if (publishedMessages[0].data.serviceName !== 'test-service') {
|
|
85
|
+
throw new Error(`Expected serviceName 'test-service', got '${publishedMessages[0].data.serviceName}'`);
|
|
86
|
+
}
|
|
87
|
+
console.log(' ✓ publishNow() works');
|
|
88
|
+
|
|
89
|
+
// Test start/stop
|
|
90
|
+
await publisher.start();
|
|
91
|
+
await new Promise(resolve => setTimeout(resolve, 250)); // Wait for 2 intervals
|
|
92
|
+
publisher.stop();
|
|
93
|
+
|
|
94
|
+
if (publishedMessages.length < 2) {
|
|
95
|
+
throw new Error(`Expected at least 2 published messages, got ${publishedMessages.length}`);
|
|
96
|
+
}
|
|
97
|
+
console.log(' ✓ start/stop works');
|
|
98
|
+
console.log(` ✓ Published ${publishedMessages.length} messages total`);
|
|
99
|
+
|
|
100
|
+
console.log('✓ createHealthPublisher test passed\n');
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error(` ✗ createHealthPublisher test failed: ${error.message}`);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Test 3: Test waitForInfrastructureReady (mock Redis)
|
|
108
|
+
console.log('Test 3: Testing waitForInfrastructureReady with mock Redis...');
|
|
109
|
+
// This test would require Redis connection, so we'll just check that function exists
|
|
110
|
+
if (typeof waitForInfrastructureReady === 'function') {
|
|
111
|
+
console.log(' ✓ waitForInfrastructureReady is a function');
|
|
112
|
+
} else {
|
|
113
|
+
console.error(` ✗ waitForInfrastructureReady is not a function`);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
console.log(' ⚠ Skipping actual Redis test (requires Redis connection)\n');
|
|
117
|
+
|
|
118
|
+
// Test 4: Test initInfrastructureQueues (mock channel)
|
|
119
|
+
console.log('Test 4: Testing initInfrastructureQueues with mock channel...');
|
|
120
|
+
// This test would require RabbitMQ connection, so we'll just check that function exists
|
|
121
|
+
if (typeof initInfrastructureQueues === 'function') {
|
|
122
|
+
console.log(' ✓ initInfrastructureQueues is a function');
|
|
123
|
+
} else {
|
|
124
|
+
console.error(` ✗ initInfrastructureQueues is not a function`);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
console.log(' ⚠ Skipping actual RabbitMQ test (requires RabbitMQ connection)\n');
|
|
128
|
+
|
|
129
|
+
// Run async tests
|
|
130
|
+
(async () => {
|
|
131
|
+
try {
|
|
132
|
+
await testHealthPublisher();
|
|
133
|
+
|
|
134
|
+
console.log('✅ All tests passed!');
|
|
135
|
+
console.log('\nNote: Full integration tests require:');
|
|
136
|
+
console.log(' - Redis connection (for waitForInfrastructureReady)');
|
|
137
|
+
console.log(' - RabbitMQ connection (for initInfrastructureQueues)');
|
|
138
|
+
console.log(' - Running infrastructure services (for end-to-end testing)');
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error('\n❌ Tests failed:', error.message);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
})();
|
|
144
|
+
|