mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-12 13:52:15 +00:00
Asserts ensureGatewayProfile keeps $connection in lockstep with the active profile's backend: activating a remote pool profile flips mode to remote, returning to default resyncs to local, a failed descriptor fetch leaves the prior connection intact, and a same-profile activation doesn't churn it. Regression coverage for #46651.
89 lines
3.5 KiB
TypeScript
89 lines
3.5 KiB
TypeScript
import { atom } from 'nanostores'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import type { HermesConnection } from '@/global'
|
|
|
|
// Keep profile.ts's side-effecting imports inert: the gateway socket layer and
|
|
// the REST query client must not run for real in a unit test.
|
|
const ensureGatewayForProfile = vi.fn(async () => undefined)
|
|
const $gateway = atom<unknown>({ id: 'live-socket' })
|
|
|
|
vi.mock('@/store/gateway', () => ({ $gateway, ensureGatewayForProfile }))
|
|
vi.mock('@/hermes', () => ({
|
|
getProfiles: vi.fn(async () => ({ profiles: [] })),
|
|
setApiRequestProfile: vi.fn()
|
|
}))
|
|
vi.mock('@/lib/query-client', () => ({ queryClient: { invalidateQueries: vi.fn() } }))
|
|
|
|
const { $activeGatewayProfile, ensureGatewayProfile } = await import('./profile')
|
|
const { $connection } = await import('./session')
|
|
|
|
const remoteConn = (over: Partial<HermesConnection> = {}): HermesConnection =>
|
|
({ baseUrl: 'https://hermes-roy.tail.ts.net', mode: 'remote', profile: 'vps-remote', ...over }) as HermesConnection
|
|
|
|
const localConn = (over: Partial<HermesConnection> = {}): HermesConnection =>
|
|
({ baseUrl: '', mode: 'local', profile: 'default', ...over }) as HermesConnection
|
|
|
|
const getConnection = vi.fn<(profile?: string | null) => Promise<HermesConnection>>()
|
|
|
|
beforeEach(() => {
|
|
getConnection.mockReset()
|
|
ensureGatewayForProfile.mockClear()
|
|
$gateway.set({ id: 'live-socket' })
|
|
$activeGatewayProfile.set('default')
|
|
$connection.set(localConn())
|
|
vi.stubGlobal('window', { hermesDesktop: { getConnection } })
|
|
})
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals()
|
|
$connection.set(null)
|
|
})
|
|
|
|
describe('ensureGatewayProfile → $connection sync (#46651)', () => {
|
|
it('refreshes $connection to the remote descriptor when activating a remote pool profile', async () => {
|
|
// Regression: the primary window backend is local, so $connection.mode is
|
|
// "local". Activating the remote profile must flip it to "remote" — without
|
|
// this, image attach uses path-based image.attach against the remote
|
|
// gateway ("image not found: C:\\…") instead of image.attach_bytes.
|
|
getConnection.mockResolvedValue(remoteConn())
|
|
|
|
await ensureGatewayProfile('vps-remote')
|
|
|
|
expect(ensureGatewayForProfile).toHaveBeenCalledWith('vps-remote')
|
|
expect(getConnection).toHaveBeenCalledWith('vps-remote')
|
|
expect($connection.get()?.mode).toBe('remote')
|
|
expect($connection.get()?.profile).toBe('vps-remote')
|
|
})
|
|
|
|
it('resyncs $connection back to local when returning to the default profile', async () => {
|
|
$activeGatewayProfile.set('vps-remote')
|
|
$connection.set(remoteConn())
|
|
getConnection.mockResolvedValue(localConn())
|
|
|
|
await ensureGatewayProfile('default')
|
|
|
|
expect(getConnection).toHaveBeenCalledWith('default')
|
|
expect($connection.get()?.mode).toBe('local')
|
|
})
|
|
|
|
it('leaves the prior connection intact when the descriptor fetch fails', async () => {
|
|
getConnection.mockRejectedValue(new Error('backend unreachable'))
|
|
|
|
await ensureGatewayProfile('vps-remote')
|
|
|
|
// Best-effort: boot/reconnect resyncs later; we must not null it out here.
|
|
expect($connection.get()?.mode).toBe('local')
|
|
})
|
|
|
|
it('does not churn $connection when the target is already the active profile', async () => {
|
|
$activeGatewayProfile.set('vps-remote')
|
|
$connection.set(remoteConn())
|
|
|
|
await ensureGatewayProfile('vps-remote')
|
|
|
|
expect(getConnection).not.toHaveBeenCalled()
|
|
expect(ensureGatewayForProfile).not.toHaveBeenCalled()
|
|
expect($connection.get()?.mode).toBe('remote')
|
|
})
|
|
})
|