mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-13 06:54:16 +00:00
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
187 lines
5.9 KiB
TypeScript
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" });
|
|
});
|
|
});
|