public void NonBlockingStdout_AllDataReceived() { RemoteInvokeHandle remote = RemoteInvoke(() => { char[] data = Enumerable.Repeat('a', 1024).ToArray(); const int StdoutFd = 1; Assert.Equal(0, Interop.Sys.Fcntl.DangerousSetIsNonBlocking((IntPtr)StdoutFd, 1)); for (int i = 0; i < 10_000; i++) { Console.Write(data); } return(SuccessExitCode); }, new RemoteInvokeOptions { StartInfo = new ProcessStartInfo() { RedirectStandardOutput = true } }); using (remote) { Assert.Equal( new string('a', 1024 * 10_000), remote.Process.StandardOutput.ReadToEnd()); } }
[PlatformSpecific(TestPlatforms.AnyUnix)] // events are triggered by Unix signals (SIGINT, SIGQUIT, SIGCHLD). public void ExitDetectionNotBlockedByHandler() { RemoteExecutor.Invoke(() => { var mre = new ManualResetEventSlim(); var tcs = new TaskCompletionSource <object>(); // CancelKeyPress is triggered by SIGINT/SIGQUIT Console.CancelKeyPress += (sender, e) => { tcs.SetResult(null); // Block CancelKeyPress Assert.True(mre.Wait(WaitFailTestTimeoutSeconds * 1000)); }; // Generate CancelKeyPress Assert.Equal(0, kill(Process.GetCurrentProcess().Id, SIGINT)); // Wait till we block CancelKeyPress Assert.True(tcs.Task.Wait(WaitFailTestTimeoutSeconds * 1000)); // Create a process and wait for it to exit. using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(() => RemoteExecutor.SuccessExitCode)) { // Process exit is detected on SIGCHLD Assert.Equal(RemoteExecutor.SuccessExitCode, handle.ExitCode); } // Release CancelKeyPress mre.Set(); }).Dispose(); }
public void GetMembers_MultipleCalls_ClearCache_ReflectionCacheTestsType() { RemoteInvokeOptions options = new RemoteInvokeOptions(); options.StartInfo.EnvironmentVariables.Add("DOTNET_MODIFIABLE_ASSEMBLIES", "debug"); using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() => { Action <Type[]> clearCache = GetClearCacheMethod(); MethodInfo mi1 = s_type.GetMethod(nameof(Method)); PropertyInfo pi1 = s_type.GetProperty(nameof(Property)); FieldInfo fi1 = s_type.GetField(nameof(Field1)); EventInfo ei1 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci1 = s_type.GetConstructor(Type.EmptyTypes); clearCache(new[] { typeof(ReflectionCacheTests) }); MethodInfo mi2 = s_type.GetMethod(nameof(Method)); PropertyInfo pi2 = s_type.GetProperty(nameof(Property)); FieldInfo fi2 = s_type.GetField(nameof(Field1)); EventInfo ei2 = s_type.GetEvent(nameof(Event1)); ConstructorInfo ci2 = s_type.GetConstructor(Type.EmptyTypes); AssertNotSameSameButEqualAndHashCodeEqual(mi1, mi2); AssertNotSameSameButEqualAndHashCodeEqual(pi1, pi2); AssertNotSameSameButEqualAndHashCodeEqual(fi1, fi2); AssertNotSameSameButEqualAndHashCodeEqual(ci1, ci2); AssertNotSameSameButEqualAndHashCodeEqual(ei1, ei2); }, options); }
public static async Task RunTestCaseAsync(Action testCase, ITestOutputHelper output) { var options = new RemoteInvokeOptions() { StartInfo = new ProcessStartInfo() { RedirectStandardOutput = true, RedirectStandardError = true } }; using RemoteInvokeHandle remoteInvokeHandle = RemoteExecutor.Invoke(testCase, options); try { Task <string> stdOutputTask = remoteInvokeHandle.Process.StandardOutput.ReadToEndAsync(); Task <string> stdErrorTask = remoteInvokeHandle.Process.StandardError.ReadToEndAsync(); await Task.WhenAll(stdErrorTask, stdOutputTask); output.WriteLine(stdOutputTask.Result); Console.Error.Write(stdErrorTask.Result); } catch (ObjectDisposedException) { Console.Error.WriteLine("Failed to collect remote process's output"); } }
public void FailFast_ExceptionStackTrace_InnerException() { // Test if inner exception details are also logged var psi = new ProcessStartInfo(); psi.RedirectStandardError = true; psi.RedirectStandardOutput = true; using (RemoteInvokeHandle handle = RemoteInvoke( () => { Environment.FailFast("message", new ArgumentException("first exception", new NullReferenceException("inner exception"))); return(SuccessExitCode); }, new RemoteInvokeOptions { StartInfo = psi })) { Process p = handle.Process; handle.Process = null; p.WaitForExit(); string consoleOutput = p.StandardError.ReadToEnd(); Assert.Contains("Exception details:", consoleOutput); Assert.Contains("first exception", consoleOutput); Assert.Contains("inner exception", consoleOutput); Assert.Contains("ArgumentException", consoleOutput); Assert.Contains("NullReferenceException", consoleOutput); } }
public void Test_EventSource_EtwManifestGeneration() { RemoteExecutor.Invoke(() => { using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(() => { var es = new SimpleEventSource(); for (var i = 0; i < 100; i++) { es.WriteSimpleInt(i); Thread.Sleep(100); } })) { var etlFileName = @"file.etl"; var tracesession = new TraceEventSession("testname", etlFileName); tracesession.EnableProvider("SimpleEventSource"); Thread.Sleep(TimeSpan.FromSeconds(5)); tracesession.Flush(); // Sleep after requesting flush to ensure that the manifest payload generated // is fully written to the etl file. Thread.Sleep(TimeSpan.FromSeconds(5)); tracesession.DisableProvider("SimpleEventSource"); tracesession.Dispose(); Assert.True(VerifyManifestAndRemoveFile(etlFileName)); } }).Dispose(); }
public void Test_EventSource_EtwManifestGenerationRollover() { RemoteExecutor.Invoke(() => { using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(() => { var es = new SimpleEventSource(); for (var i = 0; i < 100; i++) { es.WriteSimpleInt(i); Thread.Sleep(100); } })) { var initialFileName = @"initialFile.etl"; var rolloverFileName = @"rolloverFile.etl"; var tracesession = new TraceEventSession("testname", initialFileName); var max_retries = 50; tracesession.EnableProvider("SimpleEventSource"); Thread.Sleep(TimeSpan.FromSeconds(5)); tracesession.Flush(); tracesession.SetFileName(rolloverFileName); Thread.Sleep(TimeSpan.FromSeconds(5)); tracesession.Flush(); tracesession.DisableProvider("SimpleEventSource"); tracesession.Dispose(); bool initialFileHasManifest = false; bool rollOverFileHasManifest = false; for (int i = 0; i < max_retries; i++) { if (VerifyManifestAndRemoveFile(initialFileName)) { initialFileHasManifest = true; break; } Thread.Sleep(1000); } for (int i = 0; i < max_retries; i++) { if (VerifyManifestAndRemoveFile(rolloverFileName)) { rollOverFileHasManifest = true; break; } Thread.Sleep(1000); } Assert.True(initialFileHasManifest); Assert.True(rollOverFileHasManifest); } }).Dispose(); }
public static void SerializeWithBinaryFormatter_DeserializeWithBinaryWriter(string key) { AppContext.SetSwitch(enableBinaryFormatter, true); AppContext.SetSwitch(enableBinaryFormatterInTypeConverter, true); var context = new DesigntimeLicenseContext(); context.SetSavedLicenseKey(typeof(int), key); string tempPath = Path.GetTempPath(); try { using (MemoryStream stream = new MemoryStream()) { long position = stream.Position; DesigntimeLicenseContextSerializer.Serialize(stream, key, context); stream.Seek(position, SeekOrigin.Begin); VerifyStreamFormatting(stream); using (FileStream outStream = File.Create(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"))) { stream.Seek(position, SeekOrigin.Begin); stream.CopyTo(outStream); } } RemoteInvokeHandle handle = RemoteExecutor.Invoke((key) => { var assembly = typeof(DesigntimeLicenseContextSerializer).Assembly; Type runtimeLicenseContextType = assembly.GetType("System.ComponentModel.Design.RuntimeLicenseContext"); Assert.NotNull(runtimeLicenseContextType); object runtimeLicenseContext = Activator.CreateInstance(runtimeLicenseContextType); Assert.NotNull(runtimeLicenseContext); FieldInfo _savedLicenseKeys = runtimeLicenseContextType.GetField("_savedLicenseKeys", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(_savedLicenseKeys); _savedLicenseKeys.SetValue(runtimeLicenseContext, new Hashtable()); Type designtimeLicenseContextSerializer = assembly.GetType("System.ComponentModel.Design.DesigntimeLicenseContextSerializer"); Assert.NotNull(designtimeLicenseContextSerializer); MethodInfo deserializeMethod = designtimeLicenseContextSerializer.GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static); Assert.NotNull(deserializeMethod); string tempPath = Path.GetTempPath(); using (FileStream stream = File.Open(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter"), FileMode.Open)) { TargetInvocationException exception = Assert.Throws <TargetInvocationException>(() => deserializeMethod.Invoke(null, new object[] { stream, key, runtimeLicenseContext })); Assert.IsType <NotSupportedException>(exception.InnerException); } }, key); handle.Process.WaitForExit(); handle.Dispose(); } finally { File.Delete(Path.Combine(tempPath, "_temp_SerializeWithBinaryFormatter_DeserializeWithBinaryWriter")); } }
private void RunTestAsSudo(Func<string, int> testMethod, string arg) { RemoteInvokeOptions options = new RemoteInvokeOptions() { RunAsSudo = true }; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(testMethod, arg, options)) { } }
public void ChildProcessRedirectedIO_FilePathOpenShouldSucceed(string filename, int flags) { var options = new RemoteInvokeOptions { StartInfo = new ProcessStartInfo { RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true } }; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(ExecuteChildProcess, filename, flags.ToString(CultureInfo.InvariantCulture), options)) { }
public void Action() { RemoteInvokeHandle h = RemoteExecutor.Invoke(() => { }, new RemoteInvokeOptions { RollForward = "Major" }); using (h) { Assert.Equal(RemoteExecutor.SuccessExitCode, h.ExitCode); } }
protected Process CreateProcess(Func <string, int> method, string arg) { RemoteInvokeHandle handle = RemoteInvoke(method, arg, new RemoteInvokeOptions { Start = false }); Process p = handle.Process; handle.Process = null; handle.Dispose(); AddProcessForDispose(p); return(p); }
protected Process CreateProcess(Func <int> method = null) { RemoteInvokeHandle handle = RemoteInvoke(method ?? (() => SuccessExitCode), new RemoteInvokeOptions { Start = false }); Process p = handle.Process; handle.Process = null; handle.Dispose(); AddProcessForDispose(p); return(p); }
/// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary> /// <param name="method">The method to invoke.</param> /// <param name="args">The arguments to pass to the method.</param> /// <param name="options"><see cref="System.Diagnostics.RemoteInvokeOptions"/> The options to execute the remote process.</param> /// <param name="pasteArguments">Unused in UAP.</param> private static RemoteInvokeHandle RemoteInvoke(MethodInfo method, string[] args, RemoteInvokeOptions options, bool pasteArguments = false) { options = options ?? new RemoteInvokeOptions(); // Verify the specified method returns an int (the exit code) or nothing, // and that if it accepts any arguments, they're all strings. Assert.True(method.ReturnType == typeof(void) || method.ReturnType == typeof(int) || method.ReturnType == typeof(Task <int>)); Assert.All(method.GetParameters(), pi => Assert.Equal(typeof(string), pi.ParameterType)); // And make sure it's in this assembly. This isn't critical, but it helps with deployment to know // that the method to invoke is available because we're already running in this assembly. Type t = method.DeclaringType; Assembly a = t.GetTypeInfo().Assembly; int exitCode; using (AppServiceConnection remoteExecutionService = new AppServiceConnection()) { // Here, we use the app service name defined in the app service provider's Package.appxmanifest file in the <Extension> section. remoteExecutionService.AppServiceName = "com.microsoft.corefxuaptests"; remoteExecutionService.PackageFamilyName = Package.Current.Id.FamilyName; AppServiceConnectionStatus status = remoteExecutionService.OpenAsync().GetAwaiter().GetResult(); if (status != AppServiceConnectionStatus.Success) { throw new IOException($"RemoteInvoke cannot open the remote service. Open Service Status: {status}"); } ValueSet message = new ValueSet(); message.Add("AssemblyName", a.FullName); message.Add("TypeName", t.FullName); message.Add("MethodName", method.Name); int i = 0; foreach (string arg in args) { message.Add("Arg" + i, arg); i++; } AppServiceResponse response = remoteExecutionService.SendMessageAsync(message).GetAwaiter().GetResult(); Assert.True(response.Status == AppServiceResponseStatus.Success, $"response.Status = {response.Status}"); exitCode = (int)response.Message["Results"]; Assert.True(!options.CheckExitCode || exitCode == options.ExpectedExitCode, (string)response.Message["Log"] + Environment.NewLine + $"Returned Error code: {exitCode}"); } // RemoteInvokeHandle is not really needed in the UAP scenario but we use it just to have consistent interface as non UAP var handle = new RemoteInvokeHandle(null, options, null, null, null); handle.ExitCode = exitCode; return(handle); }
protected Process CreateProcess(Func <string, Task <int> > method, string arg) { Process p = null; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(method, arg, new RemoteInvokeOptions { Start = false })) { p = handle.Process; handle.Process = null; } AddProcessForDispose(p); return(p); }
protected Process CreateProcess(Func <int> method = null) { Process p = null; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(method ?? (() => RemoteExecutor.SuccessExitCode), new RemoteInvokeOptions { Start = false })) { p = handle.Process; handle.Process = null; } AddProcessForDispose(p); return(p); }
public void AsyncAction() { RemoteInvokeHandle h = RemoteExecutor.Invoke(async() => { await Task.Delay(1); }, new RemoteInvokeOptions { RollForward = "Major" }); using (h) { Assert.Equal(RemoteExecutor.SuccessExitCode, h.ExitCode); } }
public void ProfessionalColorTable_ChangeUserPreferences_GetColor_ReturnsExpected(UserPreferenceCategory category) { using RemoteInvokeHandle invokerHandle = RemoteExecutor.Invoke(() => { // Simulate a SystemEvents.UserPreferenceChanged event. var table = new ProfessionalColorTable(); Color color = table.ButtonSelectedHighlight; SystemEventsHelper.SendMessageOnUserPreferenceChanged(category); Assert.Equal(color, table.ButtonSelectedHighlight); }); // verify the remote process succeeded Assert.Equal(0, invokerHandle.ExitCode); }
public void Test_EventSource_EtwManifestGeneration() { RemoteInvokeOptions options = new RemoteInvokeOptions { TimeOut = 300_000 /* ms */ }; RemoteExecutor.Invoke(() => { RemoteInvokeOptions localOptions = new RemoteInvokeOptions { TimeOut = 300_000 /* ms */ }; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(() => { var es = new SimpleEventSource(); for (var i = 0; i < 100; i++) { es.WriteSimpleInt(i); Thread.Sleep(100); } }, localOptions)) { var etlFileName = @"file.etl"; var tracesession = new TraceEventSession("testname", etlFileName); tracesession.EnableProvider("SimpleEventSource"); Thread.Sleep(TimeSpan.FromSeconds(5)); tracesession.Flush(); tracesession.DisableProvider("SimpleEventSource"); tracesession.Dispose(); var manifestExists = false; var max_retries = 50; for (int i = 0; i < max_retries; i++) { if (VerifyManifestAndRemoveFile(etlFileName)) { manifestExists = true; break; } Thread.Sleep(1000); } Assert.True(manifestExists); } }, options).Dispose(); }
public static void IgnoreExitCode() { int exitCode = 1; RemoteInvokeHandle h = RemoteExecutor.Invoke( s => int.Parse(s), exitCode.ToString(), new RemoteInvokeOptions { RollForward = "Major", CheckExitCode = false, ExpectedExitCode = 0 }); using (h) { Assert.Equal(exitCode, h.ExitCode); } }
public static void ProcessExit_Called() { using (RemoteInvokeHandle handle = RemoteInvoke(() => { CauseAVInNative(); return(SuccessExitCode); })) { Process p = handle.Process; p.WaitForExit(); if (PlatformDetection.IsFullFramework) { Assert.Equal(SuccessExitCode, p.ExitCode); } else { Assert.NotEqual(SuccessExitCode, p.ExitCode); } } }
public static async Task RemoteInvoke(ITestOutputHelper output, Action testCase) { var options = new RemoteInvokeOptions() { StartInfo = new ProcessStartInfo() { RedirectStandardOutput = true, RedirectStandardError = true } }; using RemoteInvokeHandle remoteInvokeHandle = RemoteExecutor.Invoke(testCase, options); Task stdOutputTask = WriteStreamToOutput(remoteInvokeHandle.Process.StandardOutput, output); Task stdErrorTask = WriteStreamToOutput(remoteInvokeHandle.Process.StandardError, output); await Task.WhenAll(stdErrorTask, stdOutputTask); }
public static void ProcessExit_Called() { // We expect the launched process to crash; don't let it write the resulting AV message to the console. var psi = new ProcessStartInfo() { RedirectStandardError = true, RedirectStandardOutput = true }; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(() => CauseAVInNative(), new RemoteInvokeOptions { CheckExitCode = false, StartInfo = psi })) { Process p = handle.Process; p.WaitForExit(); Assert.NotEqual(RemoteExecutor.SuccessExitCode, p.ExitCode); } }
public unsafe void ListViewGroup_Collapse_GetGroupInfo_Success() { // Run this from another thread as we call Application.EnableVisualStyles. using RemoteInvokeHandle invokerHandle = RemoteExecutor.Invoke(() => { foreach (object[] data in CollapsedState_TestData()) { Application.EnableVisualStyles(); using var listView = new ListView(); var group = new ListViewGroup(); listView.Groups.Add(group); Assert.NotEqual(IntPtr.Zero, listView.Handle); group.CollapsedState = (ListViewGroupCollapsedState)data[0]; ListViewGroupCollapsedState expectedCollapsedState = (ListViewGroupCollapsedState)data[1]; Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPCOUNT, IntPtr.Zero, IntPtr.Zero)); var lvgroup = new LVGROUPW { cbSize = (uint)sizeof(LVGROUPW), mask = LVGF.STATE | LVGF.GROUPID, stateMask = LVGS.COLLAPSIBLE | LVGS.COLLAPSED }; Assert.Equal((IntPtr)1, User32.SendMessageW(listView.Handle, (User32.WM)LVM.GETGROUPINFOBYINDEX, (IntPtr)0, ref lvgroup)); Assert.True(lvgroup.iGroupId >= 0); Assert.Equal(expectedCollapsedState, group.CollapsedState); if (expectedCollapsedState == ListViewGroupCollapsedState.Default) { Assert.Equal(LVGS.NORMAL, lvgroup.state); } else if (expectedCollapsedState == ListViewGroupCollapsedState.Expanded) { Assert.Equal(LVGS.COLLAPSIBLE, lvgroup.state); } else { Assert.Equal(LVGS.COLLAPSIBLE | LVGS.COLLAPSED, lvgroup.state); } } }); // verify the remote process succeeded Assert.Equal(0, invokerHandle.ExitCode); }
public void FailFast_ExpectFailureExitCode() { using (RemoteInvokeHandle handle = RemoteInvoke(() => { Environment.FailFast("message"); return(SuccessExitCode); })) { Process p = handle.Process; handle.Process = null; p.WaitForExit(); Assert.NotEqual(SuccessExitCode, p.ExitCode); } using (RemoteInvokeHandle handle = RemoteInvoke(() => { Environment.FailFast("message", new Exception("uh oh")); return(SuccessExitCode); })) { Process p = handle.Process; handle.Process = null; p.WaitForExit(); Assert.NotEqual(SuccessExitCode, p.ExitCode); } }
public unsafe void TestCheckChildProcessUserAndGroupIds() { string userName = GetCurrentRealUserName(); string userId = GetUserId(userName); string userGroupId = GetUserGroupId(userName); string userGroupIds = GetUserGroupIds(userName); // If this test runs as the user, we expect to be able to match the user groups exactly. // Except on OSX, where getgrouplist may return a list of groups truncated to NGROUPS_MAX. bool checkGroupsExact = userId == geteuid().ToString() && !RuntimeInformation.IsOSPlatform(OSPlatform.OSX); // Start as username var invokeOptions = new RemoteInvokeOptions(); invokeOptions.StartInfo.UserName = userName; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(CheckUserAndGroupIds, userId, userGroupId, userGroupIds, checkGroupsExact.ToString(), invokeOptions)) { } }
protected Process CreateProcess(Func <string, int> method, string arg, bool autoDispose = true) { Process p = null; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(method, arg, new RemoteInvokeOptions { Start = false })) { p = handle.Process; handle.Process = null; } if (autoDispose) { AddProcessForDispose(p); } return(p); }
public static void RedirectedOutput_EnvVarSet_EmitsAnsiCodes(string envVar) { var psi = new ProcessStartInfo { RedirectStandardOutput = true }; psi.Environment["DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION"] = envVar; for (int i = 0; i < 3; i++) { Action <string> main = i => { Console.Write("SEPARATOR"); switch (i) { case "0": Console.ForegroundColor = ConsoleColor.Blue; break; case "1": Console.BackgroundColor = ConsoleColor.Red; break; case "2": Console.ResetColor(); break; } Console.Write("SEPARATOR"); }; using RemoteInvokeHandle remote = RemoteExecutor.Invoke(main, i.ToString(CultureInfo.InvariantCulture), new RemoteInvokeOptions() { StartInfo = psi }); bool expectedEscapes = envVar is not null && (envVar == "1" || envVar.Equals("true", StringComparison.OrdinalIgnoreCase)); string stdout = remote.Process.StandardOutput.ReadToEnd(); string[] parts = stdout.Split("SEPARATOR"); Assert.Equal(3, parts.Length); Assert.Equal(expectedEscapes, parts[1].Contains(Esc)); } }
public unsafe void TestCheckChildProcessUserAndGroupIdsElevated(bool useRootGroups) { Func <string, string, int> runsAsRoot = (string username, string useRootGroupsArg) => { // Verify we are root Assert.Equal(0U, getuid()); Assert.Equal(0U, geteuid()); Assert.Equal(0U, getgid()); Assert.Equal(0U, getegid()); string userId = GetUserId(username); string userGroupId = GetUserGroupId(username); string userGroupIds = GetUserGroupIds(username); if (bool.Parse(useRootGroupsArg)) { uint rootGroups = 0; int setGroupsRv = setgroups(1, &rootGroups); Assert.Equal(0, setGroupsRv); } // On systems with a low value of NGROUPS_MAX (e.g 16 on OSX), the groups may be truncated. // On Linux NGROUPS_MAX is 65536, so we expect to see every group. bool checkGroupsExact = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); // Start as username var invokeOptions = new RemoteInvokeOptions(); invokeOptions.StartInfo.UserName = username; using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(CheckUserAndGroupIds, userId, userGroupId, userGroupIds, checkGroupsExact.ToString(), invokeOptions)) { } return(RemoteExecutor.SuccessExitCode); }; // Start as root string userName = GetCurrentRealUserName(); using (RemoteInvokeHandle handle = RemoteExecutor.Invoke(runsAsRoot, userName, useRootGroups.ToString(), new RemoteInvokeOptions { RunAsSudo = true })) { } }
[PlatformSpecific(TestPlatforms.AnyUnix)] // SIGTERM signal. public void SigTermExitCode(int?exitCodeOnSigterm) { Action <string> action = (string sigTermExitCode) => { if (!string.IsNullOrEmpty(sigTermExitCode)) { AppDomain.CurrentDomain.ProcessExit += (sender, args) => { Assert.Same(AppDomain.CurrentDomain, sender); Environment.ExitCode = int.Parse(sigTermExitCode); }; } Console.WriteLine("Application started"); // Wait for SIGTERM System.Threading.Thread.Sleep(int.MaxValue); }; RemoteInvokeOptions options = new RemoteInvokeOptions(); options.StartInfo.RedirectStandardOutput = true; options.CheckExitCode = false; using (RemoteInvokeHandle remoteExecution = RemoteExecutor.Invoke(action, exitCodeOnSigterm?.ToString() ?? string.Empty, options)) { Process process = remoteExecution.Process; // Wait for the process to start and register the ProcessExit handler string processOutput = process.StandardOutput.ReadLine(); Assert.Equal("Application started", processOutput); // Send SIGTERM int rv = kill(process.Id, SIGTERM); Assert.Equal(0, rv); // Process exits in a timely manner bool exited = process.WaitForExit(RemoteExecutor.FailWaitTimeoutMilliseconds); Assert.True(exited); // Check exit code Assert.Equal(exitCodeOnSigterm ?? 128 + SIGTERM, process.ExitCode); } }