1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-09 17:44:48 +09:00

Make BundlerConsistencyTests stop building/copying self-contained project unnecessarily (#91829)

`BundlerConsistencyTests` were building a self-contained project and copying it for each test case. They are targeting the `Bundler` API and don't actual need a full app - just validation of how things get bundled and added to the manifest.
- Add a `HelloWorld` project for as a pre-built test asset for host tests
- Make `BundlerConsistencyTests` use a pre-built app and shared framework files instead of building/copying a self-contained project
- Move the one test `TestWithAdditionalContentAfterBundleMetadata` that actually runs the bundled app into `BundleAndRun`
This commit is contained in:
Elinor Fung 2023-09-11 08:39:38 -07:00 committed by GitHub
parent 9a68b7e9d9
commit 9d08b24d74
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 251 additions and 247 deletions

View file

@ -489,6 +489,7 @@
<!-- Host.pretest subset (consumes live built libraries assets so needs to come after libraries) -->
<ItemGroup Condition="$(_subset.Contains('+host.pretest+'))">
<ProjectToBuild Include="$(InstallerProjectRoot)tests\Assets\Projects\AppWithSubDirs\AppWithSubDirs.csproj" Category="host" />
<ProjectToBuild Include="$(InstallerProjectRoot)tests\Assets\Projects\HelloWorld\HelloWorld.csproj" Category="host" />
</ItemGroup>
<!-- Host.tests subset (consumes live built libraries assets so needs to come after libraries) -->

View file

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
</Project>

View file

@ -0,0 +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.Runtime.InteropServices;
namespace HelloWorld
{
public static class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Console.WriteLine(string.Join(Environment.NewLine, args));
Console.WriteLine(RuntimeInformation.FrameworkDescription);
}
}
}

View file

@ -8,6 +8,7 @@ using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.DotNet.CoreSetup.Test;
using BundleTests.Helpers;
using System.Runtime.InteropServices;
using System.Text;
namespace Microsoft.NET.HostModel.Tests
{
@ -120,6 +121,27 @@ namespace Microsoft.NET.HostModel.Tests
BundleRun(fixture, publishDir);
}
[Fact]
public void TestWithAdditionalContentAfterBundleMetadata()
{
var fixture = sharedTestState.TestFixture.Copy();
string singleFile = BundleHelper.BundleApp(fixture);
using (var file = File.OpenWrite(singleFile))
{
file.Position = file.Length;
var blob = Encoding.UTF8.GetBytes("Mock signature at the end of the bundle");
file.Write(blob, 0, blob.Length);
}
Command.Create(singleFile)
.CaptureStdErr()
.CaptureStdOut()
.Execute()
.Should().Pass()
.And.HaveStdOutContaining("Hello World!");
}
public class SharedTestState : IDisposable
{
public TestProjectFixture TestFixture { get; set; }

View file

@ -1,17 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using BundleTests.Helpers;
using FluentAssertions;
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.Text;
using FluentAssertions;
using Microsoft.DotNet.CoreSetup.Test;
using Microsoft.NET.HostModel.Bundle;
using Xunit;
namespace Microsoft.NET.HostModel.Tests
@ -25,80 +22,69 @@ namespace Microsoft.NET.HostModel.Tests
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);
[Fact]
public void EnableCompression_Before60_Fails()
{
// compression must be off when targeting pre-6.0
Assert.Throws<ArgumentException>(() =>
new Bundler("appName", RepoDirectoriesProvider.Default.TestAssetsOutput, BundleOptions.EnableCompression, targetFrameworkVersion: new Version(5, 0)));
CreateBundlerInstance(BundleOptions.EnableCompression, new Version(5, 0)));
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void InvalidFileSpec_Fails(string invalidSpecPath)
{
FileSpec invalidSourcePath = new FileSpec(invalidSpecPath, BundlerHostName);
Assert.False(invalidSourcePath.IsValid());
FileSpec invalidBundlePath = new FileSpec(BundlerHostName, invalidSpecPath);
Assert.False(invalidBundlePath.IsValid());
Bundler bundler = CreateBundlerInstance();
Assert.Throws<ArgumentException>(() => bundler.GenerateBundle(new[] { invalidSourcePath }));
Assert.Throws<ArgumentException>(() => bundler.GenerateBundle(new[] { invalidBundlePath }));
}
[Fact]
public void TestWithEmptySpecFails()
public void NoHostInFileSpecs_Fails()
{
var fixture = sharedTestState.TestFixture.Copy();
var appName = Path.GetFileNameWithoutExtension(BundlerHostName);
var hostName = BundleHelper.GetHostName(fixture);
var bundleDir = BundleHelper.GetBundleDir(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
Bundler bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
FileSpec[][] invalidSpecs =
// File specification without the apphost
var fileSpecs = new FileSpec[]
{
new FileSpec[] {new FileSpec(hostName, null) },
new FileSpec[] {new FileSpec(hostName, "") },
new FileSpec[] {new FileSpec(hostName, " ") }
new FileSpec($"{appName}.dll", $"{appName}.dll"),
new FileSpec($"{appName}.deps.json", $"{appName}.deps.json"),
new FileSpec($"{appName}.runtimeconfig.json", $"{appName}.runtimeconfig.json")
};
foreach (var invalidSpec in invalidSpecs)
{
Assert.Throws<ArgumentException>(() => bundler.GenerateBundle(invalidSpec));
}
}
[Fact]
public void TestWithoutSpecifyingHostFails()
{
var fixture = sharedTestState.TestFixture.Copy();
var hostName = BundleHelper.GetHostName(fixture);
var appName = Path.GetFileNameWithoutExtension(hostName);
var bundleDir = BundleHelper.GetBundleDir(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
// Generate a file specification without the apphost
var fileSpecs = new List<FileSpec>();
string[] files = { $"{appName}.dll", $"{appName}.deps.json", $"{appName}.runtimeconfig.json" };
Array.ForEach(files, x => fileSpecs.Add(new FileSpec(x, x)));
Bundler bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
Bundler bundler = CreateBundlerInstance();
Assert.Throws<ArgumentException>(() => bundler.GenerateBundle(fileSpecs));
}
[Fact]
public void TestWithExactDuplicateEntriesPasses()
public void ExactDuplicateEntries()
{
var fixture = sharedTestState.TestFixture.Copy();
string appPath = sharedTestState.App.AppDll;
string systemLibPath = sharedTestState.SystemDll;
var hostName = BundleHelper.GetHostName(fixture);
var bundleDir = BundleHelper.GetBundleDir(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
// File specification with duplicate entries with matching source paths
var fileSpecs = new FileSpec[]
{
new FileSpec(Binaries.AppHost.FilePath, BundlerHostName),
new FileSpec(appPath, "rel/app.repeat.dll"),
new FileSpec(appPath, "rel/app.repeat.dll"),
new FileSpec(systemLibPath, "rel/system.repeat.dll"),
new FileSpec(systemLibPath, "rel/system.repeat.dll")
};
// Generate a file specification with duplicate entries
var fileSpecs = new List<FileSpec>();
fileSpecs.Add(new FileSpec(BundleHelper.GetHostPath(fixture), BundleHelper.GetHostName(fixture)));
string appPath = BundleHelper.GetAppPath(fixture);
fileSpecs.Add(new FileSpec(appPath, "rel/app.repeat.dll"));
fileSpecs.Add(new FileSpec(appPath, "rel/app.repeat.dll"));
string systemLibPath = Path.Join(BundleHelper.GetPublishPath(fixture), "System.dll");
fileSpecs.Add(new FileSpec(systemLibPath, "rel/system.repeat.dll"));
fileSpecs.Add(new FileSpec(systemLibPath, "rel/system.repeat.dll"));
Bundler bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
Bundler bundler = CreateBundlerInstance();
bundler.GenerateBundle(fileSpecs);
// Exact duplicates are not duplicated in the bundle
@ -107,45 +93,35 @@ namespace Microsoft.NET.HostModel.Tests
}
[Fact]
public void TestWithDuplicateEntriesFails()
public void DuplicateBundleRelativePath_Fails()
{
var fixture = sharedTestState.TestFixture.Copy();
// File specification with duplicate entries with different source paths
var fileSpecs = new FileSpec[]
{
new FileSpec(Binaries.AppHost.FilePath, BundlerHostName),
new FileSpec(sharedTestState.App.AppDll, "rel/app.repeat"),
new FileSpec(sharedTestState.SystemDll, "rel/app.repeat"),
};
var hostName = BundleHelper.GetHostName(fixture);
var bundleDir = BundleHelper.GetBundleDir(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
// Generate a file specification with duplicate entries
var fileSpecs = new List<FileSpec>();
fileSpecs.Add(new FileSpec(BundleHelper.GetHostPath(fixture), BundleHelper.GetHostName(fixture)));
fileSpecs.Add(new FileSpec(BundleHelper.GetAppPath(fixture), "rel/app.repeat"));
fileSpecs.Add(new FileSpec(Path.Join(BundleHelper.GetPublishPath(fixture), "System.dll"), "rel/app.repeat"));
Bundler bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
Bundler bundler = CreateBundlerInstance();
Assert.Throws<ArgumentException>(() => bundler.GenerateBundle(fileSpecs))
.Message
.Should().Contain("rel/app.repeat")
.And.Contain(BundleHelper.GetAppPath(fixture));
.And.Contain(sharedTestState.App.AppDll);
}
[Fact]
public void TestWithCaseSensitiveDuplicateEntriesPasses()
public void CaseSensitiveBundleRelativePath()
{
var fixture = sharedTestState.TestFixture.Copy();
// File specification with entries with bundle paths differing only in casing
var fileSpecs = new FileSpec[]
{
new FileSpec(Binaries.AppHost.FilePath, BundlerHostName),
new FileSpec(sharedTestState.App.AppDll, "rel/app.repeat.dll"),
new FileSpec(sharedTestState.SystemDll, "rel/app.Repeat.dll"),
};
var hostName = BundleHelper.GetHostName(fixture);
var bundleDir = BundleHelper.GetBundleDir(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
// Generate a file specification with duplicate entries
var fileSpecs = new List<FileSpec>();
fileSpecs.Add(new FileSpec(BundleHelper.GetHostPath(fixture), BundleHelper.GetHostName(fixture)));
fileSpecs.Add(new FileSpec(BundleHelper.GetAppPath(fixture), "rel/app.repeat.dll"));
fileSpecs.Add(new FileSpec(Path.Join(BundleHelper.GetPublishPath(fixture), "System.dll"), "rel/app.Repeat.dll"));
Bundler bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
Bundler bundler = CreateBundlerInstance();
bundler.GenerateBundle(fileSpecs);
bundler.BundleManifest.Files.Where(entry => entry.RelativePath.Equals("rel/app.repeat.dll")).Single().Type.Should().Be(FileType.Assembly);
@ -154,27 +130,21 @@ namespace Microsoft.NET.HostModel.Tests
private (string bundleFileName, string bundleId) CreateSampleBundle(bool bundleMultipleFiles)
{
var fixture = sharedTestState.TestFixture.Copy();
var hostName = BundleHelper.GetHostName(fixture);
var bundleDir = Directory.CreateDirectory(
Path.Combine(BundleHelper.GetBundleDir(fixture).FullName, Path.GetRandomFileName()));
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
var fileSpecs = new List<FileSpec>();
fileSpecs.Add(new FileSpec(BundleHelper.GetHostPath(fixture), BundleHelper.GetHostName(fixture)));
var fileSpecs = new List<FileSpec>()
{
new FileSpec(Binaries.AppHost.FilePath, BundlerHostName)
};
if (bundleMultipleFiles)
{
fileSpecs.Add(new FileSpec(BundleHelper.GetAppPath(fixture), "rel/app.repeat.dll"));
fileSpecs.Add(new FileSpec(sharedTestState.App.AppDll, "rel/app.repeat.dll"));
}
Bundler bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
Bundler bundler = CreateBundlerInstance();
return (bundler.GenerateBundle(fileSpecs), bundler.BundleManifest.BundleID);
}
[Fact]
public void TestWithIdenticalBundlesShouldBeBinaryEqualPasses()
public void IdenticalBundles_BinaryEqual()
{
var firstBundle = CreateSampleBundle(true);
byte[] firstBundleContent = File.ReadAllBytes(firstBundle.bundleFileName);
@ -188,7 +158,7 @@ namespace Microsoft.NET.HostModel.Tests
}
[Fact]
public void TestWithUniqueBundlesShouldHaveUniqueBundleIdsPasses()
public void UniqueBundles_UniqueBundleIds()
{
string firstBundle = CreateSampleBundle(true).bundleId;
string secondBundle = CreateSampleBundle(false).bundleId;
@ -197,26 +167,21 @@ namespace Microsoft.NET.HostModel.Tests
}
[Fact]
public void TestWithMultipleDuplicateEntriesFails()
public void MultipleDuplicateBundleRelativePath_Fails()
{
var fixture = sharedTestState.TestFixture.Copy();
// File specification with a mix of duplicate entries with different/matching source paths
string appPath = sharedTestState.App.AppDll;
string systemLibPath = sharedTestState.SystemDll;
var fileSpecs = new FileSpec[]
{
new FileSpec(Binaries.AppHost.FilePath, BundlerHostName),
new FileSpec(appPath, "rel/app.repeat.dll"),
new FileSpec(appPath, "rel/app.repeat.dll"),
new FileSpec(appPath, "rel/system.repeat.dll"),
new FileSpec(systemLibPath, "rel/system.repeat.dll"),
};
var hostName = BundleHelper.GetHostName(fixture);
var bundleDir = BundleHelper.GetBundleDir(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
// Generate a file specification with duplicate entries
var fileSpecs = new List<FileSpec>();
fileSpecs.Add(new FileSpec(BundleHelper.GetHostPath(fixture), BundleHelper.GetHostName(fixture)));
string appPath = BundleHelper.GetAppPath(fixture);
fileSpecs.Add(new FileSpec(appPath, "rel/app.repeat.dll"));
fileSpecs.Add(new FileSpec(appPath, "rel/app.repeat.dll"));
string systemLibPath = Path.Join(BundleHelper.GetPublishPath(fixture), "System.dll");
fileSpecs.Add(new FileSpec(appPath, "rel/system.repeat.dll"));
fileSpecs.Add(new FileSpec(systemLibPath, "rel/system.repeat.dll"));
Bundler bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
Bundler bundler = CreateBundlerInstance();
Assert.Throws<ArgumentException>(() => bundler.GenerateBundle(fileSpecs))
.Message
.Should().Contain("rel/system.repeat.dll")
@ -226,41 +191,36 @@ namespace Microsoft.NET.HostModel.Tests
}
[Fact]
public void TestBaseNameComputation()
public void BaseNameComputation()
{
var fixture = sharedTestState.TestFixture.Copy();
var publishPath = BundleHelper.GetPublishPath(fixture);
var bundleDir = BundleHelper.GetBundleDir(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
// Rename the host from "StandaloneApp" to "Stand.Alone.App" to check that baseName computation
// Create an app with multiple periods in its name to check that baseName computation
// (and consequently deps.json and runtimeconfig.json name computations) in the bundler
// work correctly in the presence of "."s in the hostName.
var originalBaseName = "StandaloneApp";
var newBaseName = "Stand.Alone.App";
var exe = OperatingSystem.IsWindows() ? ".exe" : string.Empty;
void rename(string extension)
using (var app = TestApp.CreateEmpty("App.With.Periods"))
{
File.Move(Path.Combine(publishPath, originalBaseName + extension), Path.Combine(publishPath, newBaseName + extension));
app.PopulateFrameworkDependent(Constants.MicrosoftNETCoreApp, RepoDirectoriesProvider.Default.MicrosoftNETCoreAppVersion);
string hostName = Path.GetFileName(app.AppExe);
string depsJsonName = Path.GetFileName(app.DepsJson);
string runtimeConfigName = Path.GetFileName(app.RuntimeConfigJson);
FileSpec[] fileSpecs = new FileSpec[]
{
new FileSpec(Binaries.AppHost.FilePath, hostName),
new FileSpec(app.AppDll, Path.GetRelativePath(app.Location, app.AppDll)),
new FileSpec(app.DepsJson, depsJsonName),
new FileSpec(app.RuntimeConfigJson, runtimeConfigName),
};
var bundleDir = Directory.CreateDirectory(SharedFramework.CalculateUniqueTestDirectory(Path.Combine(app.Location, "bundle")));
var bundler = new Bundler(hostName, bundleDir.FullName);
bundler.GenerateBundle(fileSpecs);
bundler.BundleManifest.Files.Where(entry => entry.RelativePath.Equals(depsJsonName)).Single().Type.Should().Be(FileType.DepsJson);
bundler.BundleManifest.Files.Where(entry => entry.RelativePath.Equals(runtimeConfigName)).Single().Type.Should().Be(FileType.RuntimeConfigJson);
bundleDir.Should().NotHaveFile(depsJsonName);
bundleDir.Should().NotHaveFile(runtimeConfigName);
}
rename(exe);
rename(".deps.json");
rename(".runtimeconfig.json");
var hostName = newBaseName + exe;
var depsJson = newBaseName + ".deps.json";
var runtimeconfigJson = newBaseName + ".runtimeconfig.json";
var bundler = new Bundler(hostName, bundleDir.FullName, targetOS: targetOS, targetArch: targetArch);
BundleHelper.GenerateBundle(bundler, publishPath, bundleDir.FullName);
string[] jsonFiles = { depsJson, runtimeconfigJson };
bundler.BundleManifest.Files.Where(entry => entry.RelativePath.Equals(depsJson)).Single().Type.Should().Be(FileType.DepsJson);
bundler.BundleManifest.Files.Where(entry => entry.RelativePath.Equals(runtimeconfigJson)).Single().Type.Should().Be(FileType.RuntimeConfigJson);
bundleDir.Should().NotHaveFiles(jsonFiles);
}
[InlineData(BundleOptions.None)]
@ -269,126 +229,103 @@ namespace Microsoft.NET.HostModel.Tests
[InlineData(BundleOptions.BundleAllContent)]
[InlineData(BundleOptions.BundleSymbolFiles)]
[Theory]
public void TestFilesAlwaysBundled(BundleOptions options)
public void BundleOptions_IncludedExcludedFiles(BundleOptions options)
{
var fixture = sharedTestState.TestFixture.Copy();
var bundler = BundleHelper.Bundle(fixture, options);
var bundledFiles = BundleHelper.GetBundledFiles(fixture);
TestApp app = sharedTestState.App;
string devJsonName = Path.GetFileName(app.RuntimeDevConfigJson);
string appSymbolName = $"{app.Name}.pdb";
string otherContentName = "other.txt";
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)),
new FileSpec(app.RuntimeConfigJson, devJsonName),
new FileSpec(Path.Combine(app.Location, appSymbolName), appSymbolName),
new FileSpec(Binaries.CoreClr.FilePath, Binaries.CoreClr.FileName),
new FileSpec(app.RuntimeConfigJson, otherContentName),
};
Array.ForEach(bundledFiles, file => bundler.BundleManifest.Contains(file).Should().BeTrue());
}
Bundler bundler = CreateBundlerInstance(options);
bundler.GenerateBundle(fileSpecs);
[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[InlineData(BundleOptions.BundleOtherFiles)]
[InlineData(BundleOptions.BundleAllContent)]
[InlineData(BundleOptions.BundleSymbolFiles)]
[Theory]
public void TestFilesNeverBundled(BundleOptions options)
{
var fixture = sharedTestState.TestFixture.Copy();
var appBaseName = BundleHelper.GetAppBaseName(fixture);
string publishPath = BundleHelper.GetPublishPath(fixture);
// App's dll, .deps.json, and .runtimeconfig.json should always be bundled
Assert.True(bundler.BundleManifest.Contains(Path.GetFileName(app.AppDll)));
Assert.True(bundler.BundleManifest.Contains(Path.GetFileName(app.DepsJson)));
Assert.True(bundler.BundleManifest.Contains(Path.GetFileName(app.RuntimeConfigJson)));
// Make up a app.runtimeconfig.dev.json file in the publish directory.
File.Copy(Path.Combine(publishPath, $"{appBaseName}.runtimeconfig.json"),
Path.Combine(publishPath, $"{appBaseName}.runtimeconfig.dev.json"));
// App's .runtimeconfig.dev.json is always excluded
Assert.False(bundler.BundleManifest.Contains(devJsonName));
var bundler = BundleHelper.Bundle(fixture, options);
// Symbols should only be bundled if option is explicitly set
bundler.BundleManifest.Contains(appSymbolName).Should().Be(options.HasFlag(BundleOptions.BundleSymbolFiles));
bundler.BundleManifest.Contains($"{appBaseName}.runtimeconfig.dev.json").Should().BeFalse();
}
// Native libararies should only be bundled if option is explicitly set
bundler.BundleManifest.Contains(Binaries.CoreClr.FileName).Should().Be(options.HasFlag(BundleOptions.BundleNativeBinaries));
[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleSymbolFiles)]
[Theory]
public void TestBundlingSymbols(BundleOptions options)
{
var fixture = sharedTestState.TestFixture.Copy();
var appBaseName = BundleHelper.GetAppBaseName(fixture);
var bundler = BundleHelper.Bundle(fixture, options);
bundler.BundleManifest.Contains($"{appBaseName}.pdb").Should().Be(options.HasFlag(BundleOptions.BundleSymbolFiles));
}
[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[Theory]
public void TestBundlingNativeBinaries(BundleOptions options)
{
var fixture = sharedTestState.TestFixture.Copy();
var coreclr = Path.GetFileName(fixture.TestProject.CoreClrDll);
var bundler = BundleHelper.Bundle(fixture, options);
bundler.BundleManifest.Contains($"{coreclr}").Should().Be(options.HasFlag(BundleOptions.BundleNativeBinaries));
// Other files should only be bundled if option is explicitly set
bundler.BundleManifest.Contains(otherContentName).Should().Be(options.HasFlag(BundleOptions.BundleOtherFiles));
}
[Fact]
public void TestFileSizes()
public void FileSizes()
{
var fixture = sharedTestState.TestFixture.Copy();
var bundler = BundleHelper.Bundle(fixture);
var publishPath = BundleHelper.GetPublishPath(fixture);
var app = sharedTestState.App;
List<FileSpec> fileSpecs = new List<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)),
};
fileSpecs.AddRange(SingleFileTestApp.GetRuntimeFilesToBundle());
bundler.BundleManifest.Files.ForEach(file =>
Assert.True(file.Size == new FileInfo(Path.Combine(publishPath, file.RelativePath)).Length));
Bundler bundler = CreateBundlerInstance();
bundler.GenerateBundle(fileSpecs);
foreach (FileEntry file in bundler.BundleManifest.Files)
{
var spec = fileSpecs.Single(f => f.BundleRelativePath == file.RelativePath);
Assert.True(file.Size == new FileInfo(spec.SourcePath).Length);
}
}
[Fact]
public void TestAssemblyAlignment()
public void AssemblyAlignment()
{
var fixture = sharedTestState.TestFixture.Copy();
var bundler = BundleHelper.Bundle(fixture);
var targetOS = BundleHelper.GetTargetOS(fixture.CurrentRid);
var targetArch = BundleHelper.GetTargetArch(fixture.CurrentRid);
var alignment = (targetOS == OSPlatform.Linux && targetArch == Architecture.Arm64) ? 4096 : 16;
var app = sharedTestState.App;
List<FileSpec> fileSpecs = new List<FileSpec>
{
new FileSpec(Binaries.AppHost.FilePath, BundlerHostName),
new FileSpec(app.AppDll, Path.GetRelativePath(app.Location, app.AppDll)),
};
fileSpecs.AddRange(SingleFileTestApp.GetRuntimeFilesToBundle());
Bundler bundler = CreateBundlerInstance();
bundler.GenerateBundle(fileSpecs);
var alignment = OperatingSystem.IsLinux() && RuntimeInformation.OSArchitecture == Architecture.Arm64 ? 4096 : 16;
bundler.BundleManifest.Files.ForEach(file =>
Assert.True((file.Type != FileType.Assembly) || (file.Offset % alignment == 0)));
}
[Fact]
public void TestWithAdditionalContentAfterBundleMetadata()
{
var fixture = sharedTestState.TestFixture.Copy();
string singleFile = BundleHelper.BundleApp(fixture);
using (var file = File.OpenWrite(singleFile))
{
file.Position = file.Length;
var blob = Encoding.UTF8.GetBytes("Mock signature at the end of the bundle");
file.Write(blob, 0, blob.Length);
}
Command.Create(singleFile)
.CaptureStdErr()
.CaptureStdOut()
.Execute()
.Should()
.Pass()
.And
.HaveStdOutContaining("Hello World!");
}
public class SharedTestState : IDisposable
{
public TestProjectFixture TestFixture { get; set; }
public RepoDirectoriesProvider RepoDirectories { get; set; }
public const string AppName = "HelloWorld";
public TestApp App { get; }
public string SystemDll { get; }
public SharedTestState()
{
RepoDirectories = new RepoDirectoriesProvider();
App = TestApp.CreateFromBuiltAssets(AppName);
TestFixture = new TestProjectFixture("StandaloneApp", RepoDirectories);
TestFixture
.EnsureRestoredForRid(TestFixture.CurrentRid)
.PublishProject(runtime: TestFixture.CurrentRid,
selfContained: true,
outputDirectory: BundleHelper.GetPublishPath(TestFixture));
var builtDotNet = new DotNet.Cli.Build.DotNetCli(RepoDirectoriesProvider.Default.BuiltDotnet);
SystemDll = Path.Combine(builtDotNet.GreatestVersionSharedFxPath, "System.dll");
}
public void Dispose()
{
TestFixture.Dispose();
App.Dispose();
}
}
}

View file

@ -42,7 +42,7 @@ namespace Microsoft.DotNet.CoreSetup.Test
public static class CoreClr
{
public static string FileName = GetSharedLibraryFileNameForCurrentPlatform("coreclr");
public static string FilePath = Path.Combine(RepoDirectoriesProvider.Default.HostArtifacts, FileName);
public static string FilePath = Path.Combine(new DotNetCli(RepoDirectoriesProvider.Default.BuiltDotnet).GreatestVersionSharedFxPath, FileName);
public static string MockName = GetSharedLibraryFileNameForCurrentPlatform("mockcoreclr");
public static string MockPath = Path.Combine(RepoDirectoriesProvider.Default.HostTestArtifacts, MockName);

View file

@ -60,6 +60,19 @@ namespace Microsoft.DotNet.CoreSetup.Test
};
}
public static IReadOnlyList<FileSpec> GetRuntimeFilesToBundle()
{
var runtimeAssemblies = Binaries.GetRuntimeFiles().Assemblies;
List<FileSpec> fileSpecs = new List<FileSpec>();
foreach (var asset in runtimeAssemblies)
{
fileSpecs.Add(new FileSpec(asset, Path.GetFileName(asset)));
}
fileSpecs.Sort((a, b) => string.CompareOrdinal(a.BundleRelativePath, b.BundleRelativePath));
return fileSpecs;
}
public string Bundle(BundleOptions options, Version? bundleVersion = null)
{
string bundleDirectory = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(Location, "bundle"));
@ -81,11 +94,7 @@ namespace Microsoft.DotNet.CoreSetup.Test
// If this is a self-contained app, add the runtime assemblies to the bundle
if (selfContained)
{
var runtimeAssemblies = Binaries.GetRuntimeFiles().Assemblies;
foreach (var asset in runtimeAssemblies)
{
fileSpecs.Add(new FileSpec(asset, Path.GetFileName(asset)));
}
fileSpecs.AddRange(GetRuntimeFilesToBundle());
}
// Sort the file specs to keep the bundle construction deterministic.

View file

@ -50,6 +50,15 @@ namespace Microsoft.DotNet.CoreSetup.Test
};
}
public static TestApp CreateFromBuiltAssets(string appName)
{
TestApp app = CreateEmpty(appName);
TestArtifact.CopyRecursive(
Path.Combine(RepoDirectoriesProvider.Default.TestAssetsOutput, appName),
app.Location);
return app;
}
public void PopulateFrameworkDependent(string fxName, string fxVersion, Action<NetCoreAppBuilder> customizer = null)
{
var builder = NetCoreAppBuilder.PortableForNETCoreApp(this);