mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-09 21:14:22 +00:00
Co-authored-by: Pablo F.G <pablo.fernandez@prowler.com>
238 lines
6.4 KiB
TypeScript
238 lines
6.4 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const {
|
|
fetchMock,
|
|
getAuthHeadersMock,
|
|
getFormValueMock,
|
|
handleApiErrorMock,
|
|
handleApiResponseMock,
|
|
waitMock,
|
|
} = vi.hoisted(() => ({
|
|
fetchMock: vi.fn(),
|
|
getAuthHeadersMock: vi.fn(),
|
|
getFormValueMock: vi.fn(),
|
|
handleApiErrorMock: vi.fn(),
|
|
handleApiResponseMock: vi.fn(),
|
|
waitMock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("next/cache", () => ({
|
|
revalidatePath: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("next/navigation", () => ({
|
|
redirect: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/lib", () => ({
|
|
apiBaseUrl: "https://api.example.com/api/v1",
|
|
getAuthHeaders: getAuthHeadersMock,
|
|
getFormValue: getFormValueMock,
|
|
wait: waitMock,
|
|
}));
|
|
|
|
vi.mock("@/lib/provider-credentials/build-credentials", () => ({
|
|
buildSecretConfig: vi.fn(() => ({
|
|
secretType: "access-secret-key",
|
|
secret: { key: "value" },
|
|
})),
|
|
}));
|
|
|
|
vi.mock("@/lib/provider-filters", () => ({
|
|
appendSanitizedProviderInFilters: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("@/lib/server-actions-helper", () => ({
|
|
handleApiError: handleApiErrorMock,
|
|
handleApiResponse: handleApiResponseMock,
|
|
}));
|
|
|
|
import {
|
|
addCredentialsProvider,
|
|
addProvider,
|
|
checkConnectionProvider,
|
|
startProviderConnectionChecks,
|
|
updateCredentialsProvider,
|
|
} from "./providers";
|
|
|
|
describe("providers actions", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
getAuthHeadersMock.mockResolvedValue({ Authorization: "Bearer token" });
|
|
getFormValueMock.mockImplementation((formData: FormData, field: string) =>
|
|
formData.get(field),
|
|
);
|
|
handleApiErrorMock.mockReturnValue({ error: "Unexpected error" });
|
|
handleApiResponseMock.mockResolvedValue({ data: { id: "secret-1" } });
|
|
fetchMock.mockResolvedValue(
|
|
new Response(JSON.stringify({ data: { id: "secret-1" } }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("should revalidate providers after linking a cloud provider", async () => {
|
|
// Given
|
|
const formData = new FormData();
|
|
formData.set("providerType", "aws");
|
|
formData.set("providerUid", "111111111111");
|
|
|
|
// When
|
|
await addProvider(formData);
|
|
|
|
// Then
|
|
expect(handleApiResponseMock).toHaveBeenCalledWith(
|
|
expect.any(Response),
|
|
"/providers",
|
|
);
|
|
});
|
|
|
|
it("should revalidate providers after adding credentials in the wizard", async () => {
|
|
// Given
|
|
const formData = new FormData();
|
|
formData.set("providerId", "provider-1");
|
|
formData.set("providerType", "aws");
|
|
|
|
// When
|
|
await addCredentialsProvider(formData);
|
|
|
|
// Then
|
|
expect(handleApiResponseMock).toHaveBeenCalledWith(
|
|
expect.any(Response),
|
|
"/providers",
|
|
);
|
|
});
|
|
|
|
it("should revalidate providers after updating credentials in the wizard", async () => {
|
|
// Given
|
|
const formData = new FormData();
|
|
formData.set("providerId", "provider-1");
|
|
formData.set("providerType", "oraclecloud");
|
|
|
|
// When
|
|
await updateCredentialsProvider("secret-1", formData);
|
|
|
|
// Then
|
|
expect(handleApiResponseMock).toHaveBeenCalledWith(
|
|
expect.any(Response),
|
|
"/providers",
|
|
);
|
|
});
|
|
|
|
it("should revalidate providers when checking connection from the wizard", async () => {
|
|
// Given
|
|
const formData = new FormData();
|
|
formData.set("providerId", "provider-1");
|
|
|
|
// When
|
|
await checkConnectionProvider(formData);
|
|
|
|
// Then
|
|
expect(handleApiResponseMock).toHaveBeenCalledWith(
|
|
expect.any(Response),
|
|
"/providers",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("startProviderConnectionChecks", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
getAuthHeadersMock.mockResolvedValue({ Authorization: "Bearer token" });
|
|
handleApiErrorMock.mockReturnValue({ error: "Unexpected error" });
|
|
fetchMock.mockResolvedValue(new Response(null, { status: 202 }));
|
|
});
|
|
|
|
it("dispatches one check per provider and returns the task each is tested by", async () => {
|
|
// Given
|
|
handleApiResponseMock.mockImplementation(async () => ({
|
|
data: { id: `task-${handleApiResponseMock.mock.calls.length}` },
|
|
}));
|
|
|
|
// When
|
|
const outcomes = await startProviderConnectionChecks([
|
|
"provider-1",
|
|
"provider-2",
|
|
]);
|
|
|
|
// Then
|
|
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
expect(Object.keys(outcomes).sort()).toEqual(["provider-1", "provider-2"]);
|
|
expect(Object.values(outcomes).map((outcome) => outcome.taskId)).toEqual(
|
|
expect.arrayContaining(["task-1", "task-2"]),
|
|
);
|
|
});
|
|
|
|
it("skips the single-provider padding and the per-provider revalidation", async () => {
|
|
// Given
|
|
handleApiResponseMock.mockResolvedValue({ data: { id: "task-1" } });
|
|
|
|
// When
|
|
await startProviderConnectionChecks(["provider-1", "provider-2"]);
|
|
|
|
// Then
|
|
expect(waitMock).not.toHaveBeenCalled();
|
|
expect(handleApiResponseMock).toHaveBeenCalledWith(
|
|
expect.any(Response),
|
|
undefined,
|
|
);
|
|
});
|
|
|
|
it("keeps a failed dispatch to its own provider, error payload included", async () => {
|
|
// Given
|
|
const failure = { error: "Provider not found.", status: 404 };
|
|
handleApiResponseMock
|
|
.mockResolvedValueOnce({ data: { id: "task-1" } })
|
|
.mockResolvedValueOnce(failure);
|
|
|
|
// When
|
|
const outcomes = await startProviderConnectionChecks([
|
|
"provider-1",
|
|
"provider-2",
|
|
]);
|
|
|
|
// Then
|
|
expect(outcomes["provider-1"]).toEqual({ taskId: "task-1" });
|
|
expect(outcomes["provider-2"]).toEqual({ error: failure });
|
|
});
|
|
|
|
it("keeps a thrown request to its own provider", async () => {
|
|
// Given
|
|
handleApiResponseMock.mockResolvedValue({ data: { id: "task-1" } });
|
|
fetchMock
|
|
.mockResolvedValueOnce(new Response(null, { status: 202 }))
|
|
.mockRejectedValueOnce(new Error("socket hang up"));
|
|
|
|
// When
|
|
const outcomes = await startProviderConnectionChecks([
|
|
"provider-1",
|
|
"provider-2",
|
|
]);
|
|
|
|
// Then
|
|
expect(outcomes["provider-1"]).toEqual({ taskId: "task-1" });
|
|
expect(outcomes["provider-2"]).toEqual({
|
|
error: { error: "Unexpected error" },
|
|
});
|
|
});
|
|
|
|
it("ignores blank and duplicated ids", async () => {
|
|
// Given
|
|
handleApiResponseMock.mockResolvedValue({ data: { id: "task-1" } });
|
|
|
|
// When
|
|
const outcomes = await startProviderConnectionChecks([
|
|
"provider-1",
|
|
"provider-1",
|
|
"",
|
|
]);
|
|
|
|
// Then
|
|
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
expect(Object.keys(outcomes)).toEqual(["provider-1"]);
|
|
});
|
|
});
|