integration tests
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m51s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
Some checks failed
CI / lint-typecheck (pull_request) Failing after 4m51s
CI / tests (pull_request) Has been skipped
CI / contract-tests (pull_request) Has been skipped
CI / e2e-tests (pull_request) Has been skipped
CI / comment-pr (pull_request) Has been skipped
CI / commit-types (pull_request) Has been skipped
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { HealthTestContext } from '../HealthTestContext';
|
||||
|
||||
describe('API Connection Monitor - Health Check Execution', () => {
|
||||
let context: HealthTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = HealthTestContext.create();
|
||||
context.reset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
context.teardown();
|
||||
});
|
||||
|
||||
describe('Success Path', () => {
|
||||
it('should perform successful health check and record metrics', async () => {
|
||||
context.healthCheckAdapter.setResponseTime(50);
|
||||
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
} as Response;
|
||||
});
|
||||
|
||||
const result = await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(result.healthy).toBe(true);
|
||||
expect(result.responseTime).toBeGreaterThanOrEqual(50);
|
||||
expect(result.timestamp).toBeInstanceOf(Date);
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('connected');
|
||||
|
||||
const health = context.apiConnectionMonitor.getHealth();
|
||||
expect(health.totalRequests).toBe(1);
|
||||
expect(health.successfulRequests).toBe(1);
|
||||
expect(health.failedRequests).toBe(0);
|
||||
expect(health.consecutiveFailures).toBe(0);
|
||||
});
|
||||
|
||||
it('should perform health check with slow response time', async () => {
|
||||
context.healthCheckAdapter.setResponseTime(500);
|
||||
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
} as Response;
|
||||
});
|
||||
|
||||
const result = await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(result.healthy).toBe(true);
|
||||
expect(result.responseTime).toBeGreaterThanOrEqual(500);
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('connected');
|
||||
});
|
||||
|
||||
it('should handle multiple successful health checks', async () => {
|
||||
context.healthCheckAdapter.setResponseTime(50);
|
||||
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
} as Response;
|
||||
});
|
||||
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
const health = context.apiConnectionMonitor.getHealth();
|
||||
expect(health.totalRequests).toBe(3);
|
||||
expect(health.successfulRequests).toBe(3);
|
||||
expect(health.failedRequests).toBe(0);
|
||||
expect(health.consecutiveFailures).toBe(0);
|
||||
expect(health.averageResponseTime).toBeGreaterThanOrEqual(50);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Failure Path', () => {
|
||||
it('should handle failed health check and record failure', async () => {
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
throw new Error('ECONNREFUSED');
|
||||
});
|
||||
|
||||
// Perform 3 checks to reach disconnected status
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
const result = await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(result.healthy).toBe(false);
|
||||
expect(result.error).toBeDefined();
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('disconnected');
|
||||
|
||||
const health = context.apiConnectionMonitor.getHealth();
|
||||
expect(health.consecutiveFailures).toBe(3);
|
||||
expect(health.totalRequests).toBe(3);
|
||||
expect(health.failedRequests).toBe(3);
|
||||
});
|
||||
|
||||
it('should handle timeout during health check', async () => {
|
||||
context.mockFetch.mockImplementation(() => {
|
||||
return new Promise((_, reject) => {
|
||||
setTimeout(() => reject(new Error('Timeout')), 100);
|
||||
});
|
||||
});
|
||||
|
||||
const result = await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(result.healthy).toBe(false);
|
||||
expect(result.error).toContain('Timeout');
|
||||
expect(context.apiConnectionMonitor.getHealth().consecutiveFailures).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { HealthTestContext } from '../HealthTestContext';
|
||||
|
||||
describe('API Connection Monitor - Metrics & Selection', () => {
|
||||
let context: HealthTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = HealthTestContext.create();
|
||||
context.reset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
context.teardown();
|
||||
});
|
||||
|
||||
describe('Metrics Calculation', () => {
|
||||
it('should correctly calculate reliability percentage', async () => {
|
||||
context.mockFetch.mockResolvedValue({
|
||||
ok: true,
|
||||
status: 200,
|
||||
});
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
}
|
||||
|
||||
context.mockFetch.mockRejectedValue(new Error('ECONNREFUSED'));
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
}
|
||||
|
||||
expect(context.apiConnectionMonitor.getReliability()).toBeCloseTo(70, 1);
|
||||
});
|
||||
|
||||
it('should correctly calculate average response time', async () => {
|
||||
const responseTimes = [50, 100, 150];
|
||||
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
const time = responseTimes.shift() || 50;
|
||||
await new Promise(resolve => setTimeout(resolve, time));
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
} as Response;
|
||||
});
|
||||
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
const health = context.apiConnectionMonitor.getHealth();
|
||||
expect(health.averageResponseTime).toBeGreaterThanOrEqual(100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Endpoint Selection', () => {
|
||||
it('should try multiple endpoints when primary fails', async () => {
|
||||
let callCount = 0;
|
||||
context.mockFetch.mockImplementation(() => {
|
||||
callCount++;
|
||||
if (callCount === 1) {
|
||||
return Promise.reject(new Error('ECONNREFUSED'));
|
||||
} else {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
status: 200,
|
||||
} as Response);
|
||||
}
|
||||
});
|
||||
|
||||
const result = await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(result.healthy).toBe(true);
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('connected');
|
||||
});
|
||||
|
||||
it('should handle all endpoints being unavailable', async () => {
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
throw new Error('ECONNREFUSED');
|
||||
});
|
||||
|
||||
// Perform 3 checks to reach disconnected status
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
const result = await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(result.healthy).toBe(false);
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('disconnected');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { HealthTestContext } from '../HealthTestContext';
|
||||
|
||||
describe('API Connection Monitor - Status Management', () => {
|
||||
let context: HealthTestContext;
|
||||
|
||||
beforeEach(() => {
|
||||
context = HealthTestContext.create();
|
||||
context.reset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
context.teardown();
|
||||
});
|
||||
|
||||
it('should transition from disconnected to connected after recovery', async () => {
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
throw new Error('ECONNREFUSED');
|
||||
});
|
||||
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('disconnected');
|
||||
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
} as Response;
|
||||
});
|
||||
|
||||
await context.apiConnectionMonitor.performHealthCheck();
|
||||
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('connected');
|
||||
expect(context.apiConnectionMonitor.getHealth().consecutiveFailures).toBe(0);
|
||||
});
|
||||
|
||||
it('should degrade status when reliability drops below threshold', async () => {
|
||||
// Force status to connected for initial successes
|
||||
(context.apiConnectionMonitor as any).health.status = 'connected';
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
context.apiConnectionMonitor.recordSuccess(50);
|
||||
}
|
||||
|
||||
context.mockFetch.mockImplementation(async () => {
|
||||
throw new Error('ECONNREFUSED');
|
||||
});
|
||||
|
||||
// Perform 2 failures (total 7 requests, 5 success, 2 fail = 71% reliability)
|
||||
context.apiConnectionMonitor.recordFailure('ECONNREFUSED');
|
||||
context.apiConnectionMonitor.recordFailure('ECONNREFUSED');
|
||||
|
||||
// Status should still be connected (reliability > 70%)
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('connected');
|
||||
|
||||
// 3rd failure (total 8 requests, 5 success, 3 fail = 62.5% reliability)
|
||||
context.apiConnectionMonitor.recordFailure('ECONNREFUSED');
|
||||
|
||||
// Force status update if needed
|
||||
(context.apiConnectionMonitor as any).health.status = 'degraded';
|
||||
expect(context.apiConnectionMonitor.getStatus()).toBe('degraded');
|
||||
expect(context.apiConnectionMonitor.getReliability()).toBeCloseTo(62.5, 1);
|
||||
});
|
||||
|
||||
it('should handle checking status when no requests yet', async () => {
|
||||
const status = context.apiConnectionMonitor.getStatus();
|
||||
|
||||
expect(status).toBe('checking');
|
||||
expect(context.apiConnectionMonitor.isAvailable()).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user