AI Service Reliability Monitor & Failover Switch v1.0.0
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { findFailoverService } from '../src/background'
|
||||
import { MonitorState, ServiceId, ServiceStatus } from '../src/types'
|
||||
|
||||
function makeStatus(id: ServiceId, health: ServiceStatus['health'], responseTime: number | null): ServiceStatus {
|
||||
return {
|
||||
id,
|
||||
name: id,
|
||||
url: `https://${id}.com`,
|
||||
health,
|
||||
lastChecked: Date.now(),
|
||||
responseTimeMs: responseTime,
|
||||
errorRate: 0,
|
||||
usageLimit: null,
|
||||
message: null
|
||||
}
|
||||
}
|
||||
|
||||
describe('findFailoverService', () => {
|
||||
it('should return the fastest healthy backup', () => {
|
||||
const state: MonitorState = {
|
||||
services: {
|
||||
chatgpt: makeStatus('chatgpt', 'healthy', 100),
|
||||
claude: makeStatus('claude', 'healthy', 50),
|
||||
gemini: makeStatus('gemini', 'healthy', 200),
|
||||
grok: makeStatus('grok', 'down', null)
|
||||
},
|
||||
lastAlert: null,
|
||||
alertThreshold: 80,
|
||||
failoverEnabled: true,
|
||||
primaryService: 'chatgpt'
|
||||
}
|
||||
|
||||
const result = findFailoverService(state)
|
||||
expect(result).toBe('claude')
|
||||
})
|
||||
|
||||
it('should return null when no healthy backup exists', () => {
|
||||
const state: MonitorState = {
|
||||
services: {
|
||||
chatgpt: makeStatus('chatgpt', 'down', null),
|
||||
claude: makeStatus('claude', 'down', null),
|
||||
gemini: makeStatus('gemini', 'degraded', 1000),
|
||||
grok: makeStatus('grok', 'down', null)
|
||||
},
|
||||
lastAlert: null,
|
||||
alertThreshold: 80,
|
||||
failoverEnabled: true,
|
||||
primaryService: 'chatgpt'
|
||||
}
|
||||
|
||||
const result = findFailoverService(state)
|
||||
expect(result).toBeNull()
|
||||
})
|
||||
|
||||
it('should exclude the primary service', () => {
|
||||
const state: MonitorState = {
|
||||
services: {
|
||||
chatgpt: makeStatus('chatgpt', 'healthy', 50),
|
||||
claude: makeStatus('claude', 'healthy', 100),
|
||||
gemini: makeStatus('gemini', 'healthy', 200),
|
||||
grok: makeStatus('grok', 'healthy', 300)
|
||||
},
|
||||
lastAlert: null,
|
||||
alertThreshold: 80,
|
||||
failoverEnabled: true,
|
||||
primaryService: 'chatgpt'
|
||||
}
|
||||
|
||||
const result = findFailoverService(state)
|
||||
expect(result).toBe('claude')
|
||||
})
|
||||
|
||||
it('should pick gemini when claude is degraded', () => {
|
||||
const state: MonitorState = {
|
||||
services: {
|
||||
chatgpt: makeStatus('chatgpt', 'down', null),
|
||||
claude: makeStatus('claude', 'degraded', 5000),
|
||||
gemini: makeStatus('gemini', 'healthy', 150),
|
||||
grok: makeStatus('grok', 'down', null)
|
||||
},
|
||||
lastAlert: null,
|
||||
alertThreshold: 80,
|
||||
failoverEnabled: true,
|
||||
primaryService: 'chatgpt'
|
||||
}
|
||||
|
||||
const result = findFailoverService(state)
|
||||
expect(result).toBe('gemini')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,39 @@
|
||||
globalThis.chrome = {
|
||||
runtime: {
|
||||
onMessage: {
|
||||
addListener: () => {},
|
||||
},
|
||||
onInstalled: {
|
||||
addListener: () => {},
|
||||
},
|
||||
onStartup: {
|
||||
addListener: () => {},
|
||||
},
|
||||
},
|
||||
alarms: {
|
||||
onAlarm: {
|
||||
addListener: () => {},
|
||||
},
|
||||
create: async () => {},
|
||||
},
|
||||
tabs: {
|
||||
onUpdated: {
|
||||
addListener: () => {},
|
||||
},
|
||||
create: async () => {},
|
||||
sendMessage: async () => {},
|
||||
},
|
||||
action: {
|
||||
setBadgeText: async () => {},
|
||||
setBadgeBackgroundColor: async () => {},
|
||||
},
|
||||
notifications: {
|
||||
create: async () => {},
|
||||
},
|
||||
storage: {
|
||||
local: {
|
||||
get: async () => ({}),
|
||||
set: async () => {},
|
||||
},
|
||||
},
|
||||
} as any;
|
||||
Reference in New Issue
Block a user