mirror of
https://github.com/hoverkraft-tech/compose-action.git
synced 2026-03-06 08:13:10 +08:00
Some checks are pending
Internal - Main - Continuous Integration / ci (push) Waiting to run
Internal - Main - Continuous Integration / prepare-docs (push) Blocked by required conditions
Internal - Main - Continuous Integration / sync-docs (push) Blocked by required conditions
Need fix to Issue / main (push) Waiting to run
Prepare release / release (push) Waiting to run
Bumps the npm-development-dependencies group with 2 updates in the / directory: - [@ts-dev-tools/core](https://github.com/escemi-tech/ts-dev-tools) - [eslint-plugin-jsonc](https://github.com/ota-meshi/eslint-plugin-jsonc) Updates `@ts-dev-tools/core` from 1.10.0 to 1.11.1 - [Release notes](https://github.com/escemi-tech/ts-dev-tools/releases) Updates `eslint-plugin-jsonc` from 2.21.1 to 3.1.1 - [Release notes](https://github.com/ota-meshi/eslint-plugin-jsonc/releases) - [Changelog](https://github.com/ota-meshi/eslint-plugin-jsonc/blob/master/CHANGELOG.md) --- updated-dependencies: - dependency-name: "@ts-dev-tools/core" dependency-version: 1.11.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-development-dependencies - dependency-name: eslint-plugin-jsonc dependency-version: 3.1.1 dependency-type: direct:development update-type: version-update:semver-major dependency-group: npm-development-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Emilien Escalle <emilien.escalle@escemi.com>
273 lines
8.9 KiB
TypeScript
273 lines
8.9 KiB
TypeScript
import { jest, describe, it, expect, beforeEach, afterEach } from "@jest/globals";
|
|
import type { IDockerComposeResult } from "docker-compose";
|
|
import { MockAgent, setGlobalDispatcher } from "undici";
|
|
|
|
// Mock docker-compose before importing the module under test
|
|
const versionMock = jest.fn<() => Promise<IDockerComposeResult & { data: { version: string } }>>();
|
|
|
|
jest.unstable_mockModule("docker-compose", () => ({
|
|
version: versionMock,
|
|
}));
|
|
|
|
// Create manual installer adapter mock
|
|
const manualInstallerAdapterMock = {
|
|
install: jest.fn<(version: string) => Promise<void>>(),
|
|
};
|
|
|
|
// Dynamic import after mock setup
|
|
const { DockerComposeInstallerService } = await import("./docker-compose-installer.service.js");
|
|
|
|
describe("DockerComposeInstallerService", () => {
|
|
let mockAgent: MockAgent;
|
|
let service: InstanceType<typeof DockerComposeInstallerService>;
|
|
|
|
const composeVersionResponse = (version: string) => ({
|
|
exitCode: 0,
|
|
out: "",
|
|
err: "",
|
|
data: {
|
|
version,
|
|
},
|
|
});
|
|
|
|
const installCompose = (composeVersion: string | null, githubToken: string | null) =>
|
|
service.install({
|
|
composeVersion,
|
|
cwd: "/path/to/cwd",
|
|
githubToken,
|
|
});
|
|
|
|
const setPlatform = (platform: NodeJS.Platform) => {
|
|
Object.defineProperty(process, "platform", {
|
|
value: platform,
|
|
});
|
|
};
|
|
|
|
const mockLatestRelease = (version: string) => {
|
|
const mockClient = mockAgent.get("https://api.github.com");
|
|
mockClient
|
|
.intercept({
|
|
path: "/repos/docker/compose/releases/latest",
|
|
method: "GET",
|
|
})
|
|
.reply(
|
|
200,
|
|
{
|
|
tag_name: version,
|
|
},
|
|
{
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
}
|
|
);
|
|
setGlobalDispatcher(mockClient);
|
|
Object.defineProperty(globalThis, "fetch", {
|
|
value: jest.fn(),
|
|
});
|
|
};
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
mockAgent = new MockAgent();
|
|
mockAgent.disableNetConnect();
|
|
|
|
service = new DockerComposeInstallerService(manualInstallerAdapterMock as never);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.resetAllMocks();
|
|
});
|
|
|
|
describe("install", () => {
|
|
it("should install latest when compose version is not specified and Compose is missing", async () => {
|
|
// Arrange: first call to version() fails (Compose missing)
|
|
versionMock.mockRejectedValueOnce(new Error("version not installed"));
|
|
|
|
const latestVersion = "v2.0.0";
|
|
mockLatestRelease(latestVersion);
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse(latestVersion));
|
|
setPlatform("linux");
|
|
|
|
// Act
|
|
const result = await installCompose(null, "token");
|
|
|
|
// Assert
|
|
expect(result).toBe(latestVersion);
|
|
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(latestVersion);
|
|
});
|
|
|
|
it("should return current version when no version is provided", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValue(composeVersionResponse("2.0.0"));
|
|
|
|
// Act
|
|
const result = await installCompose(null, null);
|
|
|
|
// Assert
|
|
expect(result).toBe("2.0.0");
|
|
expect(manualInstallerAdapterMock.install).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should not install anything when expected version is already installed", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValue(composeVersionResponse("1.2.3"));
|
|
|
|
// Act
|
|
const result = await installCompose("v1.2.3", null);
|
|
|
|
// Assert
|
|
expect(result).toBe("1.2.3");
|
|
expect(manualInstallerAdapterMock.install).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should install the requested version if it is not already installed", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("1.2.3"));
|
|
|
|
const expectedVersion = "1.3.0";
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse(expectedVersion));
|
|
setPlatform("linux");
|
|
|
|
// Act
|
|
const result = await installCompose(expectedVersion, null);
|
|
|
|
// Assert
|
|
expect(result).toBe(expectedVersion);
|
|
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(expectedVersion);
|
|
});
|
|
|
|
it("should install the latest version if requested", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("1.2.3"));
|
|
|
|
const latestVersion = "v1.4.0";
|
|
mockLatestRelease(latestVersion);
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse(latestVersion));
|
|
setPlatform("linux");
|
|
|
|
// Act
|
|
const result = await installCompose("latest", "token");
|
|
|
|
// Assert
|
|
expect(result).toBe(latestVersion);
|
|
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(latestVersion);
|
|
});
|
|
|
|
it("should throw an error if the latest version if requested and no Github token is provided", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("1.2.3"));
|
|
|
|
// Act & Assert
|
|
await expect(installCompose("latest", null)).rejects.toThrow(
|
|
"GitHub token is required to install the latest version"
|
|
);
|
|
});
|
|
|
|
it("should throw an error on unsupported platforms", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("1.2.3"));
|
|
|
|
const expectedVersion = "1.3.0";
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse(expectedVersion));
|
|
setPlatform("win32");
|
|
|
|
// Act & Assert
|
|
await expect(installCompose(expectedVersion, null)).rejects.toThrow(
|
|
`Unsupported platform: win32`
|
|
);
|
|
|
|
expect(manualInstallerAdapterMock.install).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should install when version check fails", async () => {
|
|
// Arrange: first call to version() doesn't find
|
|
versionMock.mockRejectedValueOnce(new Error("version not installed"));
|
|
|
|
const installedVersion = "2.0.0";
|
|
|
|
// After installation, version() returns the new version
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse(installedVersion));
|
|
setPlatform("linux");
|
|
|
|
// Act
|
|
const result = await installCompose(installedVersion, "token");
|
|
|
|
// Assert
|
|
expect(result).toBe(installedVersion);
|
|
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(installedVersion);
|
|
});
|
|
|
|
it("should install latest version when missing or unspecified", async () => {
|
|
// Arrange: first call to version() doesn't find
|
|
versionMock.mockRejectedValueOnce(new Error("version check failed"));
|
|
// second call finds newly installed version
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("v1.4.0"));
|
|
|
|
const latestVersion = "v1.4.0";
|
|
mockLatestRelease(latestVersion);
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse(latestVersion));
|
|
setPlatform("linux");
|
|
|
|
// Act
|
|
const result = await installCompose("latest", "token");
|
|
|
|
// Assert
|
|
expect(result).toBe(latestVersion);
|
|
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(latestVersion);
|
|
});
|
|
|
|
it("should throw if Compose is missing and no GitHub token is provided", async () => {
|
|
// Arrange: first call to version() doesn't find
|
|
versionMock.mockRejectedValueOnce(new Error("version check failed"));
|
|
setPlatform("linux");
|
|
|
|
await expect(installCompose("latest", null)).rejects.toThrow(
|
|
"GitHub token is required to install the latest version"
|
|
);
|
|
});
|
|
|
|
it("should not install when the version is already installed and no version is specified", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValue(composeVersionResponse("1.2.3"));
|
|
|
|
// Act
|
|
const result = await installCompose("", null);
|
|
|
|
// Assert
|
|
expect(result).toBe("1.2.3");
|
|
expect(manualInstallerAdapterMock.install).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("should throw when installed version does not match target", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("1.2.3"));
|
|
|
|
const targetVersion = "v1.4.0";
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("1.3.0"));
|
|
setPlatform("linux");
|
|
|
|
// Act & Assert
|
|
await expect(installCompose(targetVersion, "token")).rejects.toThrow(
|
|
`Failed to install Docker Compose version "${targetVersion}", installed version is "1.3.0"`
|
|
);
|
|
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(targetVersion);
|
|
});
|
|
|
|
it("should throw with unknown installed version when post-install version check fails", async () => {
|
|
// Arrange
|
|
versionMock.mockResolvedValueOnce(composeVersionResponse("1.2.3"));
|
|
|
|
const targetVersion = "v1.4.0";
|
|
versionMock.mockRejectedValueOnce(new Error("version check failed after install"));
|
|
setPlatform("linux");
|
|
|
|
// Act & Assert
|
|
await expect(installCompose(targetVersion, "token")).rejects.toThrow(
|
|
`Failed to install Docker Compose version "${targetVersion}", installed version is "unknown"`
|
|
);
|
|
expect(manualInstallerAdapterMock.install).toHaveBeenCalledWith(targetVersion);
|
|
});
|
|
});
|
|
});
|