@friggframework/core 2.0.0--canary.398.7664c46.0 → 2.0.0--canary.400.bed3308.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/handlers/routers/HEALTHCHECK.md +230 -0
- package/handlers/routers/health.js +208 -0
- package/handlers/routers/health.test.js +136 -0
- package/package.json +5 -5
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Frigg Healthcheck Endpoint Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Frigg service includes comprehensive healthcheck endpoints to monitor service health, connectivity, and readiness. These endpoints follow industry best practices and are designed for use with monitoring systems, load balancers, and container orchestration platforms.
|
|
6
|
+
|
|
7
|
+
## Endpoints
|
|
8
|
+
|
|
9
|
+
### 1. Basic Health Check
|
|
10
|
+
**GET** `/health`
|
|
11
|
+
|
|
12
|
+
Simple health check endpoint that returns basic service information. No authentication required.
|
|
13
|
+
|
|
14
|
+
**Response:**
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"status": "ok",
|
|
18
|
+
"timestamp": "2024-01-10T12:00:00.000Z",
|
|
19
|
+
"service": "frigg-core-api",
|
|
20
|
+
"version": "1.0.0"
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Status Codes:**
|
|
25
|
+
- `200 OK` - Service is running
|
|
26
|
+
|
|
27
|
+
### 2. Detailed Health Check
|
|
28
|
+
**GET** `/health/detailed`
|
|
29
|
+
|
|
30
|
+
Comprehensive health check that tests all service components and dependencies.
|
|
31
|
+
|
|
32
|
+
**Response:**
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"service": "frigg-core-api",
|
|
36
|
+
"status": "healthy", // "healthy", "degraded", or "unhealthy"
|
|
37
|
+
"timestamp": "2024-01-10T12:00:00.000Z",
|
|
38
|
+
"version": "1.0.0",
|
|
39
|
+
"uptime": 3600, // seconds
|
|
40
|
+
"checks": {
|
|
41
|
+
"database": {
|
|
42
|
+
"status": "healthy",
|
|
43
|
+
"state": "connected",
|
|
44
|
+
"type": "mongodb",
|
|
45
|
+
"responseTime": 5 // milliseconds
|
|
46
|
+
},
|
|
47
|
+
"external_apis": {
|
|
48
|
+
"github": {
|
|
49
|
+
"status": "healthy",
|
|
50
|
+
"statusCode": 200,
|
|
51
|
+
"responseTime": 150,
|
|
52
|
+
"reachable": true
|
|
53
|
+
},
|
|
54
|
+
"npm": {
|
|
55
|
+
"status": "healthy",
|
|
56
|
+
"statusCode": 200,
|
|
57
|
+
"responseTime": 200,
|
|
58
|
+
"reachable": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"integrations": {
|
|
62
|
+
"status": "healthy",
|
|
63
|
+
"modules": {
|
|
64
|
+
"count": 10,
|
|
65
|
+
"available": ["module1", "module2", "..."]
|
|
66
|
+
},
|
|
67
|
+
"integrations": {
|
|
68
|
+
"count": 5,
|
|
69
|
+
"available": ["integration1", "integration2", "..."]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"memory": {
|
|
73
|
+
"status": "healthy",
|
|
74
|
+
"rss": "150 MB",
|
|
75
|
+
"heapTotal": "100 MB",
|
|
76
|
+
"heapUsed": "80 MB",
|
|
77
|
+
"external": "20 MB"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"responseTime": 250 // total endpoint response time in milliseconds
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Status Codes:**
|
|
85
|
+
- `200 OK` - Service is healthy or degraded (but operational)
|
|
86
|
+
- `503 Service Unavailable` - Service is unhealthy
|
|
87
|
+
|
|
88
|
+
### 3. Liveness Probe
|
|
89
|
+
**GET** `/health/live`
|
|
90
|
+
|
|
91
|
+
Kubernetes-style liveness probe. Returns whether the service process is alive.
|
|
92
|
+
|
|
93
|
+
**Response:**
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"status": "alive",
|
|
97
|
+
"timestamp": "2024-01-10T12:00:00.000Z"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Status Codes:**
|
|
102
|
+
- `200 OK` - Service process is alive
|
|
103
|
+
|
|
104
|
+
### 4. Readiness Probe
|
|
105
|
+
**GET** `/health/ready`
|
|
106
|
+
|
|
107
|
+
Kubernetes-style readiness probe. Returns whether the service is ready to receive traffic.
|
|
108
|
+
|
|
109
|
+
**Response:**
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"ready": true,
|
|
113
|
+
"timestamp": "2024-01-10T12:00:00.000Z",
|
|
114
|
+
"checks": {
|
|
115
|
+
"database": true,
|
|
116
|
+
"modules": true
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Status Codes:**
|
|
122
|
+
- `200 OK` - Service is ready
|
|
123
|
+
- `503 Service Unavailable` - Service is not ready
|
|
124
|
+
|
|
125
|
+
## Health Status Definitions
|
|
126
|
+
|
|
127
|
+
- **healthy**: All components are functioning normally
|
|
128
|
+
- **degraded**: Some non-critical components have issues, but core functionality is available
|
|
129
|
+
- **unhealthy**: Critical components are failing, service cannot function properly
|
|
130
|
+
|
|
131
|
+
## Component Checks
|
|
132
|
+
|
|
133
|
+
### Database Connectivity
|
|
134
|
+
- Checks MongoDB connection state
|
|
135
|
+
- Performs ping test if connected
|
|
136
|
+
- Reports connection state and response time
|
|
137
|
+
|
|
138
|
+
### External API Connectivity
|
|
139
|
+
- Tests connectivity to external services (GitHub, npm registry)
|
|
140
|
+
- Configurable timeout (default: 5 seconds)
|
|
141
|
+
- Reports reachability and response times
|
|
142
|
+
|
|
143
|
+
### Integration Status
|
|
144
|
+
- Verifies available modules and integrations are loaded
|
|
145
|
+
- Reports counts and lists of available components
|
|
146
|
+
|
|
147
|
+
### Memory Usage
|
|
148
|
+
- Reports current memory usage statistics
|
|
149
|
+
- Includes RSS, heap, and external memory metrics
|
|
150
|
+
|
|
151
|
+
## Usage Examples
|
|
152
|
+
|
|
153
|
+
### Monitoring Systems
|
|
154
|
+
Configure your monitoring system to poll `/health/detailed` every 30-60 seconds:
|
|
155
|
+
```bash
|
|
156
|
+
curl https://your-frigg-instance.com/health/detailed
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Load Balancer Health Checks
|
|
160
|
+
Configure load balancers to use the simple `/health` endpoint:
|
|
161
|
+
```bash
|
|
162
|
+
curl https://your-frigg-instance.com/health
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Kubernetes Configuration
|
|
166
|
+
```yaml
|
|
167
|
+
livenessProbe:
|
|
168
|
+
httpGet:
|
|
169
|
+
path: /health/live
|
|
170
|
+
port: 8080
|
|
171
|
+
periodSeconds: 10
|
|
172
|
+
timeoutSeconds: 5
|
|
173
|
+
|
|
174
|
+
readinessProbe:
|
|
175
|
+
httpGet:
|
|
176
|
+
path: /health/ready
|
|
177
|
+
port: 8080
|
|
178
|
+
initialDelaySeconds: 30
|
|
179
|
+
periodSeconds: 10
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Customization
|
|
183
|
+
|
|
184
|
+
### Adding External API Checks
|
|
185
|
+
To add more external API checks, modify the `externalAPIs` array in the health router:
|
|
186
|
+
```javascript
|
|
187
|
+
const externalAPIs = [
|
|
188
|
+
{ name: 'github', url: 'https://api.github.com/status' },
|
|
189
|
+
{ name: 'npm', url: 'https://registry.npmjs.org' },
|
|
190
|
+
{ name: 'your-api', url: 'https://your-api.com/health' }
|
|
191
|
+
];
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Adjusting Timeouts
|
|
195
|
+
The default timeout for external API checks is 5 seconds. Adjust as needed:
|
|
196
|
+
```javascript
|
|
197
|
+
const checkExternalAPI = (url, timeout = 5000) => {
|
|
198
|
+
// ...
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Best Practices
|
|
203
|
+
|
|
204
|
+
1. **No Authentication**: Basic health endpoints should not require authentication to allow monitoring systems easy access
|
|
205
|
+
2. **Fast Response**: Health checks should respond quickly (< 1 second)
|
|
206
|
+
3. **Graceful Degradation**: Service can continue operating even if some non-critical components fail
|
|
207
|
+
4. **Detailed Logging**: Failed health checks are logged for debugging
|
|
208
|
+
5. **Version Information**: Always include version information for tracking deployments
|
|
209
|
+
|
|
210
|
+
## Troubleshooting
|
|
211
|
+
|
|
212
|
+
### Database Connection Issues
|
|
213
|
+
- Check `MONGO_URI` environment variable
|
|
214
|
+
- Verify network connectivity to MongoDB
|
|
215
|
+
- Check MongoDB server status
|
|
216
|
+
|
|
217
|
+
### External API Failures
|
|
218
|
+
- May indicate network issues or external service downtime
|
|
219
|
+
- Service continues to operate but reports "degraded" status
|
|
220
|
+
|
|
221
|
+
### Memory Issues
|
|
222
|
+
- Monitor memory metrics over time
|
|
223
|
+
- Consider increasing container/instance memory limits if consistently high
|
|
224
|
+
|
|
225
|
+
## Security Considerations
|
|
226
|
+
|
|
227
|
+
- Health endpoints do not expose sensitive information
|
|
228
|
+
- Database connection strings and credentials are never included in responses
|
|
229
|
+
- External API checks use read-only endpoints
|
|
230
|
+
- Consider IP whitelisting for detailed health endpoints in production
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
const { Router } = require('express');
|
|
2
|
+
const mongoose = require('mongoose');
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const http = require('http');
|
|
5
|
+
const { moduleFactory, integrationFactory } = require('./../backend-utils');
|
|
6
|
+
const { createAppHandler } = require('./../app-handler-helpers');
|
|
7
|
+
const { version } = require('../../package.json');
|
|
8
|
+
|
|
9
|
+
const router = Router();
|
|
10
|
+
|
|
11
|
+
// Utility function to check external API connectivity
|
|
12
|
+
const checkExternalAPI = (url, timeout = 5000) => {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
const protocol = url.startsWith('https:') ? https : http;
|
|
15
|
+
const startTime = Date.now();
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const request = protocol.get(url, { timeout }, (res) => {
|
|
19
|
+
const responseTime = Date.now() - startTime;
|
|
20
|
+
resolve({
|
|
21
|
+
status: 'healthy',
|
|
22
|
+
statusCode: res.statusCode,
|
|
23
|
+
responseTime,
|
|
24
|
+
reachable: res.statusCode < 500
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
request.on('error', (error) => {
|
|
29
|
+
resolve({
|
|
30
|
+
status: 'unhealthy',
|
|
31
|
+
error: error.message,
|
|
32
|
+
responseTime: Date.now() - startTime,
|
|
33
|
+
reachable: false
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
request.on('timeout', () => {
|
|
38
|
+
request.destroy();
|
|
39
|
+
resolve({
|
|
40
|
+
status: 'timeout',
|
|
41
|
+
error: 'Request timeout',
|
|
42
|
+
responseTime: timeout,
|
|
43
|
+
reachable: false
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
resolve({
|
|
48
|
+
status: 'error',
|
|
49
|
+
error: error.message,
|
|
50
|
+
responseTime: Date.now() - startTime,
|
|
51
|
+
reachable: false
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Simple health check - no authentication required
|
|
58
|
+
router.get('/health', async (req, res) => {
|
|
59
|
+
const status = {
|
|
60
|
+
status: 'ok',
|
|
61
|
+
timestamp: new Date().toISOString(),
|
|
62
|
+
service: 'frigg-core-api',
|
|
63
|
+
version
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
res.status(200).json(status);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Detailed health check with component status
|
|
70
|
+
router.get('/health/detailed', async (req, res) => {
|
|
71
|
+
const startTime = Date.now();
|
|
72
|
+
const checks = {
|
|
73
|
+
service: 'frigg-core-api',
|
|
74
|
+
status: 'healthy',
|
|
75
|
+
timestamp: new Date().toISOString(),
|
|
76
|
+
version,
|
|
77
|
+
uptime: process.uptime(),
|
|
78
|
+
checks: {}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Check database connectivity
|
|
82
|
+
try {
|
|
83
|
+
const dbState = mongoose.connection.readyState;
|
|
84
|
+
const dbStateMap = {
|
|
85
|
+
0: 'disconnected',
|
|
86
|
+
1: 'connected',
|
|
87
|
+
2: 'connecting',
|
|
88
|
+
3: 'disconnecting'
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
checks.checks.database = {
|
|
92
|
+
status: dbState === 1 ? 'healthy' : 'unhealthy',
|
|
93
|
+
state: dbStateMap[dbState],
|
|
94
|
+
type: 'mongodb'
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// If connected, check database responsiveness
|
|
98
|
+
if (dbState === 1) {
|
|
99
|
+
const pingStart = Date.now();
|
|
100
|
+
await mongoose.connection.db.admin().ping();
|
|
101
|
+
checks.checks.database.responseTime = Date.now() - pingStart;
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
checks.checks.database = {
|
|
105
|
+
status: 'unhealthy',
|
|
106
|
+
error: error.message,
|
|
107
|
+
type: 'mongodb'
|
|
108
|
+
};
|
|
109
|
+
checks.status = 'degraded';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check external API connectivity (example endpoints)
|
|
113
|
+
const externalAPIs = [
|
|
114
|
+
{ name: 'github', url: 'https://api.github.com/status' },
|
|
115
|
+
{ name: 'npm', url: 'https://registry.npmjs.org' }
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
checks.checks.external_apis = {};
|
|
119
|
+
|
|
120
|
+
for (const api of externalAPIs) {
|
|
121
|
+
checks.checks.external_apis[api.name] = await checkExternalAPI(api.url);
|
|
122
|
+
if (!checks.checks.external_apis[api.name].reachable) {
|
|
123
|
+
checks.status = 'degraded';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check available integrations
|
|
128
|
+
try {
|
|
129
|
+
const availableModules = moduleFactory.getAll();
|
|
130
|
+
const availableIntegrations = integrationFactory.getAll();
|
|
131
|
+
|
|
132
|
+
checks.checks.integrations = {
|
|
133
|
+
status: 'healthy',
|
|
134
|
+
modules: {
|
|
135
|
+
count: Object.keys(availableModules).length,
|
|
136
|
+
available: Object.keys(availableModules)
|
|
137
|
+
},
|
|
138
|
+
integrations: {
|
|
139
|
+
count: Object.keys(availableIntegrations).length,
|
|
140
|
+
available: Object.keys(availableIntegrations)
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
} catch (error) {
|
|
144
|
+
checks.checks.integrations = {
|
|
145
|
+
status: 'unhealthy',
|
|
146
|
+
error: error.message
|
|
147
|
+
};
|
|
148
|
+
checks.status = 'degraded';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Memory usage
|
|
152
|
+
const memoryUsage = process.memoryUsage();
|
|
153
|
+
checks.checks.memory = {
|
|
154
|
+
status: 'healthy',
|
|
155
|
+
rss: Math.round(memoryUsage.rss / 1024 / 1024) + ' MB',
|
|
156
|
+
heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024) + ' MB',
|
|
157
|
+
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024) + ' MB',
|
|
158
|
+
external: Math.round(memoryUsage.external / 1024 / 1024) + ' MB'
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Overall response time
|
|
162
|
+
checks.responseTime = Date.now() - startTime;
|
|
163
|
+
|
|
164
|
+
// Set appropriate status code
|
|
165
|
+
const statusCode = checks.status === 'healthy' ? 200 :
|
|
166
|
+
checks.status === 'degraded' ? 200 : 503;
|
|
167
|
+
|
|
168
|
+
res.status(statusCode).json(checks);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Liveness probe - for k8s/container orchestration
|
|
172
|
+
router.get('/health/live', (req, res) => {
|
|
173
|
+
res.status(200).json({
|
|
174
|
+
status: 'alive',
|
|
175
|
+
timestamp: new Date().toISOString()
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Readiness probe - checks if service is ready to receive traffic
|
|
180
|
+
router.get('/health/ready', async (req, res) => {
|
|
181
|
+
const checks = {
|
|
182
|
+
ready: true,
|
|
183
|
+
timestamp: new Date().toISOString(),
|
|
184
|
+
checks: {}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// Check database is connected
|
|
188
|
+
const dbState = mongoose.connection.readyState;
|
|
189
|
+
checks.checks.database = dbState === 1;
|
|
190
|
+
|
|
191
|
+
// Check critical services are loaded
|
|
192
|
+
try {
|
|
193
|
+
const modules = moduleFactory.getAll();
|
|
194
|
+
checks.checks.modules = Object.keys(modules).length > 0;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
checks.checks.modules = false;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Determine overall readiness
|
|
200
|
+
checks.ready = checks.checks.database && checks.checks.modules;
|
|
201
|
+
|
|
202
|
+
const statusCode = checks.ready ? 200 : 503;
|
|
203
|
+
res.status(statusCode).json(checks);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const handler = createAppHandler('HTTP Event: Health', router);
|
|
207
|
+
|
|
208
|
+
module.exports = { handler, router };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const request = require('supertest');
|
|
2
|
+
const express = require('express');
|
|
3
|
+
const { router } = require('./health');
|
|
4
|
+
const mongoose = require('mongoose');
|
|
5
|
+
|
|
6
|
+
// Mock mongoose connection
|
|
7
|
+
jest.mock('mongoose', () => ({
|
|
8
|
+
connection: {
|
|
9
|
+
readyState: 1,
|
|
10
|
+
db: {
|
|
11
|
+
admin: () => ({
|
|
12
|
+
ping: jest.fn().mockResolvedValue(true)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
// Mock backend-utils
|
|
19
|
+
jest.mock('./../backend-utils', () => ({
|
|
20
|
+
moduleFactory: {
|
|
21
|
+
getAll: () => ({
|
|
22
|
+
'test-module': {},
|
|
23
|
+
'another-module': {}
|
|
24
|
+
})
|
|
25
|
+
},
|
|
26
|
+
integrationFactory: {
|
|
27
|
+
getAll: () => ({
|
|
28
|
+
'test-integration': {},
|
|
29
|
+
'another-integration': {}
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
describe('Health Check Endpoints', () => {
|
|
35
|
+
let app;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
app = express();
|
|
39
|
+
app.use(router);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('GET /health', () => {
|
|
43
|
+
it('should return 200 with basic health status', async () => {
|
|
44
|
+
const response = await request(app)
|
|
45
|
+
.get('/health')
|
|
46
|
+
.expect(200);
|
|
47
|
+
|
|
48
|
+
expect(response.body).toHaveProperty('status', 'ok');
|
|
49
|
+
expect(response.body).toHaveProperty('timestamp');
|
|
50
|
+
expect(response.body).toHaveProperty('service', 'frigg-core-api');
|
|
51
|
+
expect(response.body).toHaveProperty('version');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('GET /health/detailed', () => {
|
|
56
|
+
it('should return 200 with detailed health status when healthy', async () => {
|
|
57
|
+
const response = await request(app)
|
|
58
|
+
.get('/health/detailed')
|
|
59
|
+
.expect(200);
|
|
60
|
+
|
|
61
|
+
expect(response.body).toHaveProperty('status', 'healthy');
|
|
62
|
+
expect(response.body).toHaveProperty('checks');
|
|
63
|
+
expect(response.body.checks).toHaveProperty('database');
|
|
64
|
+
expect(response.body.checks).toHaveProperty('external_apis');
|
|
65
|
+
expect(response.body.checks).toHaveProperty('integrations');
|
|
66
|
+
expect(response.body.checks).toHaveProperty('memory');
|
|
67
|
+
expect(response.body).toHaveProperty('uptime');
|
|
68
|
+
expect(response.body).toHaveProperty('responseTime');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should include database connectivity status', async () => {
|
|
72
|
+
const response = await request(app)
|
|
73
|
+
.get('/health/detailed')
|
|
74
|
+
.expect(200);
|
|
75
|
+
|
|
76
|
+
expect(response.body.checks.database).toHaveProperty('status', 'healthy');
|
|
77
|
+
expect(response.body.checks.database).toHaveProperty('state', 'connected');
|
|
78
|
+
expect(response.body.checks.database).toHaveProperty('type', 'mongodb');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should include integration information', async () => {
|
|
82
|
+
const response = await request(app)
|
|
83
|
+
.get('/health/detailed')
|
|
84
|
+
.expect(200);
|
|
85
|
+
|
|
86
|
+
expect(response.body.checks.integrations).toHaveProperty('status', 'healthy');
|
|
87
|
+
expect(response.body.checks.integrations.modules).toHaveProperty('count', 2);
|
|
88
|
+
expect(response.body.checks.integrations.integrations).toHaveProperty('count', 2);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('GET /health/live', () => {
|
|
93
|
+
it('should return 200 for liveness check', async () => {
|
|
94
|
+
const response = await request(app)
|
|
95
|
+
.get('/health/live')
|
|
96
|
+
.expect(200);
|
|
97
|
+
|
|
98
|
+
expect(response.body).toHaveProperty('status', 'alive');
|
|
99
|
+
expect(response.body).toHaveProperty('timestamp');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('GET /health/ready', () => {
|
|
104
|
+
it('should return 200 when service is ready', async () => {
|
|
105
|
+
const response = await request(app)
|
|
106
|
+
.get('/health/ready')
|
|
107
|
+
.expect(200);
|
|
108
|
+
|
|
109
|
+
expect(response.body).toHaveProperty('ready', true);
|
|
110
|
+
expect(response.body).toHaveProperty('checks');
|
|
111
|
+
expect(response.body.checks).toHaveProperty('database', true);
|
|
112
|
+
expect(response.body.checks).toHaveProperty('modules', true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should return 503 when database is not connected', async () => {
|
|
116
|
+
// Mock disconnected database
|
|
117
|
+
mongoose.connection.readyState = 0;
|
|
118
|
+
|
|
119
|
+
const response = await request(app)
|
|
120
|
+
.get('/health/ready')
|
|
121
|
+
.expect(503);
|
|
122
|
+
|
|
123
|
+
expect(response.body).toHaveProperty('ready', false);
|
|
124
|
+
expect(response.body.checks).toHaveProperty('database', false);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Test utility functions
|
|
130
|
+
describe('Health Check Utilities', () => {
|
|
131
|
+
it('should handle external API timeouts gracefully', async () => {
|
|
132
|
+
// This would test the checkExternalAPI function
|
|
133
|
+
// In a real implementation, you might want to export this function
|
|
134
|
+
// for easier unit testing
|
|
135
|
+
});
|
|
136
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.
|
|
4
|
+
"version": "2.0.0--canary.400.bed3308.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@hapi/boom": "^10.0.1",
|
|
7
7
|
"aws-sdk": "^2.1200.0",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"uuid": "^9.0.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@friggframework/eslint-config": "2.0.0--canary.
|
|
26
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
27
|
-
"@friggframework/test": "2.0.0--canary.
|
|
25
|
+
"@friggframework/eslint-config": "2.0.0--canary.400.bed3308.0",
|
|
26
|
+
"@friggframework/prettier-config": "2.0.0--canary.400.bed3308.0",
|
|
27
|
+
"@friggframework/test": "2.0.0--canary.400.bed3308.0",
|
|
28
28
|
"@types/lodash": "4.17.15",
|
|
29
29
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
30
30
|
"chai": "^4.3.6",
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
},
|
|
54
54
|
"homepage": "https://github.com/friggframework/frigg#readme",
|
|
55
55
|
"description": "",
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "bed3308a80f0e6ef89071f7266eee422e1d1fab9"
|
|
57
57
|
}
|