testcontainers 9.2.1 → 9.4.0

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.
Files changed (62) hide show
  1. package/dist/package.json +17 -17
  2. package/dist/src/docker/docker-client.js +2 -45
  3. package/dist/src/docker/functions/container/create-container.d.ts +2 -1
  4. package/dist/src/docker/functions/container/create-container.js +3 -0
  5. package/dist/src/docker/functions/container/exec-container.d.ts +1 -7
  6. package/dist/src/docker/functions/container/exec-container.js +4 -4
  7. package/dist/src/docker/resolve-host.d.ts +6 -0
  8. package/dist/src/docker/resolve-host.js +60 -0
  9. package/dist/src/docker/types.d.ts +4 -0
  10. package/dist/src/docker-compose/default-docker-compose-options.js +12 -0
  11. package/dist/src/docker-compose/functions/docker-compose-up.js +2 -2
  12. package/dist/src/docker-compose-environment/docker-compose-environment.d.ts +1 -1
  13. package/dist/src/docker-compose-environment/docker-compose-environment.js +7 -5
  14. package/dist/src/dockerfile-parser.js +2 -1
  15. package/dist/src/generic-container/create-container-options.d.ts +3 -0
  16. package/dist/src/generic-container/create-container-options.js +18 -0
  17. package/dist/src/generic-container/generic-container.d.ts +18 -25
  18. package/dist/src/generic-container/generic-container.js +87 -81
  19. package/dist/src/generic-container/started-generic-container.d.ts +5 -3
  20. package/dist/src/generic-container/started-generic-container.js +13 -6
  21. package/dist/src/index.d.ts +4 -2
  22. package/dist/src/index.js +5 -3
  23. package/dist/src/modules/abstract-started-container.d.ts +3 -1
  24. package/dist/src/modules/abstract-started-container.js +10 -1
  25. package/dist/src/modules/arangodb/arangodb-container.js +1 -1
  26. package/dist/src/modules/elasticsearch/elasticsearch-container.js +7 -1
  27. package/dist/src/modules/kafka/kafka-container.d.ts +2 -3
  28. package/dist/src/modules/kafka/kafka-container.js +8 -8
  29. package/dist/src/modules/mongodb/mongodb-container.d.ts +1 -1
  30. package/dist/src/modules/mongodb/mongodb-container.js +2 -2
  31. package/dist/src/modules/mysql/mysql-container.js +1 -1
  32. package/dist/src/modules/nats/nats-container.js +4 -2
  33. package/dist/src/modules/neo4j/neo4j-container.js +1 -1
  34. package/dist/src/modules/postgresql/postgresql-container.js +2 -2
  35. package/dist/src/port-check.js +1 -1
  36. package/dist/src/reaper.js +1 -1
  37. package/dist/src/test-container.d.ts +3 -2
  38. package/dist/src/type-guards.d.ts +2 -0
  39. package/dist/src/type-guards.js +6 -4
  40. package/dist/src/wait-for-container.d.ts +1 -1
  41. package/dist/src/wait-strategy/default-wait-strategy.d.ts +3 -0
  42. package/dist/src/wait-strategy/default-wait-strategy.js +7 -0
  43. package/dist/src/wait-strategy/health-check-wait-strategy.d.ts +5 -0
  44. package/dist/src/wait-strategy/health-check-wait-strategy.js +31 -0
  45. package/dist/src/wait-strategy/host-port-wait-strategy.d.ts +13 -0
  46. package/dist/src/wait-strategy/host-port-wait-strategy.js +54 -0
  47. package/dist/src/{http-wait-strategy.d.ts → wait-strategy/http-wait-strategy.d.ts} +1 -1
  48. package/dist/src/{http-wait-strategy.js → wait-strategy/http-wait-strategy.js} +1 -1
  49. package/dist/src/wait-strategy/log-wait-strategy.d.ts +10 -0
  50. package/dist/src/wait-strategy/log-wait-strategy.js +67 -0
  51. package/dist/src/wait-strategy/shell-wait-strategy.d.ts +7 -0
  52. package/dist/src/wait-strategy/shell-wait-strategy.js +35 -0
  53. package/dist/src/{startup-check-strategy.js → wait-strategy/startup-check-strategy.js} +2 -2
  54. package/dist/src/wait-strategy/wait-strategy.d.ts +11 -0
  55. package/dist/src/wait-strategy/wait-strategy.js +13 -0
  56. package/dist/src/{wait.d.ts → wait-strategy/wait.d.ts} +4 -1
  57. package/dist/src/wait-strategy/wait.js +22 -0
  58. package/package.json +17 -17
  59. package/dist/src/wait-strategy.d.ts +0 -32
  60. package/dist/src/wait-strategy.js +0 -137
  61. package/dist/src/wait.js +0 -17
  62. /package/dist/src/{startup-check-strategy.d.ts → wait-strategy/startup-check-strategy.d.ts} +0 -0
@@ -20,7 +20,6 @@ const logger_1 = require("../logger");
20
20
  const pull_policy_1 = require("../pull-policy");
21
21
  const reaper_1 = require("../reaper");
22
22
  const docker_image_name_1 = require("../docker-image-name");
23
- const wait_strategy_1 = require("../wait-strategy");
24
23
  const port_forwarder_1 = require("../port-forwarder");
25
24
  const pull_image_1 = require("../docker/functions/image/pull-image");
26
25
  const create_container_1 = require("../docker/functions/container/create-container");
@@ -36,6 +35,8 @@ const hash_1 = require("../hash");
36
35
  const get_container_1 = require("../docker/functions/container/get-container");
37
36
  const labels_1 = require("../labels");
38
37
  const wait_for_container_1 = require("../wait-for-container");
38
+ const create_container_options_1 = require("./create-container-options");
39
+ const default_wait_strategy_1 = require("../wait-strategy/default-wait-strategy");
39
40
  const reusableContainerCreationLock = new async_lock_1.default();
40
41
  class GenericContainer {
41
42
  static fromDockerfile(context, dockerfileName = "Dockerfile") {
@@ -43,65 +44,41 @@ class GenericContainer {
43
44
  }
44
45
  constructor(image) {
45
46
  this.image = image;
46
- this.environment = {};
47
- this.networkAliases = [];
48
- this.ports = [];
49
- this.command = [];
50
- this.bindMounts = [];
51
- this.labels = {};
52
- this.tmpFs = {};
53
47
  this.startupTimeout = 60000;
54
- this.useDefaultLogDriver = false;
55
- this.privilegedMode = false;
48
+ this.networkAliases = [];
56
49
  this.pullPolicy = new pull_policy_1.DefaultPullPolicy();
57
- this.reuse = false;
58
- this.extraHosts = [];
59
- this.imageName = docker_image_name_1.DockerImageName.fromString(image);
50
+ const imageName = docker_image_name_1.DockerImageName.fromString(image);
51
+ this.opts = (0, create_container_options_1.initCreateContainerOptions)(imageName, imageName.isReaper());
60
52
  }
61
53
  start() {
62
54
  return __awaiter(this, void 0, void 0, function* () {
63
55
  const { dockerode, indexServerAddress } = yield (0, docker_client_1.dockerClient)();
64
56
  yield (0, pull_image_1.pullImage)(dockerode, indexServerAddress, {
65
- imageName: this.imageName,
57
+ imageName: this.opts.imageName,
66
58
  force: this.pullPolicy.shouldPull(),
67
59
  });
68
- if (!this.reuse && !this.imageName.isReaper()) {
60
+ if (!this.opts.reusable && !this.opts.imageName.isReaper()) {
69
61
  yield reaper_1.ReaperInstance.getInstance();
70
62
  }
71
- if (this.preStart) {
63
+ if (this.beforeContainerStarted) {
64
+ yield this.beforeContainerStarted();
65
+ }
66
+ else if (this.preStart) {
72
67
  yield this.preStart();
73
68
  }
74
- if (!this.imageName.isHelperContainer() && port_forwarder_1.PortForwarderInstance.isRunning()) {
69
+ if (!this.opts.imageName.isHelperContainer() && port_forwarder_1.PortForwarderInstance.isRunning()) {
75
70
  const portForwarder = yield port_forwarder_1.PortForwarderInstance.getInstance();
76
- this.extraHosts.push({ host: "host.testcontainers.internal", ipAddress: portForwarder.getIpAddress() });
71
+ this.opts.extraHosts.push({ host: "host.testcontainers.internal", ipAddress: portForwarder.getIpAddress() });
72
+ }
73
+ if (this.networkAliases.length > 0) {
74
+ this.opts.networkMode = undefined;
75
+ }
76
+ else {
77
+ this.opts.networkMode = this.networkMode;
77
78
  }
78
- const createContainerOptions = {
79
- imageName: this.imageName,
80
- environment: this.environment,
81
- command: this.command,
82
- entrypoint: this.entrypoint,
83
- bindMounts: this.bindMounts,
84
- tmpFs: this.tmpFs,
85
- exposedPorts: this.ports,
86
- name: this.name,
87
- labels: this.labels,
88
- reusable: this.reuse,
89
- networkMode: this.networkAliases.length > 0 ? undefined : this.networkMode,
90
- healthCheck: this.healthCheck,
91
- useDefaultLogDriver: this.useDefaultLogDriver,
92
- privilegedMode: this.privilegedMode,
93
- autoRemove: this.imageName.isReaper(),
94
- extraHosts: this.extraHosts,
95
- ipcMode: this.ipcMode,
96
- ulimits: this.ulimits,
97
- addedCapabilities: this.addedCapabilities,
98
- droppedCapabilities: this.droppedCapabilities,
99
- user: this.user,
100
- workingDir: this.workingDir,
101
- };
102
- if (this.reuse) {
103
- const containerHash = (0, hash_1.hash)(JSON.stringify(createContainerOptions));
104
- createContainerOptions.labels = Object.assign(Object.assign({}, createContainerOptions.labels), { [labels_1.LABEL_TESTCONTAINERS_CONTAINER_HASH]: containerHash });
79
+ if (this.opts.reusable) {
80
+ const containerHash = (0, hash_1.hash)(JSON.stringify(this.opts));
81
+ this.opts.labels = Object.assign(Object.assign({}, this.opts.labels), { [labels_1.LABEL_TESTCONTAINERS_CONTAINER_HASH]: containerHash });
105
82
  logger_1.log.debug(`Container reuse has been enabled, hash: ${containerHash}`);
106
83
  // We might have several async processes try to create a reusable container
107
84
  // at once, to avoid possibly creating too many of these, use a lock
@@ -114,31 +91,41 @@ class GenericContainer {
114
91
  }
115
92
  else {
116
93
  logger_1.log.debug("No container found to reuse");
117
- return this.startContainer(createContainerOptions);
94
+ return this.startContainer(this.opts);
118
95
  }
119
96
  }));
120
97
  }
121
98
  else {
122
- return this.startContainer(createContainerOptions);
99
+ return this.startContainer(this.opts);
123
100
  }
124
101
  });
125
102
  }
126
- reuseContainer(startedContainer) {
103
+ reuseContainer(container) {
127
104
  var _a;
128
105
  return __awaiter(this, void 0, void 0, function* () {
129
106
  const { host, hostIps } = yield (0, docker_client_1.dockerClient)();
130
- const inspectResult = yield (0, inspect_container_1.inspectContainer)(startedContainer);
131
- const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.ports);
132
- const waitStrategy = ((_a = this.waitStrategy) !== null && _a !== void 0 ? _a : (0, wait_strategy_1.defaultWaitStrategy)(host, startedContainer)).withStartupTimeout(this.startupTimeout);
133
- yield (0, wait_for_container_1.waitForContainer)(startedContainer, waitStrategy, host, boundPorts);
134
- return new started_generic_container_1.StartedGenericContainer(startedContainer, host, inspectResult, boundPorts, inspectResult.name, waitStrategy);
107
+ const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
108
+ const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.opts.exposedPorts);
109
+ const waitStrategy = ((_a = this.waitStrategy) !== null && _a !== void 0 ? _a : (0, default_wait_strategy_1.defaultWaitStrategy)(host, container)).withStartupTimeout(this.startupTimeout);
110
+ if (this.containerStarting) {
111
+ yield this.containerStarting(inspectResult, true);
112
+ }
113
+ yield (0, wait_for_container_1.waitForContainer)(container, waitStrategy, host, boundPorts);
114
+ const startedContainer = new started_generic_container_1.StartedGenericContainer(container, host, inspectResult, boundPorts, inspectResult.name, waitStrategy);
115
+ if (this.containerStarted) {
116
+ yield this.containerStarted(startedContainer, inspectResult, true);
117
+ }
118
+ else if (this.postStart) {
119
+ yield this.postStart(startedContainer, inspectResult, boundPorts);
120
+ }
121
+ return startedContainer;
135
122
  });
136
123
  }
137
124
  startContainer(createContainerOptions) {
138
125
  var _a;
139
126
  return __awaiter(this, void 0, void 0, function* () {
140
127
  const container = yield (0, create_container_1.createContainer)(createContainerOptions);
141
- if (!this.imageName.isHelperContainer() && port_forwarder_1.PortForwarderInstance.isRunning()) {
128
+ if (!this.opts.imageName.isHelperContainer() && port_forwarder_1.PortForwarderInstance.isRunning()) {
142
129
  const portForwarder = yield port_forwarder_1.PortForwarderInstance.getInstance();
143
130
  const portForwarderNetworkId = portForwarder.getNetworkId();
144
131
  const excludedNetworks = [portForwarderNetworkId, "none", "host"];
@@ -161,62 +148,73 @@ class GenericContainer {
161
148
  this.tarToCopy.finalize();
162
149
  yield (0, put_container_archive_1.putContainerArchive)({ container, stream: this.tarToCopy, containerPath: "/" });
163
150
  }
164
- logger_1.log.info(`Starting container ${this.imageName} with ID: ${container.id}`);
151
+ logger_1.log.info(`Starting container ${this.opts.imageName} with ID: ${container.id}`);
152
+ if (this.containerCreated) {
153
+ yield this.containerCreated(container.id);
154
+ }
165
155
  yield (0, start_container_1.startContainer)(container);
166
156
  const { host, hostIps } = yield (0, docker_client_1.dockerClient)();
167
157
  const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
168
- const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.ports);
169
- const waitStrategy = ((_a = this.waitStrategy) !== null && _a !== void 0 ? _a : (0, wait_strategy_1.defaultWaitStrategy)(host, container)).withStartupTimeout(this.startupTimeout);
170
- (yield (0, container_logs_1.containerLogs)(container))
171
- .on("data", (data) => logger_1.containerLog.trace(`${container.id}: ${data.trim()}`))
172
- .on("err", (data) => logger_1.containerLog.error(`${container.id}: ${data.trim()}`));
158
+ const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.opts.exposedPorts);
159
+ const waitStrategy = ((_a = this.waitStrategy) !== null && _a !== void 0 ? _a : (0, default_wait_strategy_1.defaultWaitStrategy)(host, container)).withStartupTimeout(this.startupTimeout);
160
+ if (logger_1.containerLog.enabled()) {
161
+ (yield (0, container_logs_1.containerLogs)(container))
162
+ .on("data", (data) => logger_1.containerLog.trace(`${container.id}: ${data.trim()}`))
163
+ .on("err", (data) => logger_1.containerLog.error(`${container.id}: ${data.trim()}`));
164
+ }
165
+ if (this.containerStarting) {
166
+ yield this.containerStarting(inspectResult, false);
167
+ }
173
168
  yield (0, wait_for_container_1.waitForContainer)(container, waitStrategy, host, boundPorts);
174
169
  const startedContainer = new started_generic_container_1.StartedGenericContainer(container, host, inspectResult, boundPorts, inspectResult.name, waitStrategy);
175
- if (this.postStart) {
170
+ if (this.containerStarted) {
171
+ yield this.containerStarted(startedContainer, inspectResult, false);
172
+ }
173
+ else if (this.postStart) {
176
174
  yield this.postStart(startedContainer, inspectResult, boundPorts);
177
175
  }
178
176
  return startedContainer;
179
177
  });
180
178
  }
181
179
  get hasExposedPorts() {
182
- return this.ports.length !== 0;
180
+ return this.opts.exposedPorts.length !== 0;
183
181
  }
184
182
  withCommand(command) {
185
- this.command = command;
183
+ this.opts.command = command;
186
184
  return this;
187
185
  }
188
186
  withEntrypoint(entrypoint) {
189
- this.entrypoint = entrypoint;
187
+ this.opts.entrypoint = entrypoint;
190
188
  return this;
191
189
  }
192
190
  withName(name) {
193
- this.name = name;
191
+ this.opts.name = name;
194
192
  return this;
195
193
  }
196
194
  withLabels(labels) {
197
- this.labels = Object.assign(Object.assign({}, this.labels), labels);
195
+ this.opts.labels = Object.assign(Object.assign({}, this.opts.labels), labels);
198
196
  return this;
199
197
  }
200
198
  withEnvironment(environment) {
201
- this.environment = Object.assign(Object.assign({}, this.environment), environment);
199
+ this.opts.environment = Object.assign(Object.assign({}, this.opts.environment), environment);
202
200
  return this;
203
201
  }
204
202
  withTmpFs(tmpFs) {
205
- this.tmpFs = Object.assign(Object.assign({}, this.tmpFs), tmpFs);
203
+ this.opts.tmpFs = Object.assign(Object.assign({}, this.opts.tmpFs), tmpFs);
206
204
  return this;
207
205
  }
208
206
  withUlimits(ulimits) {
209
- this.ulimits = Object.assign(Object.assign({}, this.ulimits), ulimits);
207
+ this.opts.ulimits = Object.assign(Object.assign({}, this.opts.ulimits), ulimits);
210
208
  return this;
211
209
  }
212
210
  withAddedCapabilities(...capabilities) {
213
211
  var _a;
214
- this.addedCapabilities = [...((_a = this.addedCapabilities) !== null && _a !== void 0 ? _a : []), ...capabilities];
212
+ this.opts.addedCapabilities = [...((_a = this.opts.addedCapabilities) !== null && _a !== void 0 ? _a : []), ...capabilities];
215
213
  return this;
216
214
  }
217
215
  withDroppedCapabilities(...capabilities) {
218
216
  var _a;
219
- this.droppedCapabilities = [...((_a = this.droppedCapabilities) !== null && _a !== void 0 ? _a : []), ...capabilities];
217
+ this.opts.droppedCapabilities = [...((_a = this.opts.droppedCapabilities) !== null && _a !== void 0 ? _a : []), ...capabilities];
220
218
  return this;
221
219
  }
222
220
  withNetwork(network) {
@@ -232,19 +230,19 @@ class GenericContainer {
232
230
  return this;
233
231
  }
234
232
  withExtraHosts(extraHosts) {
235
- this.extraHosts = [...this.extraHosts, ...extraHosts];
233
+ this.opts.extraHosts = [...this.opts.extraHosts, ...extraHosts];
236
234
  return this;
237
235
  }
238
236
  withExposedPorts(...ports) {
239
- this.ports = [...this.ports, ...ports];
237
+ this.opts.exposedPorts = [...this.opts.exposedPorts, ...ports];
240
238
  return this;
241
239
  }
242
240
  withBindMounts(bindMounts) {
243
- this.bindMounts = bindMounts.map((bindMount) => (Object.assign({ mode: "rw" }, bindMount)));
241
+ this.opts.bindMounts = bindMounts.map((bindMount) => (Object.assign({ mode: "rw" }, bindMount)));
244
242
  return this;
245
243
  }
246
244
  withHealthCheck(healthCheck) {
247
- this.healthCheck = healthCheck;
245
+ this.opts.healthCheck = healthCheck;
248
246
  return this;
249
247
  }
250
248
  withStartupTimeout(startupTimeoutMs) {
@@ -256,19 +254,19 @@ class GenericContainer {
256
254
  return this;
257
255
  }
258
256
  withDefaultLogDriver() {
259
- this.useDefaultLogDriver = true;
257
+ this.opts.useDefaultLogDriver = true;
260
258
  return this;
261
259
  }
262
260
  withPrivilegedMode() {
263
- this.privilegedMode = true;
261
+ this.opts.privilegedMode = true;
264
262
  return this;
265
263
  }
266
264
  withUser(user) {
267
- this.user = user;
265
+ this.opts.user = user;
268
266
  return this;
269
267
  }
270
268
  withReuse() {
271
- this.reuse = true;
269
+ this.opts.reusable = true;
272
270
  return this;
273
271
  }
274
272
  withPullPolicy(pullPolicy) {
@@ -276,7 +274,7 @@ class GenericContainer {
276
274
  return this;
277
275
  }
278
276
  withIpcMode(ipcMode) {
279
- this.ipcMode = ipcMode;
277
+ this.opts.ipcMode = ipcMode;
280
278
  return this;
281
279
  }
282
280
  withCopyFilesToContainer(filesToCopy) {
@@ -296,7 +294,15 @@ class GenericContainer {
296
294
  return this.tarToCopy;
297
295
  }
298
296
  withWorkingDir(workingDir) {
299
- this.workingDir = workingDir;
297
+ this.opts.workingDir = workingDir;
298
+ return this;
299
+ }
300
+ withResourcesQuota({ memory, cpu }) {
301
+ // Memory and CPU units from here: https://docs.docker.com/engine/api/v1.42/#tag/Container/operation/ContainerCreate
302
+ // see Memory, NanoCpus parameters
303
+ const ram = memory !== undefined ? memory * Math.pow(1024, 3) : undefined;
304
+ const cpuQuota = cpu !== undefined ? cpu * Math.pow(10, 9) : undefined;
305
+ this.opts.resourcesQuota = { memory: ram, cpu: cpuQuota };
300
306
  return this;
301
307
  }
302
308
  }
@@ -1,11 +1,11 @@
1
1
  /// <reference types="node" />
2
- import { ExecOptions, RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
2
+ import { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
3
3
  import Dockerode from "dockerode";
4
4
  import { ExecResult, Labels } from "../docker/types";
5
5
  import { InspectResult } from "../docker/functions/container/inspect-container";
6
6
  import { BoundPorts } from "../bound-ports";
7
7
  import { Readable } from "stream";
8
- import { WaitStrategy } from "../wait-strategy";
8
+ import { WaitStrategy } from "../wait-strategy/wait-strategy";
9
9
  export declare class StartedGenericContainer implements StartedTestContainer {
10
10
  private readonly container;
11
11
  private readonly host;
@@ -14,7 +14,9 @@ export declare class StartedGenericContainer implements StartedTestContainer {
14
14
  private readonly name;
15
15
  private readonly waitStrategy;
16
16
  constructor(container: Dockerode.Container, host: string, inspectResult: InspectResult, boundPorts: BoundPorts, name: string, waitStrategy: WaitStrategy);
17
+ protected containerIsStopping?(): Promise<void>;
17
18
  stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
19
+ protected containerIsStopped?(): Promise<void>;
18
20
  restart(options?: Partial<RestartOptions>): Promise<void>;
19
21
  private stopContainer;
20
22
  getHost(): string;
@@ -26,6 +28,6 @@ export declare class StartedGenericContainer implements StartedTestContainer {
26
28
  getNetworkNames(): string[];
27
29
  getNetworkId(networkName: string): string;
28
30
  getIpAddress(networkName: string): string;
29
- exec(command: string[], options?: Partial<ExecOptions>): Promise<ExecResult>;
31
+ exec(command: string[]): Promise<ExecResult>;
30
32
  logs(): Promise<Readable>;
31
33
  }
@@ -43,9 +43,11 @@ class StartedGenericContainer {
43
43
  const { hostIps } = yield (0, docker_client_1.dockerClient)();
44
44
  this.inspectResult = yield (0, inspect_container_1.inspectContainer)(this.container);
45
45
  const startTime = this.inspectResult.state.startedAt;
46
- (yield (0, container_logs_1.containerLogs)(this.container, { since: startTime }))
47
- .on("data", (data) => logger_1.containerLog.trace(`${this.container.id}: ${data.trim()}`))
48
- .on("err", (data) => logger_1.containerLog.error(`${this.container.id}: ${data.trim()}`));
46
+ if (logger_1.containerLog.enabled()) {
47
+ (yield (0, container_logs_1.containerLogs)(this.container, { since: startTime }))
48
+ .on("data", (data) => logger_1.containerLog.trace(`${this.container.id}: ${data.trim()}`))
49
+ .on("err", (data) => logger_1.containerLog.error(`${this.container.id}: ${data.trim()}`));
50
+ }
49
51
  this.boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, this.inspectResult).filter(Array.from(this.boundPorts.iterator()).map((port) => port[0]));
50
52
  yield (0, wait_for_container_1.waitForContainer)(this.container, this.waitStrategy, this.host, this.boundPorts, startTime);
51
53
  });
@@ -53,9 +55,15 @@ class StartedGenericContainer {
53
55
  stopContainer(options = {}) {
54
56
  return __awaiter(this, void 0, void 0, function* () {
55
57
  logger_1.log.info(`Stopping container with ID: ${this.container.id}`);
58
+ if (this.containerIsStopping) {
59
+ yield this.containerIsStopping();
60
+ }
56
61
  const resolvedOptions = Object.assign({ timeout: 0, removeVolumes: true }, options);
57
62
  yield (0, stop_container_1.stopContainer)(this.container, { timeout: resolvedOptions.timeout });
58
63
  yield (0, remove_container_1.removeContainer)(this.container, { removeVolumes: resolvedOptions.removeVolumes });
64
+ if (this.containerIsStopped) {
65
+ yield this.containerIsStopped();
66
+ }
59
67
  return new stopped_generic_container_1.StoppedGenericContainer();
60
68
  });
61
69
  }
@@ -86,9 +94,8 @@ class StartedGenericContainer {
86
94
  getIpAddress(networkName) {
87
95
  return this.inspectResult.networkSettings[networkName].ipAddress;
88
96
  }
89
- exec(command, options = {}) {
90
- const resolvedOptions = Object.assign({ stdin: true, detach: false, tty: true }, options);
91
- return (0, exec_container_1.execContainer)(this.container, command, resolvedOptions);
97
+ exec(command) {
98
+ return (0, exec_container_1.execContainer)(this.container, command);
92
99
  }
93
100
  logs() {
94
101
  return (0, container_logs_1.containerLogs)(this.container);
@@ -7,9 +7,11 @@ export { StartedDockerComposeEnvironment } from "./docker-compose-environment/st
7
7
  export { StoppedDockerComposeEnvironment } from "./docker-compose-environment/stopped-docker-compose-environment";
8
8
  export { DownedDockerComposeEnvironment } from "./docker-compose-environment/downed-docker-compose-environment";
9
9
  export { Network, StartedNetwork, StoppedNetwork } from "./network";
10
- export { Wait } from "./wait";
11
- export { StartupCheckStrategy, StartupStatus } from "./startup-check-strategy";
10
+ export { Wait } from "./wait-strategy/wait";
11
+ export { StartupCheckStrategy, StartupStatus } from "./wait-strategy/startup-check-strategy";
12
12
  export { PullPolicy, DefaultPullPolicy, AlwaysPullPolicy } from "./pull-policy";
13
+ export { InspectResult } from "./docker/functions/container/inspect-container";
14
+ export { AbstractStartedContainer } from "./modules/abstract-started-container";
13
15
  export { PostgreSqlContainer, StartedPostgreSqlContainer } from "./modules/postgresql/postgresql-container";
14
16
  export { KafkaContainer, StartedKafkaContainer } from "./modules/kafka/kafka-container";
15
17
  export { Neo4jContainer, StartedNeo4jContainer } from "./modules/neo4j/neo4j-container";
package/dist/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StartedMongoDBContainer = exports.MongoDBContainer = exports.StartedNatsContainer = exports.NatsContainer = exports.StartedMySqlContainer = exports.MySqlContainer = exports.StartedElasticsearchContainer = exports.ElasticsearchContainer = exports.StartedArangoContainer = exports.ArangoDBContainer = exports.StartedNeo4jContainer = exports.Neo4jContainer = exports.StartedKafkaContainer = exports.KafkaContainer = exports.StartedPostgreSqlContainer = exports.PostgreSqlContainer = exports.AlwaysPullPolicy = exports.DefaultPullPolicy = exports.StartupCheckStrategy = exports.Wait = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.DownedDockerComposeEnvironment = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.TestContainers = exports.GenericContainerBuilder = exports.GenericContainer = void 0;
3
+ exports.StartedMongoDBContainer = exports.MongoDBContainer = exports.StartedNatsContainer = exports.NatsContainer = exports.StartedMySqlContainer = exports.MySqlContainer = exports.StartedElasticsearchContainer = exports.ElasticsearchContainer = exports.StartedArangoContainer = exports.ArangoDBContainer = exports.StartedNeo4jContainer = exports.Neo4jContainer = exports.StartedKafkaContainer = exports.KafkaContainer = exports.StartedPostgreSqlContainer = exports.PostgreSqlContainer = exports.AbstractStartedContainer = exports.AlwaysPullPolicy = exports.DefaultPullPolicy = exports.StartupCheckStrategy = exports.Wait = exports.StoppedNetwork = exports.StartedNetwork = exports.Network = exports.DownedDockerComposeEnvironment = exports.StoppedDockerComposeEnvironment = exports.StartedDockerComposeEnvironment = exports.DockerComposeEnvironment = exports.TestContainers = exports.GenericContainerBuilder = exports.GenericContainer = void 0;
4
4
  var generic_container_1 = require("./generic-container/generic-container");
5
5
  Object.defineProperty(exports, "GenericContainer", { enumerable: true, get: function () { return generic_container_1.GenericContainer; } });
6
6
  var generic_container_builder_1 = require("./generic-container/generic-container-builder");
@@ -19,13 +19,15 @@ var network_1 = require("./network");
19
19
  Object.defineProperty(exports, "Network", { enumerable: true, get: function () { return network_1.Network; } });
20
20
  Object.defineProperty(exports, "StartedNetwork", { enumerable: true, get: function () { return network_1.StartedNetwork; } });
21
21
  Object.defineProperty(exports, "StoppedNetwork", { enumerable: true, get: function () { return network_1.StoppedNetwork; } });
22
- var wait_1 = require("./wait");
22
+ var wait_1 = require("./wait-strategy/wait");
23
23
  Object.defineProperty(exports, "Wait", { enumerable: true, get: function () { return wait_1.Wait; } });
24
- var startup_check_strategy_1 = require("./startup-check-strategy");
24
+ var startup_check_strategy_1 = require("./wait-strategy/startup-check-strategy");
25
25
  Object.defineProperty(exports, "StartupCheckStrategy", { enumerable: true, get: function () { return startup_check_strategy_1.StartupCheckStrategy; } });
26
26
  var pull_policy_1 = require("./pull-policy");
27
27
  Object.defineProperty(exports, "DefaultPullPolicy", { enumerable: true, get: function () { return pull_policy_1.DefaultPullPolicy; } });
28
28
  Object.defineProperty(exports, "AlwaysPullPolicy", { enumerable: true, get: function () { return pull_policy_1.AlwaysPullPolicy; } });
29
+ var abstract_started_container_1 = require("./modules/abstract-started-container");
30
+ Object.defineProperty(exports, "AbstractStartedContainer", { enumerable: true, get: function () { return abstract_started_container_1.AbstractStartedContainer; } });
29
31
  var postgresql_container_1 = require("./modules/postgresql/postgresql-container");
30
32
  Object.defineProperty(exports, "PostgreSqlContainer", { enumerable: true, get: function () { return postgresql_container_1.PostgreSqlContainer; } });
31
33
  Object.defineProperty(exports, "StartedPostgreSqlContainer", { enumerable: true, get: function () { return postgresql_container_1.StartedPostgreSqlContainer; } });
@@ -2,10 +2,12 @@
2
2
  import { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
3
3
  import { ExecResult, Labels } from "../docker/types";
4
4
  import { Readable } from "stream";
5
- export declare class AbstractStartedContainer {
5
+ export declare class AbstractStartedContainer implements StartedTestContainer {
6
6
  protected readonly startedTestContainer: StartedTestContainer;
7
7
  constructor(startedTestContainer: StartedTestContainer);
8
+ protected containerStopping?(): Promise<void>;
8
9
  stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
10
+ protected containerStopped?(): Promise<void>;
9
11
  restart(options?: Partial<RestartOptions>): Promise<void>;
10
12
  getHost(): string;
11
13
  getFirstMappedPort(): number;
@@ -15,7 +15,16 @@ class AbstractStartedContainer {
15
15
  this.startedTestContainer = startedTestContainer;
16
16
  }
17
17
  stop(options) {
18
- return this.startedTestContainer.stop(options);
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ if (this.containerStopping) {
20
+ yield this.containerStopping();
21
+ }
22
+ const stoppedContainer = this.startedTestContainer.stop(options);
23
+ if (this.containerStopped) {
24
+ yield this.containerStopped();
25
+ }
26
+ return stoppedContainer;
27
+ });
19
28
  }
20
29
  restart(options) {
21
30
  return __awaiter(this, void 0, void 0, function* () {
@@ -28,7 +28,7 @@ class ArangoDBContainer extends __1.GenericContainer {
28
28
  start: { get: () => super.start }
29
29
  });
30
30
  return __awaiter(this, void 0, void 0, function* () {
31
- this.withExposedPorts(...(this.hasExposedPorts ? this.ports : [ARANGODB_PORT]))
31
+ this.withExposedPorts(...(this.hasExposedPorts ? this.opts.exposedPorts : [ARANGODB_PORT]))
32
32
  .withWaitStrategy(__1.Wait.forLogMessage("Have fun!"))
33
33
  .withEnvironment({ ARANGO_ROOT_PASSWORD: this.password })
34
34
  .withStartupTimeout(120000);
@@ -22,8 +22,14 @@ class ElasticsearchContainer extends __1.GenericContainer {
22
22
  start: { get: () => super.start }
23
23
  });
24
24
  return __awaiter(this, void 0, void 0, function* () {
25
- this.withExposedPorts(...(this.hasExposedPorts ? this.ports : [ELASTIC_SEARCH_HTTP_PORT]))
25
+ this.withExposedPorts(...(this.hasExposedPorts ? this.opts.exposedPorts : [ELASTIC_SEARCH_HTTP_PORT]))
26
26
  .withEnvironment({ "discovery.type": "single-node" })
27
+ .withCopyContentToContainer([
28
+ {
29
+ content: "-Xms2G\n-Xmx2G\n",
30
+ target: "/usr/share/elasticsearch/config/jvm.options.d/elasticsearch-default-memory-vm.options",
31
+ },
32
+ ])
27
33
  .withStartupTimeout(120000);
28
34
  return new StartedElasticsearchContainer(yield _super.start.call(this));
29
35
  });
@@ -1,5 +1,4 @@
1
1
  import { GenericContainer } from "../../generic-container/generic-container";
2
- import { BoundPorts } from "../../bound-ports";
3
2
  import { StartedTestContainer } from "../..";
4
3
  import { AbstractStartedContainer } from "../abstract-started-container";
5
4
  import { InspectResult } from "../../docker/functions/container/inspect-container";
@@ -32,9 +31,9 @@ export declare class KafkaContainer extends GenericContainer {
32
31
  constructor(image?: string);
33
32
  withZooKeeper(host: string, port: number): this;
34
33
  withSaslSslListener(options: SaslSslListenerOptions): this;
35
- protected preStart(): Promise<void>;
34
+ protected beforeContainerStarted(): Promise<void>;
36
35
  start(): Promise<StartedKafkaContainer>;
37
- protected postStart(container: StartedTestContainer, inspectResult: InspectResult, boundPorts: BoundPorts): Promise<void>;
36
+ protected containerStarted(container: StartedTestContainer, inspectResult: InspectResult): Promise<void>;
38
37
  private addPlaintextAndSecureListener;
39
38
  private addPlaintextListener;
40
39
  private updateAdvertisedListeners;
@@ -44,7 +44,7 @@ class KafkaContainer extends generic_container_1.GenericContainer {
44
44
  this.saslSslConfig = options;
45
45
  return this;
46
46
  }
47
- preStart() {
47
+ beforeContainerStarted() {
48
48
  return __awaiter(this, void 0, void 0, function* () {
49
49
  const network = this.networkMode && this.networkAliases.length > 0 ? this.networkAliases[0] : "localhost";
50
50
  this.withEnvironment({ KAFKA_ADVERTISED_LISTENERS: `BROKER://${network}:${KAFKA_BROKER_PORT}` });
@@ -81,9 +81,9 @@ class KafkaContainer extends generic_container_1.GenericContainer {
81
81
  return new StartedKafkaContainer(yield _super.start.call(this));
82
82
  });
83
83
  }
84
- postStart(container, inspectResult, boundPorts) {
84
+ containerStarted(container, inspectResult) {
85
85
  return __awaiter(this, void 0, void 0, function* () {
86
- yield this.updateAdvertisedListeners(container, inspectResult, boundPorts);
86
+ yield this.updateAdvertisedListeners(container, inspectResult);
87
87
  if (this.saslSslConfig) {
88
88
  yield this.createUser(container, this.saslSslConfig.sasl);
89
89
  }
@@ -117,12 +117,12 @@ class KafkaContainer extends generic_container_1.GenericContainer {
117
117
  KAFKA_LISTENERS: `PLAINTEXT://0.0.0.0:${KAFKA_PORT},BROKER://0.0.0.0:${KAFKA_BROKER_PORT}`,
118
118
  }).withExposedPorts(KAFKA_PORT);
119
119
  }
120
- updateAdvertisedListeners(container, inspectResult, boundPorts) {
120
+ updateAdvertisedListeners(container, inspectResult) {
121
121
  return __awaiter(this, void 0, void 0, function* () {
122
122
  const brokerAdvertisedListener = `BROKER://${inspectResult.hostname}:${KAFKA_BROKER_PORT}`;
123
- let bootstrapServers = `PLAINTEXT://${container.getHost()}:${boundPorts.getBinding(KAFKA_PORT)}`;
123
+ let bootstrapServers = `PLAINTEXT://${container.getHost()}:${container.getMappedPort(KAFKA_PORT)}`;
124
124
  if (this.saslSslConfig) {
125
- bootstrapServers = `${bootstrapServers},SECURE://${container.getHost()}:${boundPorts.getBinding(this.saslSslConfig.port)}`;
125
+ bootstrapServers = `${bootstrapServers},SECURE://${container.getHost()}:${container.getMappedPort(this.saslSslConfig.port)}`;
126
126
  }
127
127
  const { output, exitCode } = yield container.exec([
128
128
  "kafka-configs",
@@ -132,7 +132,7 @@ class KafkaContainer extends generic_container_1.GenericContainer {
132
132
  "--entity-type",
133
133
  "brokers",
134
134
  "--entity-name",
135
- this.environment["KAFKA_BROKER_ID"],
135
+ this.opts.environment["KAFKA_BROKER_ID"],
136
136
  "--add-config",
137
137
  `advertised.listeners=[${bootstrapServers},${brokerAdvertisedListener}]`,
138
138
  ]);
@@ -149,7 +149,7 @@ class KafkaContainer extends generic_container_1.GenericContainer {
149
149
  // At the time of writing kafka-configs displays a warning stating that the 'zookeeper' flag is deprecated in favor of 'bootstrap-server'.
150
150
  // Unfortunately, 'bootstrap-server' can only be used to set quotas and not to create a user.
151
151
  "--zookeeper",
152
- this.environment["KAFKA_ZOOKEEPER_CONNECT"],
152
+ this.opts.environment["KAFKA_ZOOKEEPER_CONNECT"],
153
153
  "--entity-type",
154
154
  "users",
155
155
  "--entity-name",
@@ -5,7 +5,7 @@ export declare class MongoDBContainer extends GenericContainer {
5
5
  private readonly dockerImageName;
6
6
  constructor(image?: string);
7
7
  start(): Promise<StartedMongoDBContainer>;
8
- protected postStart(startedTestContainer: StartedTestContainer): Promise<void>;
8
+ protected containerStarted(startedTestContainer: StartedTestContainer): Promise<void>;
9
9
  private initReplicaSet;
10
10
  private executeMongoEvalCommand;
11
11
  private buildMongoEvalCommand;
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.StartedMongoDBContainer = exports.MongoDBContainer = void 0;
13
13
  const generic_container_1 = require("../../generic-container/generic-container");
14
14
  const abstract_started_container_1 = require("../abstract-started-container");
15
- const wait_1 = require("../../wait");
15
+ const wait_1 = require("../../wait-strategy/wait");
16
16
  const docker_image_name_1 = require("../../docker-image-name");
17
17
  const MONGODB_PORT = 27017;
18
18
  class MongoDBContainer extends generic_container_1.GenericContainer {
@@ -32,7 +32,7 @@ class MongoDBContainer extends generic_container_1.GenericContainer {
32
32
  return new StartedMongoDBContainer(yield _super.start.call(this));
33
33
  });
34
34
  }
35
- postStart(startedTestContainer) {
35
+ containerStarted(startedTestContainer) {
36
36
  return __awaiter(this, void 0, void 0, function* () {
37
37
  yield this.initReplicaSet(startedTestContainer);
38
38
  });
@@ -42,7 +42,7 @@ class MySqlContainer extends generic_container_1.GenericContainer {
42
42
  start: { get: () => super.start }
43
43
  });
44
44
  return __awaiter(this, void 0, void 0, function* () {
45
- this.withExposedPorts(...(this.hasExposedPorts ? this.ports : [MYSQL_PORT]))
45
+ this.withExposedPorts(...(this.hasExposedPorts ? this.opts.exposedPorts : [MYSQL_PORT]))
46
46
  .withEnvironment({
47
47
  MYSQL_DATABASE: this.database,
48
48
  MYSQL_ROOT_PASSWORD: this.rootPassword,
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.StartedNatsContainer = exports.NatsContainer = void 0;
13
13
  const generic_container_1 = require("../../generic-container/generic-container");
14
14
  const abstract_started_container_1 = require("../abstract-started-container");
15
- const wait_1 = require("../../wait");
15
+ const wait_1 = require("../../wait-strategy/wait");
16
16
  const CLIENT_PORT = 4222;
17
17
  const ROUTING_PORT_FOR_CLUSTERING = 6222;
18
18
  const HTTP_MANAGEMENT_PORT = 8222;
@@ -64,7 +64,9 @@ class NatsContainer extends generic_container_1.GenericContainer {
64
64
  return result;
65
65
  }
66
66
  this.withCommand(buildCmdsFromArgs(this.args))
67
- .withExposedPorts(...(this.hasExposedPorts ? this.ports : [CLIENT_PORT, ROUTING_PORT_FOR_CLUSTERING, HTTP_MANAGEMENT_PORT]))
67
+ .withExposedPorts(...(this.hasExposedPorts
68
+ ? this.opts.exposedPorts
69
+ : [CLIENT_PORT, ROUTING_PORT_FOR_CLUSTERING, HTTP_MANAGEMENT_PORT]))
68
70
  .withWaitStrategy(wait_1.Wait.forLogMessage(/.*Server is ready.*/))
69
71
  .withStartupTimeout(120000);
70
72
  return new StartedNatsContainer(yield _super.start.call(this), this.getUser(), this.getPass());