Skip to content

Commit

Permalink
Improvements to Chaos testing
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremydmiller committed Apr 14, 2023
1 parent fd0f9b8 commit e165d40
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 120 deletions.
14 changes: 9 additions & 5 deletions src/Testing/ChaosTesting/ChaosDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
using Lamar;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Oakton.Resources;
using Wolverine;
using Wolverine.ErrorHandling;
using Wolverine.Runtime;
using Xunit.Abstractions;

namespace ChaosTesting;

Expand Down Expand Up @@ -49,14 +51,16 @@ public override string ToString()

public class ChaosDriver : IAsyncDisposable, IDisposable
{
private readonly ITestOutputHelper _output;
private readonly IMessageStorageStrategy _storage;
private readonly TransportConfiguration _transportConfiguration;
private readonly Dictionary<string, IHost> _senders = new();
private readonly Dictionary<string, IHost> _receivers = new();


public ChaosDriver(IMessageStorageStrategy storage, TransportConfiguration transportConfiguration)
public ChaosDriver(ITestOutputHelper output, IMessageStorageStrategy storage, TransportConfiguration transportConfiguration)
{
_output = output;
_storage = storage;
_transportConfiguration = transportConfiguration;
}
Expand Down Expand Up @@ -143,10 +147,6 @@ public async Task SendMessages(string name, int number)
}
}
}

// TODO -- check the queue counts



public async Task<bool> WaitForAllMessagingToComplete(TimeSpan time)
{
Expand Down Expand Up @@ -200,6 +200,8 @@ public async Task<IHost> StartReceiver(string name)
opts.Services.AddResourceSetupOnStartup();
opts.Services.AddSingleton<ILoggerProvider>(new OutputLoggerProvider(_output));
_transportConfiguration.ConfigureReceiver(opts);
}).StartAsync();

Expand All @@ -226,6 +228,8 @@ public async Task<IHost> StartSender(string name)
opts.Discovery.DisableConventionalDiscovery().IncludeType<SendMessageHandler>();
opts.PublishMessage<SendMessages>().ToLocalQueue("SendMessages").MaximumParallelMessages(10);
opts.Services.AddSingleton<ILoggerProvider>(new OutputLoggerProvider(_output));
_transportConfiguration.ConfigureSender(opts);
}).StartAsync();
Expand Down
219 changes: 150 additions & 69 deletions src/Testing/ChaosTesting/ChaosSpecifications.cs
Original file line number Diff line number Diff line change
@@ -1,89 +1,170 @@
using JasperFx.Core.Reflection;
using ChaosTesting.Scripts;
using JasperFx.Core.Reflection;
using Shouldly;
using Wolverine.RabbitMQ;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace ChaosTesting;

public class ChaosSpecifications
{
static ChaosSpecifications()
private readonly ITestOutputHelper _output;
private static TransportConfiguration RabbitMqOneInlineListener = new TransportConfiguration("Rabbit MQ Inline w/ One Listener")
{
AllScripts = typeof(ChaosSpecifications)
.Assembly
.GetTypes()
.Where(x => x.IsConcreteTypeOf<ChaosScript>())
.Select(Activator.CreateInstance)
.OfType<ChaosScript>()
.ToArray();
}

public static ChaosScript[] AllScripts { get; }
ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting(),
ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting()
};

private static TransportConfiguration RabbitMqFiveParallelInlineListeners = new TransportConfiguration("Rabbit MQ Inline w/ Five Listeners")
{
ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.ListenerCount(5)),
ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting()
};

private static TransportConfiguration RabbitMqBufferedListener = new TransportConfiguration("Rabbit MQ Buffered w/ 1 Listener")
{
ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.BufferedInMemory()),
ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.BufferedInMemory())
};

private static TransportConfiguration RabbitMqDurableListener = new TransportConfiguration("Rabbit MQ Durable w/ 1 Listener")
{
ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.UseDurableInbox()),
ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.UseDurableOutbox())
};

private static TransportConfiguration RabbitMqFiveBufferedListeners = new TransportConfiguration("Rabbit MQ Buffered w/ 5 Listeners")
{
ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.BufferedInMemory().ListenerCount(5)),
ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.BufferedInMemory())
};

private static TransportConfiguration RabbitMqFiveDurableListeners = new TransportConfiguration("Rabbit MQ Durable w/ 5 Listeners")
{
ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.UseDurableInbox().ListenerCount(5)),
ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.UseDurableOutbox())
};

public static IMessageStorageStrategy[] Storage { get; } = { new MartenStorageStrategy() };

public static IEnumerable<TransportConfiguration> TransportConfigurations()
public ChaosSpecifications(ITestOutputHelper output)
{
yield return new TransportConfiguration("Rabbit MQ Inline w/ One Listener")
{
ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting(),
ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting()
};

// yield return new TransportConfiguration("Rabbit MQ Inline w/ Five Listeners")
// {
// ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.ListenerCount(5)),
// ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting()
// };
//
// yield return new TransportConfiguration("Rabbit MQ Buffered w/ 1 Listener")
// {
// ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.BufferedInMemory()),
// ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.BufferedInMemory())
// };
//
// yield return new TransportConfiguration("Rabbit MQ Buffered w/ 5 Listeners")
// {
// ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.BufferedInMemory().ListenerCount(5)),
// ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.BufferedInMemory())
// };
//
// yield return new TransportConfiguration("Rabbit MQ Durable w/ 1 Listener")
// {
// ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.UseDurableInbox()),
// ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.UseDurableOutbox())
// };
//
// yield return new TransportConfiguration("Rabbit MQ Durable w/ 5 Listeners")
// {
// ConfigureReceiver = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureListeners(x => x.UseDurableInbox().ListenerCount(5)),
// ConfigureSender = opts => opts.UseRabbitMq().AutoProvision().UseConventionalRouting().ConfigureSenders(x => x.UseDurableOutbox())
// };


_output = output;
}

public static IEnumerable<object[]> Data()
protected async Task execute<TStorage, TScript>(TransportConfiguration configuration)
where TStorage : IMessageStorageStrategy, new()
where TScript : ChaosScript, new()
{
foreach (var transportConfiguration in TransportConfigurations())
{
foreach (var storageStrategy in Storage)
{
foreach (var script in AllScripts)
{
yield return new object[] {transportConfiguration, storageStrategy, script};
}
}
}
}

[Theory]
[MemberData(nameof(Data))]
public async Task chaos_and_load_specs(TransportConfiguration transportConfiguration, IMessageStorageStrategy storageStrategy, ChaosScript script)
{
using var driver = new ChaosDriver(storageStrategy, transportConfiguration);
using var driver = new ChaosDriver(_output, new TStorage(), configuration);
await driver.InitializeAsync();

var script = new TScript();
await script.Drive(driver);

var completed = await driver.WaitForAllMessagingToComplete(script.TimeOut);

completed.ShouldBeTrue();
}

[Fact]
public Task RabbitMqOneInlineListener_Marten_Simple() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqOneInlineListener);

[Fact]
public Task RabbitMqFiveParallelInlineListeners_Marten_Simple() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveParallelInlineListeners);

[Fact]
public Task RabbitMqBufferedListener_Marten_Simple() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqBufferedListener);

[Fact]
public Task RabbitMqFiveBufferedListeners_Marten_Simple() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveBufferedListeners);


[Fact]
public Task RabbitMqDurableListener_Marten_Simple() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqDurableListener);

[Fact]
public Task RabbitMqFiveDurableListeners_Marten_Simple() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveDurableListeners);















[Fact]
public Task RabbitMqOneInlineListener_Marten_ReceiverStartsLater() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqOneInlineListener);

[Fact]
public Task RabbitMqFiveParallelInlineListeners_Marten_ReceiverStartsLater() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveParallelInlineListeners);

[Fact]
public Task RabbitMqBufferedListener_Marten_ReceiverStartsLater() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqBufferedListener);

[Fact]
public Task RabbitMqFiveBufferedListeners_Marten_ReceiverStartsLater() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveBufferedListeners);


[Fact]
public Task RabbitMqDurableListener_Marten_ReceiverStartsLater() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqDurableListener);

[Fact]
public Task RabbitMqFiveDurableListeners_Marten_ReceiverStartsLater() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveDurableListeners);






[Fact]
public Task RabbitMqOneInlineListener_Marten_ReceiverGoesUpAndDown() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqOneInlineListener);

[Fact]
public Task RabbitMqFiveParallelInlineListeners_Marten_ReceiverGoesUpAndDown() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveParallelInlineListeners);

[Fact]
public Task RabbitMqBufferedListener_Marten_ReceiverGoesUpAndDown() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqBufferedListener);

[Fact]
public Task RabbitMqFiveBufferedListeners_Marten_ReceiverGoesUpAndDown() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveBufferedListeners);


[Fact]
public Task RabbitMqDurableListener_Marten_ReceiverGoesUpAndDown() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqDurableListener);

[Fact]
public Task RabbitMqFiveDurableListeners_Marten_ReceiverGoesUpAndDown() =>
execute<MartenStorageStrategy, Simplistic>(RabbitMqFiveDurableListeners);







}
1 change: 1 addition & 0 deletions src/Testing/ChaosTesting/ChaosTesting.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="Shouldly" Version="4.1.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
66 changes: 66 additions & 0 deletions src/Testing/ChaosTesting/Logger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Microsoft.Extensions.Logging;
using Xunit.Abstractions;

namespace ChaosTesting;

public class OutputLoggerProvider : ILoggerProvider
{
private readonly ITestOutputHelper _output;

public OutputLoggerProvider(ITestOutputHelper output)
{
_output = output;
}


public void Dispose()
{

}

public ILogger CreateLogger(string categoryName)
{
return new XUnitLogger(_output, categoryName);
}
}

public class XUnitLogger : ILogger
{
private readonly ITestOutputHelper _testOutputHelper;
private readonly string _categoryName;

public XUnitLogger(ITestOutputHelper testOutputHelper, string categoryName)
{
_testOutputHelper = testOutputHelper;
_categoryName = categoryName;
}

public class Disposable : IDisposable
{
public void Dispose()
{
}
}

public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;

public IDisposable BeginScope<TState>(TState state) => new Disposable();

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (exception is DivideByZeroException) return;
if (exception is BadImageFormatException) return;

if (_categoryName == "Wolverine.Runtime.WolverineRuntime/Information" &&
logLevel == LogLevel.Information) return;

var text = formatter(state, exception);

_testOutputHelper.WriteLine($"{_categoryName}/{logLevel}: {text}");

if (exception != null)
{
_testOutputHelper.WriteLine(exception.ToString());
}
}
}
Loading

0 comments on commit e165d40

Please sign in to comment.