diff --git a/docs/features/compose.md b/docs/features/compose.md index 9ffa9860a..669a1899b 100644 --- a/docs/features/compose.md +++ b/docs/features/compose.md @@ -151,11 +151,11 @@ const environment = await new DockerComposeEnvironment(composeFilePath, composeF await environment.down(); ``` -If you need to wait for the environment to be downed, you can provide a timeout. The unit of timeout here is **second**: +If you need to wait for the environment to be downed, you can provide a timeout: ```javascript const environment = await new DockerComposeEnvironment(composeFilePath, composeFile).up(); -await environment.down({ timeout: 10 }); // timeout after 10 seconds +await environment.down({ timeout: 10_000 }); // 10 seconds ``` Volumes created by the environment are removed when stopped. This is configurable: diff --git a/docs/features/containers.md b/docs/features/containers.md index 2e03f0829..07b37023f 100644 --- a/docs/features/containers.md +++ b/docs/features/containers.md @@ -334,11 +334,11 @@ const container = await new GenericContainer("alpine").start(); await container.stop(); ``` -If you need to wait for the container to be stopped, you can provide a timeout. The unit of timeout option here is **second**: +If you need to wait for the container to be stopped, you can provide a timeout: ```javascript const container = await new GenericContainer("alpine").start(); -await container.stop({ timeout: 10 }); // 10 seconds +await container.stop({ timeout: 10_000 }); // 10 seconds ``` You can disable automatic removal of the container, which is useful for debugging, or if for example you want to copy content from the container once it has stopped: diff --git a/docs/features/wait-strategies.md b/docs/features/wait-strategies.md index 4830cc90d..123e5be68 100644 --- a/docs/features/wait-strategies.md +++ b/docs/features/wait-strategies.md @@ -1,12 +1,12 @@ # Wait Strategies -Note that the startup timeout of all wait strategies is configurable. The unit of timeout of wait strategies is **millisecond**: +Note that the startup timeout of all wait strategies is configurable: ```javascript const { GenericContainer } = require("testcontainers"); const container = await new GenericContainer("alpine") - .withStartupTimeout(120000) // wait 120 seconds + .withStartupTimeout(120_000) // 120 seconds .start(); ``` @@ -73,7 +73,7 @@ const { GenericContainer, Wait } = require("testcontainers"); const container = await new GenericContainer("alpine").withWaitStrategy(Wait.forHealthCheck()).start(); ``` -Define your own health check. The unit of timeouts and intervals here is **millisecond**: +Define your own health check: ```javascript const { GenericContainer, Wait } = require("testcontainers"); @@ -81,10 +81,10 @@ const { GenericContainer, Wait } = require("testcontainers"); const container = await new GenericContainer("alpine") .withHealthCheck({ test: ["CMD-SHELL", "curl -f http://localhost || exit 1"], - interval: 1000, - timeout: 3000, + interval: 1000, // 1 second + timeout: 3000, // 3 seconds retries: 5, - startPeriod: 1000, + startPeriod: 1000, // 1 second }) .withWaitStrategy(Wait.forHealthCheck()) .start(); @@ -148,7 +148,7 @@ const container = await new GenericContainer("redis") .withMethod("POST") .withHeaders({ X_CUSTOM_VALUE: "custom" }) .withBasicCredentials("username", "password") - .withReadTimeout(10000)) // timeout after 10 seconds + .withReadTimeout(10_000)) // 10 seconds ``` ### Use TLS @@ -186,7 +186,7 @@ This strategy is intended for use with containers that only run briefly and exit const { GenericContainer, Wait } = require("testcontainers"); const container = await new GenericContainer("alpine") - .withWaitStrategy(Wait.forOneShotStartup())) + .withWaitStrategy(Wait.forOneShotStartup()) .start(); ``` @@ -202,11 +202,11 @@ const container = await new GenericContainer("alpine") .start(); ``` -The composite wait strategy by default will respect each individual wait strategy's startup timeout. The unit of timeouts here is **millisecond**. For example: +The composite wait strategy by default will respect each individual wait strategy's startup timeout. For example: ```javascript -const w1 = Wait.forListeningPorts().withStartupTimeout(1000); // wait 1 second -const w2 = Wait.forLogMessage("READY").withStartupTimeout(2000); // wait 2 seconds +const w1 = Wait.forListeningPorts().withStartupTimeout(1000); // 1 second +const w2 = Wait.forLogMessage("READY").withStartupTimeout(2000); // 2 seconds const composite = Wait.forAll([w1, w2]); @@ -217,21 +217,21 @@ expect(w2.getStartupTimeout()).toBe(2000); The startup timeout of inner wait strategies that have not defined their own startup timeout can be set by setting the startup timeout on the composite: ```javascript -const w1 = Wait.forListeningPorts().withStartupTimeout(1000); // wait 1 second +const w1 = Wait.forListeningPorts().withStartupTimeout(1000); // 1 second const w2 = Wait.forLogMessage("READY"); -const composite = Wait.forAll([w1, w2]).withStartupTimeout(2000); // wait 2 seconds +const composite = Wait.forAll([w1, w2]).withStartupTimeout(2000); // 2 seconds expect(w1.getStartupTimeout()).toBe(1000); expect(w2.getStartupTimeout()).toBe(2000); ``` -The startup timeout of all wait strategies can be controlled by setting a deadline on the composite. In this case, the composite will throw unless all inner wait strategies have resolved before the deadline. The unit of deadline timeout is **millisecond**. +The startup timeout of all wait strategies can be controlled by setting a deadline on the composite. In this case, the composite will throw unless all inner wait strategies have resolved before the deadline. ```javascript const w1 = Wait.forListeningPorts(); const w2 = Wait.forLogMessage("READY"); -const composite = Wait.forAll([w1, w2]).withDeadline(2000); // wait 2 seconds +const composite = Wait.forAll([w1, w2]).withDeadline(2000); // 2 seconds ``` ## Other startup strategies diff --git a/packages/modules/couchbase/src/couchbase-container.ts b/packages/modules/couchbase/src/couchbase-container.ts index 30a34ccb7..92fb1873e 100644 --- a/packages/modules/couchbase/src/couchbase-container.ts +++ b/packages/modules/couchbase/src/couchbase-container.ts @@ -448,12 +448,12 @@ export class CouchbaseContainer extends GenericContainer { return jsonResponse.results[0].present; }, () => { - const message = `URL /query/service not accessible after ${this.startupTimeout || 60_000}ms`; + const message = `URL /query/service not accessible after ${this.startupTimeoutMs || 60_000}ms`; log.error(message, { containerId: client.container.getById(startedTestContainer.getId()).id }); throw new Error(message); }, - this.startupTimeout || 60_000 + this.startupTimeoutMs || 60_000 ); } @@ -509,12 +509,12 @@ export class CouchbaseContainer extends GenericContainer { return jsonResponse.results[0].online; }, () => { - const message = `URL /query/service not accessible after ${this.startupTimeout || 60_000}ms`; + const message = `URL /query/service not accessible after ${this.startupTimeoutMs || 60_000}ms`; log.error(message, { containerId: client.container.getById(startedTestContainer.getId()).id }); throw new Error(message); }, - this.startupTimeout || 60_000 + this.startupTimeoutMs || 60_000 ); } else { log.info( diff --git a/packages/testcontainers/src/common/index.ts b/packages/testcontainers/src/common/index.ts index 264aa58f0..e03676525 100644 --- a/packages/testcontainers/src/common/index.ts +++ b/packages/testcontainers/src/common/index.ts @@ -3,5 +3,6 @@ export { hash } from "./hash"; export { Logger, buildLog, composeLog, containerLog, execLog, log, pullLog } from "./logger"; export { IntervalRetry, Retry } from "./retry"; export { streamToString } from "./streams"; +export * from "./time"; export * from "./type-guards"; export { RandomUuid, Uuid } from "./uuid"; diff --git a/packages/testcontainers/src/common/retry.ts b/packages/testcontainers/src/common/retry.ts index 42c22db3e..870f06fa1 100644 --- a/packages/testcontainers/src/common/retry.ts +++ b/packages/testcontainers/src/common/retry.ts @@ -5,7 +5,7 @@ export interface Retry { fn: () => Promise, predicate: (result: T) => boolean | Promise, onTimeout: () => U, - timeout: number + timeoutMs: number ): Promise; } @@ -16,11 +16,11 @@ abstract class AbstractRetry implements Retry { fn: () => Promise, predicate: (result: T) => boolean | Promise, onTimeout: () => U, - timeout: number + timeoutMs: number ): Promise; - protected hasTimedOut(timeout: number, startTime: Time): boolean { - return this.clock.getTime() - startTime > timeout; + protected hasTimedOut(timeoutMs: number, startTime: Time): boolean { + return this.clock.getTime() - startTime > timeoutMs; } protected wait(duration: number): Promise { @@ -37,7 +37,7 @@ export class IntervalRetry extends AbstractRetry { fn: (attempt: number) => Promise, predicate: (result: T) => boolean | Promise, onTimeout: () => U, - timeout: number + timeoutMs: number ): Promise { const startTime = this.clock.getTime(); @@ -45,7 +45,7 @@ export class IntervalRetry extends AbstractRetry { let result = await fn(attemptNumber++); while (!(await predicate(result))) { - if (this.hasTimedOut(timeout, startTime)) { + if (this.hasTimedOut(timeoutMs, startTime)) { return onTimeout(); } await this.wait(this.interval); diff --git a/packages/testcontainers/src/common/time.test.ts b/packages/testcontainers/src/common/time.test.ts new file mode 100644 index 000000000..7eefc96d8 --- /dev/null +++ b/packages/testcontainers/src/common/time.test.ts @@ -0,0 +1,25 @@ +import { toNanos, toSeconds } from "./time"; + +test.for([ + [0, 0], + [10, 0], + [999, 0], + [1010, 1], + [1999, 1], + [10_000, 10], + [-10, -0], + [-999, -0], + [-1010, -1], + [-1999, -1], + [-10_000, -10], +])("should convert %i ms to %i seconds", ([ms, s]) => { + expect(toSeconds(ms)).toEqual(s); +}); + +test.for([ + [0, 0], + [1, 1_000_000], + [-1, -1_000_000], +])("should convert %i ms to %i ns", ([ms, ns]) => { + expect(toNanos(ms)).toEqual(ns); +}); diff --git a/packages/testcontainers/src/common/time.ts b/packages/testcontainers/src/common/time.ts new file mode 100644 index 000000000..a3342d2b0 --- /dev/null +++ b/packages/testcontainers/src/common/time.ts @@ -0,0 +1,3 @@ +export const toSeconds = (ms: number) => Math.trunc(ms * 1e-3); + +export const toNanos = (ms: number) => ms * 1e6; diff --git a/packages/testcontainers/src/container-runtime/clients/compose/compose-client.ts b/packages/testcontainers/src/container-runtime/clients/compose/compose-client.ts index e8e563190..cf2347b34 100644 --- a/packages/testcontainers/src/container-runtime/clients/compose/compose-client.ts +++ b/packages/testcontainers/src/container-runtime/clients/compose/compose-client.ts @@ -1,5 +1,5 @@ import compose from "docker-compose"; -import { log, pullLog } from "../../../common"; +import { log, pullLog, toSeconds } from "../../../common"; import { defaultComposeOptions } from "./default-compose-options"; import { ComposeDownOptions, ComposeOptions } from "./types"; @@ -126,7 +126,7 @@ function composeDownCommandOptions(options: ComposeDownOptions): string[] { result.push("-v"); } if (options.timeout) { - result.push("-t", `${options.timeout / 1000}`); + result.push("-t", `${toSeconds(options.timeout)}`); } return result; } diff --git a/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts b/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts index 900c6afb5..ce22b023a 100644 --- a/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts +++ b/packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts @@ -9,7 +9,7 @@ import Dockerode, { } from "dockerode"; import { IncomingMessage } from "http"; import { PassThrough, Readable } from "stream"; -import { execLog, log, streamToString } from "../../../common"; +import { execLog, log, streamToString, toSeconds } from "../../../common"; import { ContainerClient } from "./container-client"; import { ContainerCommitOptions, ContainerStatus, ExecOptions, ExecResult } from "./types"; @@ -120,8 +120,7 @@ export class DockerContainerClient implements ContainerClient { async inspect(container: Dockerode.Container): Promise { try { - const inspectInfo = await container.inspect(); - return inspectInfo; + return await container.inspect(); } catch (err) { log.error(`Failed to inspect container: ${err}`, { containerId: container.id }); throw err; @@ -131,7 +130,7 @@ export class DockerContainerClient implements ContainerClient { async stop(container: Container, opts?: { timeout: number }): Promise { try { log.debug(`Stopping container...`, { containerId: container.id }); - await container.stop({ t: opts?.timeout }); + await container.stop({ t: toSeconds(opts?.timeout ?? 0) }); log.debug(`Stopped container`, { containerId: container.id }); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (err: any) { @@ -267,7 +266,7 @@ export class DockerContainerClient implements ContainerClient { async restart(container: Container, opts?: { timeout: number }): Promise { try { log.debug(`Restarting container...`, { containerId: container.id }); - await container.restart({ t: opts?.timeout }); + await container.restart({ t: toSeconds(opts?.timeout ?? 0) }); log.debug(`Restarted container`, { containerId: container.id }); } catch (err) { log.error(`Failed to restart container: ${err}`, { containerId: container.id }); diff --git a/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.ts b/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.ts index f63f32640..252998ed2 100644 --- a/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.ts +++ b/packages/testcontainers/src/docker-compose-environment/docker-compose-environment.ts @@ -25,7 +25,7 @@ export class DockerComposeEnvironment { private pullPolicy: ImagePullPolicy = PullPolicy.defaultPolicy(); private defaultWaitStrategy: WaitStrategy = Wait.forListeningPorts(); private waitStrategy: { [containerName: string]: WaitStrategy } = {}; - private startupTimeout?: number; + private startupTimeoutMs?: number; constructor(composeFilePath: string, composeFiles: string | string[], uuid: Uuid = new RandomUuid()) { this.composeFilePath = composeFilePath; @@ -74,8 +74,8 @@ export class DockerComposeEnvironment { return this; } - public withStartupTimeout(startupTimeout: number): this { - this.startupTimeout = startupTimeout; + public withStartupTimeout(startupTimeoutMs: number): this { + this.startupTimeoutMs = startupTimeoutMs; return this; } @@ -147,8 +147,8 @@ export class DockerComposeEnvironment { const waitStrategy = this.waitStrategy[containerName] ? this.waitStrategy[containerName] : this.defaultWaitStrategy; - if (this.startupTimeout !== undefined) { - waitStrategy.withStartupTimeout(this.startupTimeout); + if (this.startupTimeoutMs !== undefined) { + waitStrategy.withStartupTimeout(this.startupTimeoutMs); } if (containerLog.enabled()) { diff --git a/packages/testcontainers/src/generic-container/generic-container.ts b/packages/testcontainers/src/generic-container/generic-container.ts index 6aad8e9b4..ae2baf35d 100644 --- a/packages/testcontainers/src/generic-container/generic-container.ts +++ b/packages/testcontainers/src/generic-container/generic-container.ts @@ -2,7 +2,7 @@ import archiver from "archiver"; import AsyncLock from "async-lock"; import { Container, ContainerCreateOptions, HostConfig } from "dockerode"; import { Readable } from "stream"; -import { containerLog, hash, log } from "../common"; +import { containerLog, hash, log, toNanos } from "../common"; import { ContainerRuntimeClient, getContainerRuntimeClient, ImageName } from "../container-runtime"; import { CONTAINER_STATUSES } from "../container-runtime/clients/container/types"; import { StartedNetwork } from "../network/network"; @@ -46,7 +46,7 @@ export class GenericContainer implements TestContainer { protected hostConfig: HostConfig; protected imageName: ImageName; - protected startupTimeout?: number; + protected startupTimeoutMs?: number; protected waitStrategy: WaitStrategy = Wait.forListeningPorts(); protected environment: Record = {}; protected exposedPorts: PortWithOptionalBinding[] = []; @@ -149,8 +149,8 @@ export class GenericContainer implements TestContainer { const boundPorts = BoundPorts.fromInspectResult(client.info.containerRuntime.hostIps, mappedInspectResult).filter( this.exposedPorts ); - if (this.startupTimeout !== undefined) { - this.waitStrategy.withStartupTimeout(this.startupTimeout); + if (this.startupTimeoutMs !== undefined) { + this.waitStrategy.withStartupTimeout(this.startupTimeoutMs); } await waitForContainer(client, container, this.waitStrategy, boundPorts); @@ -202,8 +202,8 @@ export class GenericContainer implements TestContainer { this.exposedPorts ); - if (this.startupTimeout !== undefined) { - this.waitStrategy.withStartupTimeout(this.startupTimeout); + if (this.startupTimeoutMs !== undefined) { + this.waitStrategy.withStartupTimeout(this.startupTimeoutMs); } if (containerLog.enabled() || this.logConsumer !== undefined) { @@ -395,8 +395,6 @@ export class GenericContainer implements TestContainer { } public withHealthCheck(healthCheck: HealthCheck): this { - const toNanos = (duration: number): number => duration * 1e6; - this.healthCheck = healthCheck; this.createOpts.Healthcheck = { Test: healthCheck.test, @@ -410,7 +408,7 @@ export class GenericContainer implements TestContainer { } public withStartupTimeout(startupTimeoutMs: number): this { - this.startupTimeout = startupTimeoutMs; + this.startupTimeoutMs = startupTimeoutMs; return this; } diff --git a/packages/testcontainers/src/wait-strategies/composite-wait-strategy.ts b/packages/testcontainers/src/wait-strategies/composite-wait-strategy.ts index 99dc3c2c5..6cd3112ed 100644 --- a/packages/testcontainers/src/wait-strategies/composite-wait-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/composite-wait-strategy.ts @@ -39,10 +39,10 @@ export class CompositeWaitStrategy extends AbstractWaitStrategy { }); } - public override withStartupTimeout(startupTimeout: number): this { + public override withStartupTimeout(startupTimeoutMs: number): this { this.waitStrategies .filter((waitStrategy) => !waitStrategy.isStartupTimeoutSet()) - .forEach((waitStrategy) => waitStrategy.withStartupTimeout(startupTimeout)); + .forEach((waitStrategy) => waitStrategy.withStartupTimeout(startupTimeoutMs)); return this; } diff --git a/packages/testcontainers/src/wait-strategies/health-check-wait-strategy.ts b/packages/testcontainers/src/wait-strategies/health-check-wait-strategy.ts index 47d97d8df..7beca859d 100644 --- a/packages/testcontainers/src/wait-strategies/health-check-wait-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/health-check-wait-strategy.ts @@ -12,12 +12,12 @@ export class HealthCheckWaitStrategy extends AbstractWaitStrategy { async () => (await client.container.inspect(container)).State.Health?.Status, (healthCheckStatus) => healthCheckStatus === "healthy" || healthCheckStatus === "unhealthy", () => { - const timeout = this.startupTimeout; + const timeout = this.startupTimeoutMs; const message = `Health check not healthy after ${timeout}ms`; log.error(message, { containerId: container.id }); throw new Error(message); }, - this.startupTimeout + this.startupTimeoutMs ); if (status !== "healthy") { diff --git a/packages/testcontainers/src/wait-strategies/host-port-wait-strategy.ts b/packages/testcontainers/src/wait-strategies/host-port-wait-strategy.ts index be5b8639d..7224e8889 100644 --- a/packages/testcontainers/src/wait-strategies/host-port-wait-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/host-port-wait-strategy.ts @@ -47,11 +47,11 @@ export class HostPortWaitStrategy extends AbstractWaitStrategy { () => portCheck.isBound(port), (isBound) => isBound, () => { - const message = `Port ${port} not bound after ${this.startupTimeout}ms`; + const message = `Port ${port} not bound after ${this.startupTimeoutMs}ms`; log.error(message, { containerId: container.id }); throw new Error(message); }, - this.startupTimeout + this.startupTimeoutMs ); } } diff --git a/packages/testcontainers/src/wait-strategies/http-wait-strategy.ts b/packages/testcontainers/src/wait-strategies/http-wait-strategy.ts index ef120a3ed..ed908007f 100644 --- a/packages/testcontainers/src/wait-strategies/http-wait-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/http-wait-strategy.ts @@ -13,9 +13,9 @@ export class HttpWaitStrategy extends AbstractWaitStrategy { private protocol = "http"; private method = "GET"; private headers: { [key: string]: string } = {}; - private predicates: Array<(response: Response) => Promise> = []; + private readonly predicates: Array<(response: Response) => Promise> = []; private _allowInsecure = false; - private readTimeout = 1000; + private readTimeoutMs = 1000; constructor( private readonly path: string, @@ -25,48 +25,48 @@ export class HttpWaitStrategy extends AbstractWaitStrategy { super(); } - public forStatusCode(statusCode: number): HttpWaitStrategy { + public forStatusCode(statusCode: number): this { this.predicates.push(async (response: Response) => response.status === statusCode); return this; } - public forStatusCodeMatching(predicate: (statusCode: number) => boolean): HttpWaitStrategy { + public forStatusCodeMatching(predicate: (statusCode: number) => boolean): this { this.predicates.push(async (response: Response) => predicate(response.status)); return this; } - public forResponsePredicate(predicate: (response: string) => boolean): HttpWaitStrategy { + public forResponsePredicate(predicate: (response: string) => boolean): this { this.predicates.push(async (response: Response) => predicate(await response.text())); return this; } - public withMethod(method: string): HttpWaitStrategy { + public withMethod(method: string): this { this.method = method; return this; } - public withHeaders(headers: { [key: string]: string }): HttpWaitStrategy { + public withHeaders(headers: { [key: string]: string }): this { this.headers = { ...this.headers, ...headers }; return this; } - public withBasicCredentials(username: string, password: string): HttpWaitStrategy { + public withBasicCredentials(username: string, password: string): this { const base64Encoded = Buffer.from(`${username}:${password}`).toString("base64"); this.headers = { ...this.headers, Authorization: `Basic ${base64Encoded}` }; return this; } - public withReadTimeout(readTimeout: number): HttpWaitStrategy { - this.readTimeout = readTimeout; + public withReadTimeout(startupTimeoutMs: number): this { + this.readTimeoutMs = startupTimeoutMs; return this; } - public usingTls(): HttpWaitStrategy { + public usingTls(): this { this.protocol = "https"; return this; } - public allowInsecure(): HttpWaitStrategy { + public allowInsecure(): this { this._allowInsecure = true; return this; } @@ -79,7 +79,7 @@ export class HttpWaitStrategy extends AbstractWaitStrategy { const client = await getContainerRuntimeClient(); const { abortOnContainerExit } = this.options; - await new IntervalRetry(this.readTimeout).retryUntil( + await new IntervalRetry(this.readTimeoutMs).retryUntil( async () => { try { const url = `${this.protocol}://${client.info.containerRuntime.host}:${boundPorts.getBinding(this.port)}${ @@ -98,7 +98,7 @@ export class HttpWaitStrategy extends AbstractWaitStrategy { return this.undiciResponseToFetchResponse( await request(url, { method: this.method, - signal: AbortSignal.timeout(this.readTimeout), + signal: AbortSignal.timeout(this.readTimeoutMs), headers: this.headers, dispatcher: this.getAgent(), }) @@ -127,11 +127,11 @@ export class HttpWaitStrategy extends AbstractWaitStrategy { } }, () => { - const message = `URL ${this.path} not accessible after ${this.startupTimeout}ms`; + const message = `URL ${this.path} not accessible after ${this.startupTimeoutMs}ms`; log.error(message, { containerId: container.id }); throw new Error(message); }, - this.startupTimeout + this.startupTimeoutMs ); if (abortOnContainerExit && containerExited) { diff --git a/packages/testcontainers/src/wait-strategies/log-wait-strategy.ts b/packages/testcontainers/src/wait-strategies/log-wait-strategy.ts index 005ef113b..6ccf1f88f 100644 --- a/packages/testcontainers/src/wait-strategies/log-wait-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/log-wait-strategy.ts @@ -21,10 +21,10 @@ export class LogWaitStrategy extends AbstractWaitStrategy { const stream = await client.container.logs(container, { since: startTime ? startTime.getTime() / 1000 : 0 }); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { - const message = `Log message "${this.message}" not received after ${this.startupTimeout}ms`; + const message = `Log message "${this.message}" not received after ${this.startupTimeoutMs}ms`; log.error(message, { containerId: container.id }); reject(new Error(message)); - }, this.startupTimeout); + }, this.startupTimeoutMs); const comparisonFn: (line: string) => boolean = (line: string) => { if (this.message instanceof RegExp) { diff --git a/packages/testcontainers/src/wait-strategies/shell-wait-strategy.ts b/packages/testcontainers/src/wait-strategies/shell-wait-strategy.ts index 7ae2be886..d62ab80a5 100644 --- a/packages/testcontainers/src/wait-strategies/shell-wait-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/shell-wait-strategy.ts @@ -21,11 +21,11 @@ export class ShellWaitStrategy extends AbstractWaitStrategy { }, (exitCode) => exitCode === 0, () => { - const message = `Shell command "${this.command}" not successful after ${this.startupTimeout}ms`; + const message = `Shell command "${this.command}" not successful after ${this.startupTimeoutMs}ms`; log.error(message, { containerId: container.id }); throw new Error(message); }, - this.startupTimeout + this.startupTimeoutMs ); log.debug(`Shell wait strategy complete`, { containerId: container.id }); diff --git a/packages/testcontainers/src/wait-strategies/startup-check-strategy.ts b/packages/testcontainers/src/wait-strategies/startup-check-strategy.ts index 1604221fb..14db883aa 100644 --- a/packages/testcontainers/src/wait-strategies/startup-check-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/startup-check-strategy.ts @@ -19,11 +19,11 @@ export abstract class StartupCheckStrategy extends AbstractWaitStrategy { async () => await this.checkStartupState(client.container.dockerode, container.id), (startupStatus) => startupStatus === "SUCCESS" || startupStatus === "FAIL", () => { - const message = `Container not accessible after ${this.startupTimeout}ms`; + const message = `Container not accessible after ${this.startupTimeoutMs}ms`; log.error(message, { containerId: container.id }); return new Error(message); }, - this.startupTimeout + this.startupTimeoutMs ); if (startupStatus instanceof Error) { diff --git a/packages/testcontainers/src/wait-strategies/wait-strategy.ts b/packages/testcontainers/src/wait-strategies/wait-strategy.ts index 241e44ecf..961776111 100644 --- a/packages/testcontainers/src/wait-strategies/wait-strategy.ts +++ b/packages/testcontainers/src/wait-strategies/wait-strategy.ts @@ -4,7 +4,7 @@ import { BoundPorts } from "../utils/bound-ports"; export interface WaitStrategy { waitUntilReady(container: Dockerode.Container, boundPorts: BoundPorts, startTime?: Date): Promise; - withStartupTimeout(startupTimeout: number): WaitStrategy; + withStartupTimeout(startupTimeoutMs: number): WaitStrategy; isStartupTimeoutSet(): boolean; @@ -12,7 +12,7 @@ export interface WaitStrategy { } export abstract class AbstractWaitStrategy implements WaitStrategy { - protected startupTimeout = 60_000; + protected startupTimeoutMs = 60_000; private startupTimeoutSet = false; public abstract waitUntilReady( @@ -21,8 +21,8 @@ export abstract class AbstractWaitStrategy implements WaitStrategy { startTime?: Date ): Promise; - public withStartupTimeout(startupTimeout: number): this { - this.startupTimeout = startupTimeout; + public withStartupTimeout(startupTimeoutMs: number): this { + this.startupTimeoutMs = startupTimeoutMs; this.startupTimeoutSet = true; return this; } @@ -32,6 +32,6 @@ export abstract class AbstractWaitStrategy implements WaitStrategy { } public getStartupTimeout(): number { - return this.startupTimeout; + return this.startupTimeoutMs; } }