Add tests

This commit is contained in:
Ticruz
2025-02-04 13:21:23 +01:00
committed by Jon Staab
parent 917727c86f
commit 8a2b62f693
57 changed files with 9231 additions and 25 deletions
@@ -0,0 +1,200 @@
import {ConnectionSender} from "../src/ConnectionSender"
import {Connection} from "../src/Connection"
import {Message, SocketStatus} from "../src/Socket"
import {AuthStatus} from "../src/ConnectionAuth"
import {AUTH_JOIN} from "@welshman/util"
import {vi, describe, it, expect, beforeEach, afterEach} from "vitest"
describe("ConnectionSender", () => {
let connection: Connection
let sender: ConnectionSender
beforeEach(() => {
vi.useFakeTimers()
connection = new Connection("wss://test.relay/")
connection.socket.send = vi.fn().mockResolvedValue(undefined)
connection.socket.open = vi.fn().mockResolvedValue(undefined)
connection.socket.status = SocketStatus.Open
connection.send = vi.fn().mockResolvedValue(undefined)
sender = connection.sender
})
afterEach(() => {
vi.useRealTimers()
})
describe("message deferral", () => {
it("should not defer CLOSE messages", async () => {
// First send a REQ message to set up the pending request
const reqId = "subscription-id"
sender.push([
"REQ",
reqId,
{
/* filters */
},
] as Message)
const message: Message = ["CLOSE", reqId]
// there is a setTimeout in the worker, so we need to advance timers
vi.advanceTimersByTime(50)
sender.push(message)
// there is a setTimeout in the worker, so we need to advance timers
vi.advanceTimersByTime(50)
expect(connection.socket.send).toHaveBeenCalledWith(message)
})
it("should defer messages when socket is not open", () => {
connection.socket.status = SocketStatus.Closed
const message: Message = [
"EVENT",
{
/* event data */
},
]
sender.push(message)
expect(connection.socket.send).not.toHaveBeenCalled()
expect(sender.worker.buffer).toContain(message)
})
it("should not defer AUTH messages", () => {
const message: Message = [
"AUTH",
{
/* auth data */
},
]
sender.push(message)
// there is a setTimeout in the worker, so we need to advance timers
vi.advanceTimersByTime(50)
expect(connection.socket.send).toHaveBeenCalledWith(message)
})
it("should not defer AUTH_JOIN event messages", () => {
const message: Message = ["EVENT", {kind: AUTH_JOIN}]
sender.push(message)
// there is a setTimeout in the worker, so we need to advance timers
vi.advanceTimersByTime(50)
expect(connection.socket.send).toHaveBeenCalledWith(message)
})
it("should defer messages when auth is pending", () => {
connection.socket.status = SocketStatus.Open
connection.auth.status = AuthStatus.PendingResponse
const message: Message = [
"EVENT",
{
/* event data */
},
]
sender.push(message)
vi.advanceTimersByTime(50)
expect(connection.socket.send).not.toHaveBeenCalled()
expect(sender.worker.buffer).toContain(message)
})
it("should defer REQ messages when too many pending requests", () => {
connection.socket.status = SocketStatus.Open
connection.auth.status = AuthStatus.Ok
// Set up 8 pending requests
for (let i = 0; i < 8; i++) {
connection.state.pendingRequests.set(`req${i}`, {
filters: [],
sent: Date.now(),
})
}
const message: Message = [
"REQ",
"newReq",
{
/* filter */
},
]
sender.push(message)
vi.advanceTimersByTime(50)
expect(connection.socket.send).not.toHaveBeenCalled()
expect(sender.worker.buffer).toContain(message)
})
})
describe("message handling", () => {
it("should send messages when conditions are met", () => {
connection.socket.status = SocketStatus.Open
connection.auth.status = AuthStatus.Ok
const message: Message = [
"EVENT",
{
/* event data */
},
]
sender.push(message)
vi.advanceTimersByTime(50)
expect(connection.socket.send).toHaveBeenCalledWith(message)
})
it("should handle CLOSE messages for non-existent requests", () => {
const message: Message = ["CLOSE", "non-existent-req"]
sender.push(message)
expect(connection.socket.send).not.toHaveBeenCalled()
})
it("should remove pending REQ when handling CLOSE", () => {
const reqId = "req123"
const reqMessage: Message = [
"REQ",
reqId,
{
/* filter */
},
]
sender.worker.buffer.push(reqMessage)
const closeMessage: Message = ["CLOSE", reqId]
sender.push(closeMessage)
expect(sender.worker.buffer).not.toContain(reqMessage)
})
})
describe("worker behavior", () => {
it("should process deferred messages when conditions become favorable", async () => {
connection.socket.status = SocketStatus.Closed
const message: Message = [
"EVENT",
{
/* event data */
},
]
sender.push(message)
vi.advanceTimersByTime(50)
expect(connection.socket.send).not.toHaveBeenCalled()
// Simulate socket opening and auth completing
connection.socket.status = SocketStatus.Open
connection.auth.status = AuthStatus.Ok
// Trigger worker processing
sender.worker.resume()
vi.advanceTimersByTime(50)
expect(connection.socket.send).toHaveBeenCalledWith(message)
})
it("should maintain message order", async () => {
connection.socket.status = SocketStatus.Open
connection.auth.status = AuthStatus.Ok
const messages: Message[] = [
["EVENT", {id: "1"}],
["EVENT", {id: "2"}],
["EVENT", {id: "3"}],
]
messages.forEach(msg => sender.push(msg))
vi.advanceTimersByTime(50)
const sendCalls = connection.socket.send.mock.calls
expect(sendCalls.map(call => call[0])).toEqual(messages)
})
})
})