diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs index 36f5ec5adcfd1306a556fa9032b5d9c8471baa7b..c9553d23d90ce10a7e346a29ca17f3dc53551e31 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleExtractToSpecificPath.cs @@ -1,21 +1,18 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.IO; +using System.Threading; using BundleTests.Helpers; using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.DotNet.CoreSetup.Test; using Microsoft.NET.HostModel.Bundle; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Threading; using Xunit; namespace AppHost.Bundle.Tests { - public class BundleExtractToSpecificPath : BundleTestBase, IClassFixture + public class BundleExtractToSpecificPath : IClassFixture { private SharedTestState sharedTestState; @@ -25,52 +22,48 @@ public BundleExtractToSpecificPath(SharedTestState fixture) } [Fact] - private void Bundle_Extraction_To_Specific_Path_Succeeds() + private void AbsolutePath() { - var fixture = sharedTestState.TestFixture.Copy(); - var hostName = BundleHelper.GetHostName(fixture); - - // Publish the bundle - BundleOptions options = BundleOptions.BundleNativeBinaries; - Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, options); + SingleFileTestApp app = sharedTestState.SelfContainedApp; + var bundledApp = sharedTestState.BundledApp; // Verify expected files in the bundle directory - var bundleDir = BundleHelper.GetBundleDir(fixture); - bundleDir.Should().HaveFile(hostName); - bundleDir.Should().NotHaveFiles(BundleHelper.GetBundledFiles(fixture)); + var bundleDir = Directory.GetParent(bundledApp.Path); + bundleDir.Should().OnlyHaveFiles(new[] + { + Binaries.GetExeFileNameForCurrentPlatform(app.Name), + $"{app.Name}.pdb" + }); - // Create a directory for extraction. - var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture); - extractBaseDir.Should().NotHaveDirectory(BundleHelper.GetAppBaseName(fixture)); + // Directory for extraction. + string extractBaseDir = app.GetNewExtractionRootPath(); // Run the bundled app for the first time, and extract files to // $DOTNET_BUNDLE_EXTRACT_BASE_DIR//bundle-id - Command.Create(singleFile) + Command.Create(bundledApp.Path) .CaptureStdErr() .CaptureStdOut() - .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir.FullName) + .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); - - var extractDir = BundleHelper.GetExtractionDir(fixture, bundler); - extractDir.Should().HaveFiles(BundleHelper.GetExtractedFiles(fixture, BundleOptions.BundleNativeBinaries)); - extractDir.Should().NotHaveFiles(BundleHelper.GetFilesNeverExtracted(fixture)); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); + + var extractDir = app.GetExtractionDir(extractBaseDir, bundledApp.Manifest); + extractDir.Should().OnlyHaveFiles(BundleHelper.GetExtractedFiles(bundledApp.Manifest, bundledApp.Options)); } [InlineData("./foo", BundleOptions.BundleAllContent)] [InlineData("../foo", BundleOptions.BundleAllContent)] [InlineData("foo", BundleOptions.BundleAllContent)] [InlineData("foo/bar", BundleOptions.BundleAllContent)] + [InlineData("foo\\bar", BundleOptions.BundleAllContent)] [InlineData("./foo", BundleOptions.BundleNativeBinaries)] [InlineData("../foo", BundleOptions.BundleNativeBinaries)] [InlineData("foo", BundleOptions.BundleNativeBinaries)] [InlineData("foo/bar", BundleOptions.BundleNativeBinaries)] [InlineData("foo\\bar", BundleOptions.BundleNativeBinaries)] [Theory] - private void Bundle_Extraction_To_Relative_Path_Succeeds(string relativePath, BundleOptions bundleOptions) + private void RelativePath(string relativePath, BundleOptions bundleOptions) { // As we don't modify user defined environment variables, we will not convert // any forward slashes to the standard Windows dir separator ('\'), thus @@ -84,56 +77,47 @@ private void Bundle_Extraction_To_Relative_Path_Succeeds(string relativePath, Bu if (relativePath == "foo\\bar" && !OperatingSystem.IsWindows()) return; - var fixture = sharedTestState.TestFixture.Copy(); - var bundler = BundleSelfContainedApp(fixture, out var singleFile, bundleOptions); + Manifest manifest; + string singleFile = sharedTestState.SelfContainedApp.Bundle(bundleOptions, out manifest); // Run the bundled app (extract files to ) - var cmd = Command.Create(singleFile); - cmd.WorkingDirectory(Path.GetDirectoryName(singleFile)) + Command.Create(singleFile) + .WorkingDirectory(Path.GetDirectoryName(singleFile)) .CaptureStdErr() .CaptureStdOut() .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, relativePath) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); - - var extractedFiles = BundleHelper.GetExtractedFiles(fixture, bundleOptions); - var extractedDir = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(singleFile), - relativePath, - fixture.TestProject.ProjectName, - bundler.BundleManifest.BundleID)); - - extractedDir.Should().HaveFiles(extractedFiles); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); + + using (TestArtifact extractionRoot = new TestArtifact(Path.Combine(Path.GetDirectoryName(singleFile), relativePath))) + { + var extractedDir = sharedTestState.SelfContainedApp.GetExtractionDir(extractionRoot.Location, manifest); + var extractedFiles = BundleHelper.GetExtractedFiles(manifest, bundleOptions); + extractedDir.Should().OnlyHaveFiles(extractedFiles); + } } [Fact] - private void Bundle_extraction_is_reused() + private void ExtractionDirectoryReused() { - var fixture = sharedTestState.TestFixture.Copy(); - - // Publish the bundle - BundleOptions options = BundleOptions.BundleNativeBinaries; - Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, options); + SingleFileTestApp app = sharedTestState.SelfContainedApp; + var bundledApp = sharedTestState.BundledApp; - // Create a directory for extraction. - var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture); + // Directory for extraction. + string extractBaseDir = app.GetNewExtractionRootPath(); // Run the bunded app for the first time, and extract files to // $DOTNET_BUNDLE_EXTRACT_BASE_DIR//bundle-id - Command.Create(singleFile) + Command.Create(bundledApp.Path) .CaptureStdErr() .CaptureStdOut() - .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir.FullName) + .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); - - var extractDir = BundleHelper.GetExtractionDir(fixture, bundler); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); + var extractDir = app.GetExtractionDir(extractBaseDir, bundledApp.Manifest); extractDir.Refresh(); DateTime firstWriteTime = extractDir.LastWriteTimeUtc; @@ -143,73 +127,63 @@ private void Bundle_extraction_is_reused() } // Run the bundled app again (reuse extracted files) - Command.Create(singleFile) + Command.Create(bundledApp.Path) .CaptureStdErr() .CaptureStdOut() - .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir.FullName) + .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); extractDir.Should().NotBeModifiedAfter(firstWriteTime); } [Fact] - private void Bundle_extraction_can_recover_missing_files() + private void RecoverMissingFiles() { - var fixture = sharedTestState.TestFixture.Copy(); - var hostName = BundleHelper.GetHostName(fixture); - var appName = Path.GetFileNameWithoutExtension(hostName); + SingleFileTestApp app = sharedTestState.SelfContainedApp; + var bundledApp = sharedTestState.BundledApp; - // Publish the bundle - BundleOptions options = BundleOptions.BundleNativeBinaries; - Bundler bundler = BundleSelfContainedApp(fixture, out string singleFile, options); - - // Create a directory for extraction. - var extractBaseDir = BundleHelper.GetExtractionRootDir(fixture); + // Directory for extraction. + string extractBaseDir = app.GetNewExtractionRootPath(); // Run the bunded app for the first time, and extract files to // $DOTNET_BUNDLE_EXTRACT_BASE_DIR//bundle-id - Command.Create(singleFile) + Command.Create(bundledApp.Path) .CaptureStdErr() .CaptureStdOut() - .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir.FullName) + .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); // Remove the extracted files, but keep the extraction directory - var extractDir = BundleHelper.GetExtractionDir(fixture, bundler); - var extractedFiles = BundleHelper.GetExtractedFiles(fixture, BundleOptions.BundleNativeBinaries); + var extractDir = app.GetExtractionDir(extractBaseDir, bundledApp.Manifest); + var extractedFiles = BundleHelper.GetExtractedFiles(bundledApp.Manifest, bundledApp.Options); - Array.ForEach(extractedFiles, file => File.Delete(Path.Combine(extractDir.FullName, file))); + foreach (string file in extractedFiles) + File.Delete(Path.Combine(extractDir.FullName, file)); extractDir.Should().Exist(); extractDir.Should().NotHaveFiles(extractedFiles); // Run the bundled app again (recover deleted files) - Command.Create(singleFile) + Command.Create(bundledApp.Path) .CaptureStdErr() .CaptureStdOut() - .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir.FullName) + .EnvironmentVariable(BundleHelper.DotnetBundleExtractBaseEnvVariable, extractBaseDir) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); - extractDir.Should().HaveFiles(extractedFiles); + extractDir.Should().OnlyHaveFiles(extractedFiles); } [Fact] - private void Bundle_extraction_to_nonexisting_default() + private void NonexistentDefault_Fails() { string nonExistentPath = Path.Combine( - sharedTestState.DefaultBundledAppFixture.TestProject.OutputDirectory, + Path.GetDirectoryName(sharedTestState.BundledApp.Path), "nonexistent"); string defaultExpansionEnvVariable = OperatingSystem.IsWindows() ? "TMP" : "HOME"; @@ -217,7 +191,7 @@ private void Bundle_extraction_to_nonexisting_default() $"Failed to determine default extraction location. Check if 'TMP'" : $"Default extraction directory [{nonExistentPath}] either doesn't exist or is not accessible for read/write."; - Command.Create(sharedTestState.DefaultBundledAppExecutablePath) + Command.Create(sharedTestState.BundledApp.Path) .CaptureStdErr() .CaptureStdOut() .EnvironmentVariable(defaultExpansionEnvVariable, nonExistentPath) @@ -227,56 +201,51 @@ private void Bundle_extraction_to_nonexisting_default() [Fact] [SkipOnPlatform(TestPlatforms.Windows, "On Windows the default extraction path is determined by calling GetTempPath which looks at multiple places and can't really be undefined.")] - private void Bundle_extraction_fallsback_to_getpwuid_when_HOME_env_var_is_undefined() + private void UndefinedHOME_getpwuidFallback() { string home = Environment.GetEnvironmentVariable("HOME"); - // suppose we are testing on a system where HOME is not set, use System.Environment (which also fallsback to getpwuid) if (string.IsNullOrEmpty(home)) { + // HOME is not set. Use System.Environment (which also fallsback to getpwuid) home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); } - DirectoryInfo sharedExtractDirInfo = BundleHelper.GetExtractionDir(sharedTestState.TestFixture, sharedTestState.DefaultBundledAppBundler); - string sharedExtractDir = sharedExtractDirInfo.FullName; - string extractDirSubPath = sharedExtractDir.Substring(sharedExtractDir.LastIndexOf("extract/") + "extract/".Length); - string realExtractDir = Path.Combine(home, ".net", extractDirSubPath); - var expectedExtractDir = new DirectoryInfo(realExtractDir); - - Command.Create(sharedTestState.DefaultBundledAppExecutablePath) + var bundledApp = sharedTestState.BundledApp; + Command.Create(bundledApp.Path) .CaptureStdErr() .CaptureStdOut() .EnvironmentVariable("HOME", null) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World"); + .Should().Pass() + .And.HaveStdOutContaining("Hello World"); - var extractedFiles = BundleHelper.GetExtractedFiles(sharedTestState.TestFixture, BundleOptions.BundleNativeBinaries); + DirectoryInfo expectedExtractDir = sharedTestState.SelfContainedApp.GetExtractionDir(Path.Combine(home, ".net"), bundledApp.Manifest); + var extractedFiles = BundleHelper.GetExtractedFiles(bundledApp.Manifest, bundledApp.Options); expectedExtractDir.Should().HaveFiles(extractedFiles); } - public class SharedTestState : SharedTestStateBase, IDisposable + public class SharedTestState : IDisposable { - public TestProjectFixture TestFixture { get; } + public (string Path, Manifest Manifest, BundleOptions Options) BundledApp{ get; } - public TestProjectFixture DefaultBundledAppFixture { get; } - public string DefaultBundledAppExecutablePath { get; } - public Bundler DefaultBundledAppBundler { get; } + public SingleFileTestApp SelfContainedApp { get; } public SharedTestState() { - TestFixture = PreparePublishedSelfContainedTestProject("StandaloneApp"); + SelfContainedApp = SingleFileTestApp.CreateSelfContained("HelloWorld"); + + // Copy over mockcoreclr so that the app will have a native binary + File.Copy(Binaries.CoreClr.MockPath, Path.Combine(SelfContainedApp.NonBundledLocation, Binaries.CoreClr.MockName)); - DefaultBundledAppFixture = TestFixture.Copy(); - DefaultBundledAppBundler = BundleSelfContainedApp(DefaultBundledAppFixture, out var singleFile, BundleOptions.BundleNativeBinaries); - DefaultBundledAppExecutablePath = singleFile; + // Create a bundled app that can be used by multiple tests + BundleOptions options = BundleOptions.BundleNativeBinaries; + string bundlePath = SelfContainedApp.Bundle(options, out Manifest manifest); + BundledApp = (bundlePath, manifest, options); } public void Dispose() { - DefaultBundledAppFixture.Dispose(); - TestFixture.Dispose(); + SelfContainedApp.Dispose(); } } } diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs index c05a68e5390b86fce6515853926d99e935d3b638..d64afd8d1c8223870eacd6a711b9edfe5410e0f3 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/Helpers/BundleHelper.cs @@ -52,46 +52,39 @@ public static string GetAppBaseName(TestProjectFixture fixture) return Path.GetFileNameWithoutExtension(GetAppName(fixture)); } - public static string[] GetBundledFiles(TestProjectFixture fixture) + public static List GetExtractedFiles(Manifest manifest, BundleOptions bundleOptions) { - string appBaseName = GetAppBaseName(fixture); - return new string[] { $"{appBaseName}.dll", $"{appBaseName}.deps.json", $"{appBaseName}.runtimeconfig.json" }; - } - - public static string[] GetExtractedFiles(TestProjectFixture fixture, BundleOptions bundleOptions) - { - switch (bundleOptions & ~BundleOptions.EnableCompression) + List expected = new List(); + foreach (FileEntry file in manifest.Files) { - case BundleOptions.None: - case BundleOptions.BundleOtherFiles: - case BundleOptions.BundleSymbolFiles: - throw new ArgumentException($"Bundle option {bundleOptions} doesn't extract any files to disk."); + if (!ShouldBeExtracted(file.Type, bundleOptions)) + continue; - case BundleOptions.BundleAllContent: - return Directory.GetFiles(GetPublishPath(fixture)) - .Select(f => Path.GetFileName(f)) - .Except(GetFilesNeverExtracted(fixture)).ToArray(); + expected.Add(file.RelativePath); + } - case BundleOptions.BundleNativeBinaries: - return new string[] { Path.GetFileName(fixture.TestProject.CoreClrDll) }; + return expected; - default: - throw new ArgumentException("Unsupported bundle option."); + static bool ShouldBeExtracted(FileType type, BundleOptions options) + { + switch (type) + { + case FileType.Assembly: + case FileType.DepsJson: + case FileType.RuntimeConfigJson: + return options.HasFlag(BundleOptions.BundleAllContent); + case FileType.NativeBinary: + return options.HasFlag(BundleOptions.BundleNativeBinaries); + case FileType.Symbols: + return options.HasFlag(BundleOptions.BundleSymbolFiles); + case FileType.Unknown: + return options.HasFlag(BundleOptions.BundleOtherFiles); + default: + return false; + } } } - public static string[] GetFilesNeverExtracted(TestProjectFixture fixture) - { - string appBaseName = GetAppBaseName(fixture); - return new string[] { $"{appBaseName}", - $"{appBaseName}.dll", - $"{appBaseName}.exe", - $"{appBaseName}.pdb", - $"{appBaseName}.runtimeconfig.dev.json", - Path.GetFileName(fixture.TestProject.HostFxrDll), - Path.GetFileName(fixture.TestProject.HostPolicyDll) }; - } - public static string GetPublishPath(TestProjectFixture fixture) { return Path.Combine(fixture.TestProject.ProjectDirectory, "publish"); diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs index 7e062c658a98a3273ab9b0cbdfebb3b859c0d422..69813ce270ec6988b297fc063d607e4efebc7f94 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundleAndRun.cs @@ -21,33 +21,21 @@ public BundleAndRun(BundleAndRun.SharedTestState fixture) sharedTestState = fixture; } - private void RunTheApp(string path) + private void RunTheApp(string path, bool selfContained) { Command.Create(path) .CaptureStdErr() .CaptureStdOut() + .DotNetRoot(selfContained ? null : RepoDirectoriesProvider.Default.BuiltDotnet) .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Hello World!"); - } - - private void CheckFileSigned(string path) - { - // Check if the file is signed (it should have been signed by the bundler) - Command.Create("codesign", $"-v {path}") - .CaptureStdErr() - .CaptureStdOut() - .Execute() - .Should() - .Pass(); + .Should().Pass() + .And.HaveStdOutContaining("Hello World!"); } - private string MakeUniversalBinary(string path, string rid) + private string MakeUniversalBinary(string path, Architecture architecture) { string fatApp = path + ".fat"; - string arch = BundleHelper.GetTargetArch(rid) == Architecture.Arm64 ? "arm64" : "x86_64"; + string arch = architecture == Architecture.Arm64 ? "arm64" : "x86_64"; // We will create a universal binary with just one arch slice and run it. // It is enough for testing purposes. The code that finds the releavant slice @@ -62,70 +50,36 @@ private string MakeUniversalBinary(string path, string rid) return fatApp; } - private void BundleRun(TestProjectFixture fixture, string publishPath) + [Theory] + [InlineData(true)] + [InlineData(false)] + private void RunApp(bool selfContained) { - var hostName = BundleHelper.GetHostName(fixture); - - // Run the App normally - RunTheApp(Path.Combine(publishPath, hostName)); - // Bundle to a single-file - string singleFile = BundleHelper.BundleApp(fixture); + string singleFile = selfContained + ? sharedTestState.SelfContainedApp.Bundle() + : sharedTestState.FrameworkDependentApp.Bundle(); - // check that the file structure is understood by codesign - var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid); - if (targetOS == OSPlatform.OSX) - { - CheckFileSigned(singleFile); - } + // Run the bundled app + RunTheApp(singleFile, selfContained); - // Run the extracted app - RunTheApp(singleFile); - - if (targetOS == OSPlatform.OSX) + if (OperatingSystem.IsMacOS()) { - string fatApp = MakeUniversalBinary(singleFile, fixture.CurrentRid); + string fatApp = MakeUniversalBinary(singleFile, RuntimeInformation.OSArchitecture); // Run the fat app - RunTheApp(fatApp); + RunTheApp(fatApp, selfContained); } } - private string RelativePath(string path) + [Theory] + [InlineData(true)] + [InlineData(false)] + public void AdditionalContentAfterBundleMetadata(bool selfContained) { - return Path.GetRelativePath(Directory.GetCurrentDirectory(), path) - .TrimEnd(Path.DirectorySeparatorChar); - } - - [Fact] - public void TestWithAbsolutePaths() - { - var fixture = sharedTestState.TestFixture.Copy(); - string publishDir = BundleHelper.GetPublishPath(fixture); - BundleRun(fixture, publishDir); - } - - [Fact] - public void TestWithRelativePaths() - { - var fixture = sharedTestState.TestFixture.Copy(); - string publishDir = RelativePath(BundleHelper.GetPublishPath(fixture)); - BundleRun(fixture, publishDir); - } - - [Fact] - public void TestWithRelativePathsDirSeparator() - { - var fixture = sharedTestState.TestFixture.Copy(); - string publishDir = RelativePath(BundleHelper.GetPublishPath(fixture)) + Path.DirectorySeparatorChar; - BundleRun(fixture, publishDir); - } - - [Fact] - public void TestWithAdditionalContentAfterBundleMetadata() - { - var fixture = sharedTestState.TestFixture.Copy(); - string singleFile = BundleHelper.BundleApp(fixture); + string singleFile = selfContained + ? sharedTestState.SelfContainedApp.Bundle() + : sharedTestState.FrameworkDependentApp.Bundle(); using (var file = File.OpenWrite(singleFile)) { @@ -134,35 +88,24 @@ public void TestWithAdditionalContentAfterBundleMetadata() file.Write(blob, 0, blob.Length); } - Command.Create(singleFile) - .CaptureStdErr() - .CaptureStdOut() - .Execute() - .Should().Pass() - .And.HaveStdOutContaining("Hello World!"); + RunTheApp(singleFile, selfContained); } public class SharedTestState : IDisposable { - public TestProjectFixture TestFixture { get; set; } - public TestProjectFixture LegacyFixture { get; set; } - public RepoDirectoriesProvider RepoDirectories { get; set; } + public SingleFileTestApp FrameworkDependentApp { get; } + public SingleFileTestApp SelfContainedApp { get; } public SharedTestState() { - RepoDirectories = new RepoDirectoriesProvider(); - - TestFixture = new TestProjectFixture("StandaloneApp", RepoDirectories); - TestFixture - .EnsureRestoredForRid(TestFixture.CurrentRid) - .PublishProject(runtime: TestFixture.CurrentRid, - selfContained: true, - outputDirectory: BundleHelper.GetPublishPath(TestFixture)); + FrameworkDependentApp = SingleFileTestApp.CreateFrameworkDependent("HelloWorld"); + SelfContainedApp = SingleFileTestApp.CreateSelfContained("HelloWorld"); } public void Dispose() { - TestFixture.Dispose(); + FrameworkDependentApp.Dispose(); + SelfContainedApp.Dispose(); } } } diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs index 7a9129da2bf08933d2a53e54c03e7f4364c16535..3b4233887a72efdc8a5fd0f4cbeab49026a75f7d 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.Bundle.Tests/BundlerConsistencyTests.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Runtime.InteropServices; using FluentAssertions; +using Microsoft.DotNet.Cli.Build.Framework; using Microsoft.DotNet.CoreSetup.Test; using Microsoft.NET.HostModel.Bundle; using Xunit; @@ -23,8 +24,8 @@ public BundlerConsistencyTests(SharedTestState fixture) } private static string BundlerHostName = Binaries.GetExeFileNameForCurrentPlatform(SharedTestState.AppName); - private Bundler CreateBundlerInstance(BundleOptions bundleOptions = BundleOptions.None, Version version = null) - => new Bundler(BundlerHostName, SharedFramework.CalculateUniqueTestDirectory($"{sharedTestState.App.Location}-bundle"), bundleOptions, targetFrameworkVersion: version); + private Bundler CreateBundlerInstance(BundleOptions bundleOptions = BundleOptions.None, Version version = null, bool macosCodesign = true) + => new Bundler(BundlerHostName, SharedFramework.CalculateUniqueTestDirectory($"{sharedTestState.App.Location}-bundle"), bundleOptions, targetFrameworkVersion: version, macosCodesign: macosCodesign); [Fact] public void EnableCompression_Before60_Fails() @@ -309,6 +310,40 @@ public void AssemblyAlignment() Assert.True((file.Type != FileType.Assembly) || (file.Offset % alignment == 0))); } + [Theory] + [InlineData(true)] + [InlineData(false)] + [PlatformSpecific(TestPlatforms.OSX)] + public void Codesign(bool shouldCodesign) + { + TestApp app = sharedTestState.App; + FileSpec[] fileSpecs = new FileSpec[] + { + new FileSpec(Binaries.AppHost.FilePath, BundlerHostName), + new FileSpec(app.AppDll, Path.GetRelativePath(app.Location, app.AppDll)), + new FileSpec(app.DepsJson, Path.GetRelativePath(app.Location, app.DepsJson)), + new FileSpec(app.RuntimeConfigJson, Path.GetRelativePath(app.Location, app.RuntimeConfigJson)), + }; + + Bundler bundler = CreateBundlerInstance(macosCodesign: shouldCodesign); + string bundledApp = bundler.GenerateBundle(fileSpecs); + + // Check if the file is signed + CommandResult result = Command.Create("codesign", $"-v {bundledApp}") + .CaptureStdErr() + .CaptureStdOut() + .Execute(expectedToFail: !shouldCodesign); + + if (shouldCodesign) + { + result.Should().Pass(); + } + else + { + result.Should().Fail(); + } + } + public class SharedTestState : IDisposable { public const string AppName = "HelloWorld"; diff --git a/src/installer/tests/TestUtils/SingleFileTestApp.cs b/src/installer/tests/TestUtils/SingleFileTestApp.cs index 356cdb5d5ccea4a3e473ac7fca52a1d44cc62013..fbdcbc84a39b1477000ce7b5137b9038fe72571c 100644 --- a/src/installer/tests/TestUtils/SingleFileTestApp.cs +++ b/src/installer/tests/TestUtils/SingleFileTestApp.cs @@ -73,7 +73,12 @@ public static IReadOnlyList GetRuntimeFilesToBundle() return fileSpecs; } - public string Bundle(BundleOptions options, Version? bundleVersion = null) + public string Bundle(BundleOptions options = BundleOptions.None, Version? bundleVersion = null) + { + return Bundle(options, out _, bundleVersion); + } + + public string Bundle(BundleOptions options, out Manifest manifest, Version? bundleVersion = null) { string bundleDirectory = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(Location, "bundle")); var bundler = new Bundler( @@ -113,9 +118,20 @@ public string Bundle(BundleOptions options, Version? bundleVersion = null) File.Copy(spec.SourcePath, outputFilePath, true); } + manifest = bundler.BundleManifest; return singleFile; } + public string GetNewExtractionRootPath() + { + return SharedFramework.CalculateUniqueTestDirectory(Path.Combine(Location, "extract")); + } + + public DirectoryInfo GetExtractionDir(string root, Manifest manifest) + { + return new DirectoryInfo(Path.Combine(root, Name, manifest.BundleID)); + } + private void PopulateBuiltAppDirectory() { // Copy the compiled app output - the app is expected to have been built as framework-dependent diff --git a/src/native/corehost/bundle/extractor.cpp b/src/native/corehost/bundle/extractor.cpp index a96dcc5220f311ce81aaa7cf98c5759e2dc57b64..fc0659e82dc32d071b56a0f14708e11a5ab71faa 100644 --- a/src/native/corehost/bundle/extractor.cpp +++ b/src/native/corehost/bundle/extractor.cpp @@ -63,7 +63,7 @@ pal::string_t& extractor_t::extraction_dir() append_path(&m_extraction_dir, host_name.c_str()); append_path(&m_extraction_dir, m_bundle_id.c_str()); - trace::info(_X("Files embedded within the bundled will be extracted to [%s] directory."), m_extraction_dir.c_str()); + trace::info(_X("Files embedded within the bundle will be extracted to [%s] directory."), m_extraction_dir.c_str()); } return m_extraction_dir;