Skip to content

Commit

Permalink
feat(test) updates to s3 calls on backend (#985)
Browse files Browse the repository at this point in the history
* updates to s3 calls on backend
  • Loading branch information
thetif authored Jan 9, 2025
1 parent cdfae2a commit d12b141
Show file tree
Hide file tree
Showing 23 changed files with 222 additions and 302 deletions.
197 changes: 69 additions & 128 deletions lib/lambda/getAttachmentUrl.test.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,36 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { describe, it, expect, vi, afterEach } from "vitest";
import { APIGatewayEvent } from "aws-lambda";
import { handler } from "./getAttachmentUrl";
import { response } from "libs/handler-lib";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { getStateFilter } from "../libs/api/auth/user";
import { getPackage, getPackageChangelog } from "../libs/api/package";

vi.mock("libs/handler-lib", () => ({
response: vi.fn(),
}));

vi.mock("@aws-sdk/client-sts", () => ({
STSClient: vi.fn().mockImplementation(() => ({
send: vi.fn(),
})),
AssumeRoleCommand: vi.fn(),
}));

vi.mock("@aws-sdk/client-s3", () => ({
S3Client: vi.fn().mockImplementation(() => ({
send: vi.fn(),
})),
GetObjectCommand: vi.fn(),
}));
import {
OPENSEARCH_DOMAIN,
getRequestContext,
NOT_FOUND_ITEM_ID,
HI_TEST_ITEM_ID,
TEST_ITEM_ID,
WITHDRAWN_CHANGELOG_ITEM_ID,
GET_ERROR_ITEM_ID,
ATTACHMENT_BUCKET_NAME,
ATTACHMENT_BUCKET_REGION,
} from "mocks";

vi.mock("@aws-sdk/s3-request-presigner", () => ({
getSignedUrl: vi.fn(),
}));

vi.mock("../libs/api/auth/user", () => ({
getStateFilter: vi.fn(),
}));

vi.mock("../libs/api/package", () => ({
getPackage: vi.fn(),
getPackageChangelog: vi.fn(),
}));

describe("Lambda Handler", () => {
beforeEach(() => {
afterEach(() => {
vi.clearAllMocks();
process.env.osDomain = "test-domain"; // Set the environment variable before each test
});

it("should return 400 if event body is missing", async () => {
const event = {} as APIGatewayEvent;

await handler(event);
const res = await handler(event);

expect(response).toHaveBeenCalledWith({
statusCode: 400,
body: { message: "Event body required" },
});
expect(res).toBeTruthy();
expect(res.statusCode).toEqual(400);
expect(res.body).toEqual(JSON.stringify({ message: "Event body required" }));
});

it("should return 500 if osDomain is missing", async () => {
Expand All @@ -60,155 +39,117 @@ describe("Lambda Handler", () => {
const event = {
body: JSON.stringify({
id: "test-id",
bucket: "test-bucket",
bucket: ATTACHMENT_BUCKET_NAME,
key: "test-key",
filename: "test-file",
}),
} as APIGatewayEvent;

await handler(event);
const res = await handler(event);

expect(res).toBeTruthy();
expect(res.statusCode).toEqual(500);
expect(res.body).toEqual(
JSON.stringify({ message: "ERROR: process.env.osDomain must be defined" }),
);

expect(response).toHaveBeenCalledWith({
statusCode: 500,
body: { message: "ERROR: process.env.osDomain must be defined" },
});
process.env.osDomain = OPENSEARCH_DOMAIN;
});

it("should return 404 if no package is found", async () => {
vi.mocked(getPackage).mockResolvedValueOnce(null);

const event = {
body: JSON.stringify({
id: "test-id",
bucket: "test-bucket",
id: NOT_FOUND_ITEM_ID,
bucket: ATTACHMENT_BUCKET_NAME,
key: "test-key",
filename: "test-file",
}),
requestContext: getRequestContext(),
} as APIGatewayEvent;

await handler(event);
const res = await handler(event);

expect(response).toHaveBeenCalledWith({
statusCode: 404,
body: { message: "No record found for the given id" },
});
expect(res).toBeTruthy();
expect(res.statusCode).toEqual(404);
expect(res.body).toEqual(JSON.stringify({ message: "No record found for the given id" }));
});

it("should return 404 if state access is not permitted", async () => {
vi.mocked(getPackage).mockResolvedValueOnce({
_source: { state: "test-state" },
});
vi.mocked(getStateFilter).mockResolvedValueOnce({
terms: { state: ["other-state"] },
});

const event = {
body: JSON.stringify({
id: "test-id",
bucket: "test-bucket",
id: HI_TEST_ITEM_ID,
bucket: ATTACHMENT_BUCKET_NAME,
key: "test-key",
filename: "test-file",
}),
requestContext: getRequestContext(),
} as APIGatewayEvent;

await handler(event);
const res = await handler(event);

expect(response).toHaveBeenCalledWith({
statusCode: 404,
body: { message: "state access not permitted for the given id" },
});
expect(res).toBeTruthy();
expect(res.statusCode).toEqual(403);
expect(res.body).toEqual(
JSON.stringify({ message: "state access not permitted for the given id" }),
);
});

it("should return 500 if attachment details are not found", async () => {
vi.mocked(getPackage).mockResolvedValueOnce({
_source: { state: "test-state" },
});
vi.mocked(getStateFilter).mockResolvedValueOnce({
terms: { state: ["test-state"] },
});
vi.mocked(getPackageChangelog).mockResolvedValueOnce({
hits: {
hits: [
{
_source: {
attachments: [{ bucket: "other-bucket", key: "other-key" }],
},
},
],
},
});

const event = {
body: JSON.stringify({
id: "test-id",
bucket: "test-bucket",
id: TEST_ITEM_ID,
bucket: ATTACHMENT_BUCKET_NAME,
key: "test-key",
filename: "test-file",
}),
requestContext: getRequestContext(),
} as APIGatewayEvent;

await handler(event);
const res = await handler(event);

expect(response).toHaveBeenCalledWith({
statusCode: 500,
body: { message: "Attachment details not found for given record id." },
});
expect(res).toBeTruthy();
expect(res.statusCode).toEqual(500);
expect(res.body).toEqual(
JSON.stringify({ message: "Attachment details not found for given record id." }),
);
});

it("should return 200 with the presigned URL if all checks pass", async () => {
vi.mocked(getPackage).mockResolvedValueOnce({
_source: { state: "test-state" },
});
vi.mocked(getStateFilter).mockResolvedValueOnce({
terms: { state: ["test-state"] },
});
vi.mocked(getPackageChangelog).mockResolvedValueOnce({
hits: {
hits: [
{
_source: {
attachments: [{ bucket: "test-bucket", key: "test-key" }],
},
},
],
},
});
vi.mocked(getSignedUrl).mockResolvedValueOnce("test-presigned-url");
const mockUrl = `https://${ATTACHMENT_BUCKET_NAME}.s3.${ATTACHMENT_BUCKET_REGION}.amazonaws.com/123e4567-e89b-12d3-a456-426614174000`;
vi.mocked(getSignedUrl).mockResolvedValueOnce(mockUrl);

const event = {
body: JSON.stringify({
id: "test-id",
bucket: "test-bucket",
key: "test-key",
filename: "test-file",
id: WITHDRAWN_CHANGELOG_ITEM_ID,
bucket: ATTACHMENT_BUCKET_NAME,
key: "doc001",
filename: "contract_amendment_2024.pdf",
}),
requestContext: getRequestContext(),
} as APIGatewayEvent;

await handler(event);
const res = await handler(event);

expect(response).toHaveBeenCalledWith({
statusCode: 200,
body: { url: "test-presigned-url" },
});
expect(res).toBeTruthy();
expect(res.statusCode).toEqual(200);
expect(res.body).toEqual(JSON.stringify({ url: mockUrl }));
});

it("should handle errors during processing", async () => {
vi.mocked(getPackage).mockRejectedValueOnce(new Error("Test error"));

const event = {
body: JSON.stringify({
id: "test-id",
bucket: "test-bucket",
id: GET_ERROR_ITEM_ID,
bucket: ATTACHMENT_BUCKET_NAME,
key: "test-key",
filename: "test-file",
}),
requestContext: getRequestContext(),
} as APIGatewayEvent;

await handler(event);
const res = await handler(event);

expect(response).toHaveBeenCalledWith({
statusCode: 500,
body: { message: "Internal server error" },
});
expect(res).toBeTruthy();
expect(res.statusCode).toEqual(500);
expect(res.body).toEqual(JSON.stringify({ message: "Internal server error" }));
});
});
6 changes: 3 additions & 3 deletions lib/lambda/getAttachmentUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const handler = async (event: APIGatewayEvent) => {
const body = JSON.parse(event.body);

const mainResult = await getPackage(body.id);
if (!mainResult) {
if (!mainResult || !mainResult.found) {
return response({
statusCode: 404,
body: { message: "No record found for the given id" },
Expand All @@ -46,7 +46,7 @@ export const handler = async (event: APIGatewayEvent) => {

if (!stateAccessAllowed) {
return response({
statusCode: 404,
statusCode: 403,
body: { message: "state access not permitted for the given id" },
});
}
Expand Down Expand Up @@ -97,7 +97,7 @@ async function getClient(bucket: string) {
const assumedCredentials = assumedRoleResponse.Credentials;

if (!assumedCredentials) {
throw new Error("No assumed redentials");
throw new Error("No assumed credentials");
}

// Create S3 client using the assumed role's credentials
Expand Down
8 changes: 4 additions & 4 deletions lib/lambda/getCpocs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ describe("getCpocs Handler", () => {
const res = await handler(event);

expect(res.statusCode).toEqual(400);
expect(res.body).toEqual(JSON.stringify({ message: "Event body required" }))
expect(res.body).toEqual(JSON.stringify({ message: "Event body required" }));
});

// TODO - should this be removed? when will the result be empty and not
// TODO - should this be removed? when will the result be empty and not
// just a result with an empty hit array
it("should return 400 if no Cpocs are found", async () => {
mockedServiceServer.use(emptyCpocSearchHandler);
Expand All @@ -25,7 +25,7 @@ describe("getCpocs Handler", () => {
const res = await handler(event);

expect(res.statusCode).toEqual(400);
expect(res.body).toEqual(JSON.stringify({ message: "No Cpocs found" }))
expect(res.body).toEqual(JSON.stringify({ message: "No Cpocs found" }));
});

it("should return 200 with the result if Cpocs are found", async () => {
Expand All @@ -46,6 +46,6 @@ describe("getCpocs Handler", () => {
const res = await handler(event);

expect(res.statusCode).toEqual(500);
expect(res.body).toEqual(JSON.stringify({ error: "Internal server error", message: "Response Error" }))
expect(res.body).toEqual(JSON.stringify({ message: "Internal server error" }));
});
});
4 changes: 1 addition & 3 deletions lib/lambda/getPackageActions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ describe("getPackageActions Handler", () => {

expect(res).toBeTruthy();
expect(res.statusCode).toEqual(500);
expect(res.body).toEqual(
JSON.stringify({ error: "Internal server error", message: "Response Error" }),
);
expect(res.body).toEqual(JSON.stringify({ message: "Internal server error" }));
});
});
Loading

0 comments on commit d12b141

Please sign in to comment.