diff --git a/packages/testcontainers/src/container-runtime/clients/client.ts b/packages/testcontainers/src/container-runtime/clients/client.ts index 4821f393d..3ac00f28b 100644 --- a/packages/testcontainers/src/container-runtime/clients/client.ts +++ b/packages/testcontainers/src/container-runtime/clients/client.ts @@ -6,6 +6,7 @@ import { NpipeSocketStrategy } from "../strategies/npipe-socket-strategy"; import { RootlessUnixSocketStrategy } from "../strategies/rootless-unix-socket-strategy"; import type { ContainerRuntimeClientStrategy } from "../strategies/strategy"; import { TestcontainersHostStrategy } from "../strategies/testcontainers-host-strategy"; +import type { ContainerRuntimeClientStrategyResult } from "../strategies/types"; import { UnixSocketStrategy } from "../strategies/unix-socket-strategy"; import { lookupHostIps } from "../utils/lookup-host-ips"; import { getRemoteContainerRuntimeSocketPath } from "../utils/remote-container-runtime-socket-path"; @@ -17,6 +18,7 @@ import { DockerImageClient } from "./image/docker-image-client"; import type { ImageClient } from "./image/image-client"; import { DockerNetworkClient } from "./network/docker-network-client"; import type { NetworkClient } from "./network/network-client"; +import { createNoWorkingStrategyError, type StrategyAttempt } from "./no-working-strategy-error"; import type { ContainerRuntimeInfo, HostIp, Info, NodeInfo } from "./types"; type DockerodeInfo = Awaited>; @@ -46,33 +48,34 @@ export async function getContainerRuntimeClient(): Promise { - const result = await strategy.getResult(); - - if (!result) { - log.debug(`Container runtime strategy "${strategy.getName()}" is not applicable`); - return undefined; - } - +async function initStrategy(result: ContainerRuntimeClientStrategyResult): Promise { const dockerodeOptions: DockerOptions = { ...result.dockerOptions, headers: { ...result.dockerOptions.headers, "User-Agent": `tc-node/${LIB_VERSION}` }, diff --git a/packages/testcontainers/src/container-runtime/clients/no-working-strategy-error.test.ts b/packages/testcontainers/src/container-runtime/clients/no-working-strategy-error.test.ts new file mode 100644 index 000000000..bbf1ab828 --- /dev/null +++ b/packages/testcontainers/src/container-runtime/clients/no-working-strategy-error.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { createNoWorkingStrategyError } from "./no-working-strategy-error"; + +describe("createNoWorkingStrategyError", () => { + it("should list each strategy and why it was skipped", () => { + const error = createNoWorkingStrategyError([ + { name: "ConfigurationStrategy", reason: "not applicable: DOCKER_HOST is not set" }, + { name: "UnixSocketStrategy", reason: "not applicable: /var/run/docker.sock does not exist" }, + ]); + + expect(error.message).toBe( + [ + "Could not find a working container runtime strategy. Tried:", + " - ConfigurationStrategy: not applicable: DOCKER_HOST is not set", + " - UnixSocketStrategy: not applicable: /var/run/docker.sock does not exist", + "See https://node.testcontainers.org/supported-container-runtimes/", + ].join("\n") + ); + expect(error.cause).toBeUndefined(); + }); + + it("should attach the errors of strategies that failed as the cause", () => { + const permissionDenied = new Error("connect EACCES /var/run/docker.sock"); + + const error = createNoWorkingStrategyError([ + { name: "NpipeSocketStrategy", reason: "not applicable: only used on Windows" }, + { name: "UnixSocketStrategy", reason: `failed: ${permissionDenied.message}`, error: permissionDenied }, + ]); + + expect(error.message).toContain(" - UnixSocketStrategy: failed: connect EACCES /var/run/docker.sock"); + expect(error.cause).toBeInstanceOf(AggregateError); + expect((error.cause as AggregateError).errors).toEqual([permissionDenied]); + }); +}); diff --git a/packages/testcontainers/src/container-runtime/clients/no-working-strategy-error.ts b/packages/testcontainers/src/container-runtime/clients/no-working-strategy-error.ts new file mode 100644 index 000000000..572363b33 --- /dev/null +++ b/packages/testcontainers/src/container-runtime/clients/no-working-strategy-error.ts @@ -0,0 +1,15 @@ +export type StrategyAttempt = { name: string; reason: string; error?: unknown }; + +export function createNoWorkingStrategyError(attempts: StrategyAttempt[]): Error { + const lines = attempts.map(({ name, reason }) => ` - ${name}: ${reason}`); + const errors = attempts.map(({ error }) => error).filter((error) => error !== undefined); + + return new Error( + [ + "Could not find a working container runtime strategy. Tried:", + ...lines, + "See https://node.testcontainers.org/supported-container-runtimes/", + ].join("\n"), + errors.length > 0 ? { cause: new AggregateError(errors) } : undefined + ); +} diff --git a/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.test.ts b/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.test.ts index e044d8a9e..c0e57e26a 100644 --- a/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.test.ts +++ b/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.test.ts @@ -9,12 +9,14 @@ const mockGetContainerRuntimeConfig = vi.mocked(getContainerRuntimeConfig); const mockReadFile = vi.mocked(readFile); describe("ConfigurationStrategy", { concurrent: false }, () => { - it("should return undefined if no docker host is set", async () => { + it("should not apply if no docker host is set", async () => { mockGetContainerRuntimeConfig.mockResolvedValueOnce({ dockerHost: undefined }); const result = await new ConfigurationStrategy().getResult(); - expect(result).toBeUndefined(); + expect(result).toEqual({ + notApplicable: "DOCKER_HOST is not set in the environment or ~/.testcontainers.properties", + }); }); it("should set host and port when docker host is a URL", async () => { @@ -22,14 +24,16 @@ describe("ConfigurationStrategy", { concurrent: false }, () => { const result = await new ConfigurationStrategy().getResult(); - expect(result?.uri).toEqual("tcp://docker:8025"); - expect(result?.dockerOptions).toEqual( + assert(!("notApplicable" in result)); + + expect(result.uri).toEqual("tcp://docker:8025"); + expect(result.dockerOptions).toEqual( expect.objectContaining({ host: "docker", port: "8025", }) ); - expect(result?.composeEnvironment).toEqual( + expect(result.composeEnvironment).toEqual( expect.objectContaining({ DOCKER_HOST: "tcp://docker:8025", }) @@ -41,13 +45,15 @@ describe("ConfigurationStrategy", { concurrent: false }, () => { const result = await new ConfigurationStrategy().getResult(); - expect(result?.uri).toEqual("unix:///var/run/docker.sock"); - expect(result?.dockerOptions).toEqual( + assert(!("notApplicable" in result)); + + expect(result.uri).toEqual("unix:///var/run/docker.sock"); + expect(result.dockerOptions).toEqual( expect.objectContaining({ socketPath: "/var/run/docker.sock", }) ); - expect(result?.composeEnvironment).toEqual( + expect(result.composeEnvironment).toEqual( expect.objectContaining({ DOCKER_HOST: "unix:///var/run/docker.sock", }) @@ -59,7 +65,9 @@ describe("ConfigurationStrategy", { concurrent: false }, () => { const result = await new ConfigurationStrategy().getResult(); - expect(result?.allowUserOverrides).toEqual(true); + assert(!("notApplicable" in result)); + + expect(result.allowUserOverrides).toEqual(true); }); it("should set SSL options when TLS is enabled", async () => { @@ -83,15 +91,17 @@ describe("ConfigurationStrategy", { concurrent: false }, () => { const result = await new ConfigurationStrategy().getResult(); - expect(result?.uri).toEqual("tcp://docker:8025"); - expect(result?.dockerOptions).toEqual( + assert(!("notApplicable" in result)); + + expect(result.uri).toEqual("tcp://docker:8025"); + expect(result.dockerOptions).toEqual( expect.objectContaining({ ca: "ca", cert: "cert", key: "key", }) ); - expect(result?.composeEnvironment).toEqual( + expect(result.composeEnvironment).toEqual( expect.objectContaining({ DOCKER_TLS_VERIFY: "1", DOCKER_CERT_PATH: "/certs", diff --git a/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.ts b/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.ts index 97961894d..7d51370c8 100644 --- a/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.ts +++ b/packages/testcontainers/src/container-runtime/strategies/configuration-strategy.ts @@ -3,7 +3,7 @@ import path from "node:path"; import { URL } from "node:url"; import type { DockerOptions } from "dockerode"; import type { ContainerRuntimeClientStrategy } from "./strategy"; -import type { ContainerRuntimeClientStrategyResult } from "./types"; +import type { ContainerRuntimeClientStrategyNotApplicable, ContainerRuntimeClientStrategyResult } from "./types"; import { getContainerRuntimeConfig } from "./utils/config"; export class ConfigurationStrategy implements ContainerRuntimeClientStrategy { @@ -11,11 +11,11 @@ export class ConfigurationStrategy implements ContainerRuntimeClientStrategy { return "ConfigurationStrategy"; } - async getResult(): Promise { + async getResult(): Promise { const { dockerHost, dockerTlsVerify, dockerCertPath } = await getContainerRuntimeConfig(); if (!dockerHost) { - return undefined; + return { notApplicable: "DOCKER_HOST is not set in the environment or ~/.testcontainers.properties" }; } const dockerOptions: DockerOptions = {}; diff --git a/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.test.ts b/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.test.ts index d4240f7fa..7af6b2d93 100644 --- a/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.test.ts +++ b/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.test.ts @@ -1,17 +1,18 @@ import { NpipeSocketStrategy } from "./npipe-socket-strategy"; describe("NpipeSocketStrategy", () => { - it("should return undefined when platform is not win32", async () => { + it("should not apply when platform is not win32", async () => { const result = await new NpipeSocketStrategy("linux").getResult(); - expect(result).toBeUndefined(); + expect(result).toEqual({ notApplicable: "only used on Windows" }); }); it("should return expected result", async () => { const result = await new NpipeSocketStrategy("win32").getResult(); + assert(!("notApplicable" in result)); - expect(result?.uri).toEqual("npipe:////./pipe/docker_engine"); - expect(result?.dockerOptions).toEqual({ socketPath: "//./pipe/docker_engine" }); - expect(result?.composeEnvironment).toEqual({}); - expect(result?.allowUserOverrides).toEqual(true); + expect(result.uri).toEqual("npipe:////./pipe/docker_engine"); + expect(result.dockerOptions).toEqual({ socketPath: "//./pipe/docker_engine" }); + expect(result.composeEnvironment).toEqual({}); + expect(result.allowUserOverrides).toEqual(true); }); }); diff --git a/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.ts b/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.ts index ab12ed8ae..cfbc19cd2 100644 --- a/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.ts +++ b/packages/testcontainers/src/container-runtime/strategies/npipe-socket-strategy.ts @@ -1,5 +1,5 @@ import type { ContainerRuntimeClientStrategy } from "./strategy"; -import type { ContainerRuntimeClientStrategyResult } from "./types"; +import type { ContainerRuntimeClientStrategyNotApplicable, ContainerRuntimeClientStrategyResult } from "./types"; export class NpipeSocketStrategy implements ContainerRuntimeClientStrategy { constructor(private readonly platform: NodeJS.Platform = process.platform) {} @@ -8,9 +8,9 @@ export class NpipeSocketStrategy implements ContainerRuntimeClientStrategy { return "NpipeSocketStrategy"; } - async getResult(): Promise { + async getResult(): Promise { if (this.platform !== "win32") { - return; + return { notApplicable: "only used on Windows" }; } return { diff --git a/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.test.ts b/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.test.ts index 368dbbf95..46fe19db2 100644 --- a/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.test.ts +++ b/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.test.ts @@ -8,22 +8,22 @@ vi.mock("node:fs", () => ({ existsSync: vi.fn() })); describe("RootlessUnixSocketStrategy", { concurrent: false }, () => { const mockExistsSync = vi.mocked(existsSync); - it("should return undefined for non-linux and non-darwin platforms", async () => { + it("should not apply for non-linux and non-darwin platforms", async () => { mockExistsSync.mockReturnValue(true); const strategy = new RootlessUnixSocketStrategy("win32", {}); const result = await strategy.getResult(); - expect(result).toBeUndefined(); + expect(result).toEqual({ notApplicable: "only used on Linux and macOS" }); }); - it("should return undefined when socket does not exist", async () => { + it("should not apply when socket does not exist", async () => { mockExistsSync.mockReturnValue(false); const strategy = new RootlessUnixSocketStrategy("linux", {}); const result = await strategy.getResult(); - expect(result).toBeUndefined(); + expect(result).toEqual({ notApplicable: expect.stringMatching(/^no socket found at /) }); }); it("should return client for socket from XDG_RUNTIME_DIR", async () => { @@ -32,8 +32,9 @@ describe("RootlessUnixSocketStrategy", { concurrent: false }, () => { const strategy = new RootlessUnixSocketStrategy("linux", { XDG_RUNTIME_DIR: "/tmp" }); const result = await strategy.getResult(); + assert(!("notApplicable" in result)); - expect(result?.uri).toEqual(`unix://${socketPath}`); + expect(result.uri).toEqual(`unix://${socketPath}`); }); it("should return client for socket from home run dir", async () => { @@ -42,8 +43,9 @@ describe("RootlessUnixSocketStrategy", { concurrent: false }, () => { const strategy = new RootlessUnixSocketStrategy("linux", {}); const result = await strategy.getResult(); + assert(!("notApplicable" in result)); - expect(result?.uri).toEqual(`unix://${socketPath}`); + expect(result.uri).toEqual(`unix://${socketPath}`); }); it("should return Docker client for socket from home desktop dir", async () => { @@ -52,8 +54,9 @@ describe("RootlessUnixSocketStrategy", { concurrent: false }, () => { const strategy = new RootlessUnixSocketStrategy("linux", {}); const result = await strategy.getResult(); + assert(!("notApplicable" in result)); - expect(result?.uri).toEqual(`unix://${socketPath}`); + expect(result.uri).toEqual(`unix://${socketPath}`); }); it("should return Docker client for socket from run dir", async () => { @@ -62,7 +65,8 @@ describe("RootlessUnixSocketStrategy", { concurrent: false }, () => { const strategy = new RootlessUnixSocketStrategy("linux", {}); const result = await strategy.getResult(); + assert(!("notApplicable" in result)); - expect(result?.uri).toEqual(`unix://${socketPath}`); + expect(result.uri).toEqual(`unix://${socketPath}`); }); }); diff --git a/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.ts b/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.ts index 143c751d1..d88d304a8 100644 --- a/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.ts +++ b/packages/testcontainers/src/container-runtime/strategies/rootless-unix-socket-strategy.ts @@ -3,7 +3,7 @@ import os from "node:os"; import path from "node:path"; import { isDefined } from "../../common"; import type { ContainerRuntimeClientStrategy } from "./strategy"; -import type { ContainerRuntimeClientStrategyResult } from "./types"; +import type { ContainerRuntimeClientStrategyNotApplicable, ContainerRuntimeClientStrategyResult } from "./types"; export class RootlessUnixSocketStrategy implements ContainerRuntimeClientStrategy { constructor( @@ -15,22 +15,21 @@ export class RootlessUnixSocketStrategy implements ContainerRuntimeClientStrateg return "RootlessUnixSocketStrategy"; } - async getResult(): Promise { + async getResult(): Promise { if (this.platform !== "linux" && this.platform !== "darwin") { - return; + return { notApplicable: "only used on Linux and macOS" }; } - const socketPath = [ + const candidateSocketPaths = [ this.getSocketPathFromEnv(), this.getSocketPathFromHomeRunDir(), this.getSocketPathFromHomeDesktopDir(), this.getSocketPathFromRunDir(), - ] - .filter(isDefined) - .find((candidateSocketPath) => existsSync(candidateSocketPath)); + ].filter(isDefined); + const socketPath = candidateSocketPaths.find((candidateSocketPath) => existsSync(candidateSocketPath)); if (!socketPath) { - return; + return { notApplicable: `no socket found at ${candidateSocketPaths.join(", ")}` }; } return { diff --git a/packages/testcontainers/src/container-runtime/strategies/strategy.ts b/packages/testcontainers/src/container-runtime/strategies/strategy.ts index 3f46cb45f..cf458611a 100644 --- a/packages/testcontainers/src/container-runtime/strategies/strategy.ts +++ b/packages/testcontainers/src/container-runtime/strategies/strategy.ts @@ -1,6 +1,6 @@ -import type { ContainerRuntimeClientStrategyResult } from "./types"; +import type { ContainerRuntimeClientStrategyNotApplicable, ContainerRuntimeClientStrategyResult } from "./types"; export interface ContainerRuntimeClientStrategy { getName(): string; - getResult(): Promise; + getResult(): Promise; } diff --git a/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.test.ts b/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.test.ts index f421f0f4d..e877f6b59 100644 --- a/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.test.ts +++ b/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.test.ts @@ -6,22 +6,22 @@ vi.mock("./utils/config", () => ({ })); describe("TestcontainersHostStrategy", { concurrent: false }, () => { - it("should return undefined when tc.host property is not set", async () => { + it("should not apply when tc.host property is not set", async () => { mockGetContainerRuntimeConfig.mockResolvedValue({}); const strategy = new TestcontainersHostStrategy(); const result = await strategy.getResult(); - expect(result).toBeUndefined(); + expect(result).toEqual({ notApplicable: "tc.host is not set in ~/.testcontainers.properties" }); }); - it("should be defined when tc.host property is set", async () => { + it("should apply when tc.host property is set", async () => { mockGetContainerRuntimeConfig.mockResolvedValue({ tcHost: "tcp://tc:2375" }); const strategy = new TestcontainersHostStrategy(); const result = await strategy.getResult(); - expect(result).toBeDefined(); + expect(result).not.toHaveProperty("notApplicable"); }); it("should return relevant fields", async () => { @@ -29,9 +29,10 @@ describe("TestcontainersHostStrategy", { concurrent: false }, () => { const strategy = new TestcontainersHostStrategy(); const result = await strategy.getResult(); + assert(!("notApplicable" in result)); - expect(result?.uri).toEqual("tcp://tc:2375"); - expect(result?.composeEnvironment).toEqual({ DOCKER_HOST: "tcp://tc:2375" }); - expect(result?.allowUserOverrides).toBe(false); + expect(result.uri).toEqual("tcp://tc:2375"); + expect(result.composeEnvironment).toEqual({ DOCKER_HOST: "tcp://tc:2375" }); + expect(result.allowUserOverrides).toBe(false); }); }); diff --git a/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.ts b/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.ts index eaa8b9213..4bbfdc32c 100644 --- a/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.ts +++ b/packages/testcontainers/src/container-runtime/strategies/testcontainers-host-strategy.ts @@ -1,7 +1,7 @@ import { URL } from "node:url"; import type { DockerOptions } from "dockerode"; import type { ContainerRuntimeClientStrategy } from "./strategy"; -import type { ContainerRuntimeClientStrategyResult } from "./types"; +import type { ContainerRuntimeClientStrategyNotApplicable, ContainerRuntimeClientStrategyResult } from "./types"; import { getContainerRuntimeConfig } from "./utils/config"; export class TestcontainersHostStrategy implements ContainerRuntimeClientStrategy { @@ -9,11 +9,11 @@ export class TestcontainersHostStrategy implements ContainerRuntimeClientStrateg return "TestcontainersHostStrategy"; } - async getResult(): Promise { + async getResult(): Promise { const { tcHost } = await getContainerRuntimeConfig(); if (!tcHost) { - return; + return { notApplicable: "tc.host is not set in ~/.testcontainers.properties" }; } const dockerOptions: DockerOptions = {}; diff --git a/packages/testcontainers/src/container-runtime/strategies/types.ts b/packages/testcontainers/src/container-runtime/strategies/types.ts index 0364ff138..e73dac785 100644 --- a/packages/testcontainers/src/container-runtime/strategies/types.ts +++ b/packages/testcontainers/src/container-runtime/strategies/types.ts @@ -6,3 +6,5 @@ export type ContainerRuntimeClientStrategyResult = { composeEnvironment: NodeJS.ProcessEnv; allowUserOverrides: boolean; }; + +export type ContainerRuntimeClientStrategyNotApplicable = { notApplicable: string }; diff --git a/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.test.ts b/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.test.ts index 92ecfe191..a2457beae 100644 --- a/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.test.ts +++ b/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.test.ts @@ -9,25 +9,26 @@ describe("UnixSocketStrategy", { concurrent: false }, () => { mockExistsSync.mockReturnValue(true); }); - it("should return undefined when platform is not linux or darwin", async () => { + it("should not apply when platform is not linux or darwin", async () => { const result = await new UnixSocketStrategy("win32").getResult(); - expect(result).toBeUndefined(); + expect(result).toEqual({ notApplicable: "only used on Linux and macOS" }); }); - it("should return undefined when platform is correct but socket does not exist", async () => { + it("should not apply when platform is correct but socket does not exist", async () => { mockExistsSync.mockReturnValue(false); const result = await new UnixSocketStrategy("linux").getResult(); - expect(result).toBeUndefined(); + expect(result).toEqual({ notApplicable: "/var/run/docker.sock does not exist" }); }); it("should return expected result", async () => { const result = await new UnixSocketStrategy("linux").getResult(); + assert(!("notApplicable" in result)); - expect(result?.uri).toEqual("unix:///var/run/docker.sock"); - expect(result?.dockerOptions).toEqual({ socketPath: "/var/run/docker.sock" }); - expect(result?.composeEnvironment).toEqual({}); - expect(result?.allowUserOverrides).toEqual(true); + expect(result.uri).toEqual("unix:///var/run/docker.sock"); + expect(result.dockerOptions).toEqual({ socketPath: "/var/run/docker.sock" }); + expect(result.composeEnvironment).toEqual({}); + expect(result.allowUserOverrides).toEqual(true); }); }); diff --git a/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.ts b/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.ts index f2b1532d5..1dbea109d 100644 --- a/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.ts +++ b/packages/testcontainers/src/container-runtime/strategies/unix-socket-strategy.ts @@ -1,6 +1,6 @@ import { existsSync } from "node:fs"; import type { ContainerRuntimeClientStrategy } from "./strategy"; -import type { ContainerRuntimeClientStrategyResult } from "./types"; +import type { ContainerRuntimeClientStrategyNotApplicable, ContainerRuntimeClientStrategyResult } from "./types"; export class UnixSocketStrategy implements ContainerRuntimeClientStrategy { constructor(private readonly platform: NodeJS.Platform = process.platform) {} @@ -9,9 +9,12 @@ export class UnixSocketStrategy implements ContainerRuntimeClientStrategy { return "UnixSocketStrategy"; } - async getResult(): Promise { - if ((this.platform !== "linux" && this.platform !== "darwin") || !existsSync("/var/run/docker.sock")) { - return; + async getResult(): Promise { + if (this.platform !== "linux" && this.platform !== "darwin") { + return { notApplicable: "only used on Linux and macOS" }; + } + if (!existsSync("/var/run/docker.sock")) { + return { notApplicable: "/var/run/docker.sock does not exist" }; } return {