Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
commit
03634b1ca3
11340 files changed
+3442369
No files matched your search
@@ -0,0 +1,131 @@
|
||||
import { JsonRpcGatewayClient } from '@hermes/shared'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
interface ListenerEntry {
|
||||
callback: (event: any) => void
|
||||
once: boolean
|
||||
}
|
||||
|
||||
class FakeSocket {
|
||||
static readonly CLOSED = 3
|
||||
static readonly OPEN = 1
|
||||
|
||||
readonly sent: string[] = []
|
||||
readyState = FakeSocket.OPEN
|
||||
private listeners = new Map<string, ListenerEntry[]>()
|
||||
|
||||
addEventListener(type: string, callback: (event: any) => void, options?: AddEventListenerOptions): void {
|
||||
const entries = this.listeners.get(type) ?? []
|
||||
|
||||
entries.push({ callback, once: Boolean(options?.once) })
|
||||
this.listeners.set(type, entries)
|
||||
}
|
||||
|
||||
close(): void {
|
||||
if (this.readyState === FakeSocket.CLOSED) {
|
||||
return
|
||||
}
|
||||
|
||||
this.readyState = FakeSocket.CLOSED
|
||||
this.emit('close', { code: 1000 })
|
||||
}
|
||||
|
||||
emit(type: string, event: any = {}): void {
|
||||
const entries = [...(this.listeners.get(type) ?? [])]
|
||||
|
||||
for (const entry of entries) {
|
||||
entry.callback(event)
|
||||
|
||||
if (entry.once) {
|
||||
this.removeEventListener(type, entry.callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message(frame: unknown): void {
|
||||
this.emit('message', { data: JSON.stringify(frame) })
|
||||
}
|
||||
|
||||
removeEventListener(type: string, callback: (event: any) => void): void {
|
||||
this.listeners.set(
|
||||
type,
|
||||
(this.listeners.get(type) ?? []).filter(entry => entry.callback !== callback)
|
||||
)
|
||||
}
|
||||
|
||||
send(payload: string): void {
|
||||
this.sent.push(payload)
|
||||
}
|
||||
}
|
||||
|
||||
describe('JsonRpcGatewayClient heartbeat recovery', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('invalidates a silently dead advertised socket and ignores its late frames', async () => {
|
||||
vi.useFakeTimers()
|
||||
vi.stubGlobal('WebSocket', { OPEN: FakeSocket.OPEN })
|
||||
const socket = new FakeSocket()
|
||||
const states: string[] = []
|
||||
const events: string[] = []
|
||||
|
||||
const client = new JsonRpcGatewayClient({
|
||||
heartbeatDeadlineMs: 45,
|
||||
heartbeatIntervalMs: 15,
|
||||
socketFactory: () => socket as unknown as WebSocket
|
||||
})
|
||||
|
||||
client.onState(state => states.push(state))
|
||||
client.onAny(event => events.push(event.type))
|
||||
|
||||
const connected = client.connect('ws://gateway.test/api/ws')
|
||||
socket.emit('open')
|
||||
await connected
|
||||
socket.message({
|
||||
jsonrpc: '2.0',
|
||||
method: 'event',
|
||||
params: { type: 'gateway.ready', payload: { heartbeat: true } }
|
||||
})
|
||||
|
||||
await vi.advanceTimersByTimeAsync(61)
|
||||
|
||||
expect(client.connectionState).toBe('closed')
|
||||
expect(socket.readyState).toBe(FakeSocket.CLOSED)
|
||||
expect(states.at(-1)).toBe('closed')
|
||||
|
||||
socket.message({
|
||||
jsonrpc: '2.0',
|
||||
method: 'event',
|
||||
params: { type: 'message.complete', payload: { text: 'late duplicate' } }
|
||||
})
|
||||
expect(events).toEqual(['gateway.ready'])
|
||||
})
|
||||
|
||||
it('keeps older backends open when gateway.ready does not advertise heartbeat', async () => {
|
||||
vi.useFakeTimers()
|
||||
vi.stubGlobal('WebSocket', { OPEN: FakeSocket.OPEN })
|
||||
const socket = new FakeSocket()
|
||||
|
||||
const client = new JsonRpcGatewayClient({
|
||||
heartbeatDeadlineMs: 45,
|
||||
heartbeatIntervalMs: 15,
|
||||
socketFactory: () => socket as unknown as WebSocket
|
||||
})
|
||||
|
||||
const connected = client.connect('ws://gateway.test/api/ws')
|
||||
socket.emit('open')
|
||||
await connected
|
||||
socket.message({
|
||||
jsonrpc: '2.0',
|
||||
method: 'event',
|
||||
params: { type: 'gateway.ready', payload: {} }
|
||||
})
|
||||
|
||||
await vi.advanceTimersByTimeAsync(1_000)
|
||||
expect(client.connectionState).toBe('open')
|
||||
expect(socket.readyState).toBe(FakeSocket.OPEN)
|
||||
expect(socket.sent).toEqual([])
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user