Skip to content

Commit

Permalink
port testcontainers package to deno
Browse files Browse the repository at this point in the history
  • Loading branch information
jarlah committed Oct 15, 2024
1 parent 08da47b commit 94ad4ea
Show file tree
Hide file tree
Showing 77 changed files with 9,846 additions and 322 deletions.
12 changes: 12 additions & 0 deletions packages/testcontainers/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"checkJs": false
},
"tasks": {
"dev": "deno run --allow-env --allow-read --allow-sys --allow-net --watch src/index.ts",
"test": "deno test --allow-env --allow-sys --allow-read --allow-net --no-check main_test.ts"
},
"imports": {
"@std/assert": "jsr:@std/assert@1"
}
}
9,471 changes: 9,471 additions & 0 deletions packages/testcontainers/deno.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions packages/testcontainers/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function add(a: number, b: number): number {
return a + b;
}

// Learn more at https://docs.deno.com/runtime/manual/examples/module_metadata#concepts
if (import.meta.main) {
console.log("Add 2 + 3 =", add(2, 3));
}
10 changes: 10 additions & 0 deletions packages/testcontainers/main_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { assertEquals } from "@std/assert";
import { add } from "./main.ts";
import { GenericContainer } from "./src/index.ts";

Deno.test(async function addTest() {
assertEquals(add(2, 3), 5);
await new GenericContainer("redis")

Check failure on line 7 in packages/testcontainers/main_test.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `⏎······.withExposedPorts(6379)⏎······` with `.withExposedPorts(6379)`
.withExposedPorts(6379)
.start();
});
6 changes: 3 additions & 3 deletions packages/testcontainers/src/common/file-lock.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from "path";
import { writeFile } from "fs/promises";
import path from "node:path";
import { writeFile } from "node:fs/promises";
import lockFile from "proper-lockfile";
import { log } from "./logger";
import { log } from "./logger.ts";

export async function withFileLock<T>(fileName: string, fn: () => T): Promise<T> {
const file = await createEmptyTmpFile(fileName);
Expand Down
2 changes: 1 addition & 1 deletion packages/testcontainers/src/common/hash.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import crypto from "crypto";
import crypto from "node:crypto";

export function hash(str: string): string {
return crypto.createHash("sha256").update(str).digest("hex");
Expand Down
16 changes: 9 additions & 7 deletions packages/testcontainers/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export { Logger, log, buildLog, composeLog, pullLog, execLog, containerLog } from "./logger";
export * from "./type-guards";
export { hash } from "./hash";
export { Uuid, RandomUuid } from "./uuid";
export { streamToString } from "./streams";
export { withFileLock } from "./file-lock";
export { Retry, IntervalRetry } from "./retry";
export { Logger, log, buildLog, composeLog, pullLog, execLog, containerLog } from "./logger.ts";
export * from "./type-guards.ts";
export { hash } from "./hash.ts";
export { RandomUuid } from "./uuid.ts";
export type { Uuid } from "./uuid.ts";
export { streamToString } from "./streams.ts";
export { withFileLock } from "./file-lock.ts";
export { IntervalRetry } from "./retry.ts";
export type { Retry } from "./retry.ts";
2 changes: 1 addition & 1 deletion packages/testcontainers/src/common/retry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Clock, SystemClock, Time } from "./clock";
import { Clock, SystemClock, Time } from "./clock.ts";

export interface Retry<T, U> {
retryUntil(
Expand Down
2 changes: 1 addition & 1 deletion packages/testcontainers/src/common/streams.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Readable } from "stream";
import { Readable } from "node:stream";

type Options = { trim: boolean };

Expand Down
4 changes: 2 additions & 2 deletions packages/testcontainers/src/common/uuid.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import crypto from "crypto";
import { hash } from "./hash";
import crypto from "node:crypto";
import { hash } from "./hash.ts";

export interface Uuid {
nextUuid(): string;
Expand Down
7 changes: 4 additions & 3 deletions packages/testcontainers/src/container-runtime/auth/auths.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Auth, AuthConfig, ContainerRuntimeConfig } from "./types";
import { RegistryAuthLocator } from "./registry-auth-locator";
import { registryMatches } from "./registry-matches";
import { Auth, AuthConfig, ContainerRuntimeConfig } from "./types.ts";
import { RegistryAuthLocator } from "./registry-auth-locator.ts";
import { registryMatches } from "./registry-matches.ts";
import { Buffer } from "node:buffer";

export class Auths implements RegistryAuthLocator {
public getName(): string {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CredentialProvider } from "./credential-provider";
import { ContainerRuntimeConfig } from "./types";
import { CredentialProvider } from "./credential-provider.ts";
import { ContainerRuntimeConfig } from "./types.ts";

export class CredHelpers extends CredentialProvider {
public getName(): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import {
CredentialProviderListResponse,
ContainerRuntimeConfig,
AuthConfig,
} from "./types";
import { exec, spawn } from "child_process";
import { RegistryAuthLocator } from "./registry-auth-locator";
import { registryMatches } from "./registry-matches";
import { log } from "../../common";
} from "./types.ts";
import { exec, spawn } from "node:child_process";
import { RegistryAuthLocator } from "./registry-auth-locator.ts";
import { registryMatches } from "./registry-matches.ts";
import { log } from "../../common/index.ts";

export abstract class CredentialProvider implements RegistryAuthLocator {
abstract getName(): string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CredentialProvider } from "./credential-provider";
import { ContainerRuntimeConfig } from "./types";
import { CredentialProvider } from "./credential-provider.ts";
import { ContainerRuntimeConfig } from "./types.ts";

export class CredsStore extends CredentialProvider {
public getName(): string {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import path from "path";
import os from "os";
import { AuthConfig, ContainerRuntimeConfig } from "./types";
import { existsSync } from "fs";
import { readFile } from "fs/promises";
import { CredHelpers } from "./cred-helpers";
import { CredsStore } from "./creds-store";
import { Auths } from "./auths";
import { RegistryAuthLocator } from "./registry-auth-locator";
import { log } from "../../common";
import path from "node:path";
import os from "node:os";
import { AuthConfig, ContainerRuntimeConfig } from "./types.ts";
import { existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
import { CredHelpers } from "./cred-helpers.ts";
import { CredsStore } from "./creds-store.ts";
import { Auths } from "./auths.ts";
import { RegistryAuthLocator } from "./registry-auth-locator.ts";
import { log } from "../../common/index.ts";
import process from "node:process";

const dockerConfigLocation = process.env.DOCKER_CONFIG || `${os.homedir()}/.docker`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AuthConfig, ContainerRuntimeConfig } from "./types";
import { AuthConfig, ContainerRuntimeConfig } from "./types.ts";

export interface RegistryAuthLocator {
getName(): string;
Expand Down
57 changes: 29 additions & 28 deletions packages/testcontainers/src/container-runtime/clients/client.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { ComposeClient, getComposeClient } from "./compose/compose-client";
import { ContainerClient } from "./container/container-client";
import { ImageClient } from "./image/image-client";
import { NetworkClient } from "./network/network-client";
import { ContainerRuntimeClientStrategy } from "../strategies/strategy";
import { ConfigurationStrategy } from "../strategies/configuration-strategy";
import { TestcontainersHostStrategy } from "../strategies/testcontainers-host-strategy";
import { UnixSocketStrategy } from "../strategies/unix-socket-strategy";
import { RootlessUnixSocketStrategy } from "../strategies/rootless-unix-socket-strategy";
import { NpipeSocketStrategy } from "../strategies/npipe-socket-strategy";
import { ComposeInfo, ContainerRuntimeInfo, Info, NodeInfo } from "./types";
import { ComposeClient, getComposeClient } from "./compose/compose-client.ts";
import { ContainerClient } from "./container/container-client.ts";
import { ImageClient } from "./image/image-client.ts";
import { NetworkClient } from "./network/network-client.ts";
import { ContainerRuntimeClientStrategy } from "../strategies/strategy.ts";
import { ConfigurationStrategy } from "../strategies/configuration-strategy.ts";
import { TestcontainersHostStrategy } from "../strategies/testcontainers-host-strategy.ts";
import { UnixSocketStrategy } from "../strategies/unix-socket-strategy.ts";
import { RootlessUnixSocketStrategy } from "../strategies/rootless-unix-socket-strategy.ts";
import { NpipeSocketStrategy } from "../strategies/npipe-socket-strategy.ts";
import { ComposeInfo, ContainerRuntimeInfo, Info, NodeInfo } from "./types.ts";
import Dockerode, { DockerOptions } from "dockerode";
import { getRemoteContainerRuntimeSocketPath } from "../utils/remote-container-runtime-socket-path";
import { resolveHost } from "../utils/resolve-host";
import { PodmanContainerClient } from "./container/podman-container-client";
import { DockerContainerClient } from "./container/docker-container-client";
import { DockerImageClient } from "./image/docker-image-client";
import { DockerNetworkClient } from "./network/docker-network-client";
import { lookupHostIps } from "../utils/lookup-host-ips";
import { isDefined, isEmptyString, log } from "../../common";
import { LIB_VERSION } from "../../version";
import { getRemoteContainerRuntimeSocketPath } from "../utils/remote-container-runtime-socket-path.ts";
import { resolveHost } from "../utils/resolve-host.ts";
import { PodmanContainerClient } from "./container/podman-container-client.ts";
import { DockerContainerClient } from "./container/docker-container-client.ts";
import { DockerImageClient } from "./image/docker-image-client.ts";
import { DockerNetworkClient } from "./network/docker-network-client.ts";
import { lookupHostIps } from "../utils/lookup-host-ips.ts";
import { isDefined, isEmptyString, log } from "../../common/index.ts";
import { LIB_VERSION } from "../../version.ts";
import process from "node:process";

export class ContainerRuntimeClient {
constructor(
Expand Down Expand Up @@ -47,17 +48,17 @@ export async function getContainerRuntimeClient(): Promise<ContainerRuntimeClien

for (const strategy of strategies) {
try {
log.debug(`Checking container runtime strategy "${strategy.getName()}"...`);
console.log(`Checking container runtime strategy "${strategy.getName()}"...`);
const client = await initStrategy(strategy);
if (client) {
log.debug(`Container runtime strategy "${strategy.getName()}" works`);
console.log(`Container runtime strategy "${strategy.getName()}" works`);
containerRuntimeClient = client;
return client;
}
} catch (err) {
log.debug(`Container runtime strategy "${strategy.getName()}" does not work: "${err}"`);
console.log(`Container runtime strategy "${strategy.getName()}" does not work: "${err}"`);
if (err !== null && typeof err === "object" && "stack" in err && typeof err.stack === "string") {
log.debug(err.stack);
console.log(err.stack);
}
}
}
Expand All @@ -78,15 +79,15 @@ async function initStrategy(strategy: ContainerRuntimeClientStrategy): Promise<C
};
const dockerode = new Dockerode(dockerodeOptions);

log.trace("Fetching Docker info...");
console.log("Fetching Docker info...");
const dockerodeInfo = await dockerode.info();

const indexServerAddress =
!isDefined(dockerodeInfo.IndexServerAddress) || isEmptyString(dockerodeInfo.IndexServerAddress)
? "https://index.docker.io/v1/"
: dockerodeInfo.IndexServerAddress;

log.trace("Fetching remote container runtime socket path...");
console.log("Fetching remote container runtime socket path...");
const remoteContainerRuntimeSocketPath = getRemoteContainerRuntimeSocketPath(result, dockerodeInfo.OperatingSystem);

log.trace("Resolving host...");
Expand All @@ -101,9 +102,9 @@ async function initStrategy(strategy: ContainerRuntimeClientStrategy): Promise<C
platform: process.platform,
};

log.trace("Looking up host IPs...");
console.log("Looking up host IPs...");
const hostIps = await lookupHostIps(host);

console.log(hostIps)

Check failure on line 107 in packages/testcontainers/src/container-runtime/clients/client.ts

View workflow job for this annotation

GitHub Actions / lint

Insert `;`
log.trace("Initialising clients...");
const containerClient = result.uri.includes("podman.sock")
? new PodmanContainerClient(dockerode)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ComposeDownOptions, ComposeOptions } from "./types";
import { ComposeDownOptions, ComposeOptions } from "./types.ts";
import v1 from "docker-compose";
import dockerComposeV1, { v2 as dockerComposeV2, v2 } from "docker-compose";
import { defaultComposeOptions } from "./default-compose-options";
import { ComposeInfo } from "../types";
import { log, pullLog } from "../../../common";
import { defaultComposeOptions } from "./default-compose-options.ts";
import { ComposeInfo } from "../types.ts";
import { log, pullLog } from "../../../common/index.ts";

export interface ComposeClient {
info: ComposeInfo;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { IDockerComposeOptions } from "docker-compose";
import { EOL } from "os";
import { ComposeOptions } from "./types";
import { isNotEmptyString, composeLog } from "../../../common";
import { EOL } from "node:os";
import { ComposeOptions } from "./types.ts";
import { isNotEmptyString, composeLog } from "../../../common/index.ts";
import process from "node:process";

export function defaultComposeOptions(
environment: NodeJS.ProcessEnv,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Logger } from "../../../common";
import { Logger } from "../../../common/index.ts";

export type ComposeOptions = {
filePath: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import Dockerode, {
ContainerLogsOptions,
Network,
} from "dockerode";
import { Readable } from "stream";
import { ExecOptions, ExecResult } from "./types";
import { Readable } from "node:stream";
import { ExecOptions, ExecResult } from "./types.ts";

export interface ContainerClient {
dockerode: Dockerode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import Dockerode, {
ExecCreateOptions,
Network,
} from "dockerode";
import { PassThrough, Readable } from "stream";
import { IncomingMessage } from "http";
import { ExecOptions, ExecResult } from "./types";
import { PassThrough, Readable } from "node:stream";
import { IncomingMessage } from "node:http";
import { ExecOptions, ExecResult } from "./types.ts";
import byline from "byline";
import { ContainerClient } from "./container-client";
import { execLog, log, streamToString } from "../../../common";
import { ContainerClient } from "./container-client.ts";
import { execLog, log, streamToString } from "../../../common/index.ts";

export class DockerContainerClient implements ContainerClient {
constructor(public readonly dockerode: Dockerode) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Container, ExecCreateOptions } from "dockerode";
import { ExecOptions, ExecResult } from "./types";
import { ExecOptions, ExecResult } from "./types.ts";
import byline from "byline";
import { DockerContainerClient } from "./docker-container-client";
import { execLog, log } from "../../../common";
import { DockerContainerClient } from "./docker-container-client.ts";
import { execLog, log } from "../../../common/index.ts";

export class PodmanContainerClient extends DockerContainerClient {
override async exec(container: Container, command: string[], opts?: Partial<ExecOptions>): Promise<ExecResult> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import Dockerode, { ImageBuildOptions } from "dockerode";
import byline from "byline";
import tar from "tar-fs";
import path from "path";
import { existsSync, promises as fs } from "fs";
import tar from "npm:tar-fs";
import path from "node:path";
import { existsSync, promises as fs } from "node:fs";
import dockerIgnore from "@balena/dockerignore";
import { getAuthConfig } from "../../auth/get-auth-config";
import { ImageName } from "../../image-name";
import { ImageClient } from "./image-client";
import AsyncLock from "async-lock";
import { log, buildLog, pullLog } from "../../../common";
import { getAuthConfig } from "../../auth/get-auth-config.ts";
import { ImageName } from "../../image-name.ts";
import { ImageClient } from "./image-client.ts";
// @ts-ignore missing types

Check failure on line 10 in packages/testcontainers/src/container-runtime/clients/image/docker-image-client.ts

View workflow job for this annotation

GitHub Actions / lint

Do not use "@ts-ignore" because it alters compilation errors
import AsyncLock from "npm:async-lock";
import { log, buildLog, pullLog } from "../../../common/index.ts";

export class DockerImageClient implements ImageClient {
private readonly existingImages = new Set<string>();
Expand All @@ -21,7 +22,7 @@ export class DockerImageClient implements ImageClient {
log.debug(`Building image "${opts.t}" with context "${context}"...`);
const isDockerIgnored = await this.createIsDockerIgnoredFunction(context);
const tarStream = tar.pack(context, {
ignore: (aPath) => {
ignore: (aPath: string) => {
const relativePath = path.relative(context, aPath);
if (relativePath === opts.dockerfile) {
return false;
Expand Down Expand Up @@ -58,6 +59,7 @@ export class DockerImageClient implements ImageClient {
}

const dockerIgnorePatterns = await fs.readFile(dockerIgnoreFilePath, { encoding: "utf-8" });
// @ts-ignore ignorecase is not in the types

Check failure on line 62 in packages/testcontainers/src/container-runtime/clients/image/docker-image-client.ts

View workflow job for this annotation

GitHub Actions / lint

Do not use "@ts-ignore" because it alters compilation errors
const instance = dockerIgnore({ ignorecase: false });
instance.add(dockerIgnorePatterns);
const filter = instance.createFilter();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ImageBuildOptions } from "dockerode";
import { ImageName } from "../../image-name";
import { ImageName } from "../../image-name.ts";

export interface ImageClient {
build(context: string, opts: ImageBuildOptions): Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Dockerode, { Network, NetworkCreateOptions } from "dockerode";
import { NetworkClient } from "./network-client";
import { log } from "../../../common";
import { NetworkClient } from "./network-client.ts";
import { log } from "../../../common/index.ts";

export class DockerNetworkClient implements NetworkClient {
constructor(protected readonly dockerode: Dockerode) {}
Expand Down
3 changes: 2 additions & 1 deletion packages/testcontainers/src/container-runtime/image-name.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { log } from "../common";
import process from "node:process";
import { log } from "../common/index.ts";

export class ImageName {
public readonly string: string;
Expand Down
Loading

0 comments on commit 94ad4ea

Please sign in to comment.