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

fix deadlog in Coverlet.Integration.Tests.BaseTest #1541

Merged
merged 5 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,14 @@
<Deterministic>true</Deterministic>
</PropertyGroup>

<ItemGroup>
<VSTestLogger Include="trx%3BLogFileName=TestResults-$(TargetFramework)-$(MSBuildProjectName).trx" />
<VSTestLogger Include="html%3BLogFileName=TestResults-$(TargetFramework)-$(MSBuildProjectName).html" />
</ItemGroup>

<PropertyGroup>
<VSTestResultsDirectory>$(RepoRoot)/artifacts/tests</VSTestResultsDirectory>
<VSTestLogger>@(VSTestLogger)</VSTestLogger>
</PropertyGroup>

</Project>
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</ItemGroup>

<ItemGroup>
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.5.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />
Expand Down
39 changes: 15 additions & 24 deletions eng/publish-coverlet-result-files.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
steps:
- task: Powershell@2
displayName: Prepare log files to Upload
inputs:
targetType: inline
pwsh: true
script: |
New-Item -ItemType Directory "$(Build.SourcesDirectory)/artifacts/TestLogs/"
function Copy-FileKeepPath {
param (
$Filter,$FileToCopy,$Destination,$StartIndex
)
Get-ChildItem -Path $FileToCopy -Filter $Filter -Recurse -File | ForEach-Object {
$fileName = $_.FullName
$newDestination=Join-Path -Path $Destination -ChildPath $fileName.Substring($StartIndex)
$folder=Split-Path -Path $newDestination -Parent
if (!(Test-Path -Path $folder)) {New-Item $folder -Type Directory -Force -Verbose}
Copy-Item -Path $fileName -Destination $newDestination -Recurse -Force -Verbose
}
}
$logfiles = "coverage.opencover.xml", "coverage.cobertura.xml", "coverage.json", "log.txt", "log.datacollector.*.txt", "log.host.*.txt"
foreach ($logfile in $logfiles ) {
Copy-FileKeepPath -FileToCopy "$(Build.SourcesDirectory)/test/*" -des "$(Build.SourcesDirectory)/artifacts/TestLogs/" -filter $logfile -startIndex "$(Build.SourcesDirectory)/test/coverlet.integration.tests/bin/".Length
}

- task: CopyFiles@2
displayName: Copy tests results
continueOnError: true
condition: always()
inputs:
SourceFolder: '$(Build.SourcesDirectory)'
Contents: |
**/*.trx
**/*.html
**/*.binlog
**/coverage.opencover.xml
**/coverage.cobertura.xml
**/coverage.json
**/log.txt
**/log.datacollector.*.txt
**/log.host.*.txt
TargetFolder: '$(Build.SourcesDirectory)/artifacts/TestLogs'

- task: CopyFiles@2
displayName: Copy trx files
Expand Down
29 changes: 17 additions & 12 deletions test/coverlet.core.tests/coverlet.core.tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,34 @@
<MSBuildWarningsAsMessages>NU1702</MSBuildWarningsAsMessages>
<!--For test TestInstrument_NetstandardAwareAssemblyResolver_PreserveCompilationContext-->
<PreserveCompilationContext>true</PreserveCompilationContext>
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Moq" />
<PackageReference Include="ReportGenerator.Core" />
<PackageReference Include="System.Linq.Async" />
<PackageReference Include="Tmds.ExecFunction" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" Version="7.1.4" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="ReportGenerator.Core" Version="5.1.23" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="Tmds.ExecFunction" Version="0.6.0" />
<PackageReference Include="xunit" Version="2.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\coverlet.core\coverlet.core.csproj" />
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.xunit.extensions\coverlet.tests.xunit.extensions.csproj" />

<ProjectReference Include="$(RepoRoot)test\coverlet.core.tests.samples.netstandard\coverlet.core.tests.samples.netstandard.csproj" />
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.empty\coverlet.tests.projectsample.empty.csproj" />
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.excludedbyattribute\coverlet.tests.projectsample.excludedbyattribute.csproj" />
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.fsharp\coverlet.tests.projectsample.fsharp.fsproj" />
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.fsharp\coverlet.tests.projectsample.fsharp.fsproj" />
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.netframework\coverlet.tests.projectsample.netframework.csproj" />
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.vbmynamespace\coverlet.tests.projectsample.vbmynamespace.vbproj" />
</ItemGroup>
Expand Down
34 changes: 23 additions & 11 deletions test/coverlet.integration.tests/BaseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,27 @@ private protected ClonedTemplateProject CloneTemplateProject(bool cleanupOnDispo
private protected bool RunCommand(string command, string arguments, out string standardOutput, out string standardError, string workingDirectory = "")
{
Debug.WriteLine($"BaseTest.RunCommand: {command} {arguments}\nWorkingDirectory: {workingDirectory}");
var psi = new ProcessStartInfo(command, arguments);
psi.WorkingDirectory = workingDirectory;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
Process commandProcess = Process.Start(psi)!;
// https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=net-7.0&redirectedfrom=MSDN#System_Diagnostics_Process_StandardOutput
var commandProcess = new Process();
commandProcess.StartInfo.FileName = command;
commandProcess.StartInfo.Arguments = arguments;
commandProcess.StartInfo.WorkingDirectory = workingDirectory;
commandProcess.StartInfo.RedirectStandardError = true;
commandProcess.StartInfo.RedirectStandardOutput = true;
commandProcess.StartInfo.UseShellExecute = false;
string eOut = "";
commandProcess.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => { eOut += e.Data; });
commandProcess.Start();
// To avoid deadlocks, use an asynchronous read operation on at least one of the streams.
commandProcess.BeginErrorReadLine();
standardOutput = commandProcess.StandardOutput.ReadToEnd();
if (!commandProcess.WaitForExit((int)TimeSpan.FromMinutes(5).TotalMilliseconds))
{
throw new XunitException($"Command 'dotnet {arguments}' didn't end after 5 minute");
throw new XunitException($"Command 'dotnet {arguments}' didn't end after 5 minute");
}
standardOutput = commandProcess.StandardOutput.ReadToEnd();
standardError = commandProcess.StandardError.ReadToEnd();
standardError = eOut;
return commandProcess.ExitCode == 0;
}
}

private protected bool DotnetCli(string arguments, out string standardOutput, out string standardError, string workingDirectory = "")
{
Expand Down Expand Up @@ -192,7 +200,9 @@ private protected void AddCoverletMsbuildRef(string projectPath)
string msbuildPkgVersion = GetPackageVersion("*msbuild*.nupkg");
xml.Element("Project")!
.Element("ItemGroup")!
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.msbuild"), new XAttribute("Version", msbuildPkgVersion)));
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.msbuild"), new XAttribute("Version", msbuildPkgVersion),
new XElement("PrivateAssets", "all"),
new XElement("IncludeAssets", "runtime; build; native; contentfiles; analyzers")));
xml.Save(csproj);
}

Expand All @@ -211,7 +221,9 @@ private protected void AddCoverletCollectosRef(string projectPath)
string msbuildPkgVersion = GetPackageVersion("*collector*.nupkg");
xml.Element("Project")!
.Element("ItemGroup")!
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.collector"), new XAttribute("Version", msbuildPkgVersion)));
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.collector"), new XAttribute("Version", msbuildPkgVersion),
new XElement("PrivateAssets", "all"),
new XElement("IncludeAssets", "runtime; build; native; contentfiles; analyzers")));
xml.Save(csproj);
}

Expand Down
90 changes: 53 additions & 37 deletions test/coverlet.integration.tests/DeterministicBuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ private protected void AssertCoverage(string standardOutput = "", bool checkDete
{
bool coverageChecked = false;
string reportFilePath = "";
foreach (string coverageFile in Directory.GetFiles(_testProjectPath, "coverage.json", SearchOption.AllDirectories))
foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput), "coverage.json", SearchOption.AllDirectories))
{
Classes? document = JsonConvert.DeserializeObject<Modules>(File.ReadAllText(coverageFile))?.Document("DeepThought.cs");
if (document != null)
Expand All @@ -65,7 +65,7 @@ private protected void AssertCoverage(string standardOutput = "", bool checkDete
if (checkDeterministicReport)
{
// Verify deterministic report
foreach (string coverageFile in Directory.GetFiles(_testProjectPath, "coverage.cobertura.xml", SearchOption.AllDirectories))
foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput), "coverage.cobertura.xml", SearchOption.AllDirectories))
{
Assert.Contains("/_/test/coverlet.integration.determisticbuild/DeepThought.cs", File.ReadAllText(coverageFile));
File.Delete(coverageFile);
Expand Down Expand Up @@ -149,7 +149,7 @@ public void Collectors()
Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath));

string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", deterministicReport: true);
Assert.True(DotnetCli($"test -c {_buildConfiguration} --no-build \"{_testProjectPath}\" --collect:\"XPlat Code Coverage\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(_testProjectPath, "log.txt")}", out standardOutput, out standardError), standardOutput);
bool result = DotnetCli($"test -c {_buildConfiguration} --no-build \"{_testProjectPath}\" --collect:\"XPlat Code Coverage\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(_testProjectPath, "log.txt")}", out standardOutput, out standardError);
if (!string.IsNullOrEmpty(standardError))
{
_output.WriteLine(standardError);
Expand All @@ -158,6 +158,7 @@ public void Collectors()
{
_output.WriteLine(standardOutput);
}
Assert.True(result);
Assert.Contains("Passed!", standardOutput);
AssertCoverage(standardOutput);

Expand All @@ -175,42 +176,57 @@ public void Collectors()

[Fact]
public void Collectors_SourceLink()
{
CreateDeterministicTestPropsFile();
DotnetCli($"build -c {_buildConfiguration} /p:DeterministicSourcePaths=true", out string standardOutput, out string standardError, _testProjectPath);
Assert.Contains("Build succeeded.", standardOutput);
string sourceRootMappingFilePath = Path.Combine(_testProjectPath, "bin", GetAssemblyBuildConfiguration().ToString(), _testProjectTfm!, "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild");
Assert.True(File.Exists(sourceRootMappingFilePath), sourceRootMappingFilePath);
Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath));
Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath));

string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", sourceLink: true);
Assert.True(DotnetCli($"test -c {_buildConfiguration} --no-build \"{_testProjectPath}\" --collect:\"XPlat Code Coverage\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(_testProjectPath, "log.txt")}", out standardOutput, out standardError), standardOutput);
if (!string.IsNullOrEmpty(standardError))
{
_output.WriteLine(standardError);
}
else
{
_output.WriteLine(standardOutput);
}
Assert.Contains("Passed!", standardOutput);
AssertCoverage(standardOutput, checkDeterministicReport: false);
Assert.Contains("raw.githubusercontent.com", File.ReadAllText(Directory.GetFiles(_testProjectPath, "coverage.cobertura.xml", SearchOption.AllDirectories).Single()));

// Check out/in process collectors injection
string dataCollectorLogContent = File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.datacollector.*.txt").Single());
Assert.Contains("[coverlet]Initializing CoverletCoverageDataCollector with configuration:", dataCollectorLogContent);
Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.host.*.txt").Single()));
Assert.Contains("[coverlet]Mapping resolved", dataCollectorLogContent);
{
CreateDeterministicTestPropsFile();
DotnetCli($"build -c {_buildConfiguration} /p:DeterministicSourcePaths=true", out string standardOutput, out string standardError, _testProjectPath);
Assert.Contains("Build succeeded.", standardOutput);
string sourceRootMappingFilePath = Path.Combine(_testProjectPath, "bin", GetAssemblyBuildConfiguration().ToString(), _testProjectTfm!, "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild");
Assert.True(File.Exists(sourceRootMappingFilePath), sourceRootMappingFilePath);
Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath));
Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath));

string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", sourceLink: true);
bool result = DotnetCli($"test -c {_buildConfiguration} --no-build \"{_testProjectPath}\" --collect:\"XPlat Code Coverage\" --settings \"{runSettingsPath}\" --diag:{Path.Combine(_testProjectPath, "log.txt")}", out standardOutput, out standardError);
if (!string.IsNullOrEmpty(standardError))
{
_output.WriteLine(standardError);
}
else
{
_output.WriteLine(standardOutput);
}
Assert.True(result);
Assert.Contains("Passed!", standardOutput);
AssertCoverage(standardOutput, checkDeterministicReport: false);
Assert.Contains("raw.githubusercontent.com", File.ReadAllText(Directory.GetFiles(GetReportPath(standardOutput), "coverage.cobertura.xml", SearchOption.AllDirectories).Single()));

// Check out/in process collectors injection
string dataCollectorLogContent = File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.datacollector.*.txt").Single());
Assert.Contains("[coverlet]Initializing CoverletCoverageDataCollector with configuration:", dataCollectorLogContent);
Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.host.*.txt").Single()));
Assert.Contains("[coverlet]Mapping resolved", dataCollectorLogContent);

// Process exits hang on clean seem that process doesn't close, maybe some msbuild node reuse? btw manually tested
// DotnetCli("clean", out standardOutput, out standardError, _fixture.TestProjectPath);
// Assert.False(File.Exists(sourceRootMappingFilePath));
RunCommand("git", "clean -fdx", out _, out _, _testProjectPath);
}

// Process exits hang on clean seem that process doesn't close, maybe some msbuild node reuse? btw manually tested
// DotnetCli("clean", out standardOutput, out standardError, _fixture.TestProjectPath);
// Assert.False(File.Exists(sourceRootMappingFilePath));
RunCommand("git", "clean -fdx", out _, out _, _testProjectPath);
}
private string GetReportPath(string standardOutput)
{
string reportPath = "";
if (standardOutput.Contains("coverage.json"))
{
#pragma warning disable CS8602 // Dereference of a possibly null reference.
reportPath = standardOutput.Split('\n').FirstOrDefault(line => line.Contains("coverage.json")).TrimStart();
#pragma warning restore CS8602 // Dereference of a possibly null reference.
reportPath = reportPath[reportPath.IndexOf(Directory.GetDirectoryRoot(_testProjectPath))..];
reportPath = reportPath[..reportPath.IndexOf("coverage.json")];
}
return reportPath;
}

public void Dispose()
public void Dispose()
{
File.Delete(Path.Combine(_testProjectPath, PropsFileName));
}
Expand Down