-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #353 from 0xced/single-app-no-assemblies-exception
Make sure that single-file apps can find assemblies that contains sinks
- Loading branch information
Showing
18 changed files
with
546 additions
and
24 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
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
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
23 changes: 23 additions & 0 deletions
23
...rilog.Settings.Configuration/Settings/Configuration/Assemblies/CompositeAssemblyFinder.cs
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,23 @@ | ||
using System.Reflection; | ||
|
||
namespace Serilog.Settings.Configuration.Assemblies; | ||
|
||
class CompositeAssemblyFinder : AssemblyFinder | ||
{ | ||
readonly AssemblyFinder[] _assemblyFinders; | ||
|
||
public CompositeAssemblyFinder(params AssemblyFinder[] assemblyFinders) | ||
{ | ||
_assemblyFinders = assemblyFinders; | ||
} | ||
|
||
public override IReadOnlyList<AssemblyName> FindAssembliesContainingName(string nameToFind) | ||
{ | ||
var assemblyNames = new List<AssemblyName>(); | ||
foreach (var assemblyFinder in _assemblyFinders) | ||
{ | ||
assemblyNames.AddRange(assemblyFinder.FindAssembliesContainingName(nameToFind)); | ||
} | ||
return assemblyNames; | ||
} | ||
} |
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
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
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
158 changes: 158 additions & 0 deletions
158
test/Serilog.Settings.Configuration.Tests/PublishSingleFileTests.cs
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,158 @@ | ||
using System.Diagnostics; | ||
using System.Text; | ||
using CliWrap; | ||
using CliWrap.Exceptions; | ||
using FluentAssertions; | ||
using FluentAssertions.Execution; | ||
using Serilog.Settings.Configuration.Tests.Support; | ||
using Xunit.Abstractions; | ||
|
||
namespace Serilog.Settings.Configuration.Tests; | ||
|
||
[Trait("Category", "Integration")] | ||
public sealed class PublishSingleFileTests : IDisposable, IClassFixture<TestApp> | ||
{ | ||
readonly ITestOutputHelper _outputHelper; | ||
readonly TestApp _testApp; | ||
readonly AssertionScope _scope; | ||
|
||
public PublishSingleFileTests(ITestOutputHelper outputHelper, TestApp testApp) | ||
{ | ||
_outputHelper = outputHelper; | ||
_testApp = testApp; | ||
_scope = new AssertionScope(); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_scope.Dispose(); | ||
} | ||
|
||
[Theory] | ||
[ClassData(typeof(PublishModeTheoryData))] | ||
public async Task RunTestApp_NoUsingAndNoAssembly(PublishMode publishMode) | ||
{ | ||
var (isSingleFile, stdOut, stdErr) = await RunTestAppAsync(publishMode); | ||
stdOut.Should().Be(isSingleFile ? "Expected exception" : "(Main thread) [Information] Expected success"); | ||
stdErr.Should().BeEmpty(); | ||
} | ||
|
||
[Theory] | ||
[ClassData(typeof(PublishModeTheoryData))] | ||
public async Task RunTestApp_UsingConsole(PublishMode publishMode) | ||
{ | ||
var (isSingleFile, stdOut, stdErr) = await RunTestAppAsync(publishMode, "--using-console"); | ||
stdOut.Should().Be(isSingleFile ? "() [Information] Expected success" : "(Main thread) [Information] Expected success"); | ||
if (isSingleFile) | ||
stdErr.Should().Contain("Unable to find a method called WithThreadName"); | ||
else | ||
stdErr.Should().BeEmpty(); | ||
} | ||
|
||
[Theory] | ||
[ClassData(typeof(PublishModeTheoryData))] | ||
public async Task RunTestApp_UsingThread(PublishMode publishMode) | ||
{ | ||
var (isSingleFile, stdOut, stdErr) = await RunTestAppAsync(publishMode, "--using-thread"); | ||
stdOut.Should().Be(isSingleFile ? "" : "(Main thread) [Information] Expected success"); | ||
if (isSingleFile) | ||
stdErr.Should().Contain("Unable to find a method called Console"); | ||
else | ||
stdErr.Should().BeEmpty(); | ||
} | ||
|
||
[Theory] | ||
[ClassData(typeof(PublishModeTheoryData))] | ||
public async Task RunTestApp_AssemblyThread(PublishMode publishMode) | ||
{ | ||
var (_, stdOut, stdErr) = await RunTestAppAsync(publishMode, "--assembly-thread"); | ||
stdOut.Should().BeEmpty(); | ||
stdErr.Should().Contain("Unable to find a method called Console"); | ||
} | ||
|
||
[Theory] | ||
[ClassData(typeof(PublishModeTheoryData))] | ||
public async Task RunTestApp_AssemblyConsole(PublishMode publishMode) | ||
{ | ||
var (_, stdOut, stdErr) = await RunTestAppAsync(publishMode, "--assembly-console"); | ||
stdOut.Should().Be("() [Information] Expected success"); | ||
stdErr.Should().Contain("Unable to find a method called WithThreadName"); | ||
} | ||
|
||
[Theory] | ||
[ClassData(typeof(PublishModeAndStrategyTheoryData))] | ||
public async Task RunTestApp_ConsoleAndThread(PublishMode publishMode, string strategy) | ||
{ | ||
var (_, stdOut, stdErr) = await RunTestAppAsync(publishMode, $"--{strategy}-console", $"--{strategy}-thread"); | ||
stdOut.Should().Be("(Main thread) [Information] Expected success"); | ||
stdErr.Should().BeEmpty(); | ||
} | ||
|
||
async Task<(bool IsSingleFile, string StdOut, string StdErr)> RunTestAppAsync(PublishMode publishMode, params string[] args) | ||
{ | ||
// Determine whether the app is a _true_ single file, i.e. not a .NET Core 3.x version which | ||
// [extracts bundled files to disk][1] and thus can find dlls. | ||
// [1]: https://github.com/dotnet/designs/blob/main/accepted/2020/single-file/extract.md | ||
var (isSingleFile, _) = await RunTestAppInternalAsync(publishMode, "is-single-file"); | ||
var (stdOut, stdErr) = await RunTestAppInternalAsync(publishMode, args); | ||
return (bool.Parse(isSingleFile), stdOut, stdErr); | ||
} | ||
|
||
async Task<(string StdOut, string StdErr)> RunTestAppInternalAsync(PublishMode publishMode, params string[] args) | ||
{ | ||
var stdOutBuilder = new StringBuilder(); | ||
var stdErrBuilder = new StringBuilder(); | ||
|
||
var command = Cli.Wrap(_testApp.GetExecutablePath(publishMode)) | ||
.WithArguments(args) | ||
.WithValidation(CommandResultValidation.None) | ||
.WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdOutBuilder)) | ||
.WithStandardErrorPipe(PipeTarget.ToStringBuilder(stdErrBuilder)); | ||
|
||
_outputHelper.WriteLine(command.ToString()); | ||
|
||
var stopwatch = Stopwatch.StartNew(); | ||
var result = await command.ExecuteAsync(); | ||
var executionTime = stopwatch.ElapsedMilliseconds; | ||
|
||
var stdOut = stdOutBuilder.ToString().Trim(); | ||
var stdErr = stdErrBuilder.ToString().Trim(); | ||
|
||
_outputHelper.WriteLine($"Executed in {executionTime} ms"); | ||
_outputHelper.WriteLine(stdOut.Length > 0 ? $"stdout: {stdOut}" : "nothing on stdout"); | ||
_outputHelper.WriteLine(stdErr.Length > 0 ? $"stderr: {stdErr}" : "nothing on stderr"); | ||
_outputHelper.WriteLine(""); | ||
|
||
if (result.ExitCode != 0) | ||
{ | ||
throw new CommandExecutionException(command, result.ExitCode, $"An unexpected exception has occurred while running {command}{Environment.NewLine}{stdErr}".Trim()); | ||
} | ||
|
||
return (stdOut, stdErr); | ||
} | ||
|
||
class PublishModeTheoryData : TheoryData<PublishMode> | ||
{ | ||
public PublishModeTheoryData() | ||
{ | ||
foreach (var publishMode in PublishModeExtensions.GetPublishModes()) | ||
{ | ||
Add(publishMode); | ||
} | ||
} | ||
} | ||
|
||
class PublishModeAndStrategyTheoryData : TheoryData<PublishMode, string> | ||
{ | ||
public PublishModeAndStrategyTheoryData() | ||
{ | ||
foreach (var publishMode in PublishModeExtensions.GetPublishModes()) | ||
{ | ||
foreach (var strategy in new[] { "using", "assembly" }) | ||
{ | ||
Add(publishMode, strategy); | ||
} | ||
} | ||
} | ||
} | ||
} |
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
10 changes: 10 additions & 0 deletions
10
test/Serilog.Settings.Configuration.Tests/Support/DirectoryInfoExtensions.cs
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,10 @@ | ||
namespace Serilog.Settings.Configuration.Tests; | ||
|
||
static class DirectoryInfoExtensions | ||
{ | ||
public static DirectoryInfo SubDirectory(this DirectoryInfo directory, params string[] paths) | ||
=> new(Path.GetFullPath(Path.Combine(paths.Prepend(directory.FullName).ToArray()))); | ||
|
||
public static FileInfo File(this DirectoryInfo directory, params string[] paths) | ||
=> new(Path.GetFullPath(Path.Combine(paths.Prepend(directory.FullName).ToArray()))); | ||
} |
25 changes: 25 additions & 0 deletions
25
test/Serilog.Settings.Configuration.Tests/Support/PublishMode.cs
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,25 @@ | ||
namespace Serilog.Settings.Configuration.Tests.Support; | ||
|
||
/// <summary> | ||
/// The possible application publish modes for the TestApp. | ||
/// See also the <a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/">.NET application publishing overview</a> documentation. | ||
/// </summary> | ||
public enum PublishMode | ||
{ | ||
/// <summary> | ||
/// Standard app publish, all dlls and related files are copied along the main executable. | ||
/// </summary> | ||
Standard, | ||
|
||
/// <summary> | ||
/// Publish a single file as a framework-dependent binary. | ||
/// </summary> | ||
/// <remarks>On .NET Framework, <a href="https://github.com/Fody/Costura">Costura</a> is used to publish as a single file.</remarks> | ||
SingleFile, | ||
|
||
/// <summary> | ||
/// Publish a single file as a self contained binary, i.e. including the .NET libraries and target runtime. | ||
/// </summary> | ||
/// <remarks>This mode is ignored on .NET Framework as it doesn't make sense.</remarks> | ||
SelfContained, | ||
} |
Oops, something went wrong.