184 lines
4.6 KiB
TypeScript
184 lines
4.6 KiB
TypeScript
/**
|
|
* @module
|
|
*
|
|
* Provides the ability to quickly run a mongo image in a docker instance.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* import { MongoTestContainer } from "@valkyr/testcontainers/mongo";
|
|
*
|
|
* const container = await MongoTestContainer.start("mongo");
|
|
*
|
|
* console.log(container.client()); // => MongoClient
|
|
* console.log(container.url()); // => mongodb://user:password@127.0.0.1:27017
|
|
*
|
|
* await container.stop();
|
|
* ```
|
|
*/
|
|
|
|
import { delay } from "@std/async/delay";
|
|
import { getAvailablePort } from "@std/net";
|
|
import { MongoClient, type MongoClientOptions } from "mongodb";
|
|
|
|
import type { Container } from "../docker/libraries/container.ts";
|
|
import { docker } from "../mod.ts";
|
|
|
|
/**
|
|
* Provides a simplified utility layer for starting, operating, and shutting down a
|
|
* postgres docker container.
|
|
*
|
|
* Will automatically pull the requested docker image before starting the container.
|
|
*/
|
|
export class MongoTestContainer {
|
|
readonly #connection: MongoConnectionInfo;
|
|
|
|
#client?: MongoClient;
|
|
|
|
private constructor(
|
|
readonly container: Container,
|
|
connection: MongoConnectionInfo,
|
|
) {
|
|
this.#connection = connection;
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------------
|
|
| Accessors
|
|
|--------------------------------------------------------------------------------
|
|
*/
|
|
|
|
get client(): MongoClient {
|
|
if (this.#client === undefined) {
|
|
this.#client = new MongoClient(this.url(), this.#connection.opts);
|
|
}
|
|
return this.#client;
|
|
}
|
|
|
|
/**
|
|
* MongoDb container host.
|
|
*/
|
|
get host(): string {
|
|
return this.#connection.host;
|
|
}
|
|
|
|
/**
|
|
* MongoDb container port.
|
|
*/
|
|
get port(): number {
|
|
return this.#connection.port;
|
|
}
|
|
|
|
/**
|
|
* MongoDb username applied to the container.
|
|
*/
|
|
get username(): string {
|
|
return this.#connection.user;
|
|
}
|
|
|
|
/**
|
|
* MongoDb password applied to the container.
|
|
*/
|
|
get password(): string {
|
|
return this.#connection.pass;
|
|
}
|
|
|
|
/**
|
|
* Execute a command in the Mongo container.
|
|
*/
|
|
get exec(): typeof this.container.exec {
|
|
return this.container.exec.bind(this.container);
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------------
|
|
| Lifecycle
|
|
|--------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Start a new Mongo container.
|
|
*
|
|
* @param image - Which docker image to run.
|
|
* @param config - Configuration for the Mongo container.
|
|
*/
|
|
static async start(
|
|
image: string = "mongo:8.0.3",
|
|
config: Partial<MongoConnectionInfo> = {},
|
|
): Promise<MongoTestContainer> {
|
|
const port = getAvailablePort({ preferredPort: config.port });
|
|
if (port === undefined) {
|
|
throw new Error("Unable to assign to a random port");
|
|
}
|
|
|
|
await docker.pullImage(image);
|
|
|
|
const container = await docker.createContainer({
|
|
Image: image,
|
|
Env: [
|
|
`MONGO_INITDB_ROOT_USERNAME=${config.user ?? "root"}`,
|
|
`MONGO_INITDB_ROOT_PASSWORD=${config.pass ?? "password"}`,
|
|
],
|
|
ExposedPorts: {
|
|
"27017/tcp": {},
|
|
},
|
|
HostConfig: {
|
|
PortBindings: { "27017/tcp": [{ HostIp: "0.0.0.0", HostPort: String(port) }] },
|
|
},
|
|
});
|
|
|
|
await container.start();
|
|
await container.waitForLog("ready for start up");
|
|
|
|
await delay(250);
|
|
|
|
return new MongoTestContainer(container, {
|
|
host: config.host ?? "127.0.0.1",
|
|
port,
|
|
user: config.user ?? "root",
|
|
pass: config.pass ?? "password",
|
|
opts: config.opts,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Stop and remove the Mongo container.
|
|
*/
|
|
async stop(): Promise<void> {
|
|
await this.client.close();
|
|
await this.container.remove({ force: true });
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------------
|
|
| Utilities
|
|
|--------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* Return the connection URL for the Mongo container in the format:
|
|
* `mongodb://${user}:${pass}@${host}:${port}`.
|
|
*
|
|
* Make sure to start the container before accessing this method or it will
|
|
* throw an error.
|
|
*/
|
|
url(): MongoConnectionUrl {
|
|
return `mongodb://${this.username}:${this.password}@${this.host}:${this.port}`;
|
|
}
|
|
}
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------------
|
|
| Types
|
|
|--------------------------------------------------------------------------------
|
|
*/
|
|
|
|
export type MongoConnectionUrl = `mongodb://${string}:${string}@${string}:${number}`;
|
|
|
|
export type MongoConnectionInfo = {
|
|
host: string;
|
|
port: number;
|
|
user: string;
|
|
pass: string;
|
|
opts?: MongoClientOptions;
|
|
};
|