testcontainers 11.14.0 → 12.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
36
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
4
  };
@@ -40,6 +7,7 @@ exports.withFileLock = withFileLock;
40
7
  const promises_1 = require("fs/promises");
41
8
  const path_1 = __importDefault(require("path"));
42
9
  const proper_lockfile_1 = __importDefault(require("proper-lockfile"));
10
+ const tmp_1 = __importDefault(require("tmp"));
43
11
  const logger_1 = require("./logger");
44
12
  async function withFileLock(fileName, fn) {
45
13
  const file = await createEmptyTmpFile(fileName);
@@ -61,8 +29,7 @@ async function withFileLock(fileName, fn) {
61
29
  }
62
30
  }
63
31
  async function createEmptyTmpFile(fileName) {
64
- const tmp = await Promise.resolve().then(() => __importStar(require("tmp")));
65
- const file = path_1.default.resolve(tmp.tmpdir, fileName);
32
+ const file = path_1.default.resolve(tmp_1.default.tmpdir, fileName);
66
33
  await (0, promises_1.writeFile)(file, "");
67
34
  return file;
68
35
  }
@@ -8,7 +8,7 @@ const reaper_1 = require("../reaper/reaper");
8
8
  const bound_ports_1 = require("../utils/bound-ports");
9
9
  const map_inspect_result_1 = require("../utils/map-inspect-result");
10
10
  const pull_policy_1 = require("../utils/pull-policy");
11
- const wait_1 = require("../wait-strategies/wait");
11
+ const wait_strategy_selector_1 = require("../wait-strategies/utils/wait-strategy-selector");
12
12
  const wait_for_container_1 = require("../wait-strategies/wait-for-container");
13
13
  const started_docker_compose_environment_1 = require("./started-docker-compose-environment");
14
14
  class DockerComposeEnvironment {
@@ -22,7 +22,7 @@ class DockerComposeEnvironment {
22
22
  profiles = [];
23
23
  environment = {};
24
24
  pullPolicy = pull_policy_1.PullPolicy.defaultPolicy();
25
- defaultWaitStrategy = wait_1.Wait.forListeningPorts();
25
+ defaultWaitStrategy;
26
26
  waitStrategy = {};
27
27
  startupTimeoutMs;
28
28
  clientOptions = {};
@@ -129,9 +129,11 @@ class DockerComposeEnvironment {
129
129
  const inspectResult = await client.container.inspect(container);
130
130
  const mappedInspectResult = (0, map_inspect_result_1.mapInspectResult)(inspectResult);
131
131
  const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(client.info.containerRuntime.hostIps, mappedInspectResult);
132
- const waitStrategy = this.waitStrategy[containerName]
133
- ? this.waitStrategy[containerName]
134
- : this.defaultWaitStrategy;
132
+ const waitStrategy = await (0, wait_strategy_selector_1.selectWaitStrategy)({
133
+ client,
134
+ inspectResult,
135
+ waitStrategy: this.waitStrategy[containerName] ?? this.defaultWaitStrategy,
136
+ });
135
137
  if (this.startupTimeoutMs !== undefined) {
136
138
  waitStrategy.withStartupTimeout(this.startupTimeoutMs);
137
139
  }
@@ -1,6 +1,6 @@
1
- import { ContainerCreateOptions, HostConfig } from "dockerode";
1
+ import { ContainerCreateOptions, ContainerInspectInfo, HostConfig } from "dockerode";
2
2
  import { Readable } from "stream";
3
- import { ImageName } from "../container-runtime";
3
+ import { ContainerRuntimeClient, ImageName } from "../container-runtime";
4
4
  import { StartedNetwork } from "../network/network";
5
5
  import { StartedTestContainer, TestContainer } from "../test-container";
6
6
  import { ArchiveToCopy, BindMount, ContentToCopy, CopyToContainerOptions, DirectoryToCopy, Environment, ExtraHost, FileToCopy, HealthCheck, InspectResult, Labels, ResourcesQuota, TmpFs, Ulimits } from "../types";
@@ -14,7 +14,7 @@ export declare class GenericContainer implements TestContainer {
14
14
  protected hostConfig: HostConfig;
15
15
  protected imageName: ImageName;
16
16
  protected startupTimeoutMs?: number;
17
- protected waitStrategy: WaitStrategy;
17
+ protected waitStrategy: WaitStrategy | undefined;
18
18
  protected environment: Record<string, string>;
19
19
  protected exposedPorts: PortWithOptionalBinding[];
20
20
  protected reuse: boolean;
@@ -37,6 +37,7 @@ export declare class GenericContainer implements TestContainer {
37
37
  protected containerCreated?(containerId: string): Promise<void>;
38
38
  protected containerStarting?(inspectResult: InspectResult, reused: boolean): Promise<void>;
39
39
  start(): Promise<StartedTestContainer>;
40
+ protected selectWaitStrategy(client: ContainerRuntimeClient, inspectResult: ContainerInspectInfo, waitStrategy?: WaitStrategy | undefined): Promise<WaitStrategy>;
40
41
  private reuseOrStartContainer;
41
42
  private reuseContainer;
42
43
  private startContainer;
@@ -17,7 +17,7 @@ const labels_1 = require("../utils/labels");
17
17
  const map_inspect_result_1 = require("../utils/map-inspect-result");
18
18
  const port_1 = require("../utils/port");
19
19
  const pull_policy_1 = require("../utils/pull-policy");
20
- const wait_1 = require("../wait-strategies/wait");
20
+ const wait_strategy_selector_1 = require("../wait-strategies/utils/wait-strategy-selector");
21
21
  const wait_for_container_1 = require("../wait-strategies/wait-for-container");
22
22
  const generic_container_builder_1 = require("./generic-container-builder");
23
23
  const inspect_container_util_ports_exposed_1 = require("./inspect-container-util-ports-exposed");
@@ -31,7 +31,7 @@ class GenericContainer {
31
31
  hostConfig;
32
32
  imageName;
33
33
  startupTimeoutMs;
34
- waitStrategy = wait_1.Wait.forListeningPorts();
34
+ waitStrategy;
35
35
  environment = {};
36
36
  exposedPorts = [];
37
37
  reuse = false;
@@ -50,13 +50,13 @@ class GenericContainer {
50
50
  constructor(image) {
51
51
  this.imageName = container_runtime_1.ImageName.fromString(image);
52
52
  this.createOpts = { Image: this.imageName.string };
53
- this.hostConfig = { AutoRemove: this.imageName.string === reaper_1.REAPER_IMAGE };
53
+ this.hostConfig = { AutoRemove: this.imageName.string === (0, reaper_1.getReaperImage)() };
54
54
  }
55
55
  isHelperContainer() {
56
56
  return this.isReaper() || this.imageName.string === port_forwarder_1.SSHD_IMAGE;
57
57
  }
58
58
  isReaper() {
59
- return this.imageName.string === reaper_1.REAPER_IMAGE;
59
+ return this.imageName.string === (0, reaper_1.getReaperImage)();
60
60
  }
61
61
  async start() {
62
62
  const client = await (0, container_runtime_1.getContainerRuntimeClient)();
@@ -85,6 +85,15 @@ class GenericContainer {
85
85
  }
86
86
  return this.startContainer(client);
87
87
  }
88
+ async selectWaitStrategy(client, inspectResult, waitStrategy = this.waitStrategy) {
89
+ return (0, wait_strategy_selector_1.selectWaitStrategy)({
90
+ client,
91
+ inspectResult,
92
+ waitStrategy,
93
+ healthCheck: this.healthCheck,
94
+ imageNames: [this.imageName.string],
95
+ });
96
+ }
88
97
  async reuseOrStartContainer(client) {
89
98
  const containerHash = (0, common_1.hash)(JSON.stringify(this.createOpts));
90
99
  this.createOpts.Labels = { ...this.createOpts.Labels, [labels_1.LABEL_TESTCONTAINERS_CONTAINER_HASH]: containerHash };
@@ -110,11 +119,12 @@ class GenericContainer {
110
119
  }
111
120
  const mappedInspectResult = (0, map_inspect_result_1.mapInspectResult)(inspectResult);
112
121
  const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(client.info.containerRuntime.hostIps, mappedInspectResult).filter(this.exposedPorts);
122
+ const waitStrategy = await this.selectWaitStrategy(client, inspectResult);
113
123
  if (this.startupTimeoutMs !== undefined) {
114
- this.waitStrategy.withStartupTimeout(this.startupTimeoutMs);
124
+ waitStrategy.withStartupTimeout(this.startupTimeoutMs);
115
125
  }
116
- await (0, wait_for_container_1.waitForContainer)(client, container, this.waitStrategy, boundPorts);
117
- return new started_generic_container_1.StartedGenericContainer(container, client.info.containerRuntime.host, inspectResult, boundPorts, inspectResult.Name, this.waitStrategy, this.autoRemove);
126
+ await (0, wait_for_container_1.waitForContainer)(client, container, waitStrategy, boundPorts);
127
+ return new started_generic_container_1.StartedGenericContainer(container, client.info.containerRuntime.host, inspectResult, boundPorts, inspectResult.Name, waitStrategy, this.autoRemove);
118
128
  }
119
129
  async startContainer(client) {
120
130
  const container = await client.container.create({ ...this.createOpts, HostConfig: this.hostConfig });
@@ -142,9 +152,6 @@ class GenericContainer {
142
152
  const inspectResult = await (0, inspect_container_util_ports_exposed_1.inspectContainerUntilPortsExposed)(() => client.container.inspect(container), container.id);
143
153
  const mappedInspectResult = (0, map_inspect_result_1.mapInspectResult)(inspectResult);
144
154
  const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(client.info.containerRuntime.hostIps, mappedInspectResult).filter(this.exposedPorts);
145
- if (this.startupTimeoutMs !== undefined) {
146
- this.waitStrategy.withStartupTimeout(this.startupTimeoutMs);
147
- }
148
155
  if (common_1.containerLog.enabled() || this.logConsumer !== undefined) {
149
156
  if (this.logConsumer !== undefined) {
150
157
  this.logConsumer(await client.container.logs(container));
@@ -158,8 +165,12 @@ class GenericContainer {
158
165
  if (this.containerStarting) {
159
166
  await this.containerStarting(mappedInspectResult, false);
160
167
  }
161
- await (0, wait_for_container_1.waitForContainer)(client, container, this.waitStrategy, boundPorts);
162
- const startedContainer = new started_generic_container_1.StartedGenericContainer(container, client.info.containerRuntime.host, inspectResult, boundPorts, inspectResult.Name, this.waitStrategy, this.autoRemove);
168
+ const waitStrategy = await this.selectWaitStrategy(client, inspectResult);
169
+ if (this.startupTimeoutMs !== undefined) {
170
+ waitStrategy.withStartupTimeout(this.startupTimeoutMs);
171
+ }
172
+ await (0, wait_for_container_1.waitForContainer)(client, container, waitStrategy, boundPorts);
173
+ const startedContainer = new started_generic_container_1.StartedGenericContainer(container, client.info.containerRuntime.host, inspectResult, boundPorts, inspectResult.Name, waitStrategy, this.autoRemove);
163
174
  if (this.containerStarted) {
164
175
  await this.containerStarted(startedContainer, mappedInspectResult, false);
165
176
  }
@@ -1,5 +1,12 @@
1
1
  import { ContainerRuntimeClient } from "../container-runtime";
2
- export declare const REAPER_IMAGE: string;
2
+ /**
3
+ * Resolve the Ryuk reaper image name. Read lazily so that callers (and tests)
4
+ * can set `process.env.RYUK_CONTAINER_IMAGE` _after_ this module is imported —
5
+ * including via `.env` files loaded by `dotenv` at runtime.
6
+ *
7
+ * See https://github.com/testcontainers/testcontainers-node/issues/1310.
8
+ */
9
+ export declare function getReaperImage(): string;
3
10
  export interface Reaper {
4
11
  sessionId: string;
5
12
  containerId: string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.REAPER_IMAGE = void 0;
3
+ exports.getReaperImage = getReaperImage;
4
4
  exports.getReaper = getReaper;
5
5
  const net_1 = require("net");
6
6
  const os_1 = require("os");
@@ -9,9 +9,18 @@ const container_runtime_1 = require("../container-runtime");
9
9
  const generic_container_1 = require("../generic-container/generic-container");
10
10
  const labels_1 = require("../utils/labels");
11
11
  const wait_1 = require("../wait-strategies/wait");
12
- exports.REAPER_IMAGE = process.env["RYUK_CONTAINER_IMAGE"]
13
- ? container_runtime_1.ImageName.fromString(process.env["RYUK_CONTAINER_IMAGE"]).string
14
- : container_runtime_1.ImageName.fromString("testcontainers/ryuk:0.14.0").string;
12
+ /**
13
+ * Resolve the Ryuk reaper image name. Read lazily so that callers (and tests)
14
+ * can set `process.env.RYUK_CONTAINER_IMAGE` _after_ this module is imported —
15
+ * including via `.env` files loaded by `dotenv` at runtime.
16
+ *
17
+ * See https://github.com/testcontainers/testcontainers-node/issues/1310.
18
+ */
19
+ function getReaperImage() {
20
+ return process.env["RYUK_CONTAINER_IMAGE"]
21
+ ? container_runtime_1.ImageName.fromString(process.env["RYUK_CONTAINER_IMAGE"]).string
22
+ : container_runtime_1.ImageName.fromString("testcontainers/ryuk:0.14.0").string;
23
+ }
15
24
  let reaper;
16
25
  let sessionId;
17
26
  async function getReaper(client) {
@@ -63,7 +72,7 @@ async function useExistingReaper(reaperContainer, sessionId, host) {
63
72
  }
64
73
  async function createNewReaper(sessionId, remoteSocketPath) {
65
74
  common_1.log.debug(`Creating new Reaper for session "${sessionId}" with socket path "${remoteSocketPath}"...`);
66
- const container = new generic_container_1.GenericContainer(exports.REAPER_IMAGE)
75
+ const container = new generic_container_1.GenericContainer(getReaperImage())
67
76
  .withName(`testcontainers-ryuk-${sessionId}`)
68
77
  .withExposedPorts(process.env["TESTCONTAINERS_RYUK_PORT"]
69
78
  ? { container: 8080, host: parseInt(process.env["TESTCONTAINERS_RYUK_PORT"]) }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mapInspectResult = mapInspectResult;
4
+ const health_check_1 = require("../wait-strategies/utils/health-check");
4
5
  function mapInspectResult(inspectResult) {
5
6
  const finishedAt = new Date(inspectResult.State.FinishedAt);
6
7
  return {
@@ -34,12 +35,12 @@ function mapPorts(inspectInfo) {
34
35
  .reduce((acc, curr) => ({ ...acc, ...curr }), {});
35
36
  }
36
37
  function mapHealthCheckStatus(inspectResult) {
37
- const health = inspectResult.State.Health;
38
- if (health === undefined) {
38
+ const status = (0, health_check_1.getHealthCheckStatusFromInspect)(inspectResult);
39
+ if (status === undefined) {
39
40
  return "none";
40
41
  }
41
42
  else {
42
- return health.Status;
43
+ return status;
43
44
  }
44
45
  }
45
46
  function mapNetworkSettings(inspectResult) {
@@ -1,42 +1,9 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.FixedPortGenerator = exports.RandomPortGenerator = void 0;
37
4
  class RandomPortGenerator {
38
5
  async generatePort() {
39
- const { default: getPort } = await Promise.resolve().then(() => __importStar(require("get-port")));
6
+ const { default: getPort } = await import("get-port");
40
7
  return getPort();
41
8
  }
42
9
  }
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "11.14.0";
1
+ export declare const LIB_VERSION = "12.0.1";
package/build/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LIB_VERSION = void 0;
4
- exports.LIB_VERSION = "11.14.0";
4
+ exports.LIB_VERSION = "12.0.1";
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HealthCheckWaitStrategy = void 0;
4
4
  const common_1 = require("../common");
5
5
  const container_runtime_1 = require("../container-runtime");
6
+ const health_check_1 = require("./utils/health-check");
6
7
  const wait_strategy_1 = require("./wait-strategy");
7
8
  class HealthCheckWaitStrategy extends wait_strategy_1.AbstractWaitStrategy {
8
9
  async waitUntilReady(container) {
9
10
  common_1.log.debug(`Waiting for health check...`, { containerId: container.id });
10
11
  const client = await (0, container_runtime_1.getContainerRuntimeClient)();
11
- const status = await new common_1.IntervalRetry(100).retryUntil(async () => (await client.container.inspect(container)).State.Health?.Status, (healthCheckStatus) => healthCheckStatus === "healthy" || healthCheckStatus === "unhealthy", () => {
12
+ const status = await new common_1.IntervalRetry(100).retryUntil(async () => (0, health_check_1.getHealthCheckStatusFromInspect)(await client.container.inspect(container)), (healthCheckStatus) => healthCheckStatus === "healthy" || healthCheckStatus === "unhealthy", () => {
12
13
  const timeout = this.startupTimeoutMs;
13
14
  const message = `Health check not healthy after ${timeout}ms`;
14
15
  common_1.log.error(message, { containerId: container.id });
@@ -0,0 +1,12 @@
1
+ import { ContainerInspectInfo, HealthConfig, ImageInspectInfo } from "dockerode";
2
+ import { HealthCheck, HealthCheckStatus } from "../../types";
3
+ type HealthCheckConfig = HealthConfig | HealthCheck;
4
+ type HealthCheckInspectInfo = ContainerInspectInfo | ImageInspectInfo;
5
+ export declare const isHealthCheckDisabled: (healthCheck: HealthCheckConfig | undefined) => boolean;
6
+ export declare const hasHealthCheck: (healthCheck: HealthCheckConfig | undefined) => boolean;
7
+ export declare const getHealthCheckConfig: (inspectResult: HealthCheckInspectInfo) => HealthConfig | undefined;
8
+ export declare const hasHealthCheckConfig: (inspectResult: HealthCheckInspectInfo) => boolean;
9
+ export declare const hasDisabledHealthCheckConfig: (inspectResult: HealthCheckInspectInfo) => boolean;
10
+ export declare const getHealthCheckStatusFromInspect: (inspectResult: ContainerInspectInfo) => HealthCheckStatus | undefined;
11
+ export declare const hasHealthCheckStatus: (inspectResult: ContainerInspectInfo) => boolean;
12
+ export {};
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hasHealthCheckStatus = exports.getHealthCheckStatusFromInspect = exports.hasDisabledHealthCheckConfig = exports.hasHealthCheckConfig = exports.getHealthCheckConfig = exports.hasHealthCheck = exports.isHealthCheckDisabled = void 0;
4
+ const DISABLED_HEALTH_CHECK_TEST = "NONE";
5
+ const getHealthCheckTest = (healthCheck) => {
6
+ if ("test" in healthCheck) {
7
+ return healthCheck.test;
8
+ }
9
+ return healthCheck.Test;
10
+ };
11
+ const isDisabledHealthCheck = (test) => {
12
+ return test[0].toUpperCase() === DISABLED_HEALTH_CHECK_TEST;
13
+ };
14
+ const isHealthCheckDisabled = (healthCheck) => {
15
+ if (healthCheck === undefined) {
16
+ return false;
17
+ }
18
+ const test = getHealthCheckTest(healthCheck);
19
+ if (test === undefined || test.length === 0) {
20
+ return false;
21
+ }
22
+ return isDisabledHealthCheck(test);
23
+ };
24
+ exports.isHealthCheckDisabled = isHealthCheckDisabled;
25
+ const hasHealthCheck = (healthCheck) => {
26
+ if (healthCheck === undefined) {
27
+ return false;
28
+ }
29
+ const test = getHealthCheckTest(healthCheck);
30
+ if (test === undefined || test.length === 0) {
31
+ return false;
32
+ }
33
+ return !(0, exports.isHealthCheckDisabled)(healthCheck);
34
+ };
35
+ exports.hasHealthCheck = hasHealthCheck;
36
+ const getHealthCheckConfig = (inspectResult) => {
37
+ const inspectWithHealthCheckConfig = inspectResult;
38
+ return (inspectWithHealthCheckConfig.Config?.Healthcheck ??
39
+ inspectWithHealthCheckConfig.Config?.HealthCheck ??
40
+ inspectWithHealthCheckConfig.ContainerConfig?.Healthcheck ??
41
+ inspectWithHealthCheckConfig.ContainerConfig?.HealthCheck ??
42
+ inspectWithHealthCheckConfig.Healthcheck ??
43
+ inspectWithHealthCheckConfig.HealthCheck);
44
+ };
45
+ exports.getHealthCheckConfig = getHealthCheckConfig;
46
+ const hasHealthCheckConfig = (inspectResult) => {
47
+ return (0, exports.hasHealthCheck)((0, exports.getHealthCheckConfig)(inspectResult));
48
+ };
49
+ exports.hasHealthCheckConfig = hasHealthCheckConfig;
50
+ const hasDisabledHealthCheckConfig = (inspectResult) => {
51
+ return (0, exports.isHealthCheckDisabled)((0, exports.getHealthCheckConfig)(inspectResult));
52
+ };
53
+ exports.hasDisabledHealthCheckConfig = hasDisabledHealthCheckConfig;
54
+ const getHealthCheckStatusFromInspect = (inspectResult) => {
55
+ const state = inspectResult.State;
56
+ const status = state.Health?.Status ?? state.Healthcheck?.Status;
57
+ return status === undefined || status === "" ? undefined : status;
58
+ };
59
+ exports.getHealthCheckStatusFromInspect = getHealthCheckStatusFromInspect;
60
+ const hasHealthCheckStatus = (inspectResult) => {
61
+ return (0, exports.getHealthCheckStatusFromInspect)(inspectResult) !== undefined;
62
+ };
63
+ exports.hasHealthCheckStatus = hasHealthCheckStatus;
@@ -0,0 +1,13 @@
1
+ import { ContainerInspectInfo } from "dockerode";
2
+ import { ContainerRuntimeClient } from "../../container-runtime";
3
+ import { HealthCheck } from "../../types";
4
+ import { WaitStrategy } from "../wait-strategy";
5
+ type WaitStrategySelectorOptions = {
6
+ client: ContainerRuntimeClient;
7
+ inspectResult: ContainerInspectInfo;
8
+ waitStrategy?: WaitStrategy;
9
+ healthCheck?: HealthCheck;
10
+ imageNames?: string[];
11
+ };
12
+ export declare const selectWaitStrategy: ({ client, inspectResult, waitStrategy, healthCheck, imageNames, }: WaitStrategySelectorOptions) => Promise<WaitStrategy>;
13
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectWaitStrategy = void 0;
4
+ const common_1 = require("../../common");
5
+ const container_runtime_1 = require("../../container-runtime");
6
+ const wait_1 = require("../wait");
7
+ const health_check_1 = require("./health-check");
8
+ const selectWaitStrategy = async ({ client, inspectResult, waitStrategy, healthCheck, imageNames = getImageNames(inspectResult), }) => {
9
+ if (waitStrategy)
10
+ return waitStrategy;
11
+ if ((0, health_check_1.hasHealthCheck)(healthCheck))
12
+ return wait_1.Wait.forHealthCheck();
13
+ if ((0, health_check_1.hasDisabledHealthCheckConfig)(inspectResult))
14
+ return wait_1.Wait.forListeningPorts();
15
+ if ((0, health_check_1.hasHealthCheckConfig)(inspectResult) || (0, health_check_1.hasHealthCheckStatus)(inspectResult))
16
+ return wait_1.Wait.forHealthCheck();
17
+ if (await imageHasHealthCheck(client, imageNames))
18
+ return wait_1.Wait.forHealthCheck();
19
+ return wait_1.Wait.forListeningPorts();
20
+ };
21
+ exports.selectWaitStrategy = selectWaitStrategy;
22
+ const getImageNames = (inspectResult) => {
23
+ return Array.from(new Set([inspectResult.Config.Image, inspectResult.Image].filter((imageName) => imageName !== undefined && imageName !== "")));
24
+ };
25
+ const imageHasHealthCheck = async (client, imageNames) => {
26
+ for (const imageName of imageNames) {
27
+ try {
28
+ if ((0, health_check_1.hasHealthCheckConfig)(await client.image.inspect(container_runtime_1.ImageName.fromString(imageName)))) {
29
+ return true;
30
+ }
31
+ }
32
+ catch (err) {
33
+ common_1.log.warn(`Failed to inspect image "${imageName}" for health check config: ${err}`);
34
+ }
35
+ }
36
+ return false;
37
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testcontainers",
3
- "version": "11.14.0",
3
+ "version": "12.0.1",
4
4
  "author": "Cristian Greco",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -37,14 +37,14 @@
37
37
  "byline": "^5.0.0",
38
38
  "debug": "^4.4.3",
39
39
  "docker-compose": "^1.4.2",
40
- "dockerode": "^4.0.10",
40
+ "dockerode": "^5.0.0",
41
41
  "get-port": "^7.2.0",
42
42
  "proper-lockfile": "^4.1.2",
43
43
  "properties-reader": "^3.0.1",
44
44
  "ssh-remote-port-forward": "^1.0.4",
45
45
  "tar-fs": "^3.1.2",
46
- "tmp": "^0.2.5",
47
- "undici": "^7.24.5"
46
+ "tmp": "^0.2.6",
47
+ "undici": "^7.25.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/archiver": "^7.0.0",