MockRedis

repository·main·Indexed 19 days ago

https://github.com/sds/mock_redis

An in-memory implementation of the redis-rb interface for Ruby testing environments. It allows developers to simulate Redis behavior without a running server, supporting string, list, set, hash, sorted set, and geospatial methods. Compatible with Ruby 3.x and redis-rb 5.x, and tested against Redis 6.2 and 7.0.

Tokens
6.9K
Snippets
23
Records
30
Agent score
68%

What's inside mock_redis

  1. Understand MockRedis limitations and exceptions

    main

    Because MockRedis is an in-memory object confined to a single Ruby process, it behaves differently than a real Redis server in several ways:

    Blocking List Commands

    Commands like #blmove, #blpop, #brpop, and #brpoplpush work normally if data is available. However:

    • If a nonzero timeout is used and no data is available, the command returns immediately.
    • If a 0 timeout (wait forever) is used and no data is available, a MockRedis::WouldBlock exception is raised to prevent the test from hanging indefinitely.

    Command Behavior Differences

    • #info: Returns canned values that do not update over time.
    • #sort: Supports ASC and DESC sorting, but ALPHA sort is not supported.
    • #config: Methods like :get, :set, and :resetstat are not yet implemented and return canned values.
  2. MockRedis Requirements

    main

    To use MockRedis, ensure your environment meets the following requirements:

    • Ruby: 3.x
    • redis-rb: 5.x

    Note: The implementation is tested against Redis 6.2 and 7.0. Using older Redis versions may result in different behavior or unsupported commands.

  3. Get Started with MockRedis

    main

    To use MockRedis, require the gem and instantiate a new object. It provides the same method interface as a real Redis object from the redis-rb library, allowing you to swap a real Redis connection for an in-memory one in your test suites.

    require 'mock_redis'
    
    # Initialize the mock client
    mr = MockRedis.new
    
    # Use it just like a real Redis client
    mr.set('some key', 'some value') # => "OK"
    puts mr.get('some key')           # => "some value"
  4. Configure MockRedis via URL or Environment Variables

    main

    MockRedis supports configuring its connection parameters using a URI string. This can be passed via the :url key in the options hash or by setting the REDIS_URL environment variable.

    If a :path is provided in the URI, MockRedis treats the connection as a Unix domain socket (setting the scheme to 'unix'). Otherwise, it expects a valid host in the URI.

    URI Formats:

    • Standard: redis://[password@]host[:port]/db
    • Unix Socket: unix:///path/to/socket
    # Example: Unix socket via path
    redis = MockRedis.new(url: 'unix:///tmp/redis.sock')
    
    # Example: Standard Redis URI
    redis = MockRedis.new(url: 'redis://user:pass@localhost:6379/1')
  5. Unsupported Commands in MockRedis

    main

    The following commands are not available or are not fully functional in MockRedis:

    • Debugging: #debug('object', key) and #debug('segfault') are unavailable.
    • Internals: #object is unavailable.
    • Monitoring: #monitor is unavailable.
    • Pub/Sub: #psubscribe, #publish, and #punsubscribe are unavailable.
    • Logging: #slowlog is unavailable.
    • Scripting: #script, #eval, and #evalsha are implemented as stubs and will not execute any logic.
  6. Supported Redis Commands in MockRedis

    main

    MockRedis supports most methods provided by redis-rb. Supported categories include:

    • String methods: get, set, append, incr, etc.
    • List methods: lpush, lpop, lrange, rpoplpush, etc.
    • Set methods: sadd, sinter, sismember, srandmember, etc.
    • Hash methods: hset, hget, hgetall, hmget, hincrby, hincrbyfloat, etc.
    • Sorted set methods: zadd, zrank, zunionstore, etc.
    • Expirations: expire, pexpire, ttl, pttl, etc.
    • Transactions: multi, exec, discard
    • Futures
  7. Limitations of MockRedis Stream implementations

    main

    When using MockRedis for testing Redis Streams, be aware of the following functional gaps:

    1. Argument Ignorance: For both xadd and xtrim, the approximate: true argument is currently ignored. This means the trimming behavior may not match the exact performance characteristics of a real Redis instance.
    2. Missing Commands: The following commands are not yet implemented and will likely result in errors or missing functionality if called: xgroup, xreadgroup, xack, xpending, xclaim, xinfo, and xdel.
  8. Use mapped_hmset and mapped_hmget for Ruby Hash compatibility

    main

    While standard Redis commands like hmset and hmget use flat argument lists (e.g., key, field1, val1, field2, val2), MockRedis provides mapped_ variants that are more idiomatic for Ruby developers working with Hash objects.

    • mapped_hmset(key, hash): Accepts a Ruby Hash and expands it into the required key-value pairs for the command.
    • mapped_hmget(key, *fields): Takes a list of fields and returns a Ruby Hash where keys are the requested fields and values are the retrieved data.
    redis = MockRedis.new
    my_data = { "a" => "1", "b" => "2" }
    
    # Using mapped_hmset to store a Ruby Hash
    redis.mapped_hmset("mykey", my_data)
    
    # Using mapped_hmget to get a Ruby Hash back
    result = redis.mapped_hmget("mykey", "a", "b")
    # => {"a"=>"1", "b"=>"2"}
  9. Use MockRedis connection methods

    main

    MockRedis implements several methods to mimic a real Redis client connection lifecycle, making it compatible with code expecting a standard Redis client:

    • connect: Returns the instance itself.
    • reconnect: Returns the instance itself.
    • client: Returns the instance itself.
    • with: Yields the instance to a block.
    • id (or location): Returns a string representation of the connection (e.g., "redis://127.0.0.1:6379/0").
    redis = MockRedis.new
    
    # Using the block syntax
    redis.with do |r|
      r.set('key', 'value')
    end
    
    # Checking connection identity
    puts redis.id # => "redis://127.0.0.1:6379/0"
  10. Enable command logging in MockRedis

    main

    To debug the commands being sent to the mock, you can provide a :logger in the options hash. When a logger is present and its debug? method returns true, MockRedis will log every command and its arguments, along with the execution time.

    Log Format:

    • [MockRedis] command=COMMAND_NAME args=arg1 arg2 ...
    • [MockRedis] call_time=X.XX ms
    require 'logger'
    
    logger = Logger.new(STDOUT)
    logger.level = Logger::DEBUG
    
    redis = MockRedis.new(logger: logger)
    redis.set('foo', 'bar')
    # Log output: [MockRedis] command=SET args=foo bar
    # Log output: [MockRedis] call_time=0.01 ms
  11. Initialize and connect to MockRedis

    main

    You can create a new MockRedis instance using MockRedis.new or MockRedis.connect. The initializer accepts an options hash that can be used to configure the mock environment. You can also provide a :url key in the options hash or set the REDIS_URL environment variable to configure connection details via a URI.

    Supported configuration options include:

    • :scheme: The URI scheme (defaults to 'redis').
    • :host: The hostname (defaults to '127.0.0.1').
    • :port: The port number (defaults to 6379).
    • :path: Used for Unix domain sockets; if present, the scheme is set to 'unix'.
    • :timeout: Connection timeout (defaults to 5.0).
    • :password: Authentication password.
    • :logger: A logger object for debugging commands.
    • :db: The database index (defaults to 0).
    • :time_class: A class used for time-related operations (defaults to Time).
    # Using the connect factory method
    redis = MockRedis.connect(host: 'localhost', port: 6379)
    
    # Using a connection URL
    redis = MockRedis.new(url: 'redis://127.0.0.1:6379/0')
    
    # Using environment variables
    ENV['REDIS_URL'] = 'redis://localhost:6379'
    redis = MockRedis.new