Files
prowler/ui/lib/registry/artifact-execution.test.ts

187 lines
5.9 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import { executeRegistryArtifactAddition } from "./artifact-execution";
const {
addRegistryArtifactMock,
confirmRegistryArtifactAdditionMock,
trackAndPollTaskMock,
} = vi.hoisted(() => ({
addRegistryArtifactMock: vi.fn(),
confirmRegistryArtifactAdditionMock: vi.fn(),
trackAndPollTaskMock: vi.fn(),
}));
vi.mock("@/actions/registry/registry", () => ({
addRegistryArtifact: addRegistryArtifactMock,
confirmRegistryArtifactAddition: confirmRegistryArtifactAdditionMock,
}));
vi.mock("@/store/task-watcher/store", () => ({
TASK_WATCHER_STATUS: { READY: "ready", ERROR: "error" },
trackAndPollTask: trackAndPollTaskMock,
}));
const artifactInput = { normalizedName: "prowler-aws", versionSpec: "2.0.0" };
describe("executeRegistryArtifactAddition", () => {
beforeEach(() => {
vi.clearAllMocks();
addRegistryArtifactMock.mockResolvedValue({
status: "submitted",
taskId: "artifact-task",
});
trackAndPollTaskMock.mockResolvedValue({
status: "ready",
result: { installed: true, error: null },
});
confirmRegistryArtifactAdditionMock.mockResolvedValue({
status: "confirmed",
tenantArtifacts: [],
});
});
it("persists an update target and confirms that version after the task completes", async () => {
// Given / When
await executeRegistryArtifactAddition({
...artifactInput,
operation: "update",
});
// Then
expect(trackAndPollTaskMock).toHaveBeenCalledWith(
expect.objectContaining({
meta: {
normalizedName: "prowler-aws",
operation: "update",
expectedVersion: "2.0.0",
},
}),
);
expect(confirmRegistryArtifactAdditionMock).toHaveBeenCalledWith(
"prowler-aws",
"2.0.0",
);
});
it.each([
[
"This version cannot be installed.",
"The artifact could not be installed.",
],
[
"Private diagnostic: /srv/registry/customer",
"The artifact could not be installed.",
],
[null, "The artifact could not be installed."],
["", "The artifact could not be installed."],
[" ", "The artifact could not be installed."],
])(
"returns a safe task refusal for error %j without confirmation",
async (error, message) => {
// Given
trackAndPollTaskMock.mockResolvedValue({
status: "ready",
result: { installed: false, error },
});
// When
const outcome = await executeRegistryArtifactAddition(artifactInput);
// Then
expect(outcome).toEqual({ status: "refused", message });
expect(confirmRegistryArtifactAdditionMock).not.toHaveBeenCalled();
},
);
it.each([
[
"an otherwise valid result with an extra field",
{ installed: true, error: null, reason: "private deployment detail" },
],
[
"an installed result with an error",
{ installed: true, error: "unexpected failure" },
],
])("returns error for %s without confirmation", async (_case, result) => {
// Given
trackAndPollTaskMock.mockResolvedValue({ status: "ready", result });
// When
const outcome = await executeRegistryArtifactAddition(artifactInput);
// Then
expect(outcome).toEqual({ status: "error" });
expect(confirmRegistryArtifactAdditionMock).not.toHaveBeenCalled();
});
it("maps failed tasks to unavailable without confirmation", async () => {
// Given
trackAndPollTaskMock.mockResolvedValue({
status: "error",
error: "failed",
});
// When
const outcome = await executeRegistryArtifactAddition(artifactInput);
// Then
expect(outcome).toEqual({ status: "unavailable" });
expect(confirmRegistryArtifactAdditionMock).not.toHaveBeenCalled();
});
it("uses the error catch when polling throws", async () => {
// Given
trackAndPollTaskMock.mockRejectedValue(new Error("watcher crashed"));
// When
const outcome = await executeRegistryArtifactAddition(artifactInput);
// Then
expect(outcome).toEqual({ status: "error" });
expect(confirmRegistryArtifactAdditionMock).not.toHaveBeenCalled();
});
it("does not poll a synchronous 409 onboarding outcome", async () => {
// Given
addRegistryArtifactMock.mockResolvedValue({ status: "onboarding" });
// When
const outcome = await executeRegistryArtifactAddition(artifactInput);
// Then
expect(outcome).toEqual({ status: "onboarding" });
expect(confirmRegistryArtifactAdditionMock).not.toHaveBeenCalled();
expect(trackAndPollTaskMock).not.toHaveBeenCalled();
});
it("confirms presence after a completed installed task", async () => {
// Given
// When
const outcome = await executeRegistryArtifactAddition(artifactInput);
// Then
expect(outcome).toEqual({ status: "confirmed", tenantArtifacts: [] });
expect(trackAndPollTaskMock).toHaveBeenCalledWith({
taskId: "artifact-task",
kind: "registry-artifact-add",
meta: { normalizedName: "prowler-aws" },
notifyHandler: false,
});
expect(confirmRegistryArtifactAdditionMock).toHaveBeenCalledOnce();
expect(confirmRegistryArtifactAdditionMock).toHaveBeenCalledWith(
"prowler-aws",
);
});
it("deduplicates concurrent submissions for the same artifact", async () => {
await Promise.all([
executeRegistryArtifactAddition(artifactInput),
executeRegistryArtifactAddition(artifactInput),
]);
expect(addRegistryArtifactMock).toHaveBeenCalledOnce();
expect(confirmRegistryArtifactAdditionMock).toHaveBeenCalledOnce();
});
it("reports an unconfirmed update if the confirmation request throws", async () => {
// Given
confirmRegistryArtifactAdditionMock.mockRejectedValue(
new Error("Network failure"),
);
// When
const result = await executeRegistryArtifactAddition({
...artifactInput,
operation: "update",
});
// Then
expect(result).toEqual({ status: "refresh_failed" });
});
});