Skip to content

Commit

Permalink
Host tests for using host-runtime contract
Browse files Browse the repository at this point in the history
  • Loading branch information
elinor-fung committed Nov 24, 2022
1 parent 5d744ee commit 4e6645c
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
<OutputType>Exe</OutputType>
<RuntimeFrameworkVersion>$(MNAVersion)</RuntimeFrameworkVersion>
<DefineConstants Condition="'$(OS)' == 'Windows_NT'">WINDOWS;$(DefineConstants)</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonVersion)" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace HostApiInvokerApp
{
public static unsafe class HostRuntimeContract
{
internal struct host_runtime_contract
{
public void* context;
public IntPtr bundle_probe;
public IntPtr pinvoke_override;
public delegate* unmanaged[Stdcall]<byte*, byte*, nint, void*, nint> get_runtime_property;
}

private static host_runtime_contract GetContract()
{
string contractString = (string)AppContext.GetData("HOST_RUNTIME_CONTRACT");
if (string.IsNullOrEmpty(contractString))
throw new Exception("HOST_RUNTIME_CONTRACT not found");

host_runtime_contract* contract = (host_runtime_contract*)Convert.ToUInt64(contractString, 16);
return *contract;
}

private static void Test_get_runtime_property(string[] args)
{
host_runtime_contract contract = GetContract();

foreach (string name in args)
{
string value = GetProperty(name, contract);
Console.WriteLine($"{nameof(host_runtime_contract.get_runtime_property)}: {name} = {(value == null ? "<none>" : value)}");
}

static string GetProperty(string name, host_runtime_contract contract)
{
Span<byte> nameSpan = stackalloc byte[Encoding.UTF8.GetMaxByteCount(name.Length)];
byte* namePtr = (byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(nameSpan));
int nameLen = Encoding.UTF8.GetBytes(name, nameSpan);
nameSpan[nameLen] = 0;

nint len = 256;
byte* buffer = stackalloc byte[(int)len];
nint lenActual = contract.get_runtime_property(namePtr, buffer, len, contract.context);
if (lenActual <= 0)
{
Console.WriteLine($"No value for {name} - {nameof(host_runtime_contract.get_runtime_property)} returned {lenActual}");
return null;
}

if (lenActual <= len)
return Encoding.UTF8.GetString(buffer, (int)lenActual);

len = lenActual;
byte* expandedBuffer = stackalloc byte[(int)len];
lenActual = contract.get_runtime_property(namePtr, expandedBuffer, len, contract.context);
return Encoding.UTF8.GetString(expandedBuffer, (int)lenActual);
}
}

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);
break;
default:
return false;
}

return true;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,13 @@ public static void MainCore(string[] args)
Console.WriteLine("Hello World!");
Console.WriteLine(string.Join(Environment.NewLine, args));

// A small operation involving NewtonSoft.Json to ensure the assembly is loaded properly
var t = typeof(Newtonsoft.Json.JsonReader);

// Enable tracing so that test assertion failures are easier to diagnose.
Environment.SetEnvironmentVariable("COREHOST_TRACE", "1");

// If requested, test multilevel lookup using fake Global SDK directories:
// 1. using a fake ProgramFiles location
// 2. using a fake SDK Self-Registered location
// Note that this has to be set here and not in the calling test process because
// Note that this has to be set here and not in the calling test process because
// %ProgramFiles% gets reset on process creation.
string testMultilevelLookupProgramFiles = Environment.GetEnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES");
string testMultilevelLookupSelfRegistered = Environment.GetEnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED");
Expand All @@ -65,17 +62,15 @@ public static void MainCore(string[] args)

string apiToTest = args[0];
if (HostFXR.RunTest(apiToTest, args))
{
return;
}
else if (HostPolicy.RunTest(apiToTest, args))
{

if (HostPolicy.RunTest(apiToTest, args))
return;
}
else
{
throw new ArgumentException($"Invalid API to test passed as args[0]): {apiToTest}");
}

if (HostRuntimeContract.RunTest(apiToTest, args))
return;

throw new ArgumentException($"Invalid API to test passed as args[0]): {apiToTest}");
}
}
}
15 changes: 15 additions & 0 deletions src/installer/tests/HostActivation.Tests/NativeHostApis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,21 @@ public void Hostpolicy_corehost_set_error_writer_test()
.Should().Pass();
}

[Fact]
public void HostRuntimeContract_get_runtime_property()
{
var fixture = sharedTestState.HostApiInvokerAppFixture;

fixture.BuiltDotnet.Exec(fixture.TestProject.AppDll, "host_runtime_contract.get_runtime_property", "APP_CONTEXT_BASE_DIRECTORY", "ENTRY_ASSEMBLY_NAME", "DOES_NOT_EXIST")
.CaptureStdOut()
.CaptureStdErr()
.Execute()
.Should().Pass()
.And.HaveStdOutContaining($"APP_CONTEXT_BASE_DIRECTORY = {Path.GetDirectoryName(fixture.TestProject.AppDll)}")
.And.HaveStdOutContaining($"ENTRY_ASSEMBLY_NAME = {fixture.TestProject.AssemblyName}")
.And.HaveStdOutContaining($"DOES_NOT_EXIST = <none>");
}

public class SharedTestState : IDisposable
{
public TestProjectFixture HostApiInvokerAppFixture { get; }
Expand Down

0 comments on commit 4e6645c

Please sign in to comment.