mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-10-02 00:35:59 +00:00
153 lines
4.4 KiB
TypeScript
153 lines
4.4 KiB
TypeScript
import { promisify } from "node:util";
|
|
import {
|
|
afterEach,
|
|
beforeEach,
|
|
describe,
|
|
expect,
|
|
it,
|
|
jest,
|
|
} from "@jest/globals";
|
|
|
|
const ORIGINAL_UV_PYTHON_ARCH = process.env.UV_PYTHON_ARCH;
|
|
|
|
const mockExecFile =
|
|
jest.fn<
|
|
(...args: unknown[]) => Promise<{
|
|
stdout: string;
|
|
stderr: string;
|
|
}>
|
|
>();
|
|
const mockExportVariable = jest.fn();
|
|
|
|
jest.unstable_mockModule("node:child_process", () => ({
|
|
execFile: Object.assign(mockExecFile, { [promisify.custom]: mockExecFile }),
|
|
}));
|
|
jest.unstable_mockModule("@actions/core", () => ({
|
|
exportVariable: mockExportVariable,
|
|
}));
|
|
jest.unstable_mockModule("../../src/utils/logging", () => ({
|
|
info: jest.fn(),
|
|
}));
|
|
|
|
const { setupPythonArch } = await import("../../src/utils/python-arch");
|
|
|
|
const supportedProbe = Object.assign(new Error("uv exited with code 2"), {
|
|
code: 2,
|
|
stderr:
|
|
"error: Failed to parse environment variable `UV_PYTHON_ARCH` with invalid value `setup-uv-probe`: Unknown architecture: setup-uv-probe\n",
|
|
});
|
|
const success = { stderr: "", stdout: "/cache\n" };
|
|
|
|
beforeEach(() => {
|
|
delete process.env.UV_PYTHON_ARCH;
|
|
jest.clearAllMocks();
|
|
mockExecFile
|
|
.mockReset()
|
|
.mockRejectedValueOnce(supportedProbe)
|
|
.mockResolvedValueOnce(success);
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (ORIGINAL_UV_PYTHON_ARCH === undefined) {
|
|
delete process.env.UV_PYTHON_ARCH;
|
|
} else {
|
|
process.env.UV_PYTHON_ARCH = ORIGINAL_UV_PYTHON_ARCH;
|
|
}
|
|
});
|
|
|
|
describe("setupPythonArch", () => {
|
|
it("leaves Python selection alone without an architecture", async () => {
|
|
await setupPythonArch("/tools/uv", "");
|
|
|
|
expect(mockExecFile).not.toHaveBeenCalled();
|
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("validates an inherited architecture without exporting it", async () => {
|
|
process.env.UV_PYTHON_ARCH = "aarch64";
|
|
|
|
await setupPythonArch("/tools/uv", "");
|
|
|
|
expect(mockExecFile).toHaveBeenNthCalledWith(
|
|
2,
|
|
"/tools/uv",
|
|
["--no-config", "cache", "dir"],
|
|
expect.objectContaining({
|
|
env: expect.objectContaining({ UV_PYTHON_ARCH: "aarch64" }),
|
|
}),
|
|
);
|
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
|
expect(process.env.UV_PYTHON_ARCH).toBe("aarch64");
|
|
});
|
|
|
|
it.each(["/runner temp/uv", "C:\\runner temp\\uv.exe"])(
|
|
"validates and exports the architecture using the installed uv: %s",
|
|
async (uvPath) => {
|
|
await setupPythonArch(uvPath, "x86_64");
|
|
|
|
expect(mockExecFile).toHaveBeenNthCalledWith(
|
|
1,
|
|
uvPath,
|
|
["--no-config", "cache", "dir"],
|
|
expect.objectContaining({
|
|
encoding: "utf8",
|
|
env: expect.objectContaining({ UV_PYTHON_ARCH: "setup-uv-probe" }),
|
|
}),
|
|
);
|
|
expect(mockExecFile).toHaveBeenNthCalledWith(
|
|
2,
|
|
uvPath,
|
|
["--no-config", "cache", "dir"],
|
|
expect.objectContaining({
|
|
env: expect.objectContaining({ UV_PYTHON_ARCH: "x86_64" }),
|
|
}),
|
|
);
|
|
expect(mockExportVariable).toHaveBeenCalledWith(
|
|
"UV_PYTHON_ARCH",
|
|
"x86_64",
|
|
);
|
|
},
|
|
);
|
|
|
|
it("rejects uv versions that ignore UV_PYTHON_ARCH", async () => {
|
|
mockExecFile.mockReset().mockResolvedValue(success);
|
|
|
|
await expect(setupPythonArch("/tools/uv", "x86_64")).rejects.toThrow(
|
|
"The installed version of uv does not support UV_PYTHON_ARCH",
|
|
);
|
|
expect(mockExecFile).toHaveBeenCalledTimes(1);
|
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("reports unexpected probe failures", async () => {
|
|
mockExecFile.mockReset().mockRejectedValue(
|
|
Object.assign(new Error("uv exited with code 2"), {
|
|
code: 2,
|
|
stderr: "error: unrelated configuration error\n",
|
|
}),
|
|
);
|
|
|
|
await expect(setupPythonArch("/tools/uv", "x86_64")).rejects.toThrow(
|
|
"Failed to check uv's support for UV_PYTHON_ARCH: error: unrelated configuration error",
|
|
);
|
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("reports invalid architectures before exporting them", async () => {
|
|
mockExecFile
|
|
.mockReset()
|
|
.mockRejectedValueOnce(supportedProbe)
|
|
.mockRejectedValueOnce(
|
|
Object.assign(new Error("uv exited with code 2"), {
|
|
code: 2,
|
|
stderr: "error: Unknown architecture: invalid\n",
|
|
}),
|
|
);
|
|
|
|
await expect(setupPythonArch("/tools/uv", "invalid")).rejects.toThrow(
|
|
"Failed to set Python architecture to invalid: error: Unknown architecture: invalid",
|
|
);
|
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
|
});
|
|
});
|