Skip to content

Commit

Permalink
PR comments
Browse files Browse the repository at this point in the history
  • Loading branch information
gcbeattyAWS committed Dec 19, 2024
1 parent b4cd801 commit 7e88575
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static void ToHttpResponse(this APIGatewayProxyResponse apiResponse, Http
response.Clear();

SetResponseHeaders(response, apiResponse.Headers, emulatorMode, apiResponse.MultiValueHeaders);
SetResponseBody(response, apiResponse.Body, apiResponse.IsBase64Encoded, emulatorMode);
SetResponseBody(response, apiResponse.Body, apiResponse.IsBase64Encoded);
SetContentTypeAndStatusCodeV1(response, apiResponse.Headers, apiResponse.MultiValueHeaders, apiResponse.StatusCode, emulatorMode);
}

Expand All @@ -41,7 +41,7 @@ public static void ToHttpResponse(this APIGatewayHttpApiV2ProxyResponse apiRespo
response.Clear();

SetResponseHeaders(response, apiResponse.Headers, ApiGatewayEmulatorMode.HttpV2);
SetResponseBody(response, apiResponse.Body, apiResponse.IsBase64Encoded, ApiGatewayEmulatorMode.HttpV2);
SetResponseBody(response, apiResponse.Body, apiResponse.IsBase64Encoded);
SetContentTypeAndStatusCodeV2(response, apiResponse.Headers, apiResponse.StatusCode);
}

Expand Down Expand Up @@ -151,13 +151,12 @@ private static string GenerateRequestId()
/// <param name="response">The <see cref="HttpResponse"/> to set the body on.</param>
/// <param name="body">The body content.</param>
/// <param name="isBase64Encoded">Whether the body is Base64 encoded.</param>
/// <param name="apiGatewayEmulator">The <see cref="ApiGatewayEmulatorMode"/> being used.</param>
private static void SetResponseBody(HttpResponse response, string? body, bool isBase64Encoded, ApiGatewayEmulatorMode apiGatewayEmulator)
private static void SetResponseBody(HttpResponse response, string? body, bool isBase64Encoded)
{
if (!string.IsNullOrEmpty(body))
{
byte[] bodyBytes;
if (isBase64Encoded && ApiGatewayEmulatorMode.Rest != apiGatewayEmulator) // rest api gateway doesnt automatically decode the response
if (isBase64Encoded)
{
bodyBytes = Convert.FromBase64String(body);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public class ApiGatewayIntegrationTestFixture : IAsyncLifetime
public string HttpApiV1Url { get; private set; }
public string HttpApiV2Url { get; private set; }
public string ReturnRawRequestBodyHttpApiV2Url { get; private set; }
public string BinaryMediaRestApiId { get; private set; }
public string BinaryMediaRestApiUrl { get; private set; }


public ApiGatewayIntegrationTestFixture()
{
Expand All @@ -43,6 +46,8 @@ public ApiGatewayIntegrationTestFixture()
HttpApiV1Url = string.Empty;
HttpApiV2Url = string.Empty;
ReturnRawRequestBodyHttpApiV2Url = string.Empty;
BinaryMediaRestApiId = string.Empty;
BinaryMediaRestApiUrl = string.Empty;
}

public async Task InitializeAsync()
Expand Down Expand Up @@ -105,6 +110,9 @@ private async Task RetrieveStackOutputs()

ReturnRawRequestBodyV2Id = await CloudFormationHelper.GetOutputValueAsync(StackName, "ReturnRawRequestBodyHttpApiId");
ReturnRawRequestBodyHttpApiV2Url = await CloudFormationHelper.GetOutputValueAsync(StackName, "ReturnRawRequestBodyHttpApiUrl");

BinaryMediaRestApiId = await CloudFormationHelper.GetOutputValueAsync(StackName, "BinaryMediaRestApiId");
BinaryMediaRestApiUrl = await CloudFormationHelper.GetOutputValueAsync(StackName, "BinaryMediaRestApiUrl");
}

private async Task WaitForApisAvailability()
Expand All @@ -113,6 +121,7 @@ private async Task WaitForApisAvailability()
await ApiGatewayHelper.WaitForApiAvailability(HttpApiV1Id, HttpApiV1Url, true);
await ApiGatewayHelper.WaitForApiAvailability(HttpApiV2Id, HttpApiV2Url, true);
await ApiGatewayHelper.WaitForApiAvailability(ReturnRawRequestBodyV2Id, ReturnRawRequestBodyHttpApiV2Url, true);
await ApiGatewayHelper.WaitForApiAvailability(BinaryMediaRestApiId, BinaryMediaRestApiUrl, false);
}

public async Task DisposeAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
using Microsoft.AspNetCore.Http;
using System.Text.Json;
using Amazon.Lambda.TestTool.Extensions;
using Amazon.Lambda.TestTool.Models;
using System.Text;

namespace Amazon.Lambda.TestTool.IntegrationTests
{
[Collection("ApiGateway Integration Tests")]
public class ApiGatewayResponseExtensionsTestsManual
public class ApiGatewayResponseExtensionsAdditionalTests
{
private readonly ApiGatewayIntegrationTestFixture _fixture;
private readonly HttpClient _httpClient;

public ApiGatewayResponseExtensionsTestsManual(ApiGatewayIntegrationTestFixture fixture)
public ApiGatewayResponseExtensionsAdditionalTests(ApiGatewayIntegrationTestFixture fixture)
{
_fixture = fixture;
_httpClient = new HttpClient();
Expand Down Expand Up @@ -62,5 +64,45 @@ public async Task V2_SetsContentTypeApplicationJsonWhenNoStatusProvidedAndDoesnt
var responsePayload = JsonSerializer.Deserialize<Dictionary<string, object>>(content);
Assert.Equal("value", responsePayload?["key"].ToString());
}


[Fact]
public async Task ToHttpResponse_RestAPIGatewayV1DecodesBase64()
{
var testResponse = new APIGatewayProxyResponse
{
StatusCode = 200,
Body = Convert.ToBase64String(Encoding.UTF8.GetBytes("test")),
IsBase64Encoded = true
};

var httpContext = new DefaultHttpContext();
testResponse.ToHttpResponse(httpContext, ApiGatewayEmulatorMode.Rest);
var actualResponse = await _httpClient.PostAsync(_fixture.BinaryMediaRestApiUrl, new StringContent(JsonSerializer.Serialize(testResponse)));
await _fixture.ApiGatewayTestHelper.AssertResponsesEqual(actualResponse, httpContext.Response);
Assert.Equal(200, (int)actualResponse.StatusCode);
var content = await actualResponse.Content.ReadAsStringAsync();
Assert.Equal("test", content);
}

[Fact]
public async Task ToHttpResponse_HttpV1APIGatewayV1DecodesBase64()
{
var testResponse = new APIGatewayProxyResponse
{
StatusCode = 200,
Body = Convert.ToBase64String(Encoding.UTF8.GetBytes("test")),
IsBase64Encoded = true
};

var httpContext = new DefaultHttpContext();
testResponse.ToHttpResponse(httpContext, ApiGatewayEmulatorMode.HttpV1);
var actualResponse = await _httpClient.PostAsync(_fixture.HttpApiV1Url, new StringContent(JsonSerializer.Serialize(testResponse)));

await _fixture.ApiGatewayTestHelper.AssertResponsesEqual(actualResponse, httpContext.Response);
Assert.Equal(200, (int)actualResponse.StatusCode);
var content = await actualResponse.Content.ReadAsStringAsync();
Assert.Equal("test", content);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ Resources:
};
Runtime: nodejs20.x

BinaryLambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: !Sub '${AWS::StackName}-BinaryFunction'
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
exports.handler = async (event) => {
const decodedBody = atob(event.body);
const parsedBody = JSON.parse(decodedBody.toString('utf8'));
return parsedBody;
};
Runtime: nodejs20.x

ReturnRawRequestBodyLambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
Expand Down Expand Up @@ -199,6 +214,47 @@ Resources:
Principal: apigateway.amazonaws.com
SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ReturnRawRequestBodyHttpApi}/*'

BinaryMediaRestApi:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: !Sub '${AWS::StackName}-BinaryMediaRestAPI'
BinaryMediaTypes:
- '*/*'

BinaryMediaRestApiResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
ParentId: !GetAtt BinaryMediaRestApi.RootResourceId
PathPart: 'test'
RestApiId: !Ref BinaryMediaRestApi

BinaryMediaRestApiMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: POST
ResourceId: !Ref BinaryMediaRestApiResource
RestApiId: !Ref BinaryMediaRestApi
AuthorizationType: NONE
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${BinaryLambdaFunction.Arn}/invocations'

BinaryMediaRestApiDeployment:
Type: 'AWS::ApiGateway::Deployment'
DependsOn: BinaryMediaRestApiMethod
Properties:
RestApiId: !Ref BinaryMediaRestApi
StageName: 'test'

LambdaPermissionBinaryMediaRestApi:
Type: 'AWS::Lambda::Permission'
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: !GetAtt BinaryLambdaFunction.Arn
Principal: apigateway.amazonaws.com
SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${BinaryMediaRestApi}/*'

Outputs:
RestApiId:
Description: 'ID of the REST API'
Expand Down Expand Up @@ -231,3 +287,11 @@ Outputs:
ReturnRawRequestBodyHttpApiUrl:
Description: 'URL of the JSON Inference HTTP API'
Value: !Sub 'https://${ReturnRawRequestBodyHttpApi}.execute-api.${AWS::Region}.amazonaws.com/'

BinaryMediaRestApiId:
Description: 'ID of the Binary Media REST API'
Value: !Ref BinaryMediaRestApi

BinaryMediaRestApiUrl:
Description: 'URL of the Binary Media REST API'
Value: !Sub 'https://${BinaryMediaRestApi}.execute-api.${AWS::Region}.amazonaws.com/test/test'
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using System.Text;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.TestTool.Extensions;
using Amazon.Lambda.TestTool.Models;
Expand Down Expand Up @@ -71,5 +72,26 @@ public void ToHttpResponse_APIGatewayHttpApiV2ProxyResponse_InfersResponseFormat
var bodyContent = reader.ReadToEnd();
Assert.Equal(jsonBody, bodyContent);
}

[Theory]
[InlineData(ApiGatewayEmulatorMode.HttpV1)]
[InlineData(ApiGatewayEmulatorMode.Rest)]
public void ToHttpResponse_APIGatewayV1DecodesBase64(ApiGatewayEmulatorMode emulatorMode)
{
var apiResponse = new APIGatewayProxyResponse
{
StatusCode = 200,
Body = Convert.ToBase64String(Encoding.UTF8.GetBytes("test")),
IsBase64Encoded = true
};

var httpContext = new DefaultHttpContext();
apiResponse.ToHttpResponse(httpContext, emulatorMode);

httpContext.Response.Body.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(httpContext.Response.Body);
var bodyContent = reader.ReadToEnd();
Assert.Equal("test", bodyContent);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,42 +145,6 @@ public static IEnumerable<object[]> V1TestCases()
}
};

yield return new object[]
{
"V1_SetsBodyBase64",
new ApiGatewayResponseTestCase
{
Response = new APIGatewayProxyResponse
{
StatusCode = 200,
Body = Convert.ToBase64String(Encoding.UTF8.GetBytes("{\"message\":\"Hello, World!\"}")),
IsBase64Encoded = true
},
Assertions = (response, emulatormode) =>
{
if (emulatormode == ApiGatewayEmulatorMode.Rest)
{

} else
{
Assert.Equal("{\"message\":\"Hello, World!\"}", ReadResponseBody(response));
}
},
IntegrationAssertions = async (response, emulatorMode) =>
{
var content = await response.Content.ReadAsStringAsync();
if (emulatorMode == ApiGatewayEmulatorMode.Rest)
{
Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes("{\"message\":\"Hello, World!\"}")), content); // rest doesnt decode
} else
{
Assert.Equal("{\"message\":\"Hello, World!\"}", content);
}
await Task.CompletedTask;
}
}
};

yield return new object[]
{
"V1_DefaultsToCorrectContentTYpe",
Expand Down

0 comments on commit 7e88575

Please sign in to comment.