UNPKG

testcontainers

Version:

Testcontainers is a NodeJS library that supports tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container

201 lines 10.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.StartedGenericContainer = void 0; const archiver_1 = __importDefault(require("archiver")); const async_lock_1 = __importDefault(require("async-lock")); const common_1 = require("../common"); const container_runtime_1 = require("../container-runtime"); const reaper_1 = require("../reaper/reaper"); const bound_ports_1 = require("../utils/bound-ports"); const labels_1 = require("../utils/labels"); const map_inspect_result_1 = require("../utils/map-inspect-result"); const wait_for_container_1 = require("../wait-strategies/wait-for-container"); const stopped_generic_container_1 = require("./stopped-generic-container"); class StartedGenericContainer { container; host; inspectResult; boundPorts; name; waitStrategy; autoRemove; stoppedContainer; stopContainerLock = new async_lock_1.default(); constructor(container, host, inspectResult, boundPorts, name, waitStrategy, autoRemove) { this.container = container; this.host = host; this.inspectResult = inspectResult; this.boundPorts = boundPorts; this.name = name; this.waitStrategy = waitStrategy; this.autoRemove = autoRemove; } async stop(options = {}) { return this.stopContainerLock.acquire("stop", async () => { if (this.stoppedContainer) { return this.stoppedContainer; } this.stoppedContainer = await this.stopContainer(options); return this.stoppedContainer; }); } /** * Construct the command(s) to apply changes to the container before committing it to an image. */ async getContainerCommitChangeCommands(options) { const { deleteOnExit, client } = options; const changes = options.changes || []; if (deleteOnExit) { let sessionId = this.getLabels()[labels_1.LABEL_TESTCONTAINERS_SESSION_ID]; if (!sessionId) { sessionId = await (0, reaper_1.getReaper)(client).then((reaper) => reaper.sessionId); } changes.push(`LABEL ${labels_1.LABEL_TESTCONTAINERS_SESSION_ID}=${sessionId}`); } else if (!deleteOnExit && this.getLabels()[labels_1.LABEL_TESTCONTAINERS_SESSION_ID]) { // By default, commit will save the existing labels (including the session ID) to the new image. If // deleteOnExit is false, we need to remove the session ID label. changes.push(`LABEL ${labels_1.LABEL_TESTCONTAINERS_SESSION_ID}=`); } return changes.join("\n"); } async commit(options) { const client = await (0, container_runtime_1.getContainerRuntimeClient)(); const { deleteOnExit = true, changes, ...commitOpts } = options; const changeCommands = await this.getContainerCommitChangeCommands({ deleteOnExit, changes, client }); const imageId = await client.container.commit(this.container, { ...commitOpts, changes: changeCommands }); return imageId; } async restart(options = {}) { common_1.log.info(`Restarting container...`, { containerId: this.container.id }); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); const resolvedOptions = { timeout: 0, ...options }; await client.container.restart(this.container, resolvedOptions); this.inspectResult = await client.container.inspect(this.container); const mappedInspectResult = (0, map_inspect_result_1.mapInspectResult)(this.inspectResult); const startTime = new Date(this.inspectResult.State.StartedAt); if (common_1.containerLog.enabled()) { (await client.container.logs(this.container, { since: startTime.getTime() / 1000 })) .on("data", (data) => common_1.containerLog.trace(data.trim(), { containerId: this.container.id })) .on("err", (data) => common_1.containerLog.error(data.trim(), { containerId: this.container.id })); } this.boundPorts = bound_ports_1.BoundPorts.fromInspectResult(client.info.containerRuntime.hostIps, mappedInspectResult).filter(Array.from(this.boundPorts.iterator()).map((port) => port[0])); await (0, wait_for_container_1.waitForContainer)(client, this.container, this.waitStrategy, this.boundPorts, startTime); common_1.log.info(`Restarted container`, { containerId: this.container.id }); } async stopContainer(options = {}) { common_1.log.info(`Stopping container...`, { containerId: this.container.id }); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); if (this.containerIsStopping) { await this.containerIsStopping(); } const resolvedOptions = { remove: this.autoRemove, timeout: 0, removeVolumes: true, ...options }; await client.container.stop(this.container, { timeout: resolvedOptions.timeout }); if (resolvedOptions.remove) { await client.container.remove(this.container, { removeVolumes: resolvedOptions.removeVolumes }); } common_1.log.info(`Stopped container`, { containerId: this.container.id }); if (this.containerIsStopped) { await this.containerIsStopped(); } return new stopped_generic_container_1.StoppedGenericContainer(this.container); } getHost() { return this.host; } getHostname() { return this.inspectResult.Config.Hostname; } getFirstMappedPort() { return this.boundPorts.getFirstBinding(); } getMappedPort(port) { return this.boundPorts.getBinding(port); } getId() { return this.container.id; } getName() { return this.name; } getLabels() { return this.inspectResult.Config.Labels; } getNetworkNames() { return Object.keys(this.getNetworkSettings()); } getNetworkId(networkName) { return this.getNetworkSettings()[networkName].networkId; } getIpAddress(networkName) { return this.getNetworkSettings()[networkName].ipAddress; } getNetworkSettings() { return Object.entries(this.inspectResult.NetworkSettings.Networks) .map(([networkName, network]) => ({ [networkName]: { networkId: network.NetworkID, ipAddress: network.IPAddress, }, })) .reduce((prev, next) => ({ ...prev, ...next }), {}); } async copyFilesToContainer(filesToCopy) { common_1.log.debug(`Copying files to container...`, { containerId: this.container.id }); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); const tar = (0, archiver_1.default)("tar"); filesToCopy.forEach(({ source, target }) => tar.file(source, { name: target })); tar.finalize(); await client.container.putArchive(this.container, tar, "/"); common_1.log.debug(`Copied files to container`, { containerId: this.container.id }); } async copyDirectoriesToContainer(directoriesToCopy) { common_1.log.debug(`Copying directories to container...`, { containerId: this.container.id }); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); const tar = (0, archiver_1.default)("tar"); directoriesToCopy.forEach(({ source, target }) => tar.directory(source, target)); tar.finalize(); await client.container.putArchive(this.container, tar, "/"); common_1.log.debug(`Copied directories to container`, { containerId: this.container.id }); } async copyContentToContainer(contentsToCopy) { common_1.log.debug(`Copying content to container...`, { containerId: this.container.id }); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); const tar = (0, archiver_1.default)("tar"); contentsToCopy.forEach(({ content, target, mode }) => tar.append(content, { name: target, mode: mode })); tar.finalize(); await client.container.putArchive(this.container, tar, "/"); common_1.log.debug(`Copied content to container`, { containerId: this.container.id }); } async copyArchiveToContainer(tar, target = "/") { common_1.log.debug(`Copying archive to container...`, { containerId: this.container.id }); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); await client.container.putArchive(this.container, tar, target); common_1.log.debug(`Copied archive to container`, { containerId: this.container.id }); } async copyArchiveFromContainer(path) { common_1.log.debug(`Copying archive "${path}" from container...`, { containerId: this.container.id }); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); const stream = await client.container.fetchArchive(this.container, path); common_1.log.debug(`Copied archive "${path}" from container`, { containerId: this.container.id }); return stream; } async exec(command, opts) { const commandArr = Array.isArray(command) ? command : command.split(" "); const commandStr = commandArr.join(" "); const client = await (0, container_runtime_1.getContainerRuntimeClient)(); common_1.log.debug(`Executing command "${commandStr}"...`, { containerId: this.container.id }); const output = await client.container.exec(this.container, commandArr, opts); common_1.log.debug(`Executed command "${commandStr}"...`, { containerId: this.container.id }); return output; } async logs(opts) { const client = await (0, container_runtime_1.getContainerRuntimeClient)(); return client.container.logs(this.container, opts); } } exports.StartedGenericContainer = StartedGenericContainer; //# sourceMappingURL=started-generic-container.js.map