Skip to content

Commit 89f2f3e

Browse files
authored
fix deadlog in BaseTest (#1541)
* fix deadlog in BaseTest * remove PackageReference * fix path * copy from Agent.TempDirectory * new location for test results "VSTestResultsDirectory"
1 parent 473777c commit 89f2f3e

File tree

6 files changed

+119
-84
lines changed

6 files changed

+119
-84
lines changed

Directory.Build.props

+10
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,14 @@
2525
<Deterministic>true</Deterministic>
2626
</PropertyGroup>
2727

28+
<ItemGroup>
29+
<VSTestLogger Include="trx%3BLogFileName=TestResults-$(TargetFramework)-$(MSBuildProjectName).trx" />
30+
<VSTestLogger Include="html%3BLogFileName=TestResults-$(TargetFramework)-$(MSBuildProjectName).html" />
31+
</ItemGroup>
32+
33+
<PropertyGroup>
34+
<VSTestResultsDirectory>$(RepoRoot)/artifacts/tests</VSTestResultsDirectory>
35+
<VSTestLogger>@(VSTestLogger)</VSTestLogger>
36+
</PropertyGroup>
37+
2838
</Project>

Directory.Packages.props

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
</ItemGroup>
1111

1212
<ItemGroup>
13+
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
1314
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.5.0"/>
1415
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
1516
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="7.0.0" />

eng/publish-coverlet-result-files.yml

+15-24
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
11
steps:
2-
- task: Powershell@2
3-
displayName: Prepare log files to Upload
4-
inputs:
5-
targetType: inline
6-
pwsh: true
7-
script: |
8-
New-Item -ItemType Directory "$(Build.SourcesDirectory)/artifacts/TestLogs/"
9-
function Copy-FileKeepPath {
10-
param (
11-
$Filter,$FileToCopy,$Destination,$StartIndex
12-
)
13-
Get-ChildItem -Path $FileToCopy -Filter $Filter -Recurse -File | ForEach-Object {
14-
$fileName = $_.FullName
15-
$newDestination=Join-Path -Path $Destination -ChildPath $fileName.Substring($StartIndex)
16-
$folder=Split-Path -Path $newDestination -Parent
17-
if (!(Test-Path -Path $folder)) {New-Item $folder -Type Directory -Force -Verbose}
18-
Copy-Item -Path $fileName -Destination $newDestination -Recurse -Force -Verbose
19-
}
20-
}
21-
$logfiles = "coverage.opencover.xml", "coverage.cobertura.xml", "coverage.json", "log.txt", "log.datacollector.*.txt", "log.host.*.txt"
22-
foreach ($logfile in $logfiles ) {
23-
Copy-FileKeepPath -FileToCopy "$(Build.SourcesDirectory)/test/*" -des "$(Build.SourcesDirectory)/artifacts/TestLogs/" -filter $logfile -startIndex "$(Build.SourcesDirectory)/test/coverlet.integration.tests/bin/".Length
24-
}
25-
2+
- task: CopyFiles@2
3+
displayName: Copy tests results
264
continueOnError: true
275
condition: always()
6+
inputs:
7+
SourceFolder: '$(Build.SourcesDirectory)'
8+
Contents: |
9+
**/*.trx
10+
**/*.html
11+
**/*.binlog
12+
**/coverage.opencover.xml
13+
**/coverage.cobertura.xml
14+
**/coverage.json
15+
**/log.txt
16+
**/log.datacollector.*.txt
17+
**/log.host.*.txt
18+
TargetFolder: '$(Build.SourcesDirectory)/artifacts/TestLogs'
2819

2920
- task: CopyFiles@2
3021
displayName: Copy trx files

test/coverlet.core.tests/coverlet.core.tests.csproj

+17-12
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,34 @@
88
<MSBuildWarningsAsMessages>NU1702</MSBuildWarningsAsMessages>
99
<!--For test TestInstrument_NetstandardAwareAssemblyResolver_PreserveCompilationContext-->
1010
<PreserveCompilationContext>true</PreserveCompilationContext>
11+
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
1112
</PropertyGroup>
1213

1314
<ItemGroup>
14-
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" />
15-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
16-
<PackageReference Include="Microsoft.NET.Test.Sdk" />
17-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
18-
<PackageReference Include="Moq" />
19-
<PackageReference Include="ReportGenerator.Core" />
20-
<PackageReference Include="System.Linq.Async" />
21-
<PackageReference Include="Tmds.ExecFunction" />
22-
<PackageReference Include="xunit" />
23-
<PackageReference Include="xunit.runner.visualstudio" />
15+
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" Version="7.1.4" />
16+
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="7.0.0" />
17+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
18+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
19+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
20+
<PackageReference Include="Moq" Version="4.18.4" />
21+
<PackageReference Include="ReportGenerator.Core" Version="5.1.23" />
22+
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
23+
<PackageReference Include="Tmds.ExecFunction" Version="0.6.0" />
24+
<PackageReference Include="xunit" Version="2.5.0" />
25+
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
26+
<PrivateAssets>all</PrivateAssets>
27+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
28+
</PackageReference>
2429
</ItemGroup>
2530

2631
<ItemGroup>
2732
<ProjectReference Include="$(RepoRoot)src\coverlet.core\coverlet.core.csproj" />
2833
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.xunit.extensions\coverlet.tests.xunit.extensions.csproj" />
29-
34+
3035
<ProjectReference Include="$(RepoRoot)test\coverlet.core.tests.samples.netstandard\coverlet.core.tests.samples.netstandard.csproj" />
3136
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.empty\coverlet.tests.projectsample.empty.csproj" />
3237
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.excludedbyattribute\coverlet.tests.projectsample.excludedbyattribute.csproj" />
33-
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.fsharp\coverlet.tests.projectsample.fsharp.fsproj" />
38+
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.fsharp\coverlet.tests.projectsample.fsharp.fsproj" />
3439
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.netframework\coverlet.tests.projectsample.netframework.csproj" />
3540
<ProjectReference Include="$(RepoRoot)test\coverlet.tests.projectsample.vbmynamespace\coverlet.tests.projectsample.vbmynamespace.vbproj" />
3641
</ItemGroup>

test/coverlet.integration.tests/BaseTest.cs

+23-11
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,27 @@ private protected ClonedTemplateProject CloneTemplateProject(bool cleanupOnDispo
9696
private protected bool RunCommand(string command, string arguments, out string standardOutput, out string standardError, string workingDirectory = "")
9797
{
9898
Debug.WriteLine($"BaseTest.RunCommand: {command} {arguments}\nWorkingDirectory: {workingDirectory}");
99-
var psi = new ProcessStartInfo(command, arguments);
100-
psi.WorkingDirectory = workingDirectory;
101-
psi.RedirectStandardError = true;
102-
psi.RedirectStandardOutput = true;
103-
Process commandProcess = Process.Start(psi)!;
99+
// https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.standardoutput?view=net-7.0&redirectedfrom=MSDN#System_Diagnostics_Process_StandardOutput
100+
var commandProcess = new Process();
101+
commandProcess.StartInfo.FileName = command;
102+
commandProcess.StartInfo.Arguments = arguments;
103+
commandProcess.StartInfo.WorkingDirectory = workingDirectory;
104+
commandProcess.StartInfo.RedirectStandardError = true;
105+
commandProcess.StartInfo.RedirectStandardOutput = true;
106+
commandProcess.StartInfo.UseShellExecute = false;
107+
string eOut = "";
108+
commandProcess.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => { eOut += e.Data; });
109+
commandProcess.Start();
110+
// To avoid deadlocks, use an asynchronous read operation on at least one of the streams.
111+
commandProcess.BeginErrorReadLine();
112+
standardOutput = commandProcess.StandardOutput.ReadToEnd();
104113
if (!commandProcess.WaitForExit((int)TimeSpan.FromMinutes(5).TotalMilliseconds))
105114
{
106-
throw new XunitException($"Command 'dotnet {arguments}' didn't end after 5 minute");
115+
throw new XunitException($"Command 'dotnet {arguments}' didn't end after 5 minute");
107116
}
108-
standardOutput = commandProcess.StandardOutput.ReadToEnd();
109-
standardError = commandProcess.StandardError.ReadToEnd();
117+
standardError = eOut;
110118
return commandProcess.ExitCode == 0;
111-
}
119+
}
112120

113121
private protected bool DotnetCli(string arguments, out string standardOutput, out string standardError, string workingDirectory = "")
114122
{
@@ -192,7 +200,9 @@ private protected void AddCoverletMsbuildRef(string projectPath)
192200
string msbuildPkgVersion = GetPackageVersion("*msbuild*.nupkg");
193201
xml.Element("Project")!
194202
.Element("ItemGroup")!
195-
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.msbuild"), new XAttribute("Version", msbuildPkgVersion)));
203+
.Add(new XElement("PackageReference", new XAttribute("Include", "coverlet.msbuild"), new XAttribute("Version", msbuildPkgVersion),
204+
new XElement("PrivateAssets", "all"),
205+
new XElement("IncludeAssets", "runtime; build; native; contentfiles; analyzers")));
196206
xml.Save(csproj);
197207
}
198208

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

test/coverlet.integration.tests/DeterministicBuild.cs

+53-37
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ private protected void AssertCoverage(string standardOutput = "", bool checkDete
4646
{
4747
bool coverageChecked = false;
4848
string reportFilePath = "";
49-
foreach (string coverageFile in Directory.GetFiles(_testProjectPath, "coverage.json", SearchOption.AllDirectories))
49+
foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput), "coverage.json", SearchOption.AllDirectories))
5050
{
5151
Classes? document = JsonConvert.DeserializeObject<Modules>(File.ReadAllText(coverageFile))?.Document("DeepThought.cs");
5252
if (document != null)
@@ -65,7 +65,7 @@ private protected void AssertCoverage(string standardOutput = "", bool checkDete
6565
if (checkDeterministicReport)
6666
{
6767
// Verify deterministic report
68-
foreach (string coverageFile in Directory.GetFiles(_testProjectPath, "coverage.cobertura.xml", SearchOption.AllDirectories))
68+
foreach (string coverageFile in Directory.GetFiles(GetReportPath(standardOutput), "coverage.cobertura.xml", SearchOption.AllDirectories))
6969
{
7070
Assert.Contains("/_/test/coverlet.integration.determisticbuild/DeepThought.cs", File.ReadAllText(coverageFile));
7171
File.Delete(coverageFile);
@@ -149,7 +149,7 @@ public void Collectors()
149149
Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath));
150150

151151
string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", deterministicReport: true);
152-
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);
152+
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);
153153
if (!string.IsNullOrEmpty(standardError))
154154
{
155155
_output.WriteLine(standardError);
@@ -158,6 +158,7 @@ public void Collectors()
158158
{
159159
_output.WriteLine(standardOutput);
160160
}
161+
Assert.True(result);
161162
Assert.Contains("Passed!", standardOutput);
162163
AssertCoverage(standardOutput);
163164

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

176177
[Fact]
177178
public void Collectors_SourceLink()
178-
{
179-
CreateDeterministicTestPropsFile();
180-
DotnetCli($"build -c {_buildConfiguration} /p:DeterministicSourcePaths=true", out string standardOutput, out string standardError, _testProjectPath);
181-
Assert.Contains("Build succeeded.", standardOutput);
182-
string sourceRootMappingFilePath = Path.Combine(_testProjectPath, "bin", GetAssemblyBuildConfiguration().ToString(), _testProjectTfm!, "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild");
183-
Assert.True(File.Exists(sourceRootMappingFilePath), sourceRootMappingFilePath);
184-
Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath));
185-
Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath));
186-
187-
string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", sourceLink: true);
188-
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);
189-
if (!string.IsNullOrEmpty(standardError))
190-
{
191-
_output.WriteLine(standardError);
192-
}
193-
else
194-
{
195-
_output.WriteLine(standardOutput);
196-
}
197-
Assert.Contains("Passed!", standardOutput);
198-
AssertCoverage(standardOutput, checkDeterministicReport: false);
199-
Assert.Contains("raw.githubusercontent.com", File.ReadAllText(Directory.GetFiles(_testProjectPath, "coverage.cobertura.xml", SearchOption.AllDirectories).Single()));
200-
201-
// Check out/in process collectors injection
202-
string dataCollectorLogContent = File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.datacollector.*.txt").Single());
203-
Assert.Contains("[coverlet]Initializing CoverletCoverageDataCollector with configuration:", dataCollectorLogContent);
204-
Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.host.*.txt").Single()));
205-
Assert.Contains("[coverlet]Mapping resolved", dataCollectorLogContent);
179+
{
180+
CreateDeterministicTestPropsFile();
181+
DotnetCli($"build -c {_buildConfiguration} /p:DeterministicSourcePaths=true", out string standardOutput, out string standardError, _testProjectPath);
182+
Assert.Contains("Build succeeded.", standardOutput);
183+
string sourceRootMappingFilePath = Path.Combine(_testProjectPath, "bin", GetAssemblyBuildConfiguration().ToString(), _testProjectTfm!, "CoverletSourceRootsMapping_coverletsample.integration.determisticbuild");
184+
Assert.True(File.Exists(sourceRootMappingFilePath), sourceRootMappingFilePath);
185+
Assert.NotEmpty(File.ReadAllText(sourceRootMappingFilePath));
186+
Assert.Contains("=/_/", File.ReadAllText(sourceRootMappingFilePath));
187+
188+
string runSettingsPath = AddCollectorRunsettingsFile(_testProjectPath, "[coverletsample.integration.determisticbuild]*DeepThought", sourceLink: true);
189+
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);
190+
if (!string.IsNullOrEmpty(standardError))
191+
{
192+
_output.WriteLine(standardError);
193+
}
194+
else
195+
{
196+
_output.WriteLine(standardOutput);
197+
}
198+
Assert.True(result);
199+
Assert.Contains("Passed!", standardOutput);
200+
AssertCoverage(standardOutput, checkDeterministicReport: false);
201+
Assert.Contains("raw.githubusercontent.com", File.ReadAllText(Directory.GetFiles(GetReportPath(standardOutput), "coverage.cobertura.xml", SearchOption.AllDirectories).Single()));
202+
203+
// Check out/in process collectors injection
204+
string dataCollectorLogContent = File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.datacollector.*.txt").Single());
205+
Assert.Contains("[coverlet]Initializing CoverletCoverageDataCollector with configuration:", dataCollectorLogContent);
206+
Assert.Contains("[coverlet]Initialize CoverletInProcDataCollector", File.ReadAllText(Directory.GetFiles(_testProjectPath, "log.host.*.txt").Single()));
207+
Assert.Contains("[coverlet]Mapping resolved", dataCollectorLogContent);
208+
209+
// Process exits hang on clean seem that process doesn't close, maybe some msbuild node reuse? btw manually tested
210+
// DotnetCli("clean", out standardOutput, out standardError, _fixture.TestProjectPath);
211+
// Assert.False(File.Exists(sourceRootMappingFilePath));
212+
RunCommand("git", "clean -fdx", out _, out _, _testProjectPath);
213+
}
206214

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

213-
public void Dispose()
229+
public void Dispose()
214230
{
215231
File.Delete(Path.Combine(_testProjectPath, PropsFileName));
216232
}

0 commit comments

Comments
 (0)