110 lines
4.9 KiB
C#
110 lines
4.9 KiB
C#
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.Versioning;
|
|
using Quorate.HostExec;
|
|
|
|
namespace Quorate.HostExec.Tests;
|
|
|
|
[TestClass]
|
|
[SupportedOSPlatform("linux")]
|
|
public sealed class HostExecTests
|
|
{
|
|
[TestMethod]
|
|
public async Task InstallsAndRunsGnuProxy()
|
|
{
|
|
string root = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
|
|
|
try
|
|
{
|
|
Directory.CreateDirectory(Path.Combine(root, "usr/bin"));
|
|
string probe = Path.Combine(AppContext.BaseDirectory, "HostExec.Probe");
|
|
File.CreateSymbolicLink(Path.Combine(root, "usr/bin/gcc"), probe);
|
|
ToolRoot toolRoot = ToolRoot.Open(root);
|
|
string proxy = GnuProxy.Install(toolRoot, GnuTool.Gcc);
|
|
Assert.AreEqual(
|
|
"#!/usr/share/dotnet/dotnet /opt/fsi/packages/HostExec.dll\n",
|
|
await File.ReadAllTextAsync(proxy).ConfigureAwait(false));
|
|
Assert.IsTrue(File.GetUnixFileMode(proxy).HasFlag(UnixFileMode.UserExecute));
|
|
Assert.IsTrue(File.Exists($"{proxy}.json"));
|
|
|
|
IReadOnlyList<string> supplied = Proxy.WithSysroot(root, ["-c", "source.c"]);
|
|
CollectionAssert.AreEqual(new[] { $"--sysroot={root}", "-c", "source.c" }, supplied.ToArray());
|
|
|
|
IReadOnlyList<string> retained = Proxy.WithSysroot(root, [$"--sysroot={root}", "source.c"]);
|
|
Assert.HasCount(2, retained);
|
|
Assert.ThrowsExactly<ArgumentException>(() => Proxy.WithSysroot(root, ["--sysroot=/different", "source.c"]));
|
|
Assert.ThrowsExactly<ArgumentException>(() => Proxy.WithSysroot(root, ["--sysroot"]));
|
|
Assert.ThrowsExactly<ArgumentException>(() => ToolRoot.Open("relative"));
|
|
|
|
string assembly = typeof(ToolRoot).Assembly.Location;
|
|
string runtime = Path.GetDirectoryName(typeof(object).Assembly.Location)!;
|
|
string dotnet = Path.Combine(Path.GetFullPath(Path.Combine(runtime, "../../..")), "dotnet");
|
|
await File.WriteAllTextAsync(proxy, $"#!{dotnet} {assembly}\n").ConfigureAwait(false);
|
|
var start = new ProcessStartInfo(proxy)
|
|
{
|
|
RedirectStandardOutput = true,
|
|
UseShellExecute = false
|
|
};
|
|
start.ArgumentList.Add("probe.c");
|
|
using Process child = Process.Start(start)
|
|
?? throw new InvalidOperationException("proxy did not start");
|
|
string output = await child.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
|
|
await child.WaitForExitAsync().ConfigureAwait(false);
|
|
Assert.AreEqual(0, child.ExitCode);
|
|
Assert.AreEqual($"--sysroot={root} probe.c\n", output);
|
|
}
|
|
finally
|
|
{
|
|
if (Directory.Exists(root))
|
|
{
|
|
Directory.Delete(root, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
[TestMethod]
|
|
public async Task ForwardsTermination()
|
|
{
|
|
string root = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
|
|
|
try
|
|
{
|
|
Directory.CreateDirectory(Path.Combine(root, "usr/bin"));
|
|
string probe = Path.Combine(AppContext.BaseDirectory, "HostExec.Probe");
|
|
File.CreateSymbolicLink(Path.Combine(root, "usr/bin/gcc"), probe);
|
|
string proxy = GnuProxy.Install(ToolRoot.Open(root), GnuTool.Gcc);
|
|
string assembly = typeof(ToolRoot).Assembly.Location;
|
|
string runtime = Path.GetDirectoryName(typeof(object).Assembly.Location)!;
|
|
string dotnet = Path.Combine(Path.GetFullPath(Path.Combine(runtime, "../../..")), "dotnet");
|
|
await File.WriteAllTextAsync(proxy, $"#!{dotnet} {assembly}\n").ConfigureAwait(false);
|
|
var start = new ProcessStartInfo(proxy)
|
|
{
|
|
RedirectStandardOutput = true,
|
|
UseShellExecute = false
|
|
};
|
|
start.ArgumentList.Add("--wait");
|
|
using Process child = Process.Start(start)
|
|
?? throw new InvalidOperationException("proxy did not start");
|
|
string childLine = await child.StandardOutput.ReadLineAsync()
|
|
.WaitAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false)
|
|
?? throw new InvalidDataException("probe did not report its process identity");
|
|
int childId = int.Parse(childLine, CultureInfo.InvariantCulture);
|
|
Assert.AreEqual(0, Kill(child.Id, 15));
|
|
await child.WaitForExitAsync().WaitAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false);
|
|
Assert.AreEqual(143, child.ExitCode);
|
|
Assert.AreEqual(-1, Kill(childId, 0));
|
|
}
|
|
finally
|
|
{
|
|
if (Directory.Exists(root))
|
|
{
|
|
Directory.Delete(root, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
[DllImport("libc", EntryPoint = "kill", SetLastError = true)]
|
|
[DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)]
|
|
private static extern int Kill(int processId, int signal);
|
|
}
|