Add publish tests
This commit is contained in:
@@ -0,0 +1,228 @@
|
|||||||
|
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"
|
||||||
|
import { EventEmitter } from "events"
|
||||||
|
import { Unicast, Multicast, PublishEventType, PublishStatus, unicast, multicast } from "../src/publish"
|
||||||
|
import { AbstractAdapter, AdapterEventType } from "../src/adapter"
|
||||||
|
import { ClientMessageType, RelayMessage } from "../src/message"
|
||||||
|
import { SignedEvent, makeEvent } from "@welshman/util"
|
||||||
|
import { Nip01Signer } from '@welshman/signer'
|
||||||
|
|
||||||
|
class MockAdapter extends AbstractAdapter {
|
||||||
|
constructor(readonly url: string, readonly send) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
get sockets() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
get urls() {
|
||||||
|
return [this.url]
|
||||||
|
}
|
||||||
|
|
||||||
|
receive = (message: RelayMessage) => {
|
||||||
|
this.emit(AdapterEventType.Receive, message, this.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Unicast", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.useFakeTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.useRealTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("success works", async () => {
|
||||||
|
const sendSpy = vi.fn()
|
||||||
|
const adapter = new MockAdapter('1', sendSpy)
|
||||||
|
const signer = Nip01Signer.ephemeral()
|
||||||
|
const event = await signer.sign(makeEvent(1))
|
||||||
|
|
||||||
|
const pub = unicast({
|
||||||
|
relay: '1',
|
||||||
|
context: {getAdapter: () => adapter},
|
||||||
|
event,
|
||||||
|
})
|
||||||
|
|
||||||
|
const successSpy = vi.fn()
|
||||||
|
const failureSpy = vi.fn()
|
||||||
|
const completeSpy = vi.fn()
|
||||||
|
|
||||||
|
pub.on(PublishEventType.Success, successSpy)
|
||||||
|
pub.on(PublishEventType.Failure, failureSpy)
|
||||||
|
pub.on(PublishEventType.Complete, completeSpy)
|
||||||
|
|
||||||
|
await vi.advanceTimersByTimeAsync(200)
|
||||||
|
|
||||||
|
expect(sendSpy).toHaveBeenCalledWith([ClientMessageType.Event, event])
|
||||||
|
|
||||||
|
adapter.receive(["OK", event.id, true, "hi"])
|
||||||
|
|
||||||
|
await vi.runAllTimers()
|
||||||
|
|
||||||
|
expect(successSpy).toHaveBeenCalledWith(event.id, "hi")
|
||||||
|
expect(failureSpy).not.toHaveBeenCalled()
|
||||||
|
expect(completeSpy).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("failure works", async () => {
|
||||||
|
const sendSpy = vi.fn()
|
||||||
|
const adapter = new MockAdapter('1', sendSpy)
|
||||||
|
const signer = Nip01Signer.ephemeral()
|
||||||
|
const event = await signer.sign(makeEvent(1))
|
||||||
|
|
||||||
|
const pub = unicast({
|
||||||
|
relay: '1',
|
||||||
|
context: {getAdapter: () => adapter},
|
||||||
|
event,
|
||||||
|
})
|
||||||
|
|
||||||
|
const successSpy = vi.fn()
|
||||||
|
const failureSpy = vi.fn()
|
||||||
|
const completeSpy = vi.fn()
|
||||||
|
|
||||||
|
pub.on(PublishEventType.Success, successSpy)
|
||||||
|
pub.on(PublishEventType.Failure, failureSpy)
|
||||||
|
pub.on(PublishEventType.Complete, completeSpy)
|
||||||
|
|
||||||
|
await vi.advanceTimersByTimeAsync(200)
|
||||||
|
|
||||||
|
expect(sendSpy).toHaveBeenCalledWith([ClientMessageType.Event, event])
|
||||||
|
|
||||||
|
adapter.receive(["OK", event.id, false, "hi"])
|
||||||
|
|
||||||
|
await vi.runAllTimers()
|
||||||
|
|
||||||
|
expect(successSpy).not.toHaveBeenCalled()
|
||||||
|
expect(failureSpy).toHaveBeenCalledWith(event.id, "hi")
|
||||||
|
expect(completeSpy).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("timeout works", async () => {
|
||||||
|
const sendSpy = vi.fn()
|
||||||
|
const adapter = new MockAdapter('1', sendSpy)
|
||||||
|
const signer = Nip01Signer.ephemeral()
|
||||||
|
const event = await signer.sign(makeEvent(1))
|
||||||
|
|
||||||
|
const pub = unicast({
|
||||||
|
relay: '1',
|
||||||
|
context: {getAdapter: () => adapter},
|
||||||
|
event,
|
||||||
|
})
|
||||||
|
|
||||||
|
const successSpy = vi.fn()
|
||||||
|
const failureSpy = vi.fn()
|
||||||
|
const completeSpy = vi.fn()
|
||||||
|
const timeoutSpy = vi.fn()
|
||||||
|
|
||||||
|
pub.on(PublishEventType.Success, successSpy)
|
||||||
|
pub.on(PublishEventType.Failure, failureSpy)
|
||||||
|
pub.on(PublishEventType.Complete, completeSpy)
|
||||||
|
pub.on(PublishEventType.Timeout, timeoutSpy)
|
||||||
|
|
||||||
|
await vi.runAllTimers(200)
|
||||||
|
|
||||||
|
expect(sendSpy).toHaveBeenCalledWith([ClientMessageType.Event, event])
|
||||||
|
|
||||||
|
await vi.runAllTimers()
|
||||||
|
|
||||||
|
expect(successSpy).not.toHaveBeenCalled()
|
||||||
|
expect(failureSpy).not.toHaveBeenCalled(event.id, "hi")
|
||||||
|
expect(completeSpy).toHaveBeenCalled()
|
||||||
|
expect(timeoutSpy).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("abort works", async () => {
|
||||||
|
const sendSpy = vi.fn()
|
||||||
|
const adapter = new MockAdapter('1', sendSpy)
|
||||||
|
const signer = Nip01Signer.ephemeral()
|
||||||
|
const event = await signer.sign(makeEvent(1))
|
||||||
|
|
||||||
|
const pub = unicast({
|
||||||
|
relay: '1',
|
||||||
|
context: {getAdapter: () => adapter},
|
||||||
|
event,
|
||||||
|
})
|
||||||
|
|
||||||
|
const successSpy = vi.fn()
|
||||||
|
const failureSpy = vi.fn()
|
||||||
|
const completeSpy = vi.fn()
|
||||||
|
const abortSpy = vi.fn()
|
||||||
|
|
||||||
|
pub.on(PublishEventType.Success, successSpy)
|
||||||
|
pub.on(PublishEventType.Failure, failureSpy)
|
||||||
|
pub.on(PublishEventType.Complete, completeSpy)
|
||||||
|
pub.on(PublishEventType.Timeout, abortSpy)
|
||||||
|
|
||||||
|
await vi.runAllTimers(200)
|
||||||
|
|
||||||
|
expect(sendSpy).toHaveBeenCalledWith([ClientMessageType.Event, event])
|
||||||
|
|
||||||
|
pub.abort()
|
||||||
|
|
||||||
|
await vi.runAllTimers()
|
||||||
|
|
||||||
|
expect(successSpy).not.toHaveBeenCalled()
|
||||||
|
expect(failureSpy).not.toHaveBeenCalled(event.id, "hi")
|
||||||
|
expect(completeSpy).toHaveBeenCalled()
|
||||||
|
expect(abortSpy).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Multicast", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.useFakeTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.useRealTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should all basically work", async () => {
|
||||||
|
const send1Spy = vi.fn()
|
||||||
|
const adapter1 = new MockAdapter('1', send1Spy)
|
||||||
|
const send2Spy = vi.fn()
|
||||||
|
const adapter2 = new MockAdapter('2', send2Spy)
|
||||||
|
const send3Spy = vi.fn()
|
||||||
|
const adapter3 = new MockAdapter('3', send3Spy)
|
||||||
|
const signer = Nip01Signer.ephemeral()
|
||||||
|
const event = await signer.sign(makeEvent(1))
|
||||||
|
|
||||||
|
const pub = multicast({
|
||||||
|
event,
|
||||||
|
relays: ['1', '2', '3'],
|
||||||
|
context: {
|
||||||
|
getAdapter: (url: string) => {
|
||||||
|
switch(url) {
|
||||||
|
case '1': return adapter1
|
||||||
|
case '2': return adapter2
|
||||||
|
case '3': return adapter3
|
||||||
|
default: throw new Error(`Unknown relay: ${url}`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const successSpy = vi.fn()
|
||||||
|
const failureSpy = vi.fn()
|
||||||
|
const completeSpy = vi.fn()
|
||||||
|
const timeoutSpy = vi.fn()
|
||||||
|
|
||||||
|
pub.on(PublishEventType.Success, successSpy)
|
||||||
|
pub.on(PublishEventType.Failure, failureSpy)
|
||||||
|
pub.on(PublishEventType.Complete, completeSpy)
|
||||||
|
pub.on(PublishEventType.Timeout, timeoutSpy)
|
||||||
|
|
||||||
|
adapter1.receive(["OK", event.id, true, "hi"])
|
||||||
|
adapter2.receive(["OK", event.id, false, "hi"])
|
||||||
|
|
||||||
|
|
||||||
|
await vi.runAllTimers()
|
||||||
|
|
||||||
|
expect(successSpy).toHaveBeenCalledWith(event.id, "hi", "1")
|
||||||
|
expect(failureSpy).toHaveBeenCalledWith(event.id, "hi", "2")
|
||||||
|
expect(completeSpy).toHaveBeenCalledTimes(1)
|
||||||
|
expect(timeoutSpy).toHaveBeenCalledWith("3")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,17 +1,22 @@
|
|||||||
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"
|
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"
|
||||||
import { Nip01Signer } from '@welshman/signer'
|
import { Nip01Signer } from '@welshman/signer'
|
||||||
import { LOCAL_RELAY_URL, makeEvent } from '@welshman/util'
|
import { LOCAL_RELAY_URL, makeEvent } from '@welshman/util'
|
||||||
import { ClientMessageType } from "../src/message"
|
import { ClientMessageType, RelayMessage } from "../src/message"
|
||||||
import { AdapterContext, AbstractAdapter, AdapterEventType } from "../src/adapter"
|
import { AdapterContext, AbstractAdapter, AdapterEventType } from "../src/adapter"
|
||||||
import { unireq, multireq, RequestEventType } from "../src/request"
|
import { unireq, multireq, RequestEventType } from "../src/request"
|
||||||
import { Tracker } from "../src/tracker"
|
import { Tracker } from "../src/tracker"
|
||||||
|
|
||||||
class MockAdapter extends AbstractAdapter {
|
class MockAdapter extends AbstractAdapter {
|
||||||
constructor(readonly send) {
|
constructor(readonly url: string, readonly send) {
|
||||||
super()
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
this.sockets = []
|
get sockets() {
|
||||||
this.urls = [LOCAL_RELAY_URL]
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
get urls() {
|
||||||
|
return [this.url]
|
||||||
}
|
}
|
||||||
|
|
||||||
receive = (message: RelayMessage) => {
|
receive = (message: RelayMessage) => {
|
||||||
@@ -24,9 +29,13 @@ describe("Unireq", () => {
|
|||||||
vi.useFakeTimers()
|
vi.useFakeTimers()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.useRealTimers()
|
||||||
|
})
|
||||||
|
|
||||||
it("everything basically works", async () => {
|
it("everything basically works", async () => {
|
||||||
const sendSpy = vi.fn()
|
const sendSpy = vi.fn()
|
||||||
const adapter = new MockAdapter(sendSpy)
|
const adapter = new MockAdapter('1', sendSpy)
|
||||||
const req = unireq({
|
const req = unireq({
|
||||||
relay: 'whatever',
|
relay: 'whatever',
|
||||||
filter: {kinds: [1]},
|
filter: {kinds: [1]},
|
||||||
@@ -78,11 +87,19 @@ describe("Unireq", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("Multireq", () => {
|
describe("Multireq", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.useFakeTimers()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.useRealTimers()
|
||||||
|
})
|
||||||
|
|
||||||
it("everything basically works", async () => {
|
it("everything basically works", async () => {
|
||||||
const send1Spy = vi.fn()
|
const send1Spy = vi.fn()
|
||||||
const adapter1 = new MockAdapter(send1Spy)
|
const adapter1 = new MockAdapter('1', send1Spy)
|
||||||
const send2Spy = vi.fn()
|
const send2Spy = vi.fn()
|
||||||
const adapter2 = new MockAdapter(send2Spy)
|
const adapter2 = new MockAdapter('2', send2Spy)
|
||||||
const req = multireq({
|
const req = multireq({
|
||||||
autoClose: true,
|
autoClose: true,
|
||||||
relays: ['1', '2'],
|
relays: ['1', '2'],
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export class Unicast extends (EventEmitter as new () => TypedEmitter<UnicastEven
|
|||||||
if (isRelayOk(message)) {
|
if (isRelayOk(message)) {
|
||||||
const [_, id, ok, detail] = message
|
const [_, id, ok, detail] = message
|
||||||
|
|
||||||
|
|
||||||
if (id !== this.options.event.id) return
|
if (id !== this.options.event.id) return
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
@@ -85,7 +86,7 @@ export class Unicast extends (EventEmitter as new () => TypedEmitter<UnicastEven
|
|||||||
|
|
||||||
// Start asynchronously so the caller can set up listeners
|
// Start asynchronously so the caller can set up listeners
|
||||||
yieldThread().then(() => {
|
yieldThread().then(() => {
|
||||||
this._adapter.send([ClientMessageType.Event, event])
|
this._adapter.send([ClientMessageType.Event, this.options.event])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,6 +160,7 @@ export class Multicast extends (EventEmitter as new () => TypedEmitter<Multicast
|
|||||||
|
|
||||||
if (this._completed.size === relays.length) {
|
if (this._completed.size === relays.length) {
|
||||||
this.emit(PublishEventType.Complete)
|
this.emit(PublishEventType.Complete)
|
||||||
|
this.cleanup()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -173,9 +175,7 @@ export class Multicast extends (EventEmitter as new () => TypedEmitter<Multicast
|
|||||||
}
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
for (const child of this._children) {
|
this.removeAllListeners()
|
||||||
child.cleanup()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user