diff --git a/src/command.js b/src/command.js index 0ab048f7c..f2fd3136f 100644 --- a/src/command.js +++ b/src/command.js @@ -24,6 +24,8 @@ export function throwIfInSubscriberMode(commandName, RedisMock) { 'psubscribeBuffer', 'unsubscribe', 'unsubscribeBuffer', + 'pubsub', + 'pubsubBuffer', 'punsubscribe', 'punsubscribeBuffer', 'ping', diff --git a/src/commands/index.js b/src/commands/index.js index 9126bf9c7..e5e7907da 100644 --- a/src/commands/index.js +++ b/src/commands/index.js @@ -76,6 +76,7 @@ export * from './psetex' export * from './psubscribe' export * from './pttl' export * from './publish' +export * from './pubsub' export * from './punsubscribe' export * from './quit' export * from './randomkey' diff --git a/src/commands/pubsub.js b/src/commands/pubsub.js new file mode 100644 index 000000000..a41ecf0d1 --- /dev/null +++ b/src/commands/pubsub.js @@ -0,0 +1,24 @@ +import patternMatchesString from '../commands-utils/patternMatchesString' + +export function pubsub(subCommand, pattern) { + switch (subCommand) { + case 'CHANNELS': { + let channels = [] + + this.channels?.instanceListeners?.forEach((instanceMap, channel) => { + channels.push(channel) + }) + + if (pattern) { + channels = channels.filter(x => patternMatchesString(pattern, x)) + } + + return channels + } + default: { + throw new Error('Currently not implemented as a mock') + } + } +} + +export const pubsubBuffer = pubsub diff --git a/test/integration/commands/pubsub.js b/test/integration/commands/pubsub.js new file mode 100644 index 000000000..f4442e653 --- /dev/null +++ b/test/integration/commands/pubsub.js @@ -0,0 +1,57 @@ +import Redis from 'ioredis' + +// eslint-disable-next-line import/no-relative-parent-imports +import { runTwinSuite } from '../../../test-utils' + +const testChannels = ['emails', 'messages', 'feed'] + +runTwinSuite('pubsub', command => { + // @TODO Rewrite test suite so it runs on a real Redis instance + ;(process.env.IS_E2E ? describe.skip : describe)(command, () => { + describe('CHANNELS', () => { + let redis + + beforeEach(() => { + redis = new Redis({ + host: 'pubsub', + }) + }) + + afterEach(async () => { + await Promise.all(testChannels.map(x => redis.unsubscribe(x))) + }) + + test('should return 0 when publishing without subscribers', async () => { + expect(await redis[command]('CHANNELS')).toMatchObject([]) + }) + + it('should return the single active channel', async () => { + redis.subscribe('emails') + + expect(await redis[command]('CHANNELS')).toMatchObject(['emails']) + }) + + it('should return multiple active channels', async () => { + redis.subscribe('emails') + redis.subscribe('messages') + redis.subscribe('feed') + + expect(await redis[command]('CHANNELS')).toMatchObject([ + 'emails', + 'messages', + 'feed', + ]) + }) + + it('should return filtered channels', async () => { + redis.subscribe('emails') + redis.subscribe('messages') + redis.subscribe('feed') + + expect(await redis[command]('CHANNELS', 'email*')).toMatchObject([ + 'emails', + ]) + }) + }) + }) +})