From b1c607c7e1f98fb14aa16f2c0c30a4a1245bd9db Mon Sep 17 00:00:00 2001 From: kstich Date: Thu, 28 Jan 2021 15:55:07 -0800 Subject: [PATCH] Update protocol test request body comparison This commit updates the request body comparison generation for protocol tests to safely handle having multiple bodyMediaType settings in the same suite of protocol tests. It also updates the methodology for comparing blob bodies to not be a special case in the generator, as they can have alternate media types. --- .../codegen/HttpProtocolTestGenerator.java | 39 +++++++------------ .../protocol-test-form-urlencoded-stub.ts | 2 +- .../codegen/protocol-test-json-stub.ts | 2 +- .../protocol-test-octet-stream-stub.ts | 14 +++++++ .../codegen/protocol-test-text-stub.ts | 10 +++++ .../protocol-test-unknown-type-stub.ts | 10 ++++- .../codegen/protocol-test-xml-stub.ts | 2 +- 7 files changed, 49 insertions(+), 30 deletions(-) create mode 100644 smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-octet-stream-stub.ts create mode 100644 smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-text-stub.ts diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/HttpProtocolTestGenerator.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/HttpProtocolTestGenerator.java index 518fb0643d6..7d24d96fbbc 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/HttpProtocolTestGenerator.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/HttpProtocolTestGenerator.java @@ -278,53 +278,42 @@ private void writeRequestBodyAssertions(OperationShape operation, HttpRequestTes writer.write("expect(r.body).toBeDefined();"); // Otherwise load a media type specific comparator and do a comparison. - String mediaType = testCase.getBodyMediaType().orElse(null); - - // Fast check if we have an undescribed or plain text body. - if (mediaType == null || mediaType.equals("text/plain")) { - // Handle converting to the right comparison format for blob payloads. - HttpBindingIndex httpBindingIndex = HttpBindingIndex.of(model); - List payloadBindings = httpBindingIndex.getRequestBindings(operation, Location.PAYLOAD); - if (!payloadBindings.isEmpty() && hasBlobBinding(payloadBindings)) { - writer.write("expect(r.body).toMatchObject(Uint8Array.from($S, c => c.charCodeAt(0)));", body); - } else { - writer.write("expect(r.body).toBe($S);", body); - } - return; - } - registerBodyComparatorStub(mediaType); + String mediaType = testCase.getBodyMediaType().orElse("UNKNOWN"); + String comparatorInvoke = registerBodyComparatorStub(mediaType); // Handle escaping strings with quotes inside them. writer.write("const bodyString = `$L`;", body.replace("\"", "\\\"")); - writer.write("const unequalParts: any = compareEquivalentBodies(bodyString, r.body.toString());"); + writer.write("const unequalParts: any = $L;", comparatorInvoke); writer.write("expect(unequalParts).toBeUndefined();"); }); } - private boolean hasBlobBinding(List payloadBindings) { - // Can only have one payload binding at a time. - return model.expectShape(payloadBindings.get(0).getMember().getTarget()).isBlobShape(); - } - - private void registerBodyComparatorStub(String mediaType) { + private String registerBodyComparatorStub(String mediaType) { // Load an additional stub to handle body comparisons for the // set of bodyMediaType values we know of. switch (mediaType) { case "application/x-www-form-urlencoded": additionalStubs.add("protocol-test-form-urlencoded-stub.ts"); - break; + return "compareEquivalentFormUrlencodedBodies(bodyString, r.body.toString())"; case "application/json": additionalStubs.add("protocol-test-json-stub.ts"); - break; + return "compareEquivalentJsonBodies(bodyString, r.body.toString())"; case "application/xml": writer.addDependency(TypeScriptDependency.XML_PARSER); writer.addImport("parse", "xmlParse", "fast-xml-parser"); additionalStubs.add("protocol-test-xml-stub.ts"); - break; + return "compareEquivalentXmlBodies(bodyString, r.body.toString())"; + case "application/octet-stream": + additionalStubs.add("protocol-test-octet-stream-stub.ts"); + return "compareEquivalentOctetStreamBodies(client.config, bodyString, r.body)"; + case "text/plain": + additionalStubs.add("protocol-test-text-stub.ts"); + return "compareEquivalentTextBodies(bodyString, r.body)"; default: LOGGER.warning("Unable to compare bodies with unknown media type `" + mediaType + "`, defaulting to direct comparison."); additionalStubs.add("protocol-test-unknown-type-stub.ts"); + return "compareEquivalentUnknownTypeBodies(client.config, bodyString, r.body)"; } } diff --git a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-form-urlencoded-stub.ts b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-form-urlencoded-stub.ts index e271bd84f14..ef67aff33a8 100644 --- a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-form-urlencoded-stub.ts +++ b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-form-urlencoded-stub.ts @@ -2,7 +2,7 @@ * Returns a map of key names that were un-equal to value objects showing the * discrepancies between the components. */ -const compareEquivalentBodies = (expectedBody: string, generatedBody: string): Object => { +const compareEquivalentFormUrlencodedBodies = (expectedBody: string, generatedBody: string): Object => { const fromEntries = (components: string[][]): { [key: string]: string } => { const parts: { [key: string]: string } = {}; diff --git a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-json-stub.ts b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-json-stub.ts index 24617c7a750..49e640eb91d 100644 --- a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-json-stub.ts +++ b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-json-stub.ts @@ -2,7 +2,7 @@ * Returns a map of key names that were un-equal to value objects showing the * discrepancies between the components. */ -const compareEquivalentBodies = (expectedBody: string, generatedBody: string): Object => { +const compareEquivalentJsonBodies = (expectedBody: string, generatedBody: string): Object => { const expectedParts = JSON.parse(expectedBody); const generatedParts = JSON.parse(generatedBody); diff --git a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-octet-stream-stub.ts b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-octet-stream-stub.ts new file mode 100644 index 00000000000..2d99a5abae1 --- /dev/null +++ b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-octet-stream-stub.ts @@ -0,0 +1,14 @@ +/** + * Returns a map of key names that were un-equal to value objects showing the + * discrepancies between the components. + */ +const compareEquivalentOctetStreamBodies = ( + config: any, + expectedBody: string, + generatedBody: Uint8Array +): Object => { + const expectedParts = {Value: expectedBody}; + const generatedParts = {Value: config.utf8Encoder(generatedBody)}; + + return compareParts(expectedParts, generatedParts); +} diff --git a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-text-stub.ts b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-text-stub.ts new file mode 100644 index 00000000000..ede3b37e23e --- /dev/null +++ b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-text-stub.ts @@ -0,0 +1,10 @@ +/** + * Returns a map of key names that were un-equal to value objects showing the + * discrepancies between the components. + */ +const compareEquivalentTextBodies = (expectedBody: string, generatedBody: string): Object => { + const expectedParts = {Value: expectedBody}; + const generatedParts = {Value: generatedBody}; + + return compareParts(expectedParts, generatedParts); +} diff --git a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-unknown-type-stub.ts b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-unknown-type-stub.ts index a371b1e4c51..69afea79e4e 100644 --- a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-unknown-type-stub.ts +++ b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-unknown-type-stub.ts @@ -2,9 +2,15 @@ * Returns a map of key names that were un-equal to value objects showing the * discrepancies between the components. */ -const compareEquivalentBodies = (expectedBody: string, generatedBody: string): Object => { +const compareEquivalentUnknownTypeBodies = ( + config: any, + expectedBody: string, + generatedBody: string | Uint8Array +): Object => { const expectedParts = {Value: expectedBody}; - const generatedParts = {Value: generatedBody}; + const generatedParts = { + Value: generatedBody instanceof Uint8Array ? config.utf8Encoder(generatedBody) : generatedBody + }; return compareParts(expectedParts, generatedParts); } diff --git a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-xml-stub.ts b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-xml-stub.ts index df212226b9e..568d1eb04ad 100644 --- a/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-xml-stub.ts +++ b/smithy-typescript-codegen/src/main/resources/software/amazon/smithy/typescript/codegen/protocol-test-xml-stub.ts @@ -2,7 +2,7 @@ * Returns a map of key names that were un-equal to value objects showing the * discrepancies between the components. */ -const compareEquivalentBodies = (expectedBody: string, generatedBody: string): Object => { +const compareEquivalentXmlBodies = (expectedBody: string, generatedBody: string): Object => { const decodeEscapedXml = (str: string) => { return str .replace(/&/g, "&")