Skip to content

Commit 9cc75a9

Browse files
committed
fix tests (again)
1 parent 7fd13e5 commit 9cc75a9

File tree

2 files changed

+31
-34
lines changed

2 files changed

+31
-34
lines changed

packages/testcontainers/src/reaper/reaper.test.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { ContainerRuntimeClient, getContainerRuntimeClient } from "../container-runtime";
2-
import { FindReaperContainerFn, Reaper } from "./reaper";
2+
import { Reaper } from "./reaper";
33

4-
// FindReaperContainerFn is used in each test to intentionally 'fail' to find reaper container.
5-
// Failing this check will trigger re-creation of new reaper container, which is needed for testing.
6-
// Otherwise `getReaperFn` will always get a reference to already running reaper container,
7-
// which is not desired in the context of unit testing.
4+
let getReaperFn: (client: ContainerRuntimeClient) => Promise<Reaper>;
85

9-
let getReaperFn: (client: ContainerRuntimeClient, findReaperContainerFn?: FindReaperContainerFn) => Promise<Reaper>;
6+
async function mockGetContainerRuntimeClient(realClient: ContainerRuntimeClient) {
7+
const ContainerRuntimeClient = vi.fn();
8+
ContainerRuntimeClient.prototype.info = vi.fn();
9+
vi.spyOn(ContainerRuntimeClient.prototype, "info", "get").mockReturnValue(realClient.info);
10+
ContainerRuntimeClient.prototype.container = vi.fn();
11+
ContainerRuntimeClient.prototype.container.list = vi.fn().mockReturnValue([]);
12+
const getContainerRuntimeClientMock = vi
13+
.fn(getContainerRuntimeClient)
14+
.mockImplementation(async () => new ContainerRuntimeClient());
15+
return getContainerRuntimeClientMock;
16+
}
1017

1118
describe("Reaper", { timeout: 120_000 }, () => {
1219
beforeEach(async () => {
@@ -22,7 +29,8 @@ describe("Reaper", { timeout: 120_000 }, () => {
2229

2330
it("should create Reaper container without RYUK_VERBOSE env var by default", async () => {
2431
const client = await getContainerRuntimeClient();
25-
const reaper = await getReaperFn(client, async () => undefined);
32+
const mockGetClientFn = await mockGetContainerRuntimeClient(client);
33+
const reaper = await getReaperFn(await mockGetClientFn());
2634
expect(reaper.containerId).toBeTruthy(); // will fail if TESTCONTAINERS_RYUK_DISABLED=true
2735
const reaperContainer = client.container.getById(reaper.containerId);
2836
const reaperContainerEnv = (await reaperContainer.inspect()).Config.Env;
@@ -34,7 +42,8 @@ describe("Reaper", { timeout: 120_000 }, () => {
3442
vitest.stubEnv("TESTCONTAINERS_RYUK_VERBOSE", "true");
3543
try {
3644
const client = await getContainerRuntimeClient();
37-
const reaper = await getReaperFn(client, async () => undefined);
45+
const mockGetClientFn = await mockGetContainerRuntimeClient(client);
46+
const reaper = await getReaperFn(await mockGetClientFn());
3847
expect(reaper.containerId).toBeTruthy(); // will fail if TESTCONTAINERS_RYUK_DISABLED=true
3948
const reaperContainer = client.container.getById(reaper.containerId);
4049
expect((await reaperContainer.inspect()).Config.Env).toContain("RYUK_VERBOSE=true");

packages/testcontainers/src/reaper/reaper.ts

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,34 +13,27 @@ export const REAPER_IMAGE = process.env["RYUK_CONTAINER_IMAGE"]
1313
export interface Reaper {
1414
sessionId: string;
1515

16+
containerId: string;
17+
1618
addSession(sessionId: string): void;
1719

1820
addComposeProject(projectName: string): void;
19-
20-
get containerId(): string;
2121
}
2222

23-
// see reaper.test.ts for context of this export usage.
24-
export type FindReaperContainerFn = (client: ContainerRuntimeClient) => Promise<ContainerInfo | undefined>;
25-
2623
let reaper: Reaper;
2724
let sessionId: string;
2825

29-
export async function getReaper(
30-
client: ContainerRuntimeClient,
31-
findReaperContainerFn?: FindReaperContainerFn
32-
): Promise<Reaper> {
26+
export async function getReaper(client: ContainerRuntimeClient): Promise<Reaper> {
3327
if (reaper) {
3428
return reaper;
3529
}
3630

3731
reaper = await withFileLock("testcontainers-node.lock", async () => {
38-
const findReaperFn = findReaperContainerFn ?? findReaperContainerDefault;
39-
const reaperContainer = await findReaperFn(client);
32+
const reaperContainer = await findReaperContainer(client);
4033
sessionId = reaperContainer?.Labels[LABEL_TESTCONTAINERS_SESSION_ID] ?? new RandomUuid().nextUuid();
4134

4235
if (process.env.TESTCONTAINERS_RYUK_DISABLED === "true") {
43-
return new DisabledReaper(sessionId);
36+
return new DisabledReaper(sessionId, "");
4437
} else if (reaperContainer) {
4538
return await useExistingReaper(reaperContainer, sessionId, client.info.containerRuntime.host);
4639
} else {
@@ -52,7 +45,7 @@ export async function getReaper(
5245
return reaper;
5346
}
5447

55-
async function findReaperContainerDefault(client: ContainerRuntimeClient): Promise<ContainerInfo | undefined> {
48+
async function findReaperContainer(client: ContainerRuntimeClient): Promise<ContainerInfo | undefined> {
5649
const containers = await client.container.list();
5750
return containers.find(
5851
(container) => container.State === "running" && container.Labels[LABEL_TESTCONTAINERS_RYUK] === "true"
@@ -69,7 +62,7 @@ async function useExistingReaper(reaperContainer: ContainerInfo, sessionId: stri
6962

7063
const socket = await connectToReaperSocket(host, reaperPort, reaperContainer.Id);
7164

72-
return new RyukReaper(sessionId, socket, reaperContainer.Id);
65+
return new RyukReaper(sessionId, reaperContainer.Id, socket);
7366
}
7467

7568
async function createNewReaper(sessionId: string, remoteSocketPath: string): Promise<Reaper> {
@@ -100,7 +93,7 @@ async function createNewReaper(sessionId: string, remoteSocketPath: string): Pro
10093
startedContainer.getId()
10194
);
10295

103-
return new RyukReaper(sessionId, socket, startedContainer.getId());
96+
return new RyukReaper(sessionId, startedContainer.getId(), socket);
10497
}
10598

10699
async function connectToReaperSocket(host: string, port: number, containerId: string): Promise<Socket> {
@@ -146,14 +139,10 @@ async function connectToReaperSocket(host: string, port: number, containerId: st
146139
class RyukReaper implements Reaper {
147140
constructor(
148141
public readonly sessionId: string,
149-
private readonly socket: Socket,
150-
private readonly id: string
142+
public readonly containerId: string,
143+
private readonly socket: Socket
151144
) {}
152145

153-
get containerId() {
154-
return this.id;
155-
}
156-
157146
addComposeProject(projectName: string): void {
158147
this.socket.write(`label=com.docker.compose.project=${projectName}\r\n`);
159148
}
@@ -164,13 +153,12 @@ class RyukReaper implements Reaper {
164153
}
165154

166155
class DisabledReaper implements Reaper {
167-
constructor(public readonly sessionId: string) {}
156+
constructor(
157+
public readonly sessionId: string,
158+
public readonly containerId: string
159+
) {}
168160

169161
addComposeProject(): void {}
170162

171163
addSession(): void {}
172-
173-
get containerId() {
174-
return "";
175-
}
176164
}

0 commit comments

Comments
 (0)