diff --git a/packages/modules/redis/src/redis-container.test.ts b/packages/modules/redis/src/redis-container.test.ts index a622c24ef..f8f4fba82 100644 --- a/packages/modules/redis/src/redis-container.test.ts +++ b/packages/modules/redis/src/redis-container.test.ts @@ -119,4 +119,84 @@ describe("RedisContainer", { timeout: 240_000 }, () => { client.destroy(); // } }); + + it("should start redis with custom command", async () => { + const container = new RedisContainer(IMAGE).withCommand(["redis-server", "--loglevel", "verbose"]); + await using startedContainer = await container.start(); + + // @ts-expect-error - accessing private property for testing + expect(container.createOpts.Cmd).toEqual(["redis-server", "--loglevel", "verbose"]); + + const client = createClient({ url: startedContainer.getConnectionUrl() }); + await client.connect(); + + await client.set("key", "val"); + expect(await client.get("key")).toBe("val"); + + client.destroy(); + }); + + it("should start redis-stack with custom env", async () => { + const container = new RedisContainer(REDISSTACK_IMAGE).withEnvironment({ REDIS_ARGS: "--loglevel verbose" }); + await using startedContainer = await container.start(); + + // @ts-expect-error - accessing private property for testing + expect(container.createOpts.Env).toEqual(["REDIS_ARGS=--loglevel verbose"]); + + const client = createClient({ url: startedContainer.getConnectionUrl() }); + await client.connect(); + + await client.set("key", "val"); + expect(await client.get("key")).toBe("val"); + + client.destroy(); + }); + + it("should start redis with custom command and keeping default args", async () => { + const sourcePath = fs.mkdtempSync("redis-"); + + const container = new RedisContainer(IMAGE) + .withCommand(["redis-server", "--loglevel", "verbose"]) + .withPersistence(sourcePath); + await using startedContainer = await container.start(); + + // @ts-expect-error - accessing private property for testing + expect(container.createOpts.Cmd).toEqual([ + "redis-server", + "--loglevel", + "verbose", + "--save 1 1 ", + "--appendonly yes", + ]); + + const client = createClient({ url: startedContainer.getConnectionUrl() }); + await client.connect(); + + await client.set("key", "val"); + expect(await client.get("key")).toBe("val"); + + client.destroy(); + fs.rmSync(sourcePath, { force: true, recursive: true }); + }); + + it("should start redis-stack with custom env and keeping default args", async () => { + const sourcePath = fs.mkdtempSync("redis-"); + + const container = new RedisContainer(REDISSTACK_IMAGE) + .withEnvironment({ REDIS_ARGS: "--loglevel verbose" }) + .withPersistence(sourcePath); + await using startedContainer = await container.start(); + + // @ts-expect-error - accessing private property for testing + expect(container.createOpts.Env).toEqual(["REDIS_ARGS=--loglevel verbose --save 1 1 --appendonly yes"]); + + const client = createClient({ url: startedContainer.getConnectionUrl() }); + await client.connect(); + + await client.set("key", "val"); + expect(await client.get("key")).toBe("val"); + + client.destroy(); + fs.rmSync(sourcePath, { force: true, recursive: true }); + }); }); diff --git a/packages/modules/redis/src/redis-container.ts b/packages/modules/redis/src/redis-container.ts index 2b5819843..94540dfb6 100644 --- a/packages/modules/redis/src/redis-container.ts +++ b/packages/modules/redis/src/redis-container.ts @@ -44,11 +44,21 @@ export class RedisContainer extends GenericContainer { ...(this.persistenceVolume ? ["--save 1 1 ", "--appendonly yes"] : []), ]; if (this.imageName.image.includes("redis-stack")) { + const existingRedisArgs = this.environment["REDIS_ARGS"] ?? ""; + + // merge with filter to remove empty items + const mergedRedisArgs = [existingRedisArgs, ...redisArgs].filter(Boolean).join(" "); + + // remove existing REDIS_ARGS to avoid duplicates + this.createOpts.Env = (this.createOpts.Env || []).filter((e) => !e.startsWith("REDIS_ARGS=")); + this.withEnvironment({ - REDIS_ARGS: redisArgs.join(" "), + REDIS_ARGS: mergedRedisArgs, }).withEntrypoint(["/entrypoint.sh"]); } else { - this.withCommand(["redis-server", ...redisArgs]); + const existingCmd = this.createOpts.Cmd || []; + const baseCmd = existingCmd.length ? existingCmd : ["redis-server"]; + this.withCommand([...baseCmd, ...redisArgs]); } if (this.persistenceVolume) { this.withBindMounts([{ mode: "rw", source: this.persistenceVolume, target: "/data" }]);