Skip to content

Bug: RedisMock.HSet fails on Windows (Redis 3.x) #243

@1ennyTM

Description

@1ennyTM

Summary

The HSet method in RedisMock passes a JavaScript object to ioredis's hset(), which ioredis flattens to variadic HSET key f1 v1 f2 v2. This fails on Windows where redis-memory-server uses Redis 3.0.503 (variadic HSET requires Redis 4.0+).

Environment

  • OS: Windows 11
  • Node.js: v22.x
  • redis-memory-server: downloads Redis 3.0.503 on Windows
  • Package: @devvit/redis test mocks

Steps to Reproduce

  1. Use RedisMock from @devvit/redis/test on Windows
  2. Call redisMock.plugin.HSet() with multiple field-value pairs
  3. Error occurs

Actual Error

ReplyError: ERR wrong number of arguments for 'hset' command

Reproduction Test (Vitest)

Click to expand test code
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { Redis } from 'ioredis';
import { RedisMemoryServer } from 'redis-memory-server';
import { RedisMock } from '@devvit/redis/test';

describe('HSet Bug Verification', () => {
  let redisServer: RedisMemoryServer;
  let redisConn: Redis;
  let redisMock: RedisMock;

  beforeAll(async () => {
    redisServer = new RedisMemoryServer();
    const host = await redisServer.getHost();
    const port = await redisServer.getPort();
    redisConn = new Redis({ host, port });
    redisMock = new RedisMock(redisConn, 'test');
  });

  afterAll(async () => {
    await redisConn?.quit();
    await redisServer?.stop();
  });

  it('fails HSet with multiple fields on Redis 3.x (Windows)', async () => {
    const result = await redisMock.plugin.HSet({
      key: 'mykey',
      fv: [
        { field: 'field1', value: 'value1' },
        { field: 'field2', value: 'value2' },
      ],
    });
    expect(result.value).toBeGreaterThanOrEqual(0);
  });
});

Root Cause

packages/redis/src/test/mocks/RedisMock.ts (lines 244-253)

HSet passes an object to ioredis:

const v = await this._store.conn.hset(this._makeKey(request.key, request.scope), map);

ioredis converts this to variadic args, but Redis 3.x only supports HSET key field value (single pair).

Evidence

MSet (lines 468-478) in the same file correctly uses the flattened spread pattern:

const flat: string[] = [];
for (const { key, value } of request.kv) {
  flat.push(this._makeKey(key, request.scope), value);
}
await this._store.conn.mset(...flat);

I understand the mock is experimental. Sharing in case it helps improve the test mocks.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions