From df81e3c027eeca6aaedf92687846853dd845f2a5 Mon Sep 17 00:00:00 2001 From: Phil Asmar Date: Fri, 22 Mar 2024 13:35:35 -0400 Subject: [PATCH 1/4] ci: add support for automated versioning and changelog creation --- .autover/autover.json | 19 +++ .github/workflows/create-release-pr.yml | 71 ++++++++++ .github/workflows/sync-main-dev.yml | 122 ++++++++++++++++++ CHANGELOG.md | 2 - .../AWS.Messaging.Lambda.csproj | 2 +- ...S.Messaging.Telemetry.OpenTelemetry.csproj | 2 +- src/AWS.Messaging/AWS.Messaging.csproj | 2 +- 7 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 .autover/autover.json create mode 100644 .github/workflows/create-release-pr.yml create mode 100644 .github/workflows/sync-main-dev.yml diff --git a/.autover/autover.json b/.autover/autover.json new file mode 100644 index 00000000..7d0a0827 --- /dev/null +++ b/.autover/autover.json @@ -0,0 +1,19 @@ +{ + "Projects": [ + { + "Name": "AWS.Messaging", + "Path": "src/AWS.Messaging/AWS.Messaging.csproj" + }, + { + "Name": "AWS.Messaging.Lambda", + "Path": "src/AWS.Messaging.Lambda/AWS.Messaging.Lambda.csproj" + }, + { + "Name": "AWS.Messaging.Telemetry.OpenTelemetry", + "Path": "src/AWS.Messaging.Telemetry.OpenTelemetry/AWS.Messaging.Telemetry.OpenTelemetry.csproj" + } + ], + "UseCommitsForChangelog": false, + "DefaultIncrementType": "Patch", + "ChangeFilesDetermineIncrementType": true +} \ No newline at end of file diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml new file mode 100644 index 00000000..6795d85e --- /dev/null +++ b/.github/workflows/create-release-pr.yml @@ -0,0 +1,71 @@ +# This GitHub Workflow will create a new release branch that contains the updated C# project versions and changelog. +# The workflow will also create a PR that targets `dev` from the release branch. +name: Create Release PR + +# This workflow is manually triggered when in preparation for a release. The workflow should be dispatched from the `dev` branch. +on: + workflow_dispatch: + +jobs: + release-pr: + name: Release PR + runs-on: ubuntu-latest + + steps: + # Checkout a full clone of the repo + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: '0' + # Install .NET8 which is needed for AutoVer + - name: Setup .NET 8.0 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + # Install AutoVer to automate versioning and changelog creation + - name: Install AutoVer + run: dotnet tool install --global AutoVer --version 0.0.19 + # Set up a git user to be able to run git commands later on + - name: Setup Git User + run: | + git config --global user.email "github-aws-sdk-dotnet-automation@amazon.com" + git config --global user.name "aws-sdk-dotnet-automation" + # Create the release branch which will contain the version changes and updated changelog + - name: Create Release Branch + id: create-release-branch + run: | + branch=releases/next-release + git checkout -b $branch + echo "BRANCH=$branch" >> $GITHUB_OUTPUT + # Update the version of projects based on the change files + - name: Increment Version + run: autover version + # Update the changelog based on the change files + - name: Update Changelog + run: autover changelog + # Push the release branch up as well as the created tag + - name: Push Changes + run: | + branch=${{ steps.create-release-branch.outputs.BRANCH }} + git push origin $branch + git push origin $branch --tags + # Get the release name that will be used to create a PR + - name: Read Release Name + id: read-release-name + run: | + version=$(autover changelog --release-name) + echo "VERSION=$version" >> $GITHUB_OUTPUT + # Get the changelog that will be used to create a PR + - name: Read Changelog + id: read-changelog + run: | + changelog=$(autover changelog --output-to-console) + echo "CHANGELOG<> "$GITHUB_OUTPUT" + # Create the Release PR and label it + - name: Create Pull Request + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + pr_url="$(gh pr create --title "${{ steps.read-release-name.outputs.VERSION }}" --body "${{ steps.read-changelog.outputs.CHANGELOG }}" --base dev --head ${{ steps.create-release-branch.outputs.BRANCH }})" + gh label create "Release PR" --description "A Release PR that includes versioning and changelog changes" -c "#FF0000" -f + gh pr edit $pr_url --add-label "Release PR" \ No newline at end of file diff --git a/.github/workflows/sync-main-dev.yml b/.github/workflows/sync-main-dev.yml new file mode 100644 index 00000000..fe95296a --- /dev/null +++ b/.github/workflows/sync-main-dev.yml @@ -0,0 +1,122 @@ +# This GitHub Workflow is designed to run automatically after the Release PR, which was created by the `Create Release PR` workflow, is closed. +# This workflow has 2 jobs. One will run if the `Release PR` is successfully merged, indicating that a release should go out. +# The other will run if the `Release PR` was closed and a release is not intended to go out. +name: Sync 'dev' and 'main' + +# The workflow will automatically be triggered when any PR is closed. +on: + pull_request: + types: [closed] + +permissions: + contents: write + +jobs: + # This job will check if the PR was successfully merged, it's source branch is `releases/next-release` and target branch is `dev`. + # This indicates that the merged PR was the `Release PR`. + # This job will synchronize `dev` and `main`, create a GitHub Release and delete the `releases/next-release` branch. + sync-dev-and-main: + name: Sync dev and main + if: | + github.event.pull_request.merged == true && + github.event.pull_request.head.ref == 'releases/next-release' && + github.event.pull_request.base.ref == 'dev' + runs-on: ubuntu-latest + steps: + # Checkout a full clone of the repo + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: dev + fetch-depth: 0 + # Install .NET8 which is needed for AutoVer + - name: Setup .NET 8.0 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + # Install AutoVer which is needed to retrieve information about the current release. + - name: Install AutoVer + run: dotnet tool install --global AutoVer --version 0.0.19 + # Set up a git user to be able to run git commands later on + - name: Setup Git User + run: | + git config --global user.email "github-aws-sdk-dotnet-automation@amazon.com" + git config --global user.name "aws-sdk-dotnet-automation" + # Retrieve the release name which is needed for the GitHub Release + - name: Read Release Name + id: read-release-name + run: | + version=$(autover changelog --release-name) + echo "VERSION=$version" >> $GITHUB_OUTPUT + # Retrieve the tag name which is needed for the GitHub Release + - name: Read Tag Name + id: read-tag-name + run: | + tag=$(autover changelog --tag-name) + echo "TAG=$tag" >> $GITHUB_OUTPUT + # Retrieve the changelog which is needed for the GitHub Release + - name: Read Changelog + id: read-changelog + run: | + changelog=$(autover changelog --output-to-console) + echo "CHANGELOG<> "$GITHUB_OUTPUT" + # Merge dev into main in order to synchronize the 2 branches + - name: Merge dev to main + run: | + git fetch origin + git checkout main + git merge dev + git push origin main + # Create the GitHub Release + - name: Create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "${{ steps.read-tag-name.outputs.TAG }}" --title "${{ steps.read-release-name.outputs.VERSION }}" --notes "${{ steps.read-changelog.outputs.CHANGELOG }}" + # Delete the `releases/next-release` branch + - name: Clean up + run: | + git fetch origin + git push origin --delete releases/next-release + # This job will check if the PR was closed, it's source branch is `releases/next-release` and target branch is `dev`. + # This indicates that the closed PR was the `Release PR`. + # This job will delete the tag created by AutoVer and the release branch. + clean-up-closed-release: + name: Clean up closed release + if: | + github.event.pull_request.merged == false && + github.event.pull_request.head.ref == 'releases/next-release' && + github.event.pull_request.base.ref == 'dev' + runs-on: ubuntu-latest + steps: + # Checkout a full clone of the repo + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: releases/next-release + fetch-depth: 0 + # Install .NET8 which is needed for AutoVer + - name: Setup .NET 8.0 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + # Install AutoVer which is needed to retrieve information about the current release. + - name: Install AutoVer + run: dotnet tool install --global AutoVer --version 0.0.19 + # Set up a git user to be able to run git commands later on + - name: Setup Git User + run: | + git config --global user.email "github-aws-sdk-dotnet-automation@amazon.com" + git config --global user.name "aws-sdk-dotnet-automation" + # Retrieve the tag name to be deleted + - name: Read Tag Name + id: read-tag-name + run: | + tag=$(autover changelog --tag-name) + echo "TAG=$tag" >> $GITHUB_OUTPUT + # Delete the tag created by AutoVer and the release branch + - name: Clean up + run: | + git fetch origin + git push --delete origin ${{ steps.read-tag-name.outputs.TAG }} + git push origin --delete releases/next-release \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ceed58ed..ed0c7793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,3 @@ -# Changelog - ### Release 2024-03-20 * **AWS.Messaging (0.3.0-beta)** * Added back-off logic to the SQS Poller that can perform Exponential, Interval or disable back-offs entirely. The SQS Poller will now back-off before attempting to reach SQS in case of an exception. diff --git a/src/AWS.Messaging.Lambda/AWS.Messaging.Lambda.csproj b/src/AWS.Messaging.Lambda/AWS.Messaging.Lambda.csproj index 8649cb20..f6ea3686 100644 --- a/src/AWS.Messaging.Lambda/AWS.Messaging.Lambda.csproj +++ b/src/AWS.Messaging.Lambda/AWS.Messaging.Lambda.csproj @@ -26,7 +26,7 @@ - + diff --git a/src/AWS.Messaging.Telemetry.OpenTelemetry/AWS.Messaging.Telemetry.OpenTelemetry.csproj b/src/AWS.Messaging.Telemetry.OpenTelemetry/AWS.Messaging.Telemetry.OpenTelemetry.csproj index 766f4e4a..6d523574 100644 --- a/src/AWS.Messaging.Telemetry.OpenTelemetry/AWS.Messaging.Telemetry.OpenTelemetry.csproj +++ b/src/AWS.Messaging.Telemetry.OpenTelemetry/AWS.Messaging.Telemetry.OpenTelemetry.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/AWS.Messaging/AWS.Messaging.csproj b/src/AWS.Messaging/AWS.Messaging.csproj index 564ad318..7e688b6b 100644 --- a/src/AWS.Messaging/AWS.Messaging.csproj +++ b/src/AWS.Messaging/AWS.Messaging.csproj @@ -34,7 +34,7 @@ - + From 4ac8e56afa0dcd328ba7b0c4b9da70a6e3dc92b5 Mon Sep 17 00:00:00 2001 From: Philippe El Asmar <53088140+philasmar@users.noreply.github.com> Date: Tue, 26 Mar 2024 13:28:24 +0000 Subject: [PATCH 2/4] add ability to override the version of all projects --- .github/workflows/create-release-pr.yml | 15 ++++++++++++++- .github/workflows/sync-main-dev.yml | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 6795d85e..6379c4d5 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -5,12 +5,20 @@ name: Create Release PR # This workflow is manually triggered when in preparation for a release. The workflow should be dispatched from the `dev` branch. on: workflow_dispatch: + inputs: + OVERRIDE_VERSION: + description: "Override Version" + type: string + required: false jobs: release-pr: name: Release PR runs-on: ubuntu-latest + env: + INPUT_OVERRIDE_VERSION: ${{ github.event.inputs.OVERRIDE_VERSION }} + steps: # Checkout a full clone of the repo - name: Checkout @@ -24,7 +32,7 @@ jobs: dotnet-version: 8.0.x # Install AutoVer to automate versioning and changelog creation - name: Install AutoVer - run: dotnet tool install --global AutoVer --version 0.0.19 + run: dotnet tool install --global AutoVer --version 0.0.20 # Set up a git user to be able to run git commands later on - name: Setup Git User run: | @@ -40,6 +48,11 @@ jobs: # Update the version of projects based on the change files - name: Increment Version run: autover version + if: env.INPUT_OVERRIDE_VERSION == '' + # Update the version of projects based on the override version + - name: Increment Version + run: autover version --use-version "$INPUT_OVERRIDE_VERSION" + if: env.INPUT_OVERRIDE_VERSION != '' # Update the changelog based on the change files - name: Update Changelog run: autover changelog diff --git a/.github/workflows/sync-main-dev.yml b/.github/workflows/sync-main-dev.yml index fe95296a..80489019 100644 --- a/.github/workflows/sync-main-dev.yml +++ b/.github/workflows/sync-main-dev.yml @@ -36,7 +36,7 @@ jobs: dotnet-version: 8.0.x # Install AutoVer which is needed to retrieve information about the current release. - name: Install AutoVer - run: dotnet tool install --global AutoVer --version 0.0.19 + run: dotnet tool install --global AutoVer --version 0.0.20 # Set up a git user to be able to run git commands later on - name: Setup Git User run: | @@ -102,7 +102,7 @@ jobs: dotnet-version: 8.0.x # Install AutoVer which is needed to retrieve information about the current release. - name: Install AutoVer - run: dotnet tool install --global AutoVer --version 0.0.19 + run: dotnet tool install --global AutoVer --version 0.0.20 # Set up a git user to be able to run git commands later on - name: Setup Git User run: | From b0391cc83d9d8e07acbb71547db3920cb3f8a78f Mon Sep 17 00:00:00 2001 From: Malhar Khimsaria <96malhar@gmail.com> Date: Tue, 26 Mar 2024 09:54:09 -0700 Subject: [PATCH 3/4] fix: Correctly deserialize outer envelope when processing messages relayed through EventBridge (#114) --- .../Serialization/EnvelopeSerializer.cs | 14 +- .../EventBridgeEndToEndTests.cs | 189 ++++++++++++++++++ .../SNSEndToEndTests.cs | 106 ++++++++++ .../EnvelopeSerializerTests.cs | 8 +- 4 files changed, 310 insertions(+), 7 deletions(-) create mode 100644 test/AWS.Messaging.IntegrationTests/EventBridgeEndToEndTests.cs create mode 100644 test/AWS.Messaging.IntegrationTests/SNSEndToEndTests.cs diff --git a/src/AWS.Messaging/Serialization/EnvelopeSerializer.cs b/src/AWS.Messaging/Serialization/EnvelopeSerializer.cs index 8041c3f2..ddc304d2 100644 --- a/src/AWS.Messaging/Serialization/EnvelopeSerializer.cs +++ b/src/AWS.Messaging/Serialization/EnvelopeSerializer.cs @@ -244,13 +244,13 @@ private MessageEnvelopeConfiguration GetMessageEnvelopeConfiguration(Message sqs SetSNSMetadata(envelopeConfiguration, root); } // Check if the SQS message body contains an outer envelope injected by EventBridge. - else if (root.TryGetProperty("detail", out var innerEnvelope) + else if (root.TryGetProperty("detail", out var _) && root.TryGetProperty("id", out var _) && root.TryGetProperty("version", out var _) && root.TryGetProperty("region", out var _)) { // Retrieve the inner message envelope. - envelopeConfiguration.MessageEnvelopeBody = innerEnvelope.GetString(); + envelopeConfiguration.MessageEnvelopeBody = GetJsonPropertyAsString(root, "detail"); if (string.IsNullOrEmpty(envelopeConfiguration.MessageEnvelopeBody)) { _logger.LogError("Failed to create a message envelope configuration because the EventBridge message envelope does not contain a valid 'detail' property."); @@ -316,7 +316,15 @@ private void SetEventBridgeMetadata(MessageEnvelopeConfiguration envelopeConfigu { if (node.TryGetProperty(propertyName, out var propertyValue)) { - return propertyValue.GetString(); + return propertyValue.ValueKind switch + { + JsonValueKind.Object => propertyValue.GetRawText(), + JsonValueKind.String => propertyValue.GetString(), + JsonValueKind.Number => propertyValue.ToString(), + JsonValueKind.True => propertyValue.ToString(), + JsonValueKind.False => propertyValue.ToString(), + _ => throw new InvalidDataException($"{propertyValue.ValueKind} cannot be converted to a string value"), + }; } return null; } diff --git a/test/AWS.Messaging.IntegrationTests/EventBridgeEndToEndTests.cs b/test/AWS.Messaging.IntegrationTests/EventBridgeEndToEndTests.cs new file mode 100644 index 00000000..a73b20a5 --- /dev/null +++ b/test/AWS.Messaging.IntegrationTests/EventBridgeEndToEndTests.cs @@ -0,0 +1,189 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Amazon.EventBridge.Model; +using Amazon.EventBridge; +using Amazon.SecurityToken.Model; +using Amazon.SecurityToken; +using Amazon.SQS.Model; +using Amazon.SQS; +using AWS.Messaging.IntegrationTests.Models; +using Microsoft.Extensions.DependencyInjection; +using Xunit; +using AWS.Messaging.IntegrationTests.Handlers; +using AWS.Messaging.Services; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace AWS.Messaging.IntegrationTests; + +public class EventBridgeEndToEndTests : IAsyncLifetime +{ + private readonly IAmazonEventBridge _eventBridgeClient; + private readonly IAmazonSQS _sqsClient; + private readonly IAmazonSecurityTokenService _stsClient; + private ServiceProvider _serviceProvider; + private string _eventBusArn; + private string _resourceName; + private string _sqsQueueUrl; + + public EventBridgeEndToEndTests() + { + _sqsClient = new AmazonSQSClient(); + _eventBridgeClient = new AmazonEventBridgeClient(); + _stsClient = new AmazonSecurityTokenServiceClient(); + _serviceProvider = default!; + _eventBusArn = string.Empty; + _resourceName = string.Empty; + _sqsQueueUrl = string.Empty; + } + + public async Task InitializeAsync() + { + _resourceName = $"MPFTest-{Guid.NewGuid().ToString().Split('-').Last()}"; + var createQueueResponse = await _sqsClient.CreateQueueAsync(_resourceName); + _sqsQueueUrl = createQueueResponse.QueueUrl; + var getQueueAttributesResponse = await _sqsClient.GetQueueAttributesAsync(_sqsQueueUrl, new List { "QueueArn" }); + var sqsQueueArn = getQueueAttributesResponse.QueueARN; + await _sqsClient.SetQueueAttributesAsync(new SetQueueAttributesRequest + { + QueueUrl = _sqsQueueUrl, + Attributes = new Dictionary + { + { "Policy", + @$"{{ + ""Version"": ""2008-10-17"", + ""Statement"": [ + {{ + ""Effect"": ""Allow"", + ""Principal"": {{ + ""Service"": ""events.amazonaws.com"" + }}, + ""Action"": ""SQS:SendMessage"", + ""Resource"": ""{sqsQueueArn}"" + }} + ] + }}" + } + } + }); + + var createEventBusResponse = await _eventBridgeClient.CreateEventBusAsync( + new CreateEventBusRequest + { + Name = _resourceName + }); + _eventBusArn = createEventBusResponse.EventBusArn; + + var getCallerIdentityResponse = await _stsClient.GetCallerIdentityAsync(new GetCallerIdentityRequest()); + await _eventBridgeClient.PutRuleAsync(new PutRuleRequest + { + Name = _resourceName, + EventBusName = _resourceName, + EventPattern = + @$"{{ + ""account"": [""{getCallerIdentityResponse.Account}""], + ""source"": [""/aws/messaging""] + }}" + }); + + await _eventBridgeClient.PutTargetsAsync(new PutTargetsRequest + { + EventBusName = _resourceName, + Targets = new List + { + new Target + { + Arn = sqsQueueArn, + Id = _resourceName + } + }, + Rule = _resourceName + }); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(); + serviceCollection.AddSingleton>(); + serviceCollection.AddAWSMessageBus(builder => + { + builder.AddEventBridgePublisher(_eventBusArn); + builder.AddMessageSource("/aws/messaging"); + builder.AddSQSPoller(_sqsQueueUrl, options => + { + options.VisibilityTimeoutExtensionThreshold = 3; + }); + builder.AddMessageHandler(); + }); + _serviceProvider = serviceCollection.BuildServiceProvider(); + } + + [Fact] + public async Task PublishAndProcessMessage() + { + var publishStartTime = DateTime.UtcNow; + var publisher = _serviceProvider.GetRequiredService(); + await publisher.PublishAsync(new ChatMessage + { + MessageDescription = "Test1" + }); + var publishEndTime = DateTime.UtcNow; + + var pump = _serviceProvider.GetRequiredService() as MessagePumpService; + Assert.NotNull(pump); + var source = new CancellationTokenSource(); + + await pump.StartAsync(source.Token); + + var tempStorage = _serviceProvider.GetRequiredService>(); + source.CancelAfter(60000); + while (!source.IsCancellationRequested) { } + + var messageEnvelope = Assert.Single(tempStorage.Messages); + Assert.False(string.IsNullOrEmpty(messageEnvelope.Id)); + Assert.Equal("/aws/messaging", messageEnvelope.Source.ToString()); + Assert.True(messageEnvelope.TimeStamp > publishStartTime); + Assert.True(messageEnvelope.TimeStamp < publishEndTime); + Assert.Equal("Test1", messageEnvelope.Message.MessageDescription); + } + + public async Task DisposeAsync() + { + try + { + await _eventBridgeClient.RemoveTargetsAsync(new RemoveTargetsRequest + { + EventBusName = _resourceName, + Force = true, + Ids = new List { _resourceName }, + Rule = _resourceName + }); + } + catch { } + try + { + await _eventBridgeClient.DeleteRuleAsync(new DeleteRuleRequest + { + EventBusName = _resourceName, + Name = _resourceName + }); + } + catch { } + try + { + await _eventBridgeClient.DeleteEventBusAsync(new DeleteEventBusRequest + { + Name = _resourceName + }); + } + catch { } + try + { + await _sqsClient.DeleteQueueAsync(_sqsQueueUrl); + } + catch { } + } +} diff --git a/test/AWS.Messaging.IntegrationTests/SNSEndToEndTests.cs b/test/AWS.Messaging.IntegrationTests/SNSEndToEndTests.cs new file mode 100644 index 00000000..0facbb47 --- /dev/null +++ b/test/AWS.Messaging.IntegrationTests/SNSEndToEndTests.cs @@ -0,0 +1,106 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using System; +using System.Linq; +using System.Threading.Tasks; +using Xunit; +using Amazon.SQS; +using Microsoft.Extensions.DependencyInjection; +using AWS.Messaging.IntegrationTests.Models; +using Amazon.SimpleNotificationService; +using Amazon.SimpleNotificationService.Model; +using AWS.Messaging.IntegrationTests.Handlers; +using AWS.Messaging.Services; +using Microsoft.Extensions.Hosting; +using System.Threading; + +namespace AWS.Messaging.IntegrationTests; + +public class SNSEndToEndTests : IAsyncLifetime +{ + private readonly IAmazonSimpleNotificationService _snsClient; + private readonly IAmazonSQS _sqsClient; + private ServiceProvider _serviceProvider; + private string _snsTopicArn; + private string _sqsQueueUrl; + + public SNSEndToEndTests() + { + _sqsClient = new AmazonSQSClient(); + _snsClient = new AmazonSimpleNotificationServiceClient(); + _serviceProvider = default!; + _snsTopicArn = string.Empty; + _sqsQueueUrl = string.Empty; + } + + public async Task InitializeAsync() + { + var resourceName = $"MPFTest-{Guid.NewGuid().ToString().Split('-').Last()}"; + var createQueueResponse = await _sqsClient.CreateQueueAsync(resourceName); + _sqsQueueUrl = createQueueResponse.QueueUrl; + + var createTopicResponse = await _snsClient.CreateTopicAsync(resourceName); + _snsTopicArn = createTopicResponse.TopicArn; + + await _snsClient.SubscribeQueueAsync(_snsTopicArn, _sqsClient, _sqsQueueUrl); + + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(); + serviceCollection.AddSingleton>(); + serviceCollection.AddAWSMessageBus(builder => + { + builder.AddSNSPublisher(_snsTopicArn); + builder.AddMessageSource("/aws/messaging"); + builder.AddSQSPoller(_sqsQueueUrl, options => + { + options.VisibilityTimeoutExtensionThreshold = 3; + }); + builder.AddMessageHandler(); + }); + _serviceProvider = serviceCollection.BuildServiceProvider(); + } + + [Fact] + public async Task PublishAndProcessMessage() + { + var publishStartTime = DateTime.UtcNow; + var publisher = _serviceProvider.GetRequiredService(); + await publisher.PublishAsync(new ChatMessage + { + MessageDescription = "Test1" + }); + var publishEndTime = DateTime.UtcNow; + + var pump = _serviceProvider.GetRequiredService() as MessagePumpService; + Assert.NotNull(pump); + var source = new CancellationTokenSource(); + + await pump.StartAsync(source.Token); + + var tempStorage = _serviceProvider.GetRequiredService>(); + source.CancelAfter(60000); + while (!source.IsCancellationRequested) { } + + var messageEnvelope = Assert.Single(tempStorage.Messages); + Assert.False(string.IsNullOrEmpty(messageEnvelope.Id)); + Assert.Equal("/aws/messaging", messageEnvelope.Source.ToString()); + Assert.True(messageEnvelope.TimeStamp > publishStartTime); + Assert.True(messageEnvelope.TimeStamp < publishEndTime); + Assert.Equal("Test1", messageEnvelope.Message.MessageDescription); + } + + public async Task DisposeAsync() + { + try + { + await _snsClient.DeleteTopicAsync(new DeleteTopicRequest { TopicArn = _snsTopicArn }); + } + catch { } + try + { + await _sqsClient.DeleteQueueAsync(_sqsQueueUrl); + } + catch { } + } +} diff --git a/test/AWS.Messaging.UnitTests/SerializationTests/EnvelopeSerializerTests.cs b/test/AWS.Messaging.UnitTests/SerializationTests/EnvelopeSerializerTests.cs index bd4cecd6..254d9f6a 100644 --- a/test/AWS.Messaging.UnitTests/SerializationTests/EnvelopeSerializerTests.cs +++ b/test/AWS.Messaging.UnitTests/SerializationTests/EnvelopeSerializerTests.cs @@ -268,19 +268,19 @@ public async Task ConvertToEnvelope_With_EventBridgeOuterEnvelope_In_SQSMessageB var serviceProvider = _serviceCollection.BuildServiceProvider(); var envelopeSerializer = serviceProvider.GetRequiredService(); - var innerMessageEnvelope = new MessageEnvelope + var innerMessageEnvelope = new MessageEnvelope { Id = "66659d05-e4ff-462f-81c4-09e560e66a5c", Source = new Uri("/aws/messaging", UriKind.Relative), Version = "1.0", MessageTypeIdentifier = "addressInfo", TimeStamp = _testdate, - Message = new AddressInfo + Message = JsonSerializer.Serialize(new AddressInfo { Street = "Prince St", Unit = 123, ZipCode = "00001" - } + }) }; var outerMessageEnvelope = new Dictionary @@ -293,7 +293,7 @@ public async Task ConvertToEnvelope_With_EventBridgeOuterEnvelope_In_SQSMessageB { "account", "123456789123" }, { "region", "us-west-2" }, { "resources", new List{ "arn1", "arn2" } }, - { "detail", await envelopeSerializer.SerializeAsync(innerMessageEnvelope) }, + { "detail", innerMessageEnvelope }, // The "detail" property is set as a JSON object and not a string. }; var sqsMessage = new Message From 2bf182d24a8ec47f1d141b609ec2f45387b897a6 Mon Sep 17 00:00:00 2001 From: Philippe El Asmar <53088140+philasmar@users.noreply.github.com> Date: Tue, 26 Mar 2024 15:55:51 -0400 Subject: [PATCH 4/4] chore: update README as part of release prep (#117) --- .../519a5032-f249-4598-a46e-58bba51e109e.json | 25 ++++++++++ CHANGELOG.md | 47 ++++++++++--------- README.md | 4 +- src/AWS.Messaging.Lambda/README.md | 2 +- .../README.md | 2 +- 5 files changed, 53 insertions(+), 27 deletions(-) create mode 100644 .autover/changes/519a5032-f249-4598-a46e-58bba51e109e.json diff --git a/.autover/changes/519a5032-f249-4598-a46e-58bba51e109e.json b/.autover/changes/519a5032-f249-4598-a46e-58bba51e109e.json new file mode 100644 index 00000000..8cf0c266 --- /dev/null +++ b/.autover/changes/519a5032-f249-4598-a46e-58bba51e109e.json @@ -0,0 +1,25 @@ +{ + "Projects": [ + { + "Name": "AWS.Messaging", + "Type": "Minor", + "ChangelogMessages": [ + "**AWS.Messaging** is now in _**Developer Preview**_" + ] + }, + { + "Name": "AWS.Messaging.Lambda", + "Type": "Minor", + "ChangelogMessages": [ + "**AWS.Messaging.Lambda** is now in _**Developer Preview**_" + ] + }, + { + "Name": "AWS.Messaging.Telemetry.OpenTelemetry", + "Type": "Minor", + "ChangelogMessages": [ + "**AWS.Messaging.Telemetry.OpenTelemetry** is now in _**Developer Preview**_" + ] + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ed0c7793..8d1ee91b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,25 +1,26 @@ -### Release 2024-03-20 -* **AWS.Messaging (0.3.0-beta)** - * Added back-off logic to the SQS Poller that can perform Exponential, Interval or disable back-offs entirely. The SQS Poller will now back-off before attempting to reach SQS in case of an exception. - * Added support for SourceLink -* **AWS.Messaging.Lambda (0.1.1-beta)** - * Added support for SourceLink -* **AWS.Messaging.Telemetry.OpenTelemetry (0.1.1-beta)** - * Added support for SourceLink +## Release 2024-03-20 -### Release 2024-03-08 -* **AWS.Messaging (0.2.0-beta)** - * BREAKING CHANGE: Message content is no longer included by default in logs or exceptions. Call `EnableDataMessageLogging` during setup to re-enable. - * BREAKING CHANGE: Replaced `IsSQSExceptionFatal` with `IsExceptionFatal` to allow classifying a broader range of exceptions. Expanded the default list of fatal exceptions. - * BREAKING CHANGE: Renamed `PublishAsync` to `SendAsync on the SQS-specific publisher, and create separate interface definitions to clarify "publishing" vs. "sending" depending on the destination service. - * Allow overriding the destination and AWS service client on the service-specific publishers. This allows you to set the destination and credentials on a per-message basis, which may be useful for multi-tenant applications. - * Improved validation on ECS task metadata when deriving the default value for the message source on ECS. - * Improved documentation and examples around `IMessagePublisher` +### AWS.Messaging (0.3.0-beta) +* Added back-off logic to the SQS Poller that can perform Exponential, Interval or disable back-offs entirely. The SQS Poller will now back-off before attempting to reach SQS in case of an exception. +* Added support for SourceLink +### AWS.Messaging.Lambda (0.1.1-beta) +* Added support for SourceLink +### AWS.Messaging.Telemetry.OpenTelemetry (0.1.1-beta) +* Added support for SourceLink -### Release 2023-12-08 -* **AWS.Messaging (0.1.0-beta)** - * Initial _**beta**_ release. -* **AWS.Messaging.Lambda (0.1.0-beta)** - * Initial _**beta**_ release. -* **AWS.Messaging.Telemetry.OpenTelemetry (0.1.0-beta)** - * Initial _**beta**_ release. \ No newline at end of file +## Release 2024-03-08 +### AWS.Messaging (0.2.0-beta) +* BREAKING CHANGE: Message content is no longer included by default in logs or exceptions. Call `EnableDataMessageLogging` during setup to re-enable. +* BREAKING CHANGE: Replaced `IsSQSExceptionFatal` with `IsExceptionFatal` to allow classifying a broader range of exceptions. Expanded the default list of fatal exceptions. +* BREAKING CHANGE: Renamed `PublishAsync` to `SendAsync on the SQS-specific publisher, and create separate interface definitions to clarify "publishing" vs. "sending" depending on the destination service. +* Allow overriding the destination and AWS service client on the service-specific publishers. This allows you to set the destination and credentials on a per-message basis, which may be useful for multi-tenant applications. +* Improved validation on ECS task metadata when deriving the default value for the message source on ECS. +* Improved documentation and examples around `IMessagePublisher` + +## Release 2023-12-08 +### AWS.Messaging (0.1.0-beta) +* Initial _**beta**_ release. +### AWS.Messaging.Lambda (0.1.0-beta) +* Initial _**beta**_ release. +### AWS.Messaging.Telemetry.OpenTelemetry (0.1.0-beta) +* Initial _**beta**_ release. \ No newline at end of file diff --git a/README.md b/README.md index 2b355166..e01cccf8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![nuget](https://img.shields.io/nuget/v/AWS.Messaging.svg) ![downloads](https://img.shields.io/nuget/dt/AWS.Messaging.svg)](https://www.nuget.org/packages/AWS.Messaging/) [![build status](https://img.shields.io/github/actions/workflow/status/awslabs/aws-dotnet-messaging/aws-ci.yml?branch=dev)](https://github.com/awslabs/aws-dotnet-messaging/actions/workflows/aws-ci.yml) -**Notice:** *This library is still in active development and is meant for early access and feedback purposes only. It should not be used in production environments, and any releases before 1.0.0 might include breaking changes.* +**Notice:** *This library is in **developer preview**. It provides early access to upcoming features in the **AWS Message Processing Framework for .NET**. Any releases prior to 1.0.0 might include breaking changes.* The **AWS Message Processing Framework for .NET** is an AWS-native framework that simplifies the development of .NET message processing applications that use AWS services, such as Amazon Simple Queue Service (SQS), Amazon Simple Notification Service (SNS), and Amazon EventBridge. The framework reduces the amount of boiler-plate code developers need to write, allowing you to focus on your business logic when publishing and consuming messages. * For publishers, the framework serializes the message from a .NET object to a [CloudEvents](https://cloudevents.io/)-compatible message, and then wraps that in the service-specific AWS message. It then publishes the message to the configured SQS queue, SNS topic, or EventBridge event bus. @@ -10,7 +10,7 @@ The **AWS Message Processing Framework for .NET** is an AWS-native framework tha ## Project Status -The framework is currently under active development. It already supports: +The framework is currently in **developer preview**. The following features are supported: * Publishing to SQS, SNS, and EventBridge * Handling SQS messages in a long-running, polling process * Handling SQS messages in AWS Lambda functions diff --git a/src/AWS.Messaging.Lambda/README.md b/src/AWS.Messaging.Lambda/README.md index 02f8a79a..09a2ca3d 100644 --- a/src/AWS.Messaging.Lambda/README.md +++ b/src/AWS.Messaging.Lambda/README.md @@ -1,7 +1,7 @@ # AWS Lambda plugin for AWS Message Processing Framework for .NET [![nuget](https://img.shields.io/nuget/v/AWS.Messaging.Lambda.svg) ![downloads](https://img.shields.io/nuget/dt/AWS.Messaging.Lambda.svg)](https://www.nuget.org/packages/AWS.Messaging.Lambda/) -**Notice:** *This library is still in early active development and is not ready for use beyond experimentation.* +**Notice:** *This library is in **developer preview**. It provides early access to upcoming features in the **AWS Message Processing Framework for .NET**. Any releases prior to 1.0.0 might include breaking changes.* This package is a plugin for the [AWS Message Processing Framework for .NET](https://github.com/awslabs/aws-dotnet-messaging) that allows a .NET Lambda function to handle messages that were published by the framework. diff --git a/src/AWS.Messaging.Telemetry.OpenTelemetry/README.md b/src/AWS.Messaging.Telemetry.OpenTelemetry/README.md index f70b0861..2f5d54a3 100644 --- a/src/AWS.Messaging.Telemetry.OpenTelemetry/README.md +++ b/src/AWS.Messaging.Telemetry.OpenTelemetry/README.md @@ -1,7 +1,7 @@ # OpenTelemetry plugin for AWS Message Processing Framework for .NET [![nuget](https://img.shields.io/nuget/v/AWS.Messaging.Telemetry.OpenTelemetry.svg) ![downloads](https://img.shields.io/nuget/dt/AWS.Messaging.Telemetry.OpenTelemetry.svg)](https://www.nuget.org/packages/AWS.Messaging.Telemetry.OpenTelemetry/) -**Notice:** *This library is still in early active development and is not ready for use beyond experimentation.* +**Notice:** *This library is in **developer preview**. It provides early access to upcoming features in the **AWS Message Processing Framework for .NET**. Any releases prior to 1.0.0 might include breaking changes.* This package is an [Instrumentation Library](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/glossary.md#instrumentation-library), which instruments the [AWS Message Processing Framework for .NET](https://github.com/awslabs/aws-dotnet-messaging) to collect traces about