Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(middleware-flexible-checksums): add tests for edge cases #3362

Merged
merged 9 commits into from Feb 28, 2022
Expand Up @@ -7,7 +7,6 @@ import { flexibleChecksumsMiddleware } from "./flexibleChecksumsMiddleware";
import { getChecksum } from "./getChecksum";
import { getChecksumAlgorithmForRequest } from "./getChecksumAlgorithmForRequest";
import { getChecksumLocationName } from "./getChecksumLocationName";
import { FlexibleChecksumsMiddlewareConfig } from "./getFlexibleChecksumsPlugin";
import { hasHeader } from "./hasHeader";
import { isStreaming } from "./isStreaming";
import { selectChecksumAlgorithmFunction } from "./selectChecksumAlgorithmFunction";
Expand All @@ -31,13 +30,13 @@ describe(flexibleChecksumsMiddleware.name, () => {

const mockInput = {};
const mockConfig = {} as PreviouslyResolved;
const mockMiddlewareConfig = { input: mockInput } as FlexibleChecksumsMiddlewareConfig;
const mockMiddlewareConfig = { input: mockInput, requestChecksumRequired: false };

const mockBody = { body: "mockBody" };
const mockBody = { body: "mockRequestBody" };
const mockHeaders = { "content-length": 100 };
const mockRequest = { body: mockBody, headers: mockHeaders };
const mockArgs = { request: mockRequest } as BuildHandlerArguments<any>;
const mockResult = { response: {} };
const mockResult = { response: { body: "mockResponsebody" } };

beforeEach(() => {
mockNext.mockResolvedValueOnce(mockResult);
Expand Down Expand Up @@ -89,9 +88,8 @@ describe(flexibleChecksumsMiddleware.name, () => {
};
(hasHeader as jest.Mock).mockReturnValue(true);
await handler(mockArgsWithChecksumHeader);
expect(getChecksumLocationName).toHaveBeenCalledTimes(1);
expect(selectChecksumAlgorithmFunction).toHaveBeenCalledTimes(1);
expect(hasHeader).toHaveBeenCalledTimes(1);
expect(getChecksumLocationName).toHaveBeenCalledWith(ChecksumAlgorithm.MD5);
expect(selectChecksumAlgorithmFunction).toHaveBeenCalledWith(ChecksumAlgorithm.MD5, mockConfig);
expect(mockNext).toHaveBeenCalledWith(mockArgsWithChecksumHeader);
expect(hasHeader).toHaveBeenCalledWith(mockChecksumLocationName, mockHeadersWithChecksumHeader);
});
Expand Down Expand Up @@ -126,10 +124,20 @@ describe(flexibleChecksumsMiddleware.name, () => {
it("for streaming body", async () => {
(isStreaming as jest.Mock).mockReturnValue(true);
const mockUpdatedBody = { body: "mockUpdatedBody" };

const mockBase64Encoder = jest.fn();
const mockStreamHasher = jest.fn();
const mockBodyLengthChecker = jest.fn();
const mockGetAwsChunkedEncodingStream = jest.fn().mockReturnValue(mockUpdatedBody);

const handler = flexibleChecksumsMiddleware(
{ ...mockConfig, getAwsChunkedEncodingStream: mockGetAwsChunkedEncodingStream },
{
...mockConfig,
base64Encoder: mockBase64Encoder,
bodyLengthChecker: mockBodyLengthChecker,
getAwsChunkedEncodingStream: mockGetAwsChunkedEncodingStream,
streamHasher: mockStreamHasher,
},
mockMiddlewareConfig
)(mockNext, {});
await handler(mockArgs);
Expand All @@ -150,7 +158,13 @@ describe(flexibleChecksumsMiddleware.name, () => {
body: mockUpdatedBody,
},
});
expect(mockGetAwsChunkedEncodingStream).toHaveBeenCalledTimes(1);
expect(mockGetAwsChunkedEncodingStream).toHaveBeenCalledWith(mockRequest.body, {
base64Encoder: mockBase64Encoder,
bodyLengthChecker: mockBodyLengthChecker,
checksumLocationName: mockChecksumLocationName,
checksumAlgorithmFn: mockChecksumAlgorithmFunction,
streamHasher: mockStreamHasher,
});
});

it("for non-streaming body", async () => {
Expand All @@ -172,14 +186,19 @@ describe(flexibleChecksumsMiddleware.name, () => {
it("validates checksum from the response header", async () => {
const mockRequestValidationModeMember = "mockRequestValidationModeMember";
const mockInput = { [mockRequestValidationModeMember]: "ENABLED" };
const mockResponseAlgorithms = ["ALGO1", "ALGO2"];

const handler = flexibleChecksumsMiddleware(mockConfig, {
...mockMiddlewareConfig,
input: mockInput,
requestValidationModeMember: mockRequestValidationModeMember,
responseAlgorithms: mockResponseAlgorithms,
})(mockNext, {});

await handler(mockArgs);
expect(validateChecksumFromResponse).toHaveBeenCalledTimes(1);
expect(validateChecksumFromResponse).toHaveBeenCalledWith(mockResult.response, {
config: mockConfig,
responseAlgorithms: mockResponseAlgorithms,
});
});
});
Expand Up @@ -14,6 +14,7 @@ describe(getChecksum.name, () => {

const mockBody = "mockBody";
const mockOutput = "mockOutput";
const mockRawOutput = Buffer.from(mockOutput);

beforeEach(() => {
mockOptions.base64Encoder.mockResolvedValueOnce(mockOutput);
Expand All @@ -25,17 +26,19 @@ describe(getChecksum.name, () => {

it("gets checksum from streamHasher if body is streaming", async () => {
(isStreaming as jest.Mock).mockReturnValue(true);
mockOptions.streamHasher.mockResolvedValue(mockRawOutput);
const checksum = await getChecksum(mockBody, mockOptions);
expect(checksum).toEqual(mockOutput);
expect(stringHasher).not.toHaveBeenCalled();
expect(mockOptions.streamHasher).toHaveBeenCalledTimes(1);
expect(mockOptions.streamHasher).toHaveBeenCalledWith(mockOptions.checksumAlgorithmFn, mockBody);
});

it("gets checksum from stringHasher if body is not streaming", async () => {
(isStreaming as jest.Mock).mockReturnValue(false);
(stringHasher as jest.Mock).mockResolvedValue(mockRawOutput);
const checksum = await getChecksum(mockBody, mockOptions);
expect(checksum).toEqual(mockOutput);
expect(stringHasher).toHaveBeenCalledTimes(1);
expect(mockOptions.streamHasher).not.toHaveBeenCalled();
expect(stringHasher).toHaveBeenCalledWith(mockOptions.checksumAlgorithmFn, mockBody);
});
});
Expand Up @@ -10,21 +10,22 @@ describe(getChecksumAlgorithmForRequest.name, () => {
expect(getChecksumAlgorithmForRequest({}, { requestChecksumRequired: true })).toEqual(ChecksumAlgorithm.MD5);
});

it("returns undefined if requestChecksumRequired is not set", () => {
expect(getChecksumAlgorithmForRequest({}, { requestChecksumRequired: false })).toBeUndefined();
it.each([false, undefined])("returns undefined if requestChecksumRequired=%s", (requestChecksumRequired) => {
expect(getChecksumAlgorithmForRequest({}, { requestChecksumRequired })).toBeUndefined();
});
});

describe("when requestAlgorithmMember is not set in input", () => {
const mockOptions = { requestAlgorithmMember: mockRequestAlgorithmMember };

it("returns MD5 if requestChecksumRequired is set", () => {
expect(getChecksumAlgorithmForRequest({}, { ...mockOptions, requestChecksumRequired: true })).toEqual(
ChecksumAlgorithm.MD5
);
});

it("returns undefined if requestChecksumRequired is not set", () => {
expect(getChecksumAlgorithmForRequest({}, { ...mockOptions, requestChecksumRequired: false })).toBeUndefined();
it.each([false, undefined])("returns undefined if requestChecksumRequired=%s", (requestChecksumRequired) => {
expect(getChecksumAlgorithmForRequest({}, { ...mockOptions, requestChecksumRequired })).toBeUndefined();
});
});

Expand Down
Expand Up @@ -2,16 +2,46 @@ import { getChecksumAlgorithmListForResponse } from "./getChecksumAlgorithmListF
import { PRIORITY_ORDER_ALGORITHMS } from "./types";

describe(getChecksumAlgorithmListForResponse.name, () => {
const unknownAlgorithm = "UNKNOWNALGO";

it("returns empty if responseAlgorithms is empty", () => {
expect(getChecksumAlgorithmListForResponse([])).toEqual([]);
});

it("returns empty if contents of responseAlgorithms is not in priority order", () => {
expect(getChecksumAlgorithmListForResponse(["UNKNOWNALGO"])).toEqual([]);
expect(getChecksumAlgorithmListForResponse([unknownAlgorithm])).toEqual([]);
});

describe("returns list as per priority order", () => {
it("when all algorithms are passed in reverse order", () => {
expect(getChecksumAlgorithmListForResponse([...PRIORITY_ORDER_ALGORITHMS].reverse())).toEqual(
PRIORITY_ORDER_ALGORITHMS
);
});

it.each([...Array(PRIORITY_ORDER_ALGORITHMS.length).keys()].filter((num) => num !== 0))(
"when subset of algorithms are passed in reverse order starting with element at '%s'",
(start) => {
const responseAlgorithms = PRIORITY_ORDER_ALGORITHMS.slice(start);
expect(getChecksumAlgorithmListForResponse([...responseAlgorithms].reverse())).toEqual(responseAlgorithms);
}
);

it.each([...Array(PRIORITY_ORDER_ALGORITHMS.length).keys()].filter((num) => num !== 0))(
"when subset of algorithms are passed in reverse order ending with element at '%s' from last",
(end) => {
const responseAlgorithms = PRIORITY_ORDER_ALGORITHMS.slice(PRIORITY_ORDER_ALGORITHMS.length - end);
expect(getChecksumAlgorithmListForResponse([...responseAlgorithms].reverse())).toEqual(responseAlgorithms);
}
);
});

it("returns list as per priority order", () => {
const responseAlgorithms = [...PRIORITY_ORDER_ALGORITHMS];
expect(getChecksumAlgorithmListForResponse(responseAlgorithms.reverse())).toEqual(PRIORITY_ORDER_ALGORITHMS);
it("ignores algorithms not present in priority list", () => {
expect(getChecksumAlgorithmListForResponse([unknownAlgorithm, ...PRIORITY_ORDER_ALGORITHMS].reverse())).toEqual(
PRIORITY_ORDER_ALGORITHMS
);
expect(getChecksumAlgorithmListForResponse([...PRIORITY_ORDER_ALGORITHMS, unknownAlgorithm].reverse())).toEqual(
PRIORITY_ORDER_ALGORITHMS
);
});
});
Expand Up @@ -92,6 +92,7 @@ describe(validateChecksumFromResponse.name, () => {
responseAlgorithms: mockResponseAlgorithms,
});
expect(getChecksumLocationName).toHaveBeenCalledTimes(1);
expect(getChecksumLocationName).toHaveBeenCalledWith(mockResponseAlgorithms[0]);
});

it("when checksum is populated for second algorithm", async () => {
Expand All @@ -101,6 +102,8 @@ describe(validateChecksumFromResponse.name, () => {
responseAlgorithms: mockResponseAlgorithms,
});
expect(getChecksumLocationName).toHaveBeenCalledTimes(2);
expect(getChecksumLocationName).toHaveBeenNthCalledWith(1, mockResponseAlgorithms[0]);
expect(getChecksumLocationName).toHaveBeenNthCalledWith(2, mockResponseAlgorithms[1]);
});
});

Expand Down