Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public DotNetFramework RuntimeConfig(Action<RuntimeConfig> runtimeConfigCustomiz
{
string runtimeConfigPath = Path.Combine(_path, _name + ".runtimeconfig.json");
_backup.Backup(runtimeConfigPath);
RuntimeConfig runtimeConfig = HostActivation.RuntimeConfig.FromFile(runtimeConfigPath);
RuntimeConfig runtimeConfig = Test.RuntimeConfig.FromFile(runtimeConfigPath);
runtimeConfigCustomizer(runtimeConfig);
runtimeConfig.Save();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<AssemblyName>HostActivation.Tests</AssemblyName>
<PackageId>HostActivation.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<DefineConstants Condition="'$(TargetOS)' == 'windows'">$(DefineConstants);WINDOWS</DefineConstants>
<!-- Reduce the length of the test output dir to make it more reliable on Windows. -->
<TestsOutputName>ha</TestsOutputName>
<UsesTestAssets>true</UsesTestAssets>
Expand All @@ -17,7 +16,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelVersion)" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.3.0" />
</ItemGroup>

Expand Down
50 changes: 3 additions & 47 deletions src/installer/tests/HostActivation.Tests/PortableAppActivation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ public void AppHost_GUI_FrameworkDependent_MissingRuntimeFramework_ErrorReported
.MultilevelLookup(false)
.Start();

WaitForPopupFromProcess(command.Process);
WindowsUtils.WaitForPopupFromProcess(command.Process);
command.Process.Kill();

var result = command.WaitForExit(true)
Expand Down Expand Up @@ -559,7 +559,7 @@ public void AppHost_GUI_MissingRuntime_ErrorReportedInDialog()
.MultilevelLookup(false)
.Start();

WaitForPopupFromProcess(command.Process);
WindowsUtils.WaitForPopupFromProcess(command.Process);
command.Process.Kill();

var expectedErrorCode = Constants.ErrorCode.CoreHostLibMissingFailure.ToString("x");
Expand Down Expand Up @@ -601,7 +601,7 @@ public void AppHost_GUI_NoCustomErrorWriter_FrameworkMissing_ErrorReportedInDial
.MultilevelLookup(false)
.Start();

WaitForPopupFromProcess(command.Process);
WindowsUtils.WaitForPopupFromProcess(command.Process);
command.Process.Kill();

command.WaitForExit(true)
Expand Down Expand Up @@ -689,50 +689,6 @@ private string CreateAStore(TestProjectFixture testProjectFixture)
return storeoutputDirectory;
}

#if WINDOWS
private delegate bool EnumThreadWindowsDelegate(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadWindowsDelegate plfn, IntPtr lParam);

private IntPtr WaitForPopupFromProcess(Process process, int timeout = 60000)
{
IntPtr windowHandle = IntPtr.Zero;
int timeRemaining = timeout;
while (timeRemaining > 0)
{
foreach (ProcessThread thread in process.Threads)
{
// We take the last window we find. There really should only be one at most anyways.
EnumThreadWindows(thread.Id,
(hWnd, lParam) => {
windowHandle = hWnd;
return true;
},
IntPtr.Zero);
}

if (windowHandle != IntPtr.Zero)
{
break;
}

System.Threading.Thread.Sleep(100);
timeRemaining -= 100;
}

// Do not fail if the window could be detected, sometimes the check is fragile and doesn't work.
// Not worth the trouble trying to figure out why (only happens rarely in the CI system).
// We will rely on product tracing in the failure case.
return windowHandle;
}
#else
private IntPtr WaitForPopupFromProcess(Process process, int timeout = 60000)
{
throw new PlatformNotSupportedException();
}
#endif

public class SharedTestState : IDisposable
{
public TestProjectFixture PortableAppFixture_Built { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using BundleTests.Helpers;
using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.DotNet.CoreSetup.Test;
Expand All @@ -22,9 +23,7 @@ public BundledAppWithSubDirs(SharedTestState fixture)
private void RunTheApp(string path, TestProjectFixture fixture)
{
Command.Create(path)
.EnvironmentVariable("COREHOST_TRACE", "1")
.CaptureStdErr()
.CaptureStdOut()
.EnableTracingAndCaptureOutputs()
.EnvironmentVariable("DOTNET_ROOT", fixture.BuiltDotnet.BinPath)
.EnvironmentVariable("DOTNET_ROOT(x86)", fixture.BuiltDotnet.BinPath)
.EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0")
Expand Down Expand Up @@ -52,6 +51,46 @@ public void Bundled_Framework_dependent_App_Run_Succeeds(BundleOptions options)
RunTheApp(singleFile, fixture);
}

[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[InlineData(BundleOptions.BundleAllContent)]
[Theory]
[PlatformSpecific(TestPlatforms.Windows)] // GUI app host is only supported on Windows.
public void Bundled_Framework_dependent_App_GUI_DownlevelHostFxr_ErrorDialog(BundleOptions options)
{
var fixture = sharedTestState.TestFrameworkDependentFixture.Copy();
UseFrameworkDependentHost(fixture);
var singleFile = BundleHelper.BundleApp(fixture, options);
AppHostExtensions.SetWindowsGraphicalUserInterfaceBit(singleFile);

string dotnetWithMockHostFxr = SharedFramework.CalculateUniqueTestDirectory(Path.Combine(TestArtifact.TestArtifactsPath, "bundleErrors"));
using (new TestArtifact(dotnetWithMockHostFxr))
{
Directory.CreateDirectory(dotnetWithMockHostFxr);
string expectedErrorCode = Constants.ErrorCode.BundleExtractionFailure.ToString("x");

var dotnetBuilder = new DotNetBuilder(dotnetWithMockHostFxr, sharedTestState.RepoDirectories.BuiltDotnet, "hostfxrFrameworkMissingFailure")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the name be mockhostfxrBundleVersionFailure? Or am I not understanding how these tests are supposed to be set up?

.RemoveHostFxr()
.AddMockHostFxr(new Version(5, 0, 0));
var dotnet = dotnetBuilder.Build();

Command command = Command.Create(singleFile)
.EnableTracingAndCaptureOutputs()
.DotNetRoot(dotnet.BinPath, sharedTestState.RepoDirectories.BuildArchitecture)
.MultilevelLookup(false)
.Start();

WindowsUtils.WaitForPopupFromProcess(command.Process);
command.Process.Kill();

command
.WaitForExit(true)
.Should().Fail()
.And.HaveStdErrContaining("Bundle header version compatibility check failed.")
.And.HaveStdErrContaining($"Showing error dialog for application: '{Path.GetFileName(singleFile)}' - error code: 0x{expectedErrorCode}");
}
}

[InlineData(BundleOptions.None)]
[InlineData(BundleOptions.BundleNativeBinaries)]
[InlineData(BundleOptions.BundleAllContent)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.DotNet.CoreSetup.Test;
using System;
using System.IO;

namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
namespace Microsoft.DotNet.CoreSetup.Test
{
public static class CommandExtensions
{
Expand Down Expand Up @@ -38,11 +39,11 @@ public static Command EnableTracingAndCaptureOutputs(this Command command)
public static Command DotNetRoot(this Command command, string dotNetRoot, string architecture = null)
{
if (!string.IsNullOrEmpty(architecture))
return command.EnvironmentVariable($"DOTNET_ROOT_{architecture.ToUpper()}", dotNetRoot);
return command.EnvironmentVariable(Constants.DotnetRoot.ArchitectureEnvironmentVariablePrefix + architecture.ToUpper(), dotNetRoot);

return command
.EnvironmentVariable("DOTNET_ROOT", dotNetRoot)
.EnvironmentVariable("DOTNET_ROOT(x86)", dotNetRoot);
.EnvironmentVariable(Constants.DotnetRoot.EnvironmentVariable, dotNetRoot)
.EnvironmentVariable(Constants.DotnetRoot.WindowsX86EnvironmentVariable, dotNetRoot);
}

public static Command MultilevelLookup(this Command command, bool enable)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
namespace Microsoft.DotNet.CoreSetup.Test
{
internal static class Constants
public static class Constants
{
public const string MicrosoftNETCoreApp = "Microsoft.NETCore.App";

Expand Down Expand Up @@ -72,6 +72,13 @@ public static class HostTracing
public const string TraceFileEnvironmentVariable = "COREHOST_TRACEFILE";
}

public static class DotnetRoot
{
public const string EnvironmentVariable = "DOTNET_ROOT";
public const string WindowsX86EnvironmentVariable = "DOTNET_ROOT(x86)";
public const string ArchitectureEnvironmentVariablePrefix = "DOTNET_ROOT_";
}

public static class ErrorCode
{
public const int InvalidArgFailure = unchecked((int)0x80008081);
Expand All @@ -81,6 +88,7 @@ public static class ErrorCode
public const int LibHostInvalidArgs = unchecked((int)0x80008092);
public const int AppArgNotRunnable = unchecked((int)0x80008094);
public const int FrameworkMissingFailure = unchecked((int)0x80008096);
public const int BundleExtractionFailure = unchecked((int)0x8000809f);

public const int COMPlusException = unchecked((int)0xe0434352);
public const int SIGABRT = 134;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System;
using System.IO;

namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
namespace Microsoft.DotNet.CoreSetup.Test
{
/// <summary>
/// Helper class for creating a mock version of a dotnet installation
Expand Down Expand Up @@ -68,16 +68,19 @@ public DotNetBuilder AddMicrosoftNETCoreAppFrameworkMockHostPolicy(string versio
/// Use a mock version of HostFxr.
/// </summary>
/// <param name="version">Version to add</param>
/// <remarks>
/// Currently, the only mock version of HostFxr that we have is mockhostfxr_2_2.
/// </remarks>
public DotNetBuilder AddMockHostFxr(Version version)
{
string hostfxrPath = Path.Combine(_path, "host", "fxr", version.ToString());
Directory.CreateDirectory(hostfxrPath);
bool hasCustomErrorWriter = version.Major >= 3;

string mockHostFxrFileName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform(hasCustomErrorWriter ? "mockhostfxr" : "mockhostfxr_2_2");
string mockHostFxrFileNameBase = version switch
{
{ Major: 2, Minor: 2 } => "mockhostfxr_2_2",
{ Major: 5, Minor: 0 } => "mockhostfxr_5_0",
_ => throw new InvalidOperationException($"Unsupported version {version} of mockhostfxr.")
};

string mockHostFxrFileName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform(mockHostFxrFileNameBase);
File.Copy(
Path.Combine(_repoDirectories.Artifacts, "corehost_test", mockHostFxrFileName),
Path.Combine(hostfxrPath, RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr")),
Expand Down
2 changes: 1 addition & 1 deletion src/installer/tests/TestUtils/FileUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.IO;
using System.IO.MemoryMappedFiles;

namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
namespace Microsoft.DotNet.CoreSetup.Test
{
public static class FileUtils
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using System.IO;
using System.Linq;

namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
namespace Microsoft.DotNet.CoreSetup.Test
{
public class NetCoreAppBuilder
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using System.IO;
using System.Linq;

namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
namespace Microsoft.DotNet.CoreSetup.Test
{
public class RuntimeConfig
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.DotNet.CoreSetup.Test
/// <summary>
/// Helper class for creating, modifying and cleaning up shared frameworks
/// </summary>
internal static class SharedFramework
public static class SharedFramework
{
private static readonly Mutex id_mutex = new Mutex();

Expand Down
1 change: 0 additions & 1 deletion src/installer/tests/TestUtils/TestArtifact.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#nullable enable

using Microsoft.DotNet.CoreSetup.Test.HostActivation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand Down
2 changes: 2 additions & 0 deletions src/installer/tests/TestUtils/TestUtils.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<PackageReference Include="FluentAssertions" Version="4.19.4" />
<PackageReference Include="Microsoft.DotNet.XUnitExtensions" Version="$(MicrosoftDotNetXUnitExtensionsVersion)" />
<PackageReference Include="xunit.core" Version="$(XUnitVersion)" ExcludeAssets="build" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelVersion)" />
</ItemGroup>

</Project>
54 changes: 54 additions & 0 deletions src/installer/tests/TestUtils/WindowsUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.Diagnostics;
using System.Runtime.InteropServices;

namespace Microsoft.DotNet.CoreSetup.Test
{
public static class WindowsUtils
{
private delegate bool EnumThreadWindowsDelegate(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int dwThreadId, EnumThreadWindowsDelegate plfn, IntPtr lParam);

public static IntPtr WaitForPopupFromProcess(Process process, int timeout = 60000)
{
if (!OperatingSystem.IsWindows())
{
throw new PlatformNotSupportedException();
}

IntPtr windowHandle = IntPtr.Zero;
int timeRemaining = timeout;
while (timeRemaining > 0)
{
foreach (ProcessThread thread in process.Threads)
{
// We take the last window we find. There really should only be one at most anyways.
EnumThreadWindows(thread.Id,
(hWnd, lParam) => {
windowHandle = hWnd;
return true;
},
IntPtr.Zero);
}

if (windowHandle != IntPtr.Zero)
{
break;
}

System.Threading.Thread.Sleep(100);
timeRemaining -= 100;
}

// Do not fail if the window could be detected, sometimes the check is fragile and doesn't work.
// Not worth the trouble trying to figure out why (only happens rarely in the CI system).
// We will rely on product tracing in the failure case.
return windowHandle;
}
}
}
Loading