testcontainers 8.10.2-beta.0 → 8.12.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.
package/README.md CHANGED
@@ -162,6 +162,16 @@ const container2 = await new GenericContainer("alpine")
162
162
  assert(container1.getId() === container2.getId());
163
163
  ```
164
164
 
165
+ Restarting a container:
166
+
167
+ ```javascript
168
+ const { GenericContainer } = require("testcontainers");
169
+
170
+ const container = await new GenericContainer("alpine")
171
+ .start();
172
+ const restartedContainer = await container.restart();
173
+ ```
174
+
165
175
  Creating a container with a specified name:
166
176
 
167
177
  ```javascript
@@ -0,0 +1,5 @@
1
+ import Dockerode from "dockerode";
2
+ export declare type RestartContainerOptions = {
3
+ timeout: number;
4
+ };
5
+ export declare const restartContainer: (container: Dockerode.Container, options: RestartContainerOptions) => Promise<void>;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.restartContainer = void 0;
13
+ const logger_1 = require("../../../logger");
14
+ const restartContainer = (container, options) => __awaiter(void 0, void 0, void 0, function* () {
15
+ try {
16
+ yield container.restart({ t: options.timeout / 1000 });
17
+ }
18
+ catch (err) {
19
+ logger_1.log.error(`Failed to restart container ${container.id}: ${err}`);
20
+ throw err;
21
+ }
22
+ });
23
+ exports.restartContainer = restartContainer;
@@ -119,7 +119,7 @@ class DockerComposeEnvironment {
119
119
  }
120
120
  throw err;
121
121
  }
122
- return new started_generic_container_1.StartedGenericContainer(container, (yield (0, docker_client_1.dockerClient)()).host, inspectResult, boundPorts, containerName);
122
+ return new started_generic_container_1.StartedGenericContainer(container, (yield (0, docker_client_1.dockerClient)()).host, inspectResult, boundPorts, containerName, this.getWaitStrategy((yield (0, docker_client_1.dockerClient)()).host, container, containerName).withStartupTimeout(this.startupTimeout));
123
123
  })))).reduce((map, startedGenericContainer) => {
124
124
  const containerName = startedGenericContainer.getName();
125
125
  return Object.assign(Object.assign({}, map), { [containerName]: startedGenericContainer });
@@ -119,7 +119,7 @@ class GenericContainer {
119
119
  const inspectResult = yield (0, inspect_container_1.inspectContainer)(startedContainer);
120
120
  const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(inspectResult).filter(this.ports);
121
121
  yield this.waitForContainer(startedContainer, boundPorts);
122
- return new started_generic_container_1.StartedGenericContainer(startedContainer, (yield (0, docker_client_1.dockerClient)()).host, inspectResult, boundPorts, inspectResult.name);
122
+ return new started_generic_container_1.StartedGenericContainer(startedContainer, (yield (0, docker_client_1.dockerClient)()).host, inspectResult, boundPorts, inspectResult.name, this.getWaitStrategy((yield (0, docker_client_1.dockerClient)()).host, startedContainer).withStartupTimeout(this.startupTimeout));
123
123
  });
124
124
  }
125
125
  startContainer(createContainerOptions) {
@@ -156,7 +156,7 @@ class GenericContainer {
156
156
  const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
157
157
  const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(inspectResult).filter(this.ports);
158
158
  yield this.waitForContainer(container, boundPorts);
159
- const startedContainer = new started_generic_container_1.StartedGenericContainer(container, (yield (0, docker_client_1.dockerClient)()).host, inspectResult, boundPorts, inspectResult.name);
159
+ const startedContainer = new started_generic_container_1.StartedGenericContainer(container, (yield (0, docker_client_1.dockerClient)()).host, inspectResult, boundPorts, inspectResult.name, this.getWaitStrategy((yield (0, docker_client_1.dockerClient)()).host, container).withStartupTimeout(this.startupTimeout));
160
160
  if (this.postStart) {
161
161
  yield this.postStart(startedContainer, inspectResult, boundPorts);
162
162
  }
@@ -1,20 +1,24 @@
1
1
  /// <reference types="node" />
2
- import { StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
2
+ import { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
3
3
  import Dockerode from "dockerode";
4
4
  import { Command, ContainerName, ExecResult, Host, Id as ContainerId, Labels } from "../docker/types";
5
5
  import { InspectResult } from "../docker/functions/container/inspect-container";
6
6
  import { BoundPorts } from "../bound-ports";
7
7
  import { Port } from "../port";
8
8
  import { Readable } from "stream";
9
+ import { WaitStrategy } from "../wait-strategy";
9
10
  export declare class StartedGenericContainer implements StartedTestContainer {
10
11
  private readonly container;
11
12
  private readonly host;
12
- private readonly inspectResult;
13
- private readonly boundPorts;
13
+ private inspectResult;
14
+ private boundPorts;
14
15
  private readonly name;
15
- constructor(container: Dockerode.Container, host: Host, inspectResult: InspectResult, boundPorts: BoundPorts, name: ContainerName);
16
+ private readonly waitStrategy;
17
+ constructor(container: Dockerode.Container, host: Host, inspectResult: InspectResult, boundPorts: BoundPorts, name: ContainerName, waitStrategy: WaitStrategy);
16
18
  stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
19
+ restart(options?: Partial<RestartOptions>): Promise<void>;
17
20
  private stopContainer;
21
+ private waitForContainer;
18
22
  getHost(): Host;
19
23
  getMappedPort(port: Port): Port;
20
24
  getId(): ContainerId;
@@ -10,25 +10,39 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.StartedGenericContainer = void 0;
13
+ const inspect_container_1 = require("../docker/functions/container/inspect-container");
14
+ const bound_ports_1 = require("../bound-ports");
13
15
  const logger_1 = require("../logger");
14
16
  const remove_container_1 = require("../docker/functions/container/remove-container");
15
17
  const exec_container_1 = require("../docker/functions/container/exec-container");
16
18
  const container_logs_1 = require("../docker/functions/container/container-logs");
17
19
  const stopped_generic_container_1 = require("./stopped-generic-container");
18
20
  const stop_container_1 = require("../docker/functions/container/stop-container");
21
+ const restart_container_1 = require("../docker/functions/container/restart-container");
19
22
  class StartedGenericContainer {
20
- constructor(container, host, inspectResult, boundPorts, name) {
23
+ constructor(container, host, inspectResult, boundPorts, name, waitStrategy) {
21
24
  this.container = container;
22
25
  this.host = host;
23
26
  this.inspectResult = inspectResult;
24
27
  this.boundPorts = boundPorts;
25
28
  this.name = name;
29
+ this.waitStrategy = waitStrategy;
26
30
  }
27
31
  stop(options = {}) {
28
32
  return __awaiter(this, void 0, void 0, function* () {
29
33
  return this.stopContainer(options);
30
34
  });
31
35
  }
36
+ restart(options = {}) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ const resolvedOptions = Object.assign({ timeout: 0 }, options);
39
+ yield (0, restart_container_1.restartContainer)(this.container, resolvedOptions);
40
+ // Inspect the restarted container and update the bound ports
41
+ this.inspectResult = yield (0, inspect_container_1.inspectContainer)(this.container);
42
+ this.boundPorts = yield bound_ports_1.BoundPorts.fromInspectResult(this.inspectResult).filter(Array.from(this.boundPorts.iterator()).map((port) => port[0]));
43
+ yield this.waitForContainer(this.container, this.boundPorts);
44
+ });
45
+ }
32
46
  stopContainer(options = {}) {
33
47
  return __awaiter(this, void 0, void 0, function* () {
34
48
  logger_1.log.info(`Stopping container with ID: ${this.container.id}`);
@@ -38,6 +52,26 @@ class StartedGenericContainer {
38
52
  return new stopped_generic_container_1.StoppedGenericContainer();
39
53
  });
40
54
  }
55
+ waitForContainer(container, boundPorts) {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ logger_1.log.debug(`Waiting for container to be ready: ${container.id}`);
58
+ try {
59
+ yield this.waitStrategy.waitUntilReady(container, boundPorts);
60
+ logger_1.log.info("Container is ready");
61
+ }
62
+ catch (err) {
63
+ logger_1.log.error(`Container failed to be ready: ${err}`);
64
+ try {
65
+ yield (0, stop_container_1.stopContainer)(container, { timeout: 0 });
66
+ yield (0, remove_container_1.removeContainer)(container, { removeVolumes: true });
67
+ }
68
+ catch (stopErr) {
69
+ logger_1.log.error(`Failed to stop container after it failed to be ready: ${stopErr}`);
70
+ }
71
+ throw err;
72
+ }
73
+ });
74
+ }
41
75
  getHost() {
42
76
  return this.host;
43
77
  }
package/dist/index.d.ts CHANGED
@@ -15,3 +15,4 @@ export { Neo4jContainer, StartedNeo4jContainer } from "./modules/neo4j/neo4j-con
15
15
  export { ArangoDBContainer, StartedArangoContainer } from "./modules/arangodb/arangodb-container";
16
16
  export { ElasticsearchContainer, StartedElasticsearchContainer } from "./modules/elasticsearch/elasticsearch-container";
17
17
  export { MySqlContainer, StartedMySqlContainer } from "./modules/mysql/mysql-container";
18
+ export { NatsContainer, StartedNatsContainer, NatsConnectionOptions, NatsTlsOptions, } from "./modules/nats/nats-container";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- 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.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.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.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");
@@ -42,3 +42,6 @@ Object.defineProperty(exports, "StartedElasticsearchContainer", { enumerable: tr
42
42
  var mysql_container_1 = require("./modules/mysql/mysql-container");
43
43
  Object.defineProperty(exports, "MySqlContainer", { enumerable: true, get: function () { return mysql_container_1.MySqlContainer; } });
44
44
  Object.defineProperty(exports, "StartedMySqlContainer", { enumerable: true, get: function () { return mysql_container_1.StartedMySqlContainer; } });
45
+ var nats_container_1 = require("./modules/nats/nats-container");
46
+ Object.defineProperty(exports, "NatsContainer", { enumerable: true, get: function () { return nats_container_1.NatsContainer; } });
47
+ Object.defineProperty(exports, "StartedNatsContainer", { enumerable: true, get: function () { return nats_container_1.StartedNatsContainer; } });
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
2
+ import { RestartOptions, StartedTestContainer, StopOptions, StoppedTestContainer } from "../test-container";
3
3
  import { Port } from "../port";
4
4
  import { ContainerName, Host, Id, Command, ExecResult, Labels } from "../docker/types";
5
5
  import { Readable } from "stream";
@@ -7,6 +7,7 @@ export declare class AbstractStartedContainer {
7
7
  protected readonly startedTestContainer: StartedTestContainer;
8
8
  constructor(startedTestContainer: StartedTestContainer);
9
9
  stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
10
+ restart(options?: Partial<RestartOptions>): Promise<void>;
10
11
  getHost(): Host;
11
12
  getMappedPort(port: Port): Port;
12
13
  getName(): ContainerName;
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  exports.AbstractStartedContainer = void 0;
4
13
  class AbstractStartedContainer {
@@ -8,6 +17,11 @@ class AbstractStartedContainer {
8
17
  stop(options) {
9
18
  return this.startedTestContainer.stop(options);
10
19
  }
20
+ restart(options) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ return this.startedTestContainer.restart(options);
23
+ });
24
+ }
11
25
  getHost() {
12
26
  return this.startedTestContainer.getHost();
13
27
  }
@@ -0,0 +1,55 @@
1
+ import { GenericContainer } from "../../generic-container/generic-container";
2
+ import { StartedTestContainer } from "../../test-container";
3
+ import { AbstractStartedContainer } from "../abstract-started-container";
4
+ export declare class NatsContainer extends GenericContainer {
5
+ private args;
6
+ constructor(image?: string);
7
+ withUser(user: string): this;
8
+ withPass(pass: string): this;
9
+ withArg(name: string, value: string): this;
10
+ private static ensureDashInFrontOfArgumentName;
11
+ start(): Promise<StartedNatsContainer>;
12
+ private getUser;
13
+ private getPass;
14
+ }
15
+ export declare class StartedNatsContainer extends AbstractStartedContainer {
16
+ readonly username: string;
17
+ readonly password: string;
18
+ private readonly connectionOptions;
19
+ constructor(startedTestContainer: StartedTestContainer, username: string, password: string);
20
+ getConnectionOptions(): NatsConnectionOptions;
21
+ }
22
+ export interface NatsConnectionOptions {
23
+ debug?: boolean;
24
+ maxPingOut?: number;
25
+ maxReconnectAttempts?: number;
26
+ name?: string;
27
+ noEcho?: boolean;
28
+ noRandomize?: boolean;
29
+ pass?: string;
30
+ pedantic?: boolean;
31
+ pingInterval?: number;
32
+ port?: number;
33
+ reconnect?: boolean;
34
+ reconnectDelayHandler?: () => number;
35
+ reconnectJitter?: number;
36
+ reconnectJitterTLS?: number;
37
+ reconnectTimeWait?: number;
38
+ servers?: Array<string> | string;
39
+ timeout?: number;
40
+ tls?: NatsTlsOptions;
41
+ token?: string;
42
+ user?: string;
43
+ verbose?: boolean;
44
+ waitOnFirstConnect?: boolean;
45
+ ignoreClusterUpdates?: boolean;
46
+ inboxPrefix?: string;
47
+ }
48
+ export interface NatsTlsOptions {
49
+ certFile?: string;
50
+ cert?: string;
51
+ caFile?: string;
52
+ ca?: string;
53
+ keyFile?: string;
54
+ key?: string;
55
+ }
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.StartedNatsContainer = exports.NatsContainer = void 0;
13
+ const generic_container_1 = require("../../generic-container/generic-container");
14
+ const uuid_1 = require("../../uuid");
15
+ const abstract_started_container_1 = require("../abstract-started-container");
16
+ const wait_1 = require("../../wait");
17
+ const CLIENT_PORT = 4222;
18
+ const ROUTING_PORT_FOR_CLUSTERING = 6222;
19
+ const HTTP_MANAGEMENT_PORT = 8222;
20
+ const USER_ARGUMENT_KEY = "--user";
21
+ const PASS_ARGUMENT_KEY = "--pass";
22
+ class NatsContainer extends generic_container_1.GenericContainer {
23
+ constructor(image = "nats:2.8-alpine") {
24
+ super(image);
25
+ this.args = {};
26
+ this.args[USER_ARGUMENT_KEY] = new uuid_1.RandomUuid().nextUuid();
27
+ this.args[PASS_ARGUMENT_KEY] = new uuid_1.RandomUuid().nextUuid();
28
+ }
29
+ withUser(user) {
30
+ this.args[USER_ARGUMENT_KEY] = user;
31
+ return this;
32
+ }
33
+ withPass(pass) {
34
+ this.args[PASS_ARGUMENT_KEY] = pass;
35
+ return this;
36
+ }
37
+ withArg(name, value) {
38
+ name = NatsContainer.ensureDashInFrontOfArgumentName(name);
39
+ this.args[name] = value;
40
+ return this;
41
+ }
42
+ static ensureDashInFrontOfArgumentName(name) {
43
+ if (name.startsWith("--") || name.startsWith("-")) {
44
+ return name;
45
+ }
46
+ if (name.length == 1) {
47
+ return "-" + name;
48
+ }
49
+ else {
50
+ return "--" + name;
51
+ }
52
+ }
53
+ start() {
54
+ const _super = Object.create(null, {
55
+ start: { get: () => super.start }
56
+ });
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ function buildCmdsFromArgs(args) {
59
+ const result = [];
60
+ result.push("nats-server");
61
+ for (const argsKey in args) {
62
+ result.push(argsKey);
63
+ result.push(args[argsKey]);
64
+ }
65
+ return result;
66
+ }
67
+ this.withCmd(buildCmdsFromArgs(this.args))
68
+ .withExposedPorts(...(this.hasExposedPorts ? this.ports : [CLIENT_PORT, ROUTING_PORT_FOR_CLUSTERING, HTTP_MANAGEMENT_PORT]))
69
+ .withWaitStrategy(wait_1.Wait.forLogMessage(new RegExp(".*Server is ready.*")))
70
+ .withStartupTimeout(120000);
71
+ return new StartedNatsContainer(yield _super.start.call(this), this.getUser(), this.getPass());
72
+ });
73
+ }
74
+ getUser() {
75
+ return this.args[USER_ARGUMENT_KEY];
76
+ }
77
+ getPass() {
78
+ return this.args[PASS_ARGUMENT_KEY];
79
+ }
80
+ }
81
+ exports.NatsContainer = NatsContainer;
82
+ class StartedNatsContainer extends abstract_started_container_1.AbstractStartedContainer {
83
+ constructor(startedTestContainer, username, password) {
84
+ super(startedTestContainer);
85
+ this.username = username;
86
+ this.password = password;
87
+ const port = startedTestContainer.getMappedPort(CLIENT_PORT);
88
+ this.connectionOptions = {
89
+ servers: `${this.startedTestContainer.getHost()}:${port}`,
90
+ user: this.username,
91
+ pass: this.password,
92
+ };
93
+ }
94
+ getConnectionOptions() {
95
+ return this.connectionOptions;
96
+ }
97
+ }
98
+ exports.StartedNatsContainer = StartedNatsContainer;
@@ -23,12 +23,16 @@ export interface TestContainer {
23
23
  withCopyFileToContainer(sourcePath: string, containerPath: string): this;
24
24
  withCopyContentToContainer(content: string | Buffer | Readable, containerPath: string): this;
25
25
  }
26
+ export interface RestartOptions {
27
+ timeout: number;
28
+ }
26
29
  export interface StopOptions {
27
30
  timeout: number;
28
31
  removeVolumes: boolean;
29
32
  }
30
33
  export interface StartedTestContainer {
31
34
  stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
35
+ restart(options?: Partial<RestartOptions>): Promise<void>;
32
36
  getHost(): Host;
33
37
  getMappedPort(port: Port): Port;
34
38
  getName(): ContainerName;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "testcontainers",
3
3
  "author": "Cristian Greco",
4
- "version": "8.10.2-beta.0",
4
+ "version": "8.12.0",
5
5
  "main": "dist/index",
6
6
  "types": "dist/index",
7
7
  "keywords": [
@@ -74,7 +74,8 @@
74
74
  "ts-jest": "^27.1.4",
75
75
  "ts-node": "^10.7.0",
76
76
  "typescript": "^4.6.3",
77
- "wait-for-expect": "^3.0.2"
77
+ "wait-for-expect": "^3.0.2",
78
+ "nats": "^2.7.1"
78
79
  },
79
80
  "lint-staged": {
80
81
  "src/**/*.ts": [