Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It doesn't trigger any events on creating a new connection to capture at on methods #1351

Open
SeyyedKhandon opened this issue Sep 9, 2024 · 0 comments

Comments

@SeyyedKhandon
Copy link

I'm trying to mock ioredis so to be able to test it, but unfortunately, am not able to do it properly, I triedioredis-mock but it doesnt trigger any event on ready, so it does not work for me or I dont know how to do it properly, please someone shed some light on it

const createCacheInstance = async () => {
  const address = process.env.REDIS_CLUSTER_ADDRESS
  const password = process.env.REDIS_AUTH_TOKEN

  logger.info(`Redis cluster env address:${address}`)

  try {
    if (!address || !password)
      throw new Error('Environment variables {REDIS_CLUSTER_ADDRESS or REDIS_AUTH_TOKEN} are not available')

    const host = address.split(':')[0]
    const port = Number(address.split(':')[1])
    logger.info(`Redis cluster host:${host} port:${port}`)

    const tlsMode = process.env.NODE_ENV === 'production' ? { tls: {} } : {} // https://github.com/redis/ioredis?tab=readme-ov-file#special-note-aws-elasticache-clusters-with-tls

    const redisCluster = new Redis.Cluster([{ host, port }], {
      slotsRefreshTimeout: 2000, // to prevent [Failed to refresh slots cache error](https://github.com/redis/ioredis/issues/711)
      scaleReads: 'all', // Send write queries to masters and read queries to masters or slaves randomly.
      dnsLookup: (address, callback) => callback(null, address), // https://github.com/redis/ioredis?tab=readme-ov-file#special-note-aws-elasticache-clusters-with-tls
      redisOptions: { password, ...tlsMode },
    })

    return await new Promise<{ redisCluster?: Cluster; error?: Error }>((resolve, reject) => {
      redisCluster
        .on('connecting', () => {
          cacheStatus = redisCluster.status
          logger.info('Connecting to Redis DB')
        })
        .on('connect', () => {
          cacheStatus = redisCluster.status
          logger.info('Connected to Redis DB')
        })
        .on('ready', () => {
          cacheStatus = redisCluster.status
          logger.info('Redis cache instance is ready to use')
          resolve({ redisCluster })
        })
        .on('end', () => {
          cacheStatus = redisCluster.status
          logger.warn('Redis cache connection has been closed')
        })
        .on('error', async (error) => {
          cacheStatus = redisCluster.status
          cacheError = error
          logger.error(error)
          try {
            await redisCluster.quit()
          } catch (e) {
            logger.error({ message: 'Error while closing the Redis cache connection', e })
          }
          reject({ error })
        })
    })
  } catch (e) {
    const error = e as Error
    logger.error(error)
    cacheStatus = 'error'
    cacheError = error
    return { error }
  }
}

What I tried which results in "Connection is closed." "ClusterAllFailedError: Failed to refresh slots cache. which seems I need to mock the connection itself too, but am not sure how?

import { afterAll, describe, expect, it, vi } from 'vitest'
import cacheManager, { useCache } from './index'
import { useHashTagKeyMaker } from './helper'

const mocks = vi.hoisted(() => {
  return {
    redisCluster: vi.fn().mockImplementation(() => ({
      set: vi.fn(),
      get: vi.fn(),
      exists: vi.fn(),
      del: vi.fn(),
      sadd: vi.fn(),
      smembers: vi.fn(),
      srem: vi.fn(),
      scard: vi.fn(),
      smismember: vi.fn(),
      flushdb: vi.fn(),
      nodes: vi.fn().mockReturnValue([{ flushdb: vi.fn() }]),
      on: vi.fn().mockImplementation((event, callback) => {
        if (event === 'ready') {
          callback()
        }
        return this
      }),
      quit: vi.fn(),
      status: 'ready',
    })),
  }
})

vi.mock('ioredis', async () => {
  const actual = await vi.importActual('ioredis')
  return {
    ...actual,
    Cluster: mocks.redisCluster,
  }
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant