Skip to content

Commit

Permalink
Fixed a bug in the launchpad web fixture that was trying to dispose o…
Browse files Browse the repository at this point in the history
…f the host even if it had not yet been set properly. (#1792)
  • Loading branch information
david-driscoll authored Feb 3, 2024
1 parent 219e5a3 commit a4f83ca
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 92 deletions.
7 changes: 7 additions & 0 deletions .build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ public static int Main()
public Target Restore => _ => _.Inherit<ICanRestoreWithDotNetCore>(x => x.CoreRestore);
public Target Test => _ => _.Inherit<ICanTestWithDotNetCore>(x => x.CoreTest);

/// <summary>
/// Only run the JetBrains cleanup code when running on the server
/// </summary>
public Target JetBrainsCleanupCode => _ => _
.Inherit<ICanDotNetFormat>(x => x.JetBrainsCleanupCode)
.OnlyWhenStatic(() => IsServerBuild);

[Solution(GenerateProjects = true)] private Solution Solution { get; } = null!;
Nuke.Common.ProjectModel.Solution IHaveSolution.Solution => Solution;

Expand Down
173 changes: 81 additions & 92 deletions src/AspNetCore.Testing/LaunchPadWebAppFixture.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using Alba;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

namespace Rocket.Surgery.LaunchPad.AspNetCore.Testing;

/// <summary>
/// A fixture used to bootstrap the alba test server with a custom sql extension
/// A fixture used to bootstrap the alba test server with a custom sql extension
/// </summary>
public abstract class LaunchPadWebAppFixture<TEntryPoint> : ILaunchPadWebAppFixture
where TEntryPoint : class
Expand All @@ -16,105 +15,111 @@ public abstract class LaunchPadWebAppFixture<TEntryPoint> : ILaunchPadWebAppFixt
private IAlbaHost? _host;

/// <summary>
/// The base constructor for use with hte web app fixture
/// The base constructor for use with hte web app fixture
/// </summary>
/// <param name="resettableAlbaExtension"></param>
/// <param name="extensions"></param>
protected LaunchPadWebAppFixture(IResettableAlbaExtension? resettableAlbaExtension, params IAlbaExtension[] extensions)
protected LaunchPadWebAppFixture(IResettableAlbaExtension resettableAlbaExtension, params IAlbaExtension[] extensions) : this(
[resettableAlbaExtension, ..extensions,]
)
{
_loggerFactory = new AppFixtureLoggerFactory();
_sqlExtension = resettableAlbaExtension;
_extensions = new IAlbaExtension[]
{
new LaunchPadExtension(this, _loggerFactory),
// ReSharper disable once NullableWarningSuppressionIsUsed
_sqlExtension!
}
// ReSharper disable once NullableWarningSuppressionIsUsed
.Where(z => z != null!)
.Concat(extensions)
.ToArray();
}

// ReSharper disable once NullableWarningSuppressionIsUsed
/// <summary>
/// The underlying alba host
/// The base constructor for use with hte web app fixture
/// </summary>
public IAlbaHost AlbaHost => _host!;
/// <param name="extensions"></param>
protected LaunchPadWebAppFixture(params IAlbaExtension[] extensions)
{
_loggerFactory = new();
_extensions = [new LaunchPadExtension(this, _loggerFactory), ..extensions,];
}

/// <summary>
/// Set the loggerfactory when initializing the test
/// Method used to start the alba host
/// </summary>
/// <param name="loggerFactory"></param>
public void SetLoggerFactory(ILoggerFactory loggerFactory)
public async Task InitializeAsync()
{
_loggerFactory.SetLoggerFactory(loggerFactory);
_host = await Alba.AlbaHost.For<TEntryPoint>(_extensions);
}

/// <summary>
/// Method to reset the database if provided
/// Method used to dispose the alba host
/// </summary>
public void Reset()
public async Task DisposeAsync()
{
if (_sqlExtension is null || _host is null) return;
_sqlExtension.Reset(AlbaHost.Services);
if (_host is { }) await _host.DisposeAsync();
_loggerFactory.Dispose();
if (_sqlExtension != null) await _sqlExtension.DisposeAsync();
}

/// <summary>
/// Method to reset the database if provided
/// The dispose method
/// </summary>
public async Task ResetAsync()
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (_sqlExtension is null || _host is null) return;
if (!disposing) return;
_loggerFactory.Dispose();
_sqlExtension?.Dispose();
_host?.Dispose();
}

await _sqlExtension.ResetAsync(AlbaHost.Services);
// ReSharper disable once NullableWarningSuppressionIsUsed
/// <summary>
/// The underlying alba host
/// </summary>
public IAlbaHost AlbaHost => _host!;

/// <summary>
/// Set the logger factory when initializing the test
/// </summary>
/// <param name="loggerFactory"></param>
public void SetLoggerFactory(ILoggerFactory loggerFactory)
{
_loggerFactory.SetLoggerFactory(loggerFactory);
}

/// <summary>
/// Method used to start the alba host
/// Method to reset the database if provided
/// </summary>
public async Task InitializeAsync()
public void Reset()
{
_host = await Alba.AlbaHost.For<TEntryPoint>(_extensions);
if (_sqlExtension is null || _host is null) return;
_sqlExtension.Reset(AlbaHost.Services);
}

/// <summary>
/// Method used to dispose the alba host
/// Method to reset the database if provided
/// </summary>
public async Task DisposeAsync()
public Task ResetAsync()
{
await AlbaHost.DisposeAsync();
_loggerFactory.Dispose();
if (_sqlExtension is null || _host is null) return Task.CompletedTask;

if (_sqlExtension != null)
{
await _sqlExtension.DisposeAsync();
}
return _sqlExtension.ResetAsync(AlbaHost.Services);
}

#pragma warning disable CA1816
#pragma warning disable CA1816
async ValueTask IAsyncDisposable.DisposeAsync()
#pragma warning restore CA1816
#pragma warning restore CA1816
{
await DisposeAsync().ConfigureAwait(false);
}

/// <summary>
/// The dispose method
/// The dispose method
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
public void Dispose()
{
if (!disposing) return;
_loggerFactory.Dispose();
_sqlExtension?.Dispose();
AlbaHost.Dispose();
Dispose(true);
GC.SuppressFinalize(this);
}

class AppFixtureLoggerFactory : ILoggerFactory
private class AppFixtureLoggerFactory : ILoggerFactory
{
private readonly List<DeferredLogger> _deferredLoggers = new();
private ILoggerFactory? _innerLoggerFactory;
private List<DeferredLogger> _deferredLoggers = new();

public void SetLoggerFactory(ILoggerFactory loggerFactory)
{
Expand All @@ -125,11 +130,15 @@ public void SetLoggerFactory(ILoggerFactory loggerFactory)
}
}

public void Dispose()
private DeferredLogger AddDeferredLogger(string categoryName)
{
_innerLoggerFactory?.Dispose();
var logger = new DeferredLogger(categoryName);
_deferredLoggers.Add(logger);
return logger;
}

public void Dispose() { }

public void AddProvider(ILoggerProvider provider)
{
_innerLoggerFactory?.AddProvider(provider);
Expand All @@ -139,33 +148,36 @@ public ILogger CreateLogger(string categoryName)
{
return _innerLoggerFactory?.CreateLogger(categoryName) ?? AddDeferredLogger(categoryName);
}

private DeferredLogger AddDeferredLogger(string categoryName)
{
var logger = new DeferredLogger(categoryName);
_deferredLoggers.Add(logger);
return logger;
}
}

class DeferredLogger : ILogger
private class DeferredLogger(string categoryName) : ILogger
{
public string CategoryName { get; }
private List<(LogLevel logLevel, EventId eventId, string text)> _deferredLogs = new();
private readonly List<(LogLevel logLevel, EventId eventId, string text)> _deferredLogs = [];
private ILogger? _logger;
public string CategoryName { get; } = categoryName;

public DeferredLogger(string categoryName)
public void SetLogger(ILogger logger)
{
CategoryName = categoryName;
_logger = logger;
foreach (var log in _deferredLogs)
{
#pragma warning disable CA1848
#pragma warning disable CA2254
// ReSharper disable once TemplateIsNotCompileTimeConstantProblem
_logger.Log(log.logLevel, log.eventId, log.text);
#pragma warning restore CA2254
#pragma warning restore CA1848
}
}

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (_logger is null)
{
_deferredLogs.Add((logLevel, eventId, formatter(state, exception)));
_deferredLogs.Add(( logLevel, eventId, formatter(state, exception) ));
return;
}

_logger.Log(logLevel, eventId, state, exception, formatter);
}

Expand All @@ -178,28 +190,5 @@ public bool IsEnabled(LogLevel logLevel)
{
return _logger?.BeginScope(state);
}

public void SetLogger(ILogger logger)
{
_logger = logger;
foreach (var log in _deferredLogs)
{
#pragma warning disable CA1848
#pragma warning disable CA2254
// ReSharper disable once TemplateIsNotCompileTimeConstantProblem
_logger.Log(log.logLevel, log.eventId, log.text);
#pragma warning restore CA2254
#pragma warning restore CA1848
}
}
}

/// <summary>
/// The dispose method
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

0 comments on commit a4f83ca

Please sign in to comment.