diff --git a/src/installer/tests/Assets/TestProjects/BundleProbeTester/BundleProbeTester.csproj b/src/installer/tests/Assets/TestProjects/BundleProbeTester/BundleProbeTester.csproj
deleted file mode 100644
index cb2391b1e4918..0000000000000
--- a/src/installer/tests/Assets/TestProjects/BundleProbeTester/BundleProbeTester.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- $(NetCoreAppCurrent)
- Exe
- $(TestTargetRid)
- $(MNAVersion)
- true
-
-
-
- true
-
-
-
diff --git a/src/installer/tests/Assets/TestProjects/BundleProbeTester/Program.cs b/src/installer/tests/Assets/TestProjects/BundleProbeTester/Program.cs
deleted file mode 100644
index fdd1fdeb32f24..0000000000000
--- a/src/installer/tests/Assets/TestProjects/BundleProbeTester/Program.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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 BundleProbeTester
-{
- public static class Program
- {
- // The return type on BundleProbeDelegate is byte instead of bool because
- // using non-blitable bool type caused a failure (incorrect value) on linux-musl-x64.
- // The bundle-probe callback is only called from native code in the product
- // Therefore the type on this test is adjusted to circumvent the failure.
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate byte BundleProbeDelegate([MarshalAs(UnmanagedType.LPUTF8Str)] string path, IntPtr offset, IntPtr size, IntPtr compressedSize);
-
- unsafe static bool Probe(BundleProbeDelegate bundleProbe, string path, bool isExpected)
- {
- Int64 size, offset, compressedSize;
- bool exists = bundleProbe(path, (IntPtr)(&offset), (IntPtr)(&size), (IntPtr)(&compressedSize)) != 0;
-
- switch (exists, isExpected)
- {
- case (true, true):
- if (compressedSize < 0 || compressedSize > size)
- {
- Console.WriteLine($"Invalid compressedSize obtained for {path} within bundle.");
- return false;
- }
-
- if (size > 0 && offset > 0)
- {
- return true;
- }
-
- Console.WriteLine($"Invalid location obtained for {path} within bundle.");
- return false;
-
- case (true, false):
- Console.WriteLine($"Unexpected file {path} found in bundle.");
- return false;
-
- case (false, true):
- Console.WriteLine($"Expected file {path} not found in bundle.");
- return false;
-
- case (false, false):
- return true;
- }
- }
-
- public static int Main(string[] args)
- {
- bool isSingleFile = args.Length > 0 && args[0].Equals("SingleFile");
- object probeObject = System.AppDomain.CurrentDomain.GetData("BUNDLE_PROBE");
-
- if (!isSingleFile)
- {
- if (probeObject != null)
- {
- Console.WriteLine("BUNDLE_PROBE property passed in for a non-single-file app");
- return -1;
- }
-
- Console.WriteLine("No BUNDLE_PROBE");
- return 0;
- }
-
- if (probeObject == null)
- {
- Console.WriteLine("BUNDLE_PROBE property not passed in for a single-file app");
- return -2;
- }
-
- string probeString = probeObject as string;
- IntPtr probePtr = (IntPtr)Convert.ToUInt64(probeString, 16);
- BundleProbeDelegate bundleProbeDelegate = Marshal.GetDelegateForFunctionPointer(probePtr);
- bool success =
- Probe(bundleProbeDelegate, "BundleProbeTester.dll", isExpected: true) &&
- Probe(bundleProbeDelegate, "BundleProbeTester.runtimeconfig.json", isExpected: true) &&
- Probe(bundleProbeDelegate, "System.Private.CoreLib.dll", isExpected: true) &&
- Probe(bundleProbeDelegate, "hostpolicy.dll", isExpected: false) &&
- Probe(bundleProbeDelegate, "--", isExpected: false) &&
- Probe(bundleProbeDelegate, "", isExpected: false);
-
- if (!success)
- {
- return -3;
- }
-
- Console.WriteLine("BUNDLE_PROBE OK");
- return 0;
- }
- }
-}
diff --git a/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostApiInvokerApp.csproj b/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostApiInvokerApp.csproj
index d040ee25bcfec..056d9ce8dfef6 100644
--- a/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostApiInvokerApp.csproj
+++ b/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostApiInvokerApp.csproj
@@ -3,6 +3,7 @@
$(NetCoreAppCurrent)
Exe
+ $(TestTargetRid)
$(MNAVersion)
WINDOWS;$(DefineConstants)
true
diff --git a/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostRuntimeContract.cs b/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostRuntimeContract.cs
index a2a4d6161acea..f9f1b15295eaa 100644
--- a/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostRuntimeContract.cs
+++ b/src/installer/tests/Assets/TestProjects/HostApiInvokerApp/HostRuntimeContract.cs
@@ -15,7 +15,7 @@ internal struct host_runtime_contract
public nint size;
public void* context;
public delegate* unmanaged[Stdcall] get_runtime_property;
- public IntPtr bundle_probe;
+ public delegate* unmanaged[Stdcall] bundle_probe;
public IntPtr pinvoke_override;
}
@@ -68,12 +68,52 @@ static string GetProperty(string name, host_runtime_contract contract)
}
}
+ public static void Test_bundle_probe(string[] args)
+ {
+ host_runtime_contract contract = GetContract();
+ if (contract.bundle_probe == null)
+ {
+ Console.WriteLine("host_runtime_contract.bundle_probe is not set");
+ return;
+ }
+
+ bool success = true;
+ foreach (string path in args)
+ {
+ Probe(contract, path);
+ }
+
+ unsafe static void Probe(host_runtime_contract contract, string path)
+ {
+ Span pathSpan = stackalloc byte[Encoding.UTF8.GetMaxByteCount(path.Length)];
+ byte* pathPtr = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(pathSpan));
+ int pathLen = Encoding.UTF8.GetBytes(path, pathSpan);
+ pathSpan[pathLen] = 0;
+
+ Int64 size, offset, compressedSize;
+ bool exists = contract.bundle_probe(pathPtr, (IntPtr)(&offset), (IntPtr)(&size), (IntPtr)(&compressedSize)) != 0;
+
+ Console.WriteLine($"{nameof(host_runtime_contract.get_runtime_property)}: {path} - found = {exists}");
+ if (exists)
+ {
+ if (compressedSize < 0 || compressedSize > size)
+ throw new Exception($"Invalid compressedSize obtained for {path} within bundle.");
+
+ if (size <= 0 || offset <= 0)
+ throw new Exception($"Invalid location obtained for {path} within bundle.");
+ }
+ }
+ }
+
public static bool RunTest(string apiToTest, string[] args)
{
switch (apiToTest)
{
case $"{nameof(host_runtime_contract)}.{nameof(host_runtime_contract.get_runtime_property)}":
- Test_get_runtime_property(args);
+ Test_get_runtime_property(args[1..]);
+ break;
+ case $"{nameof(host_runtime_contract)}.{nameof(host_runtime_contract.bundle_probe)}":
+ Test_bundle_probe(args[1..]);
break;
default:
return false;
diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleProbe.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleProbe.cs
index 8679f834a638a..1c61a709d3b50 100644
--- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleProbe.cs
+++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleProbe.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Linq;
using BundleTests.Helpers;
using Microsoft.DotNet.Cli.Build.Framework;
using Microsoft.DotNet.CoreSetup.Test;
@@ -19,35 +20,45 @@ public BundleProbe(SharedTestState fixture)
}
[Fact]
- private void Bundle_Probe_Not_Passed_For_Non_Single_File_App()
+ private void NonSingleFileApp_NoProbe()
{
var fixture = sharedTestState.TestFixture.Copy();
string appExe = BundleHelper.GetHostPath(fixture);
- Command.Create(appExe)
+ Command.Create(appExe, "host_runtime_contract.bundle_probe")
.CaptureStdErr()
.CaptureStdOut()
.Execute()
- .Should()
- .Pass()
- .And
- .HaveStdOutContaining("No BUNDLE_PROBE");
+ .Should().Pass()
+ .And.HaveStdOutContaining("host_runtime_contract.bundle_probe is not set");
}
[Fact]
- private void Bundle_Probe_Passed_For_Single_File_App()
+ private void SingleFileApp_ProbeFiles()
{
var fixture = sharedTestState.TestFixture.Copy();
string singleFile = BundleSelfContainedApp(fixture);
- Command.Create(singleFile, "SingleFile")
+ (string Path, bool ShouldBeFound)[] itemsToProbe = new[]
+ {
+ ($"{fixture.TestProject.AssemblyName}.dll", true),
+ ($"{fixture.TestProject.AssemblyName}.runtimeconfig.json", true),
+ ("System.Private.CoreLib.dll", true),
+ ("hostpolicy.dll", false),
+ ("--", false),
+ (string.Empty, false),
+ };
+
+ var result = Command.Create(singleFile, $"host_runtime_contract.bundle_probe {string.Join(" ", itemsToProbe.Select(i => i.Path))}")
.CaptureStdErr()
.CaptureStdOut()
- .Execute()
- .Should()
- .Pass()
- .And
- .HaveStdOutContaining("BUNDLE_PROBE OK");
+ .Execute();
+
+ result.Should().Pass();
+ foreach (var item in itemsToProbe)
+ {
+ result.Should().HaveStdOutContaining($"{item.Path} - found = {item.ShouldBeFound}");
+ }
}
public class SharedTestState : SharedTestStateBase, IDisposable
@@ -56,7 +67,7 @@ public class SharedTestState : SharedTestStateBase, IDisposable
public SharedTestState()
{
- TestFixture = PreparePublishedSelfContainedTestProject("BundleProbeTester");
+ TestFixture = PreparePublishedSelfContainedTestProject("HostApiInvokerApp");
}
public void Dispose()