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

Flow ILogger to InstrumentationHelper 2 #727

Merged
merged 31 commits into from
Mar 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a6e0687
Merge pull request #1 from tonerdo/master
daveMueller Aug 17, 2019
84c0aff
Merge pull request #2 from tonerdo/master
daveMueller Sep 5, 2019
5b4e316
Merge pull request #3 from tonerdo/master
daveMueller Sep 11, 2019
45075e1
Merge pull request #4 from tonerdo/master
daveMueller Sep 14, 2019
ef7d0b0
Merge pull request #5 from tonerdo/master
daveMueller Sep 17, 2019
a50f143
Merge pull request #6 from tonerdo/master
daveMueller Sep 24, 2019
28e038c
Merge pull request #7 from tonerdo/master
daveMueller Oct 9, 2019
a8198b6
Merge pull request #8 from tonerdo/master
daveMueller Oct 20, 2019
fce0e2d
Merge pull request #9 from tonerdo/master
daveMueller Dec 18, 2019
8b8505b
Merge pull request #10 from tonerdo/master
daveMueller Jan 18, 2020
566262b
Merge pull request #11 from tonerdo/master
daveMueller Jan 21, 2020
eb5969d
Merge pull request #12 from tonerdo/master
daveMueller Jan 26, 2020
a3f4a2f
Merge pull request #13 from tonerdo/master
daveMueller Jan 30, 2020
a911496
added log message and adapted tests
daveMueller Feb 4, 2020
301e854
added ServiceCollection to console
daveMueller Feb 4, 2020
2389683
added logger to console
daveMueller Feb 4, 2020
f2ad480
adaptions to collector
daveMueller Feb 8, 2020
6c98d66
new instance of InstrumentationHelper when run out of process
daveMueller Feb 9, 2020
3ff7f61
changes to instrumentation task
daveMueller Feb 9, 2020
53099cf
nit
daveMueller Feb 9, 2020
7f9ba39
changed initialization of container
daveMueller Feb 17, 2020
c6fb0fc
Merge pull request #14 from tonerdo/master
daveMueller Feb 19, 2020
62fd124
Merge branch 'master' into 559_FlowILogger2
daveMueller Feb 19, 2020
8070676
changed back to use LazyInitializer
daveMueller Feb 19, 2020
f18a558
code review
daveMueller Mar 1, 2020
4c3c445
code review
daveMueller Mar 1, 2020
be7a78f
remove logger from di container; removed default initialization of di…
daveMueller Mar 8, 2020
37a0859
test
daveMueller Mar 8, 2020
12f04e1
code review
daveMueller Mar 11, 2020
e311dbf
code review
daveMueller Mar 11, 2020
fb398b3
use same logger on test
MarcoRossignoli Mar 13, 2020
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
19 changes: 19 additions & 0 deletions src/coverlet.collector/DataCollection/CoverletCoverageCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
using System.Xml;
using Coverlet.Collector.Utilities;
using Coverlet.Collector.Utilities.Interfaces;
using Coverlet.Core;
using Coverlet.Core.Abstracts;
using Coverlet.Core.Helpers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection;

namespace Coverlet.Collector.DataCollection
Expand Down Expand Up @@ -75,6 +79,7 @@ public override void Initialize(
_dataSink = dataSink;
_dataCollectionContext = environmentContext.SessionDataCollectionContext;
_logger = new TestPlatformLogger(logger, _dataCollectionContext);
DependencyInjection.Set(GetServiceProvider(_eqtTrace, _logger));

// Register events
_events.SessionStart += OnSessionStart;
Expand Down Expand Up @@ -203,5 +208,19 @@ private static IEnumerable<string> GetPropertyValueWrapper(SessionStartEventArgs
{
return sessionStartEventArgs.GetPropertyValue<IEnumerable<string>>(CoverletConstants.TestSourcesPropertyName);
}

private static IServiceProvider GetServiceProvider(TestPlatformEqtTrace eqtTrace, TestPlatformLogger logger)
MarcoRossignoli marked this conversation as resolved.
Show resolved Hide resolved
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<ILogger, CoverletLogger>(_ => new CoverletLogger(eqtTrace, logger));

// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();

return serviceCollection.BuildServiceProvider();
}
}
}
19 changes: 16 additions & 3 deletions src/coverlet.console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,31 @@
using Coverlet.Core;
using Coverlet.Core.Abstracts;
using Coverlet.Core.Enums;
using Coverlet.Core.Extensions;
using Coverlet.Core.Helpers;
using Coverlet.Core.Reporters;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.DependencyInjection;

namespace Coverlet.Console
{
class Program
{
static int Main(string[] args)
{
var logger = new ConsoleLogger();
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<ILogger, ConsoleLogger>();

// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();

DependencyInjection.Set(serviceCollection.BuildServiceProvider());

var logger = (ConsoleLogger) DependencyInjection.Current.GetService<ILogger>();
var fileSystem = DependencyInjection.Current.GetService<IFileSystem>();

var app = new CommandLineApplication();
app.Name = "coverlet";
app.FullName = "Cross platform .NET Core code coverage tool";
Expand Down Expand Up @@ -60,7 +74,6 @@ static int Main(string[] args)
// Adjust log level based on user input.
logger.Level = verbosity.ParsedValue;
}
var fileSystem = DependencyInjection.Current.GetService<IFileSystem>();
Coverage coverage = new Coverage(module.Value,
includeFilters.Values.ToArray(),
includeDirectories.Values.ToArray(),
Expand Down
1 change: 1 addition & 0 deletions src/coverlet.core/Abstracts/IInstrumentationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ internal interface IInstrumentationHelper
bool EmbeddedPortablePdbHasLocalSource(string module, out string firstNotFoundDocument);
bool PortablePdbHasLocalSource(string module, out string firstNotFoundDocument);
bool IsLocalMethod(string method);
void SetLogger(ILogger logger);
}
}
25 changes: 3 additions & 22 deletions src/coverlet.core/DependencyInjection.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,22 @@
using System;

using Coverlet.Core.Abstracts;
using Coverlet.Core.Helpers;
using Microsoft.Extensions.DependencyInjection;

namespace Coverlet.Core
{
internal static class DependencyInjection
{
private static Lazy<IServiceProvider> _serviceProvider = new Lazy<IServiceProvider>(() => InitDefaultServices(), true);
private static IServiceProvider _serviceProvider;

public static IServiceProvider Current
{
get
{
return _serviceProvider.Value;
return _serviceProvider;
}
}

public static void Set(IServiceProvider serviceProvider)
{
_serviceProvider = new Lazy<IServiceProvider>(() => serviceProvider);
_serviceProvider = serviceProvider;
}

private static IServiceProvider InitDefaultServices()
{
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IRetryHelper, RetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<IConsole, SystemConsole>();

// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();

return serviceCollection.BuildServiceProvider();
}

}
}
12 changes: 9 additions & 3 deletions src/coverlet.core/Helpers/InstrumentationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ internal class InstrumentationHelper : IInstrumentationHelper
private readonly ConcurrentDictionary<string, string> _backupList = new ConcurrentDictionary<string, string>();
private readonly IRetryHelper _retryHelper;
private readonly IFileSystem _fileSystem;
private ILogger _logger;

public InstrumentationHelper(IProcessExitHandler processExitHandler, IRetryHelper retryHelper, IFileSystem fileSystem)
public InstrumentationHelper(IProcessExitHandler processExitHandler, IRetryHelper retryHelper, IFileSystem fileSystem, ILogger logger)
{
processExitHandler.Add((s, e) => RestoreOriginalModules());
_retryHelper = retryHelper;
_fileSystem = fileSystem;
_logger = logger;
}

public string[] GetCoverableModules(string module, string[] directories, bool includeTestAssembly)
Expand Down Expand Up @@ -153,8 +155,7 @@ public bool PortablePdbHasLocalSource(string module, out string firstNotFoundDoc
}
catch (BadImageFormatException)
{
// TODO log this to warning
// In case of non portable pdb we get exception so we skip file sources check
_logger.LogWarning($"{nameof(BadImageFormatException)} during MetadataReaderProvider.FromPortablePdbStream in InstrumentationHelper.PortablePdbHasLocalSource, unable to check if module has got local source.");
return true;
}
foreach (DocumentHandle docHandle in metadataReader.Documents)
Expand Down Expand Up @@ -367,6 +368,11 @@ public bool IsTypeIncluded(string module, string type, string[] includeFilters)
public bool IsLocalMethod(string method)
=> new Regex(WildcardToRegex("<*>*__*|*")).IsMatch(method);

public void SetLogger(ILogger logger)
{
_logger = logger;
}

private bool IsTypeFilterMatch(string module, string type, string[] filters)
{
Debug.Assert(module != null);
Expand Down
4 changes: 4 additions & 0 deletions src/coverlet.msbuild.tasks/CoverageResultTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ public override bool Execute()
Coverage coverage = null;
using (Stream instrumenterStateStream = fileSystem.NewFileStream(InstrumenterState.ItemSpec, FileMode.Open))
{
var instrumentationHelper = DependencyInjection.Current.GetService<IInstrumentationHelper>();
MarcoRossignoli marked this conversation as resolved.
Show resolved Hide resolved
// Task.Log is teared down after a task and thus the new MSBuildLogger must be passed to the InstrumentationHelper
// https://github.com/microsoft/msbuild/issues/5153
instrumentationHelper.SetLogger(_logger);
coverage = new Coverage(CoveragePrepareResult.Deserialize(instrumenterStateStream), this._logger, DependencyInjection.Current.GetService<IInstrumentationHelper>(), fileSystem);
}

Expand Down
16 changes: 15 additions & 1 deletion src/coverlet.msbuild.tasks/InstrumentationTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

using Coverlet.Core;
using Coverlet.Core.Abstracts;
using Coverlet.Core.Extensions;
using Coverlet.Core.Helpers;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Extensions.DependencyInjection;
using ILogger = Coverlet.Core.Abstracts.ILogger;

namespace Coverlet.MSbuild.Tasks
{
Expand Down Expand Up @@ -119,6 +121,18 @@ public override bool Execute()
{
WaitForDebuggerIfEnabled();

IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IRetryHelper, RetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, ProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient<IConsole, SystemConsole>();
serviceCollection.AddTransient<ILogger, MSBuildLogger>(x => _logger);

MarcoRossignoli marked this conversation as resolved.
Show resolved Hide resolved
// We need to keep singleton/static semantics
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
MarcoRossignoli marked this conversation as resolved.
Show resolved Hide resolved

DependencyInjection.Set(serviceCollection.BuildServiceProvider());

try
{
var includeFilters = _include?.Split(',');
Expand Down
2 changes: 1 addition & 1 deletion test/coverlet.core.tests/Coverage/CoverageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Coverlet.Core.Tests
{
public partial class CoverageTests
{
private readonly InstrumentationHelper _instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem());
private readonly InstrumentationHelper _instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object);
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
MarcoRossignoli marked this conversation as resolved.
Show resolved Hide resolved

[Fact]
Expand Down
53 changes: 33 additions & 20 deletions test/coverlet.core.tests/Coverage/InstrumenterHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ private static BuildConfiguration GetAssemblyBuildConfiguration()

static class TestInstrumentationHelper
{
private static IServiceProvider _processWideContainer;

/// <summary>
/// caller sample: TestInstrumentationHelper.GenerateHtmlReport(result, sourceFileFilter: @"+**\Samples\Instrumentation.cs");
/// TestInstrumentationHelper.GenerateHtmlReport(result);
Expand Down Expand Up @@ -335,14 +337,16 @@ public static void GenerateHtmlReport(CoverageResult coverageResult, IReporter r

public static CoverageResult GetCoverageResult(string filePath)
{
SetTestContainer();
using var result = new FileStream(filePath, FileMode.Open);
var logger = new Mock<ILogger>();
logger.Setup(l => l.LogVerbose(It.IsAny<string>())).Callback((string message) =>
{
Assert.DoesNotContain("not found for module: ", message);
});
_processWideContainer.GetRequiredService<IInstrumentationHelper>().SetLogger(logger.Object);
CoveragePrepareResult coveragePrepareResultLoaded = CoveragePrepareResult.Deserialize(result);
Coverage coverage = new Coverage(coveragePrepareResultLoaded, logger.Object, DependencyInjection.Current.GetService<IInstrumentationHelper>(), new FileSystem());
Coverage coverage = new Coverage(coveragePrepareResultLoaded, logger.Object, _processWideContainer.GetService<IInstrumentationHelper>(), new FileSystem());
return coverage.GetCoverageResult();
}

Expand All @@ -353,22 +357,7 @@ async public static Task<CoveragePrepareResult> Run<T>(Func<dynamic, Task> callM
throw new ArgumentNullException(nameof(persistPrepareResultToFile));
}

var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IRetryHelper, CustomRetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, CustomProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
if (disableRestoreModules)
{
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelperForDebugging>();
}
else
{
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
}

// Setup correct retry helper to avoid exception in InstrumentationHelper.RestoreOriginalModules on remote process exit
DependencyInjection.Set(serviceCollection.BuildServiceProvider());

SetTestContainer(disableRestoreModules);

// Rename test file to avoid locks
string location = typeof(T).Assembly.Location;
Expand All @@ -392,7 +381,7 @@ async public static Task<CoveragePrepareResult> Run<T>(Func<dynamic, Task> callM
{
"[xunit.*]*",
"[coverlet.*]*"
}).ToArray(), Array.Empty<string>(), Array.Empty<string>(), true, false, "", false, new Logger(logFile), DependencyInjection.Current.GetService<IInstrumentationHelper>(), DependencyInjection.Current.GetService<IFileSystem>());
}).ToArray(), Array.Empty<string>(), Array.Empty<string>(), true, false, "", false, new Logger(logFile), _processWideContainer.GetService<IInstrumentationHelper>(), _processWideContainer.GetService<IFileSystem>());
CoveragePrepareResult prepareResult = coverage.PrepareModules();

Assert.Single(prepareResult.Results);
Expand Down Expand Up @@ -421,6 +410,30 @@ async public static Task<CoveragePrepareResult> Run<T>(Func<dynamic, Task> callM

return prepareResult;
}

private static void SetTestContainer(bool disableRestoreModules = false)
{
LazyInitializer.EnsureInitialized(ref _processWideContainer, () =>
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IRetryHelper, CustomRetryHelper>();
serviceCollection.AddTransient<IProcessExitHandler, CustomProcessExitHandler>();
serviceCollection.AddTransient<IFileSystem, FileSystem>();
serviceCollection.AddTransient(_ => new Mock<ILogger>().Object);

// We need to keep singleton/static semantics
if (disableRestoreModules)
{
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelperForDebugging>();
}
else
{
serviceCollection.AddSingleton<IInstrumentationHelper, InstrumentationHelper>();
}

return serviceCollection.BuildServiceProvider();
});
}
}

class CustomProcessExitHandler : IProcessExitHandler
Expand Down Expand Up @@ -514,8 +527,8 @@ public void LogWarning(string message)

class InstrumentationHelperForDebugging : InstrumentationHelper
{
public InstrumentationHelperForDebugging(IProcessExitHandler processExitHandler, IRetryHelper retryHelper, IFileSystem fileSystem)
: base(processExitHandler, retryHelper, fileSystem)
public InstrumentationHelperForDebugging(IProcessExitHandler processExitHandler, IRetryHelper retryHelper, IFileSystem fileSystem, ILogger logger)
: base(processExitHandler, retryHelper, fileSystem, logger)
{

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
using Xunit;
using System.Collections.Generic;
using System.Linq;
using Moq;
using Coverlet.Core.Abstracts;

namespace Coverlet.Core.Helpers.Tests
{
public class InstrumentationHelperTests
{
private readonly InstrumentationHelper _instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem());
private readonly InstrumentationHelper _instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object);

[Fact]
public void TestGetDependencies()
Expand Down
6 changes: 3 additions & 3 deletions test/coverlet.core.tests/Instrumentation/InstrumenterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Coverlet.Core.Instrumentation.Tests
{
public class InstrumenterTests
{
private readonly InstrumentationHelper _instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem());
private readonly InstrumentationHelper _instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), new FileSystem(), new Mock<ILogger>().Object);
private readonly Mock<ILogger> _mockLogger = new Mock<ILogger>();
MarcoRossignoli marked this conversation as resolved.
Show resolved Hide resolved

[Fact]
Expand Down Expand Up @@ -76,7 +76,7 @@ public void TestCoreLibInstrumentation()
}
});

InstrumentationHelper instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object);
InstrumentationHelper instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object);
Instrumenter instrumenter = new Instrumenter(Path.Combine(directory.FullName, files[0]), "_coverlet_instrumented", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), false, _mockLogger.Object, instrumentationHelper, partialMockFileSystem.Object);

Assert.True(instrumenter.CanInstrument());
Expand Down Expand Up @@ -440,7 +440,7 @@ public void SkipPpdbWithoutLocalSource()
}
});

InstrumentationHelper instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object);
InstrumentationHelper instrumentationHelper = new InstrumentationHelper(new ProcessExitHandler(), new RetryHelper(), partialMockFileSystem.Object, _mockLogger.Object);
string sample = Directory.GetFiles(Path.Combine(Directory.GetCurrentDirectory(), "TestAssets"), dllFileName).First();
var loggerMock = new Mock<ILogger>();
Instrumenter instrumenter = new Instrumenter(sample, "_75d9f96508d74def860a568f426ea4a4_instrumented", Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), Array.Empty<string>(), false, loggerMock.Object, instrumentationHelper, partialMockFileSystem.Object);
Expand Down