diff --git a/packages/testcontainers/src/port-forwarder/port-forwarder-reuse.test.ts b/packages/testcontainers/src/port-forwarder/port-forwarder-reuse.test.ts new file mode 100644 index 000000000..86178a19e --- /dev/null +++ b/packages/testcontainers/src/port-forwarder/port-forwarder-reuse.test.ts @@ -0,0 +1,62 @@ +import { GenericContainer } from "../generic-container/generic-container"; +import { RandomUniquePortGenerator } from "../utils/port-generator"; +import { createTestServer } from "../utils/test-helper"; + +describe("Port Forwarder reuse", { timeout: 180_000 }, () => { + it("should expose additional ports", async () => { + const portGen = new RandomUniquePortGenerator(); + + const { TestContainers: TC1 } = await import("../test-containers"); + const { PortForwarderInstance: PFI1 } = await import("../port-forwarder/port-forwarder"); + const port1 = await portGen.generatePort(); + const server1 = await createTestServer(port1); + await TC1.exposeHostPorts(port1); + const portForwarder1ContainerId = (await PFI1.getInstance()).getContainerId(); + + vi.resetModules(); + const { TestContainers: TC2 } = await import("../test-containers"); + const { PortForwarderInstance: PFI2 } = await import("../port-forwarder/port-forwarder"); + const port2 = await portGen.generatePort(); + const server2 = await createTestServer(port2); + await TC2.exposeHostPorts(port2); + const portForwarder2ContainerId = (await PFI2.getInstance()).getContainerId(); + + const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); + + expect(portForwarder1ContainerId).toEqual(portForwarder2ContainerId); + const { output: output1 } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${port1}`]); + expect(output1).toEqual(expect.stringContaining("hello world")); + const { output: output2 } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${port2}`]); + expect(output2).toEqual(expect.stringContaining("hello world")); + + await new Promise((resolve) => server1.close(resolve)); + await new Promise((resolve) => server2.close(resolve)); + await container.stop(); + }); + + it("should reuse same ports", async () => { + const portGen = new RandomUniquePortGenerator(); + const port = await portGen.generatePort(); + const server = await createTestServer(port); + + const { TestContainers: TC1 } = await import("../test-containers"); + const { PortForwarderInstance: PFI1 } = await import("../port-forwarder/port-forwarder"); + await TC1.exposeHostPorts(port); + const portForwarder1ContainerId = (await PFI1.getInstance()).getContainerId(); + + vi.resetModules(); + const { TestContainers: TC2 } = await import("../test-containers"); + const { PortForwarderInstance: PFI2 } = await import("../port-forwarder/port-forwarder"); + await TC2.exposeHostPorts(port); + const portForwarder2ContainerId = (await PFI2.getInstance()).getContainerId(); + + const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); + + expect(portForwarder1ContainerId).toEqual(portForwarder2ContainerId); + const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${port}`]); + expect(output).toEqual(expect.stringContaining("hello world")); + + await new Promise((resolve) => server.close(resolve)); + await container.stop(); + }); +}); diff --git a/packages/testcontainers/src/port-forwarder/port-forwarder.test.ts b/packages/testcontainers/src/port-forwarder/port-forwarder.test.ts index 96fe11b42..c7e263e36 100644 --- a/packages/testcontainers/src/port-forwarder/port-forwarder.test.ts +++ b/packages/testcontainers/src/port-forwarder/port-forwarder.test.ts @@ -1,141 +1,60 @@ -import { createServer, Server } from "http"; +import { Server } from "http"; import { GenericContainer } from "../generic-container/generic-container"; import { Network } from "../network/network"; import { TestContainers } from "../test-containers"; import { RandomUniquePortGenerator } from "../utils/port-generator"; +import { createTestServer } from "../utils/test-helper"; describe("PortForwarder", { timeout: 180_000 }, () => { let randomPort: number; let server: Server; - afterEach(() => { - server.close(); + beforeEach(async () => { + randomPort = await new RandomUniquePortGenerator().generatePort(); + server = await createTestServer(randomPort); }); - describe("Behaviour", () => { - beforeEach(async () => { - randomPort = await new RandomUniquePortGenerator().generatePort(); - server = await createTestServer(randomPort); - }); - - it("should expose host ports to the container", async () => { - await TestContainers.exposeHostPorts(randomPort); - - const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); - - const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); - expect(output).toEqual(expect.stringContaining("hello world")); - - await container.stop(); - }); - - it("should expose host ports to the container with custom network", async () => { - await TestContainers.exposeHostPorts(randomPort); - - const network = await new Network().start(); - const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").withNetwork(network).start(); - - const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); - expect(output).toEqual(expect.stringContaining("hello world")); - - await container.stop(); - await network.stop(); - }); - - it("should expose host ports to the container with custom network and network alias", async () => { - await TestContainers.exposeHostPorts(randomPort); - - const network = await new Network().start(); - const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") - .withNetwork(network) - .withNetworkAliases("foo") - .start(); - - const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); - expect(output).toEqual(expect.stringContaining("hello world")); - - await container.stop(); - await network.stop(); - }); + afterEach(async () => { + await new Promise((resolve) => server.close(resolve)); }); - describe("Reuse", () => { - afterEach(() => { - vi.resetModules(); - }); + it("should expose host ports to the container", async () => { + await TestContainers.exposeHostPorts(randomPort); - describe("Different host ports", () => { - beforeEach(async () => { - randomPort = await new RandomUniquePortGenerator().generatePort(); - server = await createTestServer(randomPort); - }); + const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); - it("1", async () => { - const { TestContainers } = await import("../test-containers"); - await TestContainers.exposeHostPorts(randomPort); + const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); + expect(output).toEqual(expect.stringContaining("hello world")); - const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); - - const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); - expect(output).toEqual(expect.stringContaining("hello world")); - - await container.stop(); - }); - - it("2", async () => { - const { TestContainers } = await import("../test-containers"); - await TestContainers.exposeHostPorts(randomPort); - - const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); - - const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); - expect(output).toEqual(expect.stringContaining("hello world")); - - await container.stop(); - }); - }); - - describe("Same host ports", () => { - beforeAll(async () => { - randomPort = await new RandomUniquePortGenerator().generatePort(); - }); - - beforeEach(async () => { - server = await createTestServer(randomPort); - }); + await container.stop(); + }); - it("1", async () => { - const { TestContainers } = await import("../test-containers"); - await TestContainers.exposeHostPorts(randomPort); + it("should expose host ports to the container with custom network", async () => { + await TestContainers.exposeHostPorts(randomPort); - const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); + const network = await new Network().start(); + const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").withNetwork(network).start(); - const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); - expect(output).toEqual(expect.stringContaining("hello world")); + const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); + expect(output).toEqual(expect.stringContaining("hello world")); - await container.stop(); - }); + await container.stop(); + await network.stop(); + }); - it("2", async () => { - const { TestContainers } = await import("../test-containers"); - await TestContainers.exposeHostPorts(randomPort); + it("should expose host ports to the container with custom network and network alias", async () => { + await TestContainers.exposeHostPorts(randomPort); - const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14").start(); + const network = await new Network().start(); + const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") + .withNetwork(network) + .withNetworkAliases("foo") + .start(); - const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); - expect(output).toEqual(expect.stringContaining("hello world")); + const { output } = await container.exec(["curl", "-s", `http://host.testcontainers.internal:${randomPort}`]); + expect(output).toEqual(expect.stringContaining("hello world")); - await container.stop(); - }); - }); + await container.stop(); + await network.stop(); }); }); - -async function createTestServer(port: number): Promise { - const server = createServer((req, res) => { - res.writeHead(200); - res.end("hello world"); - }); - await new Promise((resolve) => server.listen(port, resolve)); - return server; -} diff --git a/packages/testcontainers/src/utils/port-generator.ts b/packages/testcontainers/src/utils/port-generator.ts index 6078b09f2..f441500f6 100644 --- a/packages/testcontainers/src/utils/port-generator.ts +++ b/packages/testcontainers/src/utils/port-generator.ts @@ -4,8 +4,8 @@ export interface PortGenerator { class RandomPortGenerator { public async generatePort(): Promise { - const { default: getPort, portNumbers } = await import("get-port"); - return getPort({ port: portNumbers(10000, 65535) }); + const { default: getPort } = await import("get-port"); + return getPort(); } } diff --git a/packages/testcontainers/src/utils/test-helper.ts b/packages/testcontainers/src/utils/test-helper.ts index 16210782f..dc1ff07b9 100644 --- a/packages/testcontainers/src/utils/test-helper.ts +++ b/packages/testcontainers/src/utils/test-helper.ts @@ -1,4 +1,5 @@ import { GetEventsOptions, ImageInspectInfo } from "dockerode"; +import { createServer, Server } from "http"; import { Readable } from "stream"; import { Agent } from "undici"; import { IntervalRetry } from "../common"; @@ -143,3 +144,12 @@ export async function stopStartingContainer(container: GenericContainer, name: s await client.container.getById(name).stop(); await containerStartPromise; } + +export async function createTestServer(port: number): Promise { + const server = createServer((req, res) => { + res.writeHead(200); + res.end("hello world"); + }); + await new Promise((resolve) => server.listen(port, resolve)); + return server; +}