Add SDK Symbols tests (#19528)
Co-authored-by: Viktor Hofer <viktor.hofer@microsoft.com>
This commit is contained in:
parent
bf738fd99f
commit
94d9faf698
4 changed files with 162 additions and 37 deletions
|
@ -78,31 +78,7 @@ namespace Microsoft.DotNet.UnifiedBuild.Tasks
|
||||||
|
|
||||||
foreach (string file in Directory.GetFiles(SdkLayoutPath, "*", SearchOption.AllDirectories))
|
foreach (string file in Directory.GetFiles(SdkLayoutPath, "*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
if (file.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) &&
|
if (PdbUtilities.FileInSdkLayoutRequiresAPdb(file, out string guid))
|
||||||
!file.EndsWith(".resources.dll", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
string guid = string.Empty;
|
|
||||||
using var pdbStream = File.OpenRead(file);
|
|
||||||
using var peReader = new PEReader(pdbStream);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Check if pdb is embedded
|
|
||||||
if (peReader.ReadDebugDirectory().Any(entry => entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var debugDirectory = peReader.ReadDebugDirectory().First(entry => entry.Type == DebugDirectoryEntryType.CodeView);
|
|
||||||
var codeViewData = peReader.ReadCodeViewDebugDirectoryData(debugDirectory);
|
|
||||||
guid = $"{codeViewData.Guid.ToString("N").Replace("-", string.Empty)}";
|
|
||||||
}
|
|
||||||
catch (Exception e) when (e is BadImageFormatException || e is InvalidOperationException)
|
|
||||||
{
|
|
||||||
// Ignore binaries without debug info
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (guid != string.Empty)
|
|
||||||
{
|
{
|
||||||
string debugId = GetDebugId(guid, file);
|
string debugId = GetDebugId(guid, file);
|
||||||
if (!allPdbGuids.ContainsKey(debugId))
|
if (!allPdbGuids.ContainsKey(debugId))
|
||||||
|
@ -122,7 +98,6 @@ namespace Microsoft.DotNet.UnifiedBuild.Tasks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return filesWithoutPDBs;
|
return filesWithoutPDBs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Reflection.PortableExecutable;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.UnifiedBuild.Tasks
|
||||||
|
{
|
||||||
|
public static class PdbUtilities
|
||||||
|
{
|
||||||
|
// Checks if a file in Sdk layout requires an external Pdb.
|
||||||
|
// Also returns the Pdb GUID, if one was found in PE.
|
||||||
|
public static bool FileInSdkLayoutRequiresAPdb(string file, out string guid)
|
||||||
|
{
|
||||||
|
guid = string.Empty;
|
||||||
|
|
||||||
|
// Files under packs/ are used for build only, no need for Pdbs
|
||||||
|
return !file.Contains(Path.DirectorySeparatorChar + "packs" + Path.DirectorySeparatorChar) ?
|
||||||
|
FileHasCompanionPdbInfo(file, out guid) :
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a file has debug data indicating an external companion Pdb.
|
||||||
|
// Also returns the Pdb GUID, if one was found in PE.
|
||||||
|
private static bool FileHasCompanionPdbInfo(string file, out string guid)
|
||||||
|
{
|
||||||
|
guid = string.Empty;
|
||||||
|
|
||||||
|
if (file.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) &&
|
||||||
|
!file.EndsWith(".resources.dll", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
using var pdbStream = File.OpenRead(file);
|
||||||
|
using var peReader = new PEReader(pdbStream);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check if pdb is embedded
|
||||||
|
if (peReader.ReadDebugDirectory().Any(entry => entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var debugDirectory = peReader.ReadDebugDirectory().First(entry => entry.Type == DebugDirectoryEntryType.CodeView);
|
||||||
|
var codeViewData = peReader.ReadCodeViewDebugDirectoryData(debugDirectory);
|
||||||
|
guid = $"{codeViewData.Guid.ToString("N").Replace("-", string.Empty)}";
|
||||||
|
}
|
||||||
|
catch (Exception e) when (e is BadImageFormatException || e is InvalidOperationException)
|
||||||
|
{
|
||||||
|
// Ignore binaries without debug info
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return guid != string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,10 @@
|
||||||
<VSTestUseMSBuildOutput>false</VSTestUseMSBuildOutput>
|
<VSTestUseMSBuildOutput>false</VSTestUseMSBuildOutput>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="$(TasksDir)Microsoft.DotNet.UnifiedBuild.Tasks\PdbUtilities.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\TestUtilities\TestUtilities.csproj" />
|
<ProjectReference Include="..\TestUtilities\TestUtilities.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
using Microsoft.DotNet.UnifiedBuild.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.SourceBuild.SmokeTests;
|
||||||
|
|
||||||
|
public class SymbolsTests : SdkTests
|
||||||
|
{
|
||||||
|
private static string SymbolsTestsRoot { get; } = Path.Combine(Directory.GetCurrentDirectory(), nameof(SymbolsTests));
|
||||||
|
|
||||||
|
public SymbolsTests(ITestOutputHelper outputHelper) : base(outputHelper) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies that all symbols have valid sourcelinks.
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public void VerifySdkSymbols()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Directory.Exists(SymbolsTestsRoot))
|
||||||
|
{
|
||||||
|
Directory.Delete(SymbolsTestsRoot, true);
|
||||||
|
}
|
||||||
|
Directory.CreateDirectory(SymbolsTestsRoot);
|
||||||
|
|
||||||
|
string symbolsRoot = Directory.CreateDirectory(Path.Combine(SymbolsTestsRoot, "symbols")).FullName;
|
||||||
|
|
||||||
|
// We are validating dotnet-symbols-sdk-*.tar.gz which contains source-built sdk symbols
|
||||||
|
Utilities.ExtractTarball(
|
||||||
|
Utilities.GetFile(Path.GetDirectoryName(Config.SourceBuiltArtifactsPath)!, "dotnet-symbols-sdk-*.tar.gz"),
|
||||||
|
symbolsRoot,
|
||||||
|
OutputHelper);
|
||||||
|
|
||||||
|
IList<string> failedFiles = VerifySdkFilesHaveMatchingSymbols(symbolsRoot, Config.DotNetDirectory);
|
||||||
|
|
||||||
|
if (failedFiles.Count > 0)
|
||||||
|
{
|
||||||
|
OutputHelper.WriteLine($"Did not find PDBs for the following SDK files:");
|
||||||
|
foreach (string file in failedFiles)
|
||||||
|
{
|
||||||
|
OutputHelper.WriteLine(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.True(failedFiles.Count == 0);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Directory.Delete(SymbolsTestsRoot, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IList<string> VerifySdkFilesHaveMatchingSymbols(string symbolsRoot, string sdkRoot)
|
||||||
|
{
|
||||||
|
Assert.True(Directory.Exists(sdkRoot), $"Path, with SDK files to validate, does not exist: {sdkRoot}");
|
||||||
|
|
||||||
|
var failedFiles = new ConcurrentBag<string>();
|
||||||
|
|
||||||
|
IEnumerable<string> allFiles = Directory.GetFiles(sdkRoot, "*", SearchOption.AllDirectories);
|
||||||
|
Parallel.ForEach(allFiles, file =>
|
||||||
|
{
|
||||||
|
if (PdbUtilities.FileInSdkLayoutRequiresAPdb(file, out string guid))
|
||||||
|
{
|
||||||
|
string symbolFile = Path.ChangeExtension(file.Replace(sdkRoot, symbolsRoot), ".pdb");
|
||||||
|
if (!File.Exists(symbolFile))
|
||||||
|
{
|
||||||
|
failedFiles.Add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return failedFiles.ToList();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue