Skip to content

Commit 5134356

Browse files
Port bindings can be undefined
1 parent 52a9050 commit 5134356

File tree

2 files changed

+51
-37
lines changed

2 files changed

+51
-37
lines changed

packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.test.ts

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,54 +11,66 @@ function mockInspectResult(
1111
},
1212
NetworkSettings: {
1313
Ports: ports,
14-
Networks: {},
1514
},
16-
} as unknown as ContainerInspectInfo;
15+
} as ContainerInspectInfo;
1716
}
1817

19-
test("returns the inspect result when all ports are exposed", async () => {
20-
const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] });
21-
const inspectFn = vi.fn().mockResolvedValueOnce(data);
18+
describe.sequential("inspectContainerUntilPortsExposed", () => {
19+
it("returns the inspect result when all ports are exposed", async () => {
20+
const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] });
21+
const inspectFn = vi.fn().mockResolvedValueOnce(data);
2222

23-
const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id");
23+
const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id");
2424

25-
expect(result).toEqual(data);
26-
});
25+
expect(result).toEqual(data);
26+
});
2727

28-
test("returns the inspect result when no ports are exposed", async () => {
29-
const data = mockInspectResult({}, {});
30-
const inspectFn = vi.fn().mockResolvedValueOnce(data);
28+
it("returns the inspect result when no ports are exposed", async () => {
29+
const data = mockInspectResult({}, {});
30+
const inspectFn = vi.fn().mockResolvedValueOnce(data);
3131

32-
const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id");
32+
const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id");
3333

34-
expect(result).toEqual(data);
35-
});
34+
expect(result).toEqual(data);
35+
});
3636

37-
test("retries the inspect if ports are not yet exposed", async () => {
38-
const data1 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] });
39-
const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] });
40-
const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2);
37+
it("retries the inspect if ports are not yet exposed", async () => {
38+
const data1 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] });
39+
const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] });
40+
const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2);
4141

42-
const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id");
42+
const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id");
4343

44-
expect(result).toEqual(data2);
45-
expect(inspectFn).toHaveBeenCalledTimes(3);
46-
});
44+
expect(result).toEqual(data2);
45+
expect(inspectFn).toHaveBeenCalledTimes(3);
46+
});
4747

48-
test("throws an error when host ports are not exposed within timeout", async () => {
49-
const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] });
50-
const inspectFn = vi.fn().mockResolvedValue(data);
48+
it("retries the inspect if port bindings are undefined", async () => {
49+
const data1 = mockInspectResult(undefined, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] });
50+
const data2 = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [{ HostIp: "0.0.0.0", HostPort: "45000" }] });
51+
const inspectFn = vi.fn().mockResolvedValueOnce(data1).mockResolvedValueOnce(data1).mockResolvedValueOnce(data2);
5152

52-
await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow(
53-
"Container did not expose all ports after starting"
54-
);
55-
});
53+
const result = await inspectContainerUntilPortsExposed(inspectFn, "container-id");
54+
55+
expect(result).toEqual(data2);
56+
expect(inspectFn).toHaveBeenCalledTimes(3);
57+
});
58+
59+
it("throws an error when host ports are not exposed within timeout", async () => {
60+
const data = mockInspectResult({ "8080/tcp": [] }, { "8080/tcp": [] });
61+
const inspectFn = vi.fn().mockResolvedValue(data);
62+
63+
await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow(
64+
"Container did not expose all ports after starting"
65+
);
66+
});
5667

57-
test("throws an error when container ports not exposed within timeout", async () => {
58-
const data = mockInspectResult({ "8080/tcp": [] }, {});
59-
const inspectFn = vi.fn().mockResolvedValue(data);
68+
it("throws an error when container ports not exposed within timeout", async () => {
69+
const data = mockInspectResult({ "8080/tcp": [] }, {});
70+
const inspectFn = vi.fn().mockResolvedValue(data);
6071

61-
await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow(
62-
"Container did not expose all ports after starting"
63-
);
72+
await expect(inspectContainerUntilPortsExposed(inspectFn, "container-id", 0)).rejects.toThrow(
73+
"Container did not expose all ports after starting"
74+
);
75+
});
6476
});

packages/testcontainers/src/generic-container/inspect-container-util-ports-exposed.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ export async function inspectContainerUntilPortsExposed(
99
const result = await new IntervalRetry<ContainerInspectInfo, Error>(250).retryUntil(
1010
() => inspectFn(),
1111
(inspectResult) => {
12-
const exposedPorts = Object.keys(inspectResult.HostConfig.PortBindings);
13-
return exposedPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0);
12+
const portBindings = inspectResult?.HostConfig?.PortBindings;
13+
if (!portBindings) return false;
14+
const expectedlyBoundPorts = Object.keys(portBindings);
15+
return expectedlyBoundPorts.every((exposedPort) => inspectResult.NetworkSettings.Ports[exposedPort]?.length > 0);
1416
},
1517
() => {
1618
const message = `Container did not expose all ports after starting`;

0 commit comments

Comments
 (0)