diff --git a/packages/net2/__tests__/publish.test.ts b/packages/net2/__tests__/publish.test.ts new file mode 100644 index 0000000..70157ed --- /dev/null +++ b/packages/net2/__tests__/publish.test.ts @@ -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") + }) +}) diff --git a/packages/net2/__tests__/request.test.ts b/packages/net2/__tests__/request.test.ts index d84f014..ffec9f2 100644 --- a/packages/net2/__tests__/request.test.ts +++ b/packages/net2/__tests__/request.test.ts @@ -1,17 +1,22 @@ import { describe, expect, it, vi, beforeEach, afterEach } from "vitest" import { Nip01Signer } from '@welshman/signer' 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 { unireq, multireq, RequestEventType } from "../src/request" import { Tracker } from "../src/tracker" class MockAdapter extends AbstractAdapter { - constructor(readonly send) { + constructor(readonly url: string, readonly send) { super() + } - this.sockets = [] - this.urls = [LOCAL_RELAY_URL] + get sockets() { + return [] + } + + get urls() { + return [this.url] } receive = (message: RelayMessage) => { @@ -24,9 +29,13 @@ describe("Unireq", () => { vi.useFakeTimers() }) + afterEach(() => { + vi.useRealTimers() + }) + it("everything basically works", async () => { const sendSpy = vi.fn() - const adapter = new MockAdapter(sendSpy) + const adapter = new MockAdapter('1', sendSpy) const req = unireq({ relay: 'whatever', filter: {kinds: [1]}, @@ -78,11 +87,19 @@ describe("Unireq", () => { }) describe("Multireq", () => { + beforeEach(() => { + vi.useFakeTimers() + }) + + afterEach(() => { + vi.useRealTimers() + }) + it("everything basically works", async () => { const send1Spy = vi.fn() - const adapter1 = new MockAdapter(send1Spy) + const adapter1 = new MockAdapter('1', send1Spy) const send2Spy = vi.fn() - const adapter2 = new MockAdapter(send2Spy) + const adapter2 = new MockAdapter('2', send2Spy) const req = multireq({ autoClose: true, relays: ['1', '2'], diff --git a/packages/net2/src/publish.ts b/packages/net2/src/publish.ts index 7693eb7..eccf946 100644 --- a/packages/net2/src/publish.ts +++ b/packages/net2/src/publish.ts @@ -58,6 +58,7 @@ export class Unicast extends (EventEmitter as new () => TypedEmitter TypedEmitter { - 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 TypedEmitter