-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve WithExtensions so it can be used universally (#92)
- Loading branch information
Showing
4 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="ExtensionsSpecs.cs" company="Akka.NET Project"> | ||
// Copyright (C) 2013-2022 .NET Foundation <https://github.com/akkadotnet/akka.net> | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
using Akka.Actor; | ||
using Akka.Event; | ||
using Akka.TestKit.Xunit2.Internals; | ||
using FluentAssertions; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
using LogLevel = Microsoft.Extensions.Logging.LogLevel; | ||
|
||
namespace Akka.Hosting.Tests; | ||
|
||
public class ExtensionsSpecs | ||
{ | ||
private readonly ITestOutputHelper _helper; | ||
|
||
public ExtensionsSpecs(ITestOutputHelper helper) | ||
{ | ||
_helper = helper; | ||
} | ||
|
||
public async Task<IHost> StartHost(Action<AkkaConfigurationBuilder, IServiceProvider> testSetup) | ||
{ | ||
var host = new HostBuilder() | ||
.ConfigureLogging(builder => | ||
{ | ||
builder.AddProvider(new XUnitLoggerProvider(_helper, LogLevel.Information)); | ||
}) | ||
.ConfigureServices(service => | ||
{ | ||
service.AddAkka("TestActorSystem", testSetup); | ||
}).Build(); | ||
|
||
await host.StartAsync(); | ||
return host; | ||
} | ||
|
||
[Fact(DisplayName = "WithExtensions should not override extensions declared in HOCON")] | ||
public async Task ShouldNotOverrideHocon() | ||
{ | ||
using var host = await StartHost((builder, _) => | ||
{ | ||
builder.AddHocon("akka.extensions = [\"Akka.Hosting.Tests.ExtensionsSpecs+FakeExtensionOneProvider, Akka.Hosting.Tests\"]"); | ||
builder.WithExtensions(typeof(FakeExtensionTwoProvider)); | ||
}); | ||
|
||
var system = host.Services.GetRequiredService<ActorSystem>(); | ||
system.TryGetExtension<FakeExtensionOne>(out _).Should().BeTrue(); | ||
system.TryGetExtension<FakeExtensionTwo>(out _).Should().BeTrue(); | ||
} | ||
|
||
[Fact(DisplayName = "WithExtensions should be able to be called multiple times")] | ||
public async Task CanBeCalledMultipleTimes() | ||
{ | ||
using var host = await StartHost((builder, _) => | ||
{ | ||
builder.WithExtensions(typeof(FakeExtensionOneProvider)); | ||
builder.WithExtensions(typeof(FakeExtensionTwoProvider)); | ||
}); | ||
|
||
var system = host.Services.GetRequiredService<ActorSystem>(); | ||
system.TryGetExtension<FakeExtensionOne>(out _).Should().BeTrue(); | ||
system.TryGetExtension<FakeExtensionTwo>(out _).Should().BeTrue(); | ||
} | ||
|
||
public class FakeExtensionOne: IExtension | ||
{ | ||
} | ||
|
||
public class FakeExtensionOneProvider : ExtensionIdProvider<FakeExtensionOne> | ||
{ | ||
public override FakeExtensionOne CreateExtension(ExtendedActorSystem system) | ||
{ | ||
return new FakeExtensionOne(); | ||
} | ||
} | ||
|
||
public class FakeExtensionTwo: IExtension | ||
{ | ||
} | ||
|
||
public class FakeExtensionTwoProvider : ExtensionIdProvider<FakeExtensionTwo> | ||
{ | ||
public override FakeExtensionTwo CreateExtension(ExtendedActorSystem system) | ||
{ | ||
return new FakeExtensionTwo(); | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
using System; | ||
using Microsoft.Extensions.Logging; | ||
using Xunit.Abstractions; | ||
|
||
namespace Akka.Hosting.Tests; | ||
|
||
public class XUnitLogger: ILogger | ||
{ | ||
private const string NullFormatted = "[null]"; | ||
|
||
private readonly string _category; | ||
private readonly ITestOutputHelper _helper; | ||
private readonly LogLevel _logLevel; | ||
|
||
public XUnitLogger(string category, ITestOutputHelper helper, LogLevel logLevel) | ||
{ | ||
_category = category; | ||
_helper = helper; | ||
_logLevel = logLevel; | ||
} | ||
|
||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) | ||
{ | ||
if (!IsEnabled(logLevel)) | ||
return; | ||
|
||
if (!TryFormatMessage(state, exception, formatter, out var formattedMessage)) | ||
return; | ||
|
||
WriteLogEntry(logLevel, eventId, formattedMessage, exception); | ||
} | ||
|
||
private void WriteLogEntry(LogLevel logLevel, EventId eventId, string message, Exception exception) | ||
{ | ||
var level = logLevel switch | ||
{ | ||
LogLevel.Critical => "CRT", | ||
LogLevel.Debug => "DBG", | ||
LogLevel.Error => "ERR", | ||
LogLevel.Information => "INF", | ||
LogLevel.Warning => "WRN", | ||
LogLevel.Trace => "DBG", | ||
_ => "???" | ||
}; | ||
|
||
var msg = $"{DateTime.Now}:{level}:{_category}:{eventId} {message}"; | ||
if (exception != null) | ||
msg += $"\n{exception.GetType()} {exception.Message}\n{exception.StackTrace}"; | ||
_helper.WriteLine(msg); | ||
} | ||
|
||
public bool IsEnabled(LogLevel logLevel) | ||
{ | ||
return logLevel switch | ||
{ | ||
LogLevel.None => false, | ||
_ => logLevel >= _logLevel | ||
}; | ||
} | ||
|
||
public IDisposable BeginScope<TState>(TState state) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
private static bool TryFormatMessage<TState>( | ||
TState state, | ||
Exception exception, | ||
Func<TState, Exception, string> formatter, | ||
out string result) | ||
{ | ||
formatter = formatter ?? throw new ArgumentNullException(nameof(formatter)); | ||
|
||
var formattedMessage = formatter(state, exception); | ||
if (formattedMessage == NullFormatted) | ||
{ | ||
result = null; | ||
return false; | ||
} | ||
|
||
result = formattedMessage; | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Microsoft.Extensions.Logging; | ||
using Xunit.Abstractions; | ||
|
||
namespace Akka.Hosting.Tests; | ||
|
||
public class XUnitLoggerProvider : ILoggerProvider | ||
{ | ||
private readonly ITestOutputHelper _helper; | ||
private readonly LogLevel _logLevel; | ||
|
||
public XUnitLoggerProvider(ITestOutputHelper helper, LogLevel logLevel) | ||
{ | ||
_helper = helper; | ||
_logLevel = logLevel; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
// no-op | ||
} | ||
|
||
public ILogger CreateLogger(string categoryName) | ||
{ | ||
return new XUnitLogger(categoryName, _helper, _logLevel); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters