From b567bc82c3fe3142dd304bb2f9f96788ac06731a Mon Sep 17 00:00:00 2001 From: Sridhar Periyasamy Date: Mon, 18 Apr 2016 10:51:32 -0700 Subject: [PATCH] Add crossgen tests Simple tests which does static analysis of managed assemblies metadata to make sure that they are crossgened. Currently it verifies that all the assemblies in CLI SDK and SharedFx directroty are crossgened. --- scripts/dotnet-cli-build/TestTargets.cs | 1 + .../PeReaderUtils.cs | 13 ++++ test/crossgen.Tests/crossgen.Tests.cs | 78 +++++++++++++++++++ test/crossgen.Tests/crossgen.Tests.xproj | 21 +++++ test/crossgen.Tests/project.json | 28 +++++++ 5 files changed, 141 insertions(+) create mode 100644 test/crossgen.Tests/crossgen.Tests.cs create mode 100644 test/crossgen.Tests/crossgen.Tests.xproj create mode 100644 test/crossgen.Tests/project.json diff --git a/scripts/dotnet-cli-build/TestTargets.cs b/scripts/dotnet-cli-build/TestTargets.cs index 3e55c2a34..b3a1b3a18 100644 --- a/scripts/dotnet-cli-build/TestTargets.cs +++ b/scripts/dotnet-cli-build/TestTargets.cs @@ -18,6 +18,7 @@ namespace Microsoft.DotNet.Cli.Build public static readonly string[] TestProjects = new[] { "ArgumentForwardingTests", + "crossgen.Tests", "EndToEnd", "dotnet.Tests", "dotnet-build.Tests", diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/PeReaderUtils.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/PeReaderUtils.cs index 58afcc22f..5b909c46e 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/PeReaderUtils.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/PeReaderUtils.cs @@ -11,6 +11,19 @@ namespace Microsoft.DotNet.Tools.Test.Utilities { public static class PeReaderUtils { + public static bool IsCrossgened(this PEReader peReader) + { + bool isCrossgened = false; + + if (peReader.HasMetadata) + { + // 4 is the magic numbers that is set in the CLR header's flags when crossgened. + isCrossgened = (int)peReader.PEHeaders.CorHeader.Flags == 4; + } + + return isCrossgened; + } + public static string GetAssemblyAttributeValue(string assemblyPath, string attributeName) { if (!File.Exists(assemblyPath)) diff --git a/test/crossgen.Tests/crossgen.Tests.cs b/test/crossgen.Tests/crossgen.Tests.cs new file mode 100644 index 000000000..d2e9067cf --- /dev/null +++ b/test/crossgen.Tests/crossgen.Tests.cs @@ -0,0 +1,78 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection.PortableExecutable; +using Microsoft.DotNet.ProjectModel; +using Microsoft.DotNet.Tools.Test.Utilities; +using FluentAssertions; +using Xunit; + +namespace Microsoft.DotNet.Tests +{ + /// + /// Static analysis of assemblies to make sure that they are crossgened. + /// + public class CrossgenTests : TestBase + { + [Fact] + public void CLI_SDK_assemblies_must_be_crossgened() + { + string dotnetDir = FindDotnetDirInPath(); + string cliPath = Directory.EnumerateFiles(dotnetDir, "dotnet.dll", SearchOption.AllDirectories).First(); + cliPath = Path.GetDirectoryName(cliPath); + CheckDirectoryIsCrossgened(cliPath); + } + + [Fact] + public void Shared_Fx_assemblies_must_be_crossgened() + { + string dotnetDir = FindDotnetDirInPath(); + string sharedFxPath = Directory.EnumerateFiles(dotnetDir, "mscorlib*.dll", SearchOption.AllDirectories).First(); + sharedFxPath = Path.GetDirectoryName(sharedFxPath); + CheckDirectoryIsCrossgened(sharedFxPath); + } + + private static void CheckDirectoryIsCrossgened(string pathToAssemblies) + { + Console.WriteLine($"Checking directory '{pathToAssemblies}' for crossgened assemblies"); + + var dlls = Directory.EnumerateFiles(pathToAssemblies, "*.dll", SearchOption.TopDirectoryOnly); + var exes = Directory.EnumerateFiles(pathToAssemblies, "*.exe", SearchOption.TopDirectoryOnly); + var assemblies = dlls.Concat(exes); + assemblies.Count().Should().NotBe(0, $"No assemblies found at directory '{pathToAssemblies}'"); + + foreach (var assembly in assemblies) + { + using (var asmStream = File.OpenRead(assembly)) + { + using (var peReader = new PEReader(asmStream)) + { + if (peReader.HasMetadata) + { + peReader.IsCrossgened().Should().BeTrue($"Managed assembly '{assembly}' is not crossgened."); + } + } + } + } + } + + private static string FindDotnetDirInPath() + { + string dotnetExecutable = $"dotnet{FileNameSuffixes.CurrentPlatform.Exe}"; + foreach (string path in (Environment.GetEnvironmentVariable("PATH") ?? "").Split(Path.PathSeparator)) + { + string dotnetPath = Path.Combine(path, dotnetExecutable); + if (File.Exists(dotnetPath)) + { + return Path.GetDirectoryName(dotnetPath); + } + } + + throw new FileNotFoundException($"Unable to find '{dotnetExecutable}' in the $PATH"); + } + } +} diff --git a/test/crossgen.Tests/crossgen.Tests.xproj b/test/crossgen.Tests/crossgen.Tests.xproj new file mode 100644 index 000000000..3f40f37bb --- /dev/null +++ b/test/crossgen.Tests/crossgen.Tests.xproj @@ -0,0 +1,21 @@ + + + + 14.0.23107 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 414afbf1-b501-40e5-bf68-8c7d921c4e5d + crossgen.Tests + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/crossgen.Tests/project.json b/test/crossgen.Tests/project.json new file mode 100644 index 000000000..088dacc18 --- /dev/null +++ b/test/crossgen.Tests/project.json @@ -0,0 +1,28 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-*" + }, + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, + "Microsoft.DotNet.Cli.Utils": { + "target": "project" + }, + "xunit": "2.1.0", + "xunit.netcore.extensions": "1.0.0-prerelease-00206", + "dotnet-test-xunit": "1.0.0-dev-140469-38" + }, + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "netstandardapp1.5", + "dnxcore50", + "portable-net45+win8" + ] + } + }, + "testRunner": "xunit" +}