diff --git a/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Handlers/IdempotencyFunctionMethodDecorated.cs b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Handlers/IdempotencyFunctionMethodDecorated.cs new file mode 100644 index 000000000..4a4045889 --- /dev/null +++ b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Handlers/IdempotencyFunctionMethodDecorated.cs @@ -0,0 +1,99 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using Amazon.DynamoDBv2; +using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.Core; + +namespace AWS.Lambda.Powertools.Idempotency.Tests.Handlers; + +public class IdempotencyFunctionMethodDecorated +{ + public bool MethodCalled; + + public IdempotencyFunctionMethodDecorated(AmazonDynamoDBClient client) + { + Idempotency.Configure(builder => + builder + .UseDynamoDb(storeBuilder => + storeBuilder + .WithTableName("idempotency_table") + .WithDynamoDBClient(client) + )); + } + + + public async Task Handle(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) + { + Idempotency.RegisterLambdaContext(context); + var result= await InternalFunctionHandler(apigProxyEvent); + + return result; + } + + private async Task InternalFunctionHandler(APIGatewayProxyRequest apigProxyEvent) + { + Dictionary headers = new() + { + {"Content-Type", "application/json"}, + {"Access-Control-Allow-Origin", "*"}, + {"Access-Control-Allow-Methods", "GET, OPTIONS"}, + {"Access-Control-Allow-Headers", "*"} + }; + + try + { + var address = JsonDocument.Parse(apigProxyEvent.Body).RootElement.GetProperty("address").GetString(); + var pageContents = await GetPageContents(address); + var output = $"{{ \"message\": \"hello world\", \"location\": \"{pageContents}\" }}"; + + return new APIGatewayProxyResponse + { + Body = output, + StatusCode = 200, + Headers = headers + }; + + } + catch (IOException) + { + return new APIGatewayProxyResponse + { + Body = "{}", + StatusCode = 500, + Headers = headers + }; + } + } + + [Idempotent] + private async Task GetPageContents(string address) + { + MethodCalled = true; + + var client = new HttpClient(); + using var response = await client.GetAsync(address); + using var content = response.Content; + var pageContent = await content.ReadAsStringAsync(); + + return pageContent; + } +} \ No newline at end of file diff --git a/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/IdempotencyTest.cs b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/IdempotencyTest.cs index c01706829..018e672a4 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/IdempotencyTest.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/IdempotencyTest.cs @@ -1,24 +1,27 @@ /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * + * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at - * + * * http://aws.amazon.com/apache2.0 - * + * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ +using System; +using System.Collections.Generic; using System.IO; using System.Text.Json; using System.Threading.Tasks; using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.Model; using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.TestUtilities; using AWS.Lambda.Powertools.Idempotency.Tests.Handlers; using AWS.Lambda.Powertools.Idempotency.Tests.Persistence; using FluentAssertions; @@ -66,5 +69,57 @@ public async Task EndToEndTest() TableName = _tableName }); scanResponse.Count.Should().Be(1); + + // delete row dynamo + var key = new Dictionary + { + ["id"] = new AttributeValue { S = "testFunction.GetPageContents#ff323c6f0c5ceb97eed49121babcec0f" } + }; + await _client.DeleteItemAsync(new DeleteItemRequest{TableName = _tableName, Key = key}); + } + + [Fact] + [Trait("Category", "Integration")] + public async Task EndToEndTestMethod() + { + var function = new IdempotencyFunctionMethodDecorated(_client); + + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }; + + var context = new TestLambdaContext + { + RemainingTime = TimeSpan.FromSeconds(30) + }; + + var request = JsonSerializer.Deserialize(await File.ReadAllTextAsync("./resources/apigw_event2.json"),options); + + var response = await function.Handle(request, context); + function.MethodCalled.Should().BeTrue(); + + function.MethodCalled = false; + + var response2 = await function.Handle(request, context); + function.MethodCalled.Should().BeFalse(); + + // Assert + JsonSerializer.Serialize(response).Should().Be(JsonSerializer.Serialize(response2)); + response.Body.Should().Contain("hello world"); + response2.Body.Should().Contain("hello world"); + + var scanResponse = await _client.ScanAsync(new ScanRequest + { + TableName = _tableName + }); + scanResponse.Count.Should().Be(1); + + // delete row dynamo + var key = new Dictionary + { + ["id"] = new AttributeValue { S = "testFunction.GetPageContents#ff323c6f0c5ceb97eed49121babcec0f" } + }; + await _client.DeleteItemAsync(new DeleteItemRequest{TableName = _tableName, Key = key}); } } \ No newline at end of file diff --git a/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs index c5eda8c2b..d98368546 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Idempotency.Tests/Internal/IdempotentAspectTests.cs @@ -311,7 +311,7 @@ public void Handle_WhenIdempotencyOnSubMethodAnnotated_AndSecondCall_AndNotExpir // Arrange var store = Substitute.For(); store.SaveInProgress(Arg.Any(), Arg.Any(), Arg.Any()) - .Throws(new IdempotencyItemAlreadyExistsException()); + .Returns(_ => throw new IdempotencyItemAlreadyExistsException()); Idempotency.Configure(builder => builder.WithPersistenceStore(store)); @@ -327,7 +327,7 @@ public void Handle_WhenIdempotencyOnSubMethodAnnotated_AndSecondCall_AndNotExpir .Returns(record); // Act - var function = new IdempotencyInternalFunction(false); + var function = new IdempotencyInternalFunction(true); Basket resultBasket = function.HandleRequest(product, new TestLambdaContext()); // assert