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

Integration tests #381

Merged
merged 27 commits into from
Aug 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bb0a576
Ignore UpgradeLog*.htm
martincostello Aug 18, 2018
8d46a51
Add missing collections
martincostello Aug 18, 2018
67ec7b9
Simplify and update test dependencies
martincostello Aug 18, 2018
55107fd
Add xunit logging infrastructure
martincostello Aug 18, 2018
ccb6fcd
Update README note about ILoggerFactory
martincostello Aug 18, 2018
15b450c
Shuffle around references
martincostello Aug 18, 2018
2f64da5
Add Build.ps1 to solution
martincostello Aug 18, 2018
243cc06
Fix broken integration tests
martincostello Aug 18, 2018
a58876c
Enable some skipped tests
martincostello Aug 18, 2018
8120fed
Refactor test configuration
martincostello Aug 18, 2018
f835732
Add xunit configuration files
martincostello Aug 18, 2018
4c480c3
More test configuration refactor
martincostello Aug 18, 2018
bf78f30
Remove remaining RegionEndpoint usages
martincostello Aug 18, 2018
bfc7f82
Remove hard-coded URL
martincostello Aug 18, 2018
17cd680
Fix integration tests
martincostello Aug 18, 2018
bef5e32
Create integration test fixture
martincostello Aug 18, 2018
f41c0d3
Tweak tests to try and fix them
martincostello Aug 18, 2018
2ac6ef1
Add AWS-specific fact and theory attributes
martincostello Aug 18, 2018
db6f7d1
Run integration tests
martincostello Aug 18, 2018
1e85496
Run goaws in CI
martincostello Aug 18, 2018
d4894b4
Try and prevent queue collisions
martincostello Aug 18, 2018
505b12e
Improve assert messages
martincostello Aug 18, 2018
399e9c9
Disable tests for region failover in simulator
martincostello Aug 18, 2018
2742635
Use MartinCostello.Logging.XUnit
martincostello Aug 19, 2018
a6d72f3
Update xunit-logging
martincostello Aug 30, 2018
5ec3675
Make integration tests opt-in on Windows
martincostello Aug 30, 2018
5073b8c
Do not start docker container if integration tests disabled
martincostello Aug 30, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
_ReSharper*
.dotnetcli
.vs
.DS_Store
artifacts
bin
lint.db
obj
out
packages
project.lock.json
thumbs.db
BenchmarkDotNet.Artifacts
TestResult.xml
UpgradeLog*.htm
!3rdparty/*/bin
lint.db
BenchmarkDotNet.Artifacts
.DS_Store
thumbs.db
13 changes: 12 additions & 1 deletion Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ param(
[Parameter(Mandatory = $false)][string] $VersionSuffix = "",
[Parameter(Mandatory = $false)][string] $OutputPath = "",
[Parameter(Mandatory = $false)][switch] $SkipTests,
[Parameter(Mandatory = $false)][switch] $EnableCodeCoverage
[Parameter(Mandatory = $false)][switch] $EnableCodeCoverage,
[Parameter(Mandatory = $false)][switch] $EnableIntegrationTests
)

$ErrorActionPreference = "Stop"
Expand All @@ -20,6 +21,10 @@ $testProjects = @(
(Join-Path $solutionPath "JustSaying.UnitTests\JustSaying.UnitTests.csproj")
)

if ($EnableIntegrationTests -eq $true) {
$testProjects += (Join-Path $solutionPath "JustSaying.IntegrationTests\JustSaying.IntegrationTests.csproj");
}

$dotnetVersion = (Get-Content $sdkFile | Out-String | ConvertFrom-Json).sdk.version

if ($OutputPath -eq "") {
Expand Down Expand Up @@ -139,6 +144,12 @@ ForEach ($libraryProject in $libraryProjects) {
DotNetPack $libraryProject
}

if (($null -ne $env:CI) -And ($EnableIntegrationTests -eq $true)) {
& docker pull pafortin/goaws
& docker run -d --name goaws -p 4100:4100 pafortin/goaws
$env:AWS_SERVICE_URL="http://localhost:4100"
}

if ($SkipTests -eq $false) {
Write-Host "Running tests..." -ForegroundColor Green
ForEach ($testProject in $testProjects) {
Expand Down
19 changes: 19 additions & 0 deletions JustSaying.IntegrationTests/AwsFactAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using JustSaying.TestingFramework;
using Xunit;

namespace JustSaying.IntegrationTests
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class AwsFactAttribute : FactAttribute
{
public AwsFactAttribute()
: base()
{
if (!TestEnvironment.IsSimulatorConfigured && !TestEnvironment.HasCredentials)
{
Skip = "This test requires either an AWS simulator URL or AWS credentials to be configured.";
}
}
}
}
19 changes: 19 additions & 0 deletions JustSaying.IntegrationTests/AwsTheoryAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using JustSaying.TestingFramework;
using Xunit;

namespace JustSaying.IntegrationTests
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class AwsTheoryAttribute : TheoryAttribute
{
public AwsTheoryAttribute()
: base()
{
if (!TestEnvironment.IsSimulatorConfigured && !TestEnvironment.HasCredentials)
{
Skip = "This test requires either an AWS simulator URL or AWS credentials to be configured.";
}
}
}
}
106 changes: 70 additions & 36 deletions JustSaying.IntegrationTests/AwsTools/BasicHandlingThrottlingTest.cs
Original file line number Diff line number Diff line change
@@ -1,96 +1,130 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Amazon;
using Amazon.SQS.Model;
using JustSaying.AwsTools.MessageHandling;
using JustSaying.AwsTools.QueueCreation;
using JustSaying.Messaging.MessageHandling;
using JustSaying.Messaging.MessageSerialisation;
using JustSaying.Messaging.Monitoring;
using JustSaying.TestingFramework;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
using Xunit.Abstractions;

namespace JustSaying.IntegrationTests.AwsTools
{
// OK, I know it ain't pretty, but we needed this asap & it does the job. Deal with it. :)]
[Collection(GlobalSetup.CollectionName)]
public class BasicHandlingThrottlingTest
{
[Xunit.Theory(Skip= "Explicitly ran")]
public BasicHandlingThrottlingTest(ITestOutputHelper outputHelper)
{
OutputHelper = outputHelper;
}

private ITestOutputHelper OutputHelper { get; }

[AwsTheory]
[InlineData(1000)]
// Use this to manually test the performance / throttling of getting messages out of the queue.
public async Task HandlingManyMessages(int throttleMessageCount)
{
var locker = new object();
var awsQueueClient = CreateMeABus.DefaultClientFactory().GetSqsClient(RegionEndpoint.EUWest1);
// Arrange
var fixture = new JustSayingFixture(OutputHelper);
var client = fixture.CreateSqsClient();

var queue = new SqsQueueByName(fixture.Region, fixture.UniqueName, client, 1, fixture.LoggerFactory);

var q = new SqsQueueByName(RegionEndpoint.EUWest1, "throttle_test", awsQueueClient, 1, new LoggerFactory());
if (!await q.ExistsAsync())
if (!await queue.ExistsAsync())
{
await q.CreateAsync(new SqsBasicConfiguration());
await Task.Delay(TimeSpan.FromMinutes(1)); // wait 60 secs for queue creation to be guaranteed completed by aws. :(
await queue.CreateAsync(new SqsBasicConfiguration());

if (!fixture.IsSimulator)
{
// Wait for up to 60 secs for queue creation to be guaranteed completed by AWS
using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)))
{
while (!cts.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(2));

if (await queue.ExistsAsync())
{
break;
}
}
}
}
}

Assert.True(await q.ExistsAsync());
Assert.True(await queue.ExistsAsync(), "The queue was not created.");

Console.WriteLine($"{DateTime.Now} - Adding {throttleMessageCount} messages to the queue.");
OutputHelper.WriteLine($"{DateTime.Now} - Adding {throttleMessageCount} messages to the queue.");

var entriesAdded = 0;

// Add some messages
do
{
var entries = new List<SendMessageBatchRequestEntry>();

for (var j = 0; j < 10; j++)
{
var batchEntry = new SendMessageBatchRequestEntry
{
MessageBody = "{\"Subject\":\"GenericMessage\", \"Message\": \"" + entriesAdded.ToString() + "\"}",
Id = Guid.NewGuid().ToString()
};
{
MessageBody = $"{{\"Subject\":\"GenericMessage\", \"Message\": \"{entriesAdded}\"}}",
Id = Guid.NewGuid().ToString()
};

entries.Add(batchEntry);
entriesAdded++;
}
await awsQueueClient.SendMessageBatchAsync(new SendMessageBatchRequest { QueueUrl = q.Url, Entries = entries });

await client.SendMessageBatchAsync(queue.Url, entries);
}
while (entriesAdded < throttleMessageCount);

Console.WriteLine($"{DateTime.Now} - Done adding messages.");
OutputHelper.WriteLine($"{DateTime.Now} - Done adding messages.");

var handleCount = 0;
var serialisations = Substitute.For<IMessageSerialisationRegister>();
var monitor = Substitute.For<IMessageMonitor>();
var handler = Substitute.For<IHandlerAsync<GenericMessage>>();
handler.Handle(null).ReturnsForAnyArgs(true).AndDoes(x => {lock (locker) { handleCount++; } });
var handler = Substitute.For<IHandlerAsync<SimpleMessage>>();
handler.Handle(null).ReturnsForAnyArgs(true).AndDoes(_ => Interlocked.Increment(ref handleCount));

serialisations.DeserializeMessage(string.Empty).ReturnsForAnyArgs(new GenericMessage());
var listener = new SqsNotificationListener(q, serialisations, monitor, new LoggerFactory());
serialisations.DeserializeMessage(string.Empty).ReturnsForAnyArgs(new SimpleMessage());
var listener = new SqsNotificationListener(queue, serialisations, monitor, fixture.LoggerFactory);
listener.AddMessageHandler(() => handler);

var stopwatch = new Stopwatch();
stopwatch.Start();
// Act
var stopwatch = Stopwatch.StartNew();

listener.Listen();
var waitCount = 0;
do

using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5)))
{
await Task.Delay(TimeSpan.FromSeconds(5));
Console.WriteLine($"{DateTime.Now} - Handled {handleCount} messages. Waiting for completion.");
waitCount++;
do
{
if (!fixture.IsSimulator)
{
await Task.Delay(TimeSpan.FromSeconds(5));
}

OutputHelper.WriteLine($"{DateTime.Now} - Handled {handleCount} messages. Waiting for completion.");
}
while (handleCount < throttleMessageCount && !cts.IsCancellationRequested);
}
while (handleCount < throttleMessageCount && waitCount < 100);

listener.StopListening();
stopwatch.Stop();

Console.WriteLine($"{DateTime.Now} - Handled {handleCount} messages.");
Console.WriteLine($"{DateTime.Now} - Took {stopwatch.ElapsedMilliseconds} ms");
Console.WriteLine(
$"{DateTime.Now} - Throughput {(float) handleCount/stopwatch.ElapsedMilliseconds*1000} msg/sec");
OutputHelper.WriteLine($"{DateTime.Now} - Handled {handleCount:N0} messages.");
OutputHelper.WriteLine($"{DateTime.Now} - Took {stopwatch.ElapsedMilliseconds} ms");
OutputHelper.WriteLine($"{DateTime.Now} - Throughput {(float)handleCount / stopwatch.ElapsedMilliseconds * 1000} messages/second");

// Assert
Assert.Equal(throttleMessageCount, handleCount);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,26 @@

namespace JustSaying.IntegrationTests.AwsTools
{
public class NoTopicCreationAwsClientFactory : IAwsClientFactory
internal class NoTopicCreationAwsClientFactory : IAwsClientFactory
{

public IAmazonSimpleNotificationService GetSnsClient(RegionEndpoint region)
{
var innerClient = CreateMeABus.DefaultClientFactory().GetSnsClient(region);
var client = Substitute.For<IAmazonSimpleNotificationService>();

client.CreateTopicAsync(Arg.Any<CreateTopicRequest>())
.ThrowsForAnyArgs(x => new AuthorizationErrorException("Denied"));
.ThrowsForAnyArgs(x => new AuthorizationErrorException("Denied"));

client.FindTopicAsync(Arg.Any<string>())
.ReturnsForAnyArgs(r => innerClient.FindTopicAsync(r.Arg<string>()));
.ReturnsForAnyArgs(r => innerClient.FindTopicAsync(r.Arg<string>()));

client.GetTopicAttributesAsync(Arg.Any<string>())
.ReturnsForAnyArgs(r => innerClient.GetTopicAttributesAsync(r.Arg<string>()));
.ReturnsForAnyArgs(r => innerClient.GetTopicAttributesAsync(r.Arg<string>()));

return client;
}


public IAmazonSQS GetSqsClient(RegionEndpoint region)
{
var innerClient = CreateMeABus.DefaultClientFactory().GetSqsClient(region);
return innerClient;
}
=> CreateMeABus.DefaultClientFactory().GetSqsClient(region);
}
}
Loading