nostream/test/unit/handlers/delegated-event-message-handler.spec.ts
Ricardo Arturo Cabral Mejía f9c53eeeb8 feat: massive update
Signed-off-by: Ricardo Arturo Cabral Mejía <me@ricardocabral.io>
2023-02-02 00:19:26 -05:00

229 lines
7.6 KiB
TypeScript

import chai from 'chai'
import chaiAsPromised from 'chai-as-promised'
import EventEmitter from 'events'
import Sinon from 'sinon'
import sinonChai from 'sinon-chai'
chai.use(sinonChai)
chai.use(chaiAsPromised)
import { IncomingEventMessage, MessageType } from '../../../src/@types/messages'
import { DelegatedEventMessageHandler } from '../../../src/handlers/delegated-event-message-handler'
import { Event } from '../../../src/@types/event'
import { EventMessageHandler } from '../../../src/handlers/event-message-handler'
import { IUserRepository } from '../../../src/@types/repositories'
import { WebSocketAdapterEvent } from '../../../src/constants/adapter'
const { expect } = chai
describe('DelegatedEventMessageHandler', () => {
let webSocket: EventEmitter
let handler: DelegatedEventMessageHandler
let userRepository: IUserRepository
let event: Event
let message: IncomingEventMessage
let sandbox: Sinon.SinonSandbox
let originalConsoleWarn: any = undefined
beforeEach(() => {
sandbox = Sinon.createSandbox()
originalConsoleWarn = console.warn
console.warn = () => undefined
event = {
content: 'hello',
created_at: 1665546189,
id: 'f'.repeat(64),
kind: 1,
pubkey: 'f'.repeat(64),
sig: 'f'.repeat(128),
tags: [
['delegation', 'delegator', 'rune', 'signature'],
],
}
})
afterEach(() => {
console.warn = originalConsoleWarn
sandbox.restore()
})
describe('handleMessage', () => {
let canAcceptEventStub: Sinon.SinonStub
let isEventValidStub: Sinon.SinonStub
let strategyFactoryStub: Sinon.SinonStub
let onMessageSpy: Sinon.SinonSpy
let strategyExecuteStub: Sinon.SinonStub
let isRateLimitedStub: Sinon.SinonStub
let isUserAdmitted: Sinon.SinonStub
beforeEach(() => {
canAcceptEventStub = sandbox.stub(DelegatedEventMessageHandler.prototype, 'canAcceptEvent' as any)
isEventValidStub = sandbox.stub(DelegatedEventMessageHandler.prototype, 'isEventValid' as any)
isUserAdmitted = sandbox.stub(EventMessageHandler.prototype, 'isUserAdmitted' as any)
strategyExecuteStub = sandbox.stub()
strategyFactoryStub = sandbox.stub().returns({
execute: strategyExecuteStub,
})
onMessageSpy = sandbox.fake.returns(undefined)
webSocket = new EventEmitter()
webSocket.on(WebSocketAdapterEvent.Message, onMessageSpy)
message = [MessageType.EVENT, event]
isRateLimitedStub = sandbox.stub(EventMessageHandler.prototype, 'isRateLimited' as any)
handler = new DelegatedEventMessageHandler(
webSocket as any,
strategyFactoryStub,
userRepository,
() => ({}) as any,
() => ({ hit: async () => false }),
)
})
afterEach(() => {
isEventValidStub.restore()
canAcceptEventStub.restore()
webSocket.removeAllListeners()
})
it('rejects event if it can\'t be accepted', async () => {
canAcceptEventStub.returns('reason')
await handler.handleMessage(message)
expect(canAcceptEventStub).to.have.been.calledOnceWithExactly(event)
expect(onMessageSpy).to.have.been.calledOnceWithExactly(
[
MessageType.OK,
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
false,
'reason',
],
)
expect(strategyFactoryStub).not.to.have.been.called
})
it('rejects event if invalid', async () => {
isEventValidStub.returns('reason')
await handler.handleMessage(message)
expect(isEventValidStub).to.have.been.calledOnceWithExactly(event)
expect(onMessageSpy).not.to.have.been.calledOnceWithExactly()
expect(strategyFactoryStub).not.to.have.been.called
})
it('rejects event if rate-limited', async () => {
isRateLimitedStub.resolves(true)
await handler.handleMessage(message)
expect(isRateLimitedStub).to.have.been.calledOnceWithExactly(event)
expect(onMessageSpy).to.have.been.calledOnceWithExactly(
[MessageType.OK, event.id, false, 'rate-limited: slow down'],
)
expect(strategyFactoryStub).not.to.have.been.called
})
it('rejects event is user is not admitted', async () => {
isUserAdmitted.resolves('not admitted')
await handler.handleMessage(message)
expect(isRateLimitedStub).to.have.been.calledOnceWithExactly(event)
expect(isUserAdmitted).to.have.been.calledOnceWithExactly(event)
expect(onMessageSpy).to.have.been.calledOnceWithExactly([
MessageType.OK,
event.id,
false,
'not admitted',
])
})
it('does not call strategy if none given', async () => {
isEventValidStub.returns(undefined)
canAcceptEventStub.returns(undefined)
strategyFactoryStub.returns(undefined)
await handler.handleMessage(message)
expect(isEventValidStub).to.have.been.calledOnceWithExactly(event)
expect(onMessageSpy).not.to.have.been.calledOnceWithExactly()
expect(strategyFactoryStub).to.have.been.calledOnceWithExactly([
event,
webSocket,
])
expect(strategyExecuteStub).not.to.have.been.called
})
it('calls strategy with event', async () => {
isEventValidStub.returns(undefined)
canAcceptEventStub.returns(undefined)
await handler.handleMessage(message)
expect(isEventValidStub).to.have.been.calledOnceWithExactly(event)
expect(onMessageSpy).not.to.have.been.calledOnceWithExactly()
expect(strategyFactoryStub).to.have.been.calledOnceWithExactly([
event,
webSocket,
])
expect(strategyExecuteStub).to.have.been.calledOnceWithExactly(event)
})
it('does not reject if strategy rejects', async () => {
const error = new Error('mistakes were made')
isEventValidStub.returns(undefined)
canAcceptEventStub.returns(undefined)
strategyExecuteStub.rejects(error)
return expect(handler.handleMessage(message)).to.eventually.be.fulfilled
})
})
describe('isEventValid', () => {
let parentIsEventValidStub: Sinon.SinonStub
beforeEach(() => {
parentIsEventValidStub = Sinon.stub(EventMessageHandler.prototype, 'isEventValid' as any)
event = {
'id': 'a080fd288b60ac2225ff2e2d815291bd730911e583e177302cc949a15dc2b2dc',
'pubkey': '62903b1ff41559daf9ee98ef1ae67cc52f301bb5ce26d14baba3052f649c3f49',
'created_at': 1660896109,
'kind': 1,
'tags': [
[
'delegation',
'86f0689bd48dcd19c67a19d994f938ee34f251d8c39976290955ff585f2db42e',
'kind=1&created_at>1640995200',
'c33c88ba78ec3c760e49db591ac5f7b129e3887c8af7729795e85a0588007e5ac89b46549232d8f918eefd73e726cb450135314bfda419c030d0b6affe401ec1',
],
],
'content': 'Hello world',
'sig': 'cd4a3cd20dc61dcbc98324de561a07fd23b3d9702115920c0814b5fb822cc5b7c5bcdaf3fa326d24ed50c5b9c8214d66c75bae34e3a84c25e4d122afccb66eb6',
}
})
afterEach(() => {
parentIsEventValidStub.restore()
})
it('returns undefined if event and delegate tag is valid', async () => {
parentIsEventValidStub.resolves(undefined)
expect(await (handler as any).isEventValid(event)).to.be.undefined
})
it('returns reason if event is not valid', () => {
parentIsEventValidStub.resolves('reason')
return expect((handler as any).isEventValid(event)).to.eventually.equal('reason')
})
it('returns reason if delegate signature is not valid', () => {
parentIsEventValidStub.resolves(undefined)
event.tags[0][3] = 'wrong sig'
return expect((handler as any).isEventValid(event)).to.eventually.equal('invalid: delegation verification failed')
})
})
})