增加一键重启所有网关按钮
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
resolveGatewayRestartTargets,
|
||||
restartGatewaysForProfiles,
|
||||
} from '../../packages/server/src/services/hermes/gateway-autostart'
|
||||
|
||||
describe('batch gateway restart', () => {
|
||||
it('maps each profile to its own gateway target in per-profile mode', () => {
|
||||
expect(resolveGatewayRestartTargets(['default', 'work'], false)).toEqual([
|
||||
{ targetProfile: 'default', requestedProfile: 'default' },
|
||||
{ targetProfile: 'work', requestedProfile: 'work' },
|
||||
])
|
||||
})
|
||||
|
||||
it('restarts a shared gateway once in unified mode', () => {
|
||||
expect(resolveGatewayRestartTargets(['default', 'work', 'reviewer'], true)).toEqual([
|
||||
{ targetProfile: 'default', requestedProfile: 'default' },
|
||||
])
|
||||
})
|
||||
|
||||
it('keeps the first requested profile for a duplicated target', () => {
|
||||
expect(resolveGatewayRestartTargets(['work', 'default'], true)).toEqual([
|
||||
{ targetProfile: 'default', requestedProfile: 'work' },
|
||||
])
|
||||
})
|
||||
|
||||
it('falls back to the default profile for a blank name', () => {
|
||||
expect(resolveGatewayRestartTargets([''], false)).toEqual([
|
||||
{ targetProfile: 'default', requestedProfile: 'default' },
|
||||
])
|
||||
})
|
||||
|
||||
it('stops, starts and waits for every restarted gateway', async () => {
|
||||
const stopGateway = vi.fn().mockResolvedValue(undefined)
|
||||
const startGateway = vi.fn().mockResolvedValue(undefined)
|
||||
const waitForGateway = vi.fn().mockResolvedValue(true)
|
||||
|
||||
const results = await restartGatewaysForProfiles(['default', 'work'], {
|
||||
unified: false,
|
||||
stopGateway,
|
||||
startGateway,
|
||||
waitForGateway,
|
||||
})
|
||||
|
||||
expect(results).toEqual([
|
||||
{ profile: 'default', targetProfile: 'default', running: true },
|
||||
{ profile: 'work', targetProfile: 'work', running: true },
|
||||
])
|
||||
expect(stopGateway).toHaveBeenCalledTimes(2)
|
||||
expect(startGateway).toHaveBeenCalledTimes(2)
|
||||
expect(waitForGateway).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('restarts a shared gateway only once in unified mode', async () => {
|
||||
const stopGateway = vi.fn().mockResolvedValue(undefined)
|
||||
const startGateway = vi.fn().mockResolvedValue(undefined)
|
||||
const waitForGateway = vi.fn().mockResolvedValue(true)
|
||||
|
||||
const results = await restartGatewaysForProfiles(['default', 'work'], {
|
||||
unified: true,
|
||||
stopGateway,
|
||||
startGateway,
|
||||
waitForGateway,
|
||||
})
|
||||
|
||||
expect(results).toEqual([
|
||||
{ profile: 'default', targetProfile: 'default', running: true },
|
||||
])
|
||||
expect(stopGateway).toHaveBeenCalledTimes(1)
|
||||
expect(startGateway).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('keeps going when one gateway fails and reports the error', async () => {
|
||||
const stopGateway = vi.fn()
|
||||
.mockResolvedValueOnce(undefined)
|
||||
.mockRejectedValueOnce(new Error('stop failed'))
|
||||
const startGateway = vi.fn().mockResolvedValue(undefined)
|
||||
const waitForGateway = vi.fn().mockResolvedValue(true)
|
||||
|
||||
const results = await restartGatewaysForProfiles(['default', 'work'], {
|
||||
unified: false,
|
||||
stopGateway,
|
||||
startGateway,
|
||||
waitForGateway,
|
||||
})
|
||||
|
||||
expect(results).toEqual([
|
||||
{ profile: 'default', targetProfile: 'default', running: true },
|
||||
{ profile: 'work', targetProfile: 'work', running: false, error: 'stop failed' },
|
||||
])
|
||||
})
|
||||
|
||||
it('reports a gateway that never reports running as failed', async () => {
|
||||
const stopGateway = vi.fn().mockResolvedValue(undefined)
|
||||
const startGateway = vi.fn().mockResolvedValue(undefined)
|
||||
const waitForGateway = vi.fn().mockResolvedValue(false)
|
||||
|
||||
const results = await restartGatewaysForProfiles(['default'], {
|
||||
unified: false,
|
||||
stopGateway,
|
||||
startGateway,
|
||||
waitForGateway,
|
||||
})
|
||||
|
||||
expect(results[0]?.running).toBe(false)
|
||||
expect(results[0]?.error).toContain('did not report running')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,65 @@
|
||||
import Koa from 'koa'
|
||||
import bodyParser from '@koa/bodyparser'
|
||||
import { createServer, type Server as HttpServer } from 'http'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const controllerMocks = vi.hoisted(() => ({
|
||||
restartAllGateways: vi.fn(),
|
||||
restartAllProfiles: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('../../packages/server/src/controllers/hermes/profiles', async (importOriginal) => ({
|
||||
...(await importOriginal() as any),
|
||||
restartAllGateways: controllerMocks.restartAllGateways,
|
||||
restartAllProfiles: controllerMocks.restartAllProfiles,
|
||||
}))
|
||||
|
||||
import { profileRoutes } from '../../packages/server/src/routes/hermes/profiles'
|
||||
|
||||
function listen(server: HttpServer): Promise<string> {
|
||||
return new Promise((resolve) => server.listen(0, '127.0.0.1', () => {
|
||||
const addr = server.address()
|
||||
if (!addr || typeof addr === 'string') throw new Error('missing address')
|
||||
resolve(`http://127.0.0.1:${addr.port}`)
|
||||
}))
|
||||
}
|
||||
|
||||
describe('profile bulk restart routes', () => {
|
||||
let httpServer: HttpServer
|
||||
let baseUrl: string
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks()
|
||||
controllerMocks.restartAllGateways.mockImplementation((ctx: any) => {
|
||||
ctx.body = { success: true }
|
||||
})
|
||||
controllerMocks.restartAllProfiles.mockImplementation((ctx: any) => {
|
||||
ctx.body = { success: true }
|
||||
})
|
||||
|
||||
const app = new Koa()
|
||||
app.use(bodyParser())
|
||||
app.use(profileRoutes.routes())
|
||||
app.use(profileRoutes.allowedMethods())
|
||||
httpServer = createServer(app.callback())
|
||||
baseUrl = await listen(httpServer)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await new Promise<void>((resolve) => httpServer.close(() => resolve()))
|
||||
})
|
||||
|
||||
it('routes the gateway bulk restart to its own handler', async () => {
|
||||
const res = await fetch(`${baseUrl}/api/hermes/profiles/gateways/restart-all`, { method: 'POST' })
|
||||
expect(res.status).toBe(200)
|
||||
expect(controllerMocks.restartAllGateways).toHaveBeenCalledTimes(1)
|
||||
expect(controllerMocks.restartAllProfiles).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('routes the profile bulk restart to its own handler', async () => {
|
||||
const res = await fetch(`${baseUrl}/api/hermes/profiles/restart-all`, { method: 'POST' })
|
||||
expect(res.status).toBe(200)
|
||||
expect(controllerMocks.restartAllProfiles).toHaveBeenCalledTimes(1)
|
||||
expect(controllerMocks.restartAllGateways).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user