using System.Diagnostics; #if !NET8_0_OR_GREATER using Renci.SshNet.Abstractions; #endif using Renci.SshNet.Common; namespace Renci.SshNet.IntegrationTests.OldIntegrationTests { /// /// Represents SSH command that can be executed. /// [TestClass] public class SshCommandTest : IntegrationTestBase { [TestMethod] public void Test_Run_SingleCommand() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { #region Example SshCommand RunCommand Result client.Connect(); var testValue = Guid.NewGuid().ToString(); using var command = client.RunCommand(string.Format("echo {0}", testValue)); var result = command.Result; result = result.Substring(0, result.Length - 1); // Remove \n character returned by command client.Disconnect(); #endregion Assert.AreEqual(testValue, result); } } [TestMethod] public void Test_Execute_SingleCommand() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { #region Example SshCommand CreateCommand Execute client.Connect(); var testValue = Guid.NewGuid().ToString(); var command = string.Format("echo -n {0}", testValue); using var cmd = client.CreateCommand(command); var result = cmd.Execute(); client.Disconnect(); #endregion Assert.AreEqual(testValue, result); } } [TestMethod] [Timeout(5000)] public void Test_CancelAsync_Unfinished_Command() { using var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); client.Connect(); var testValue = Guid.NewGuid().ToString(); using var cmd = client.CreateCommand($"sleep 15s; echo {testValue}"); var asyncResult = cmd.BeginExecute(); cmd.CancelAsync(); var tce = Assert.ThrowsException(() => cmd.EndExecute(asyncResult)); Assert.AreEqual(CancellationToken.None, tce.CancellationToken); Assert.IsTrue(asyncResult.IsCompleted); Assert.IsTrue(asyncResult.AsyncWaitHandle.WaitOne(0)); Assert.AreEqual(string.Empty, cmd.Result); Assert.AreEqual("TERM", cmd.ExitSignal); Assert.IsNull(cmd.ExitStatus); } [TestMethod] [Timeout(5000)] public async Task Test_CancelAsync_Kill_Unfinished_Command() { using var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); client.Connect(); var testValue = Guid.NewGuid().ToString(); using var cmd = client.CreateCommand($"sleep 15s; echo {testValue}"); var asyncResult = cmd.BeginExecute(); Task executeTask = Task.Factory.FromAsync(asyncResult, cmd.EndExecute); cmd.CancelAsync(forceKill: true); var tce = await Assert.ThrowsExceptionAsync(() => executeTask); Assert.AreEqual(CancellationToken.None, tce.CancellationToken); Assert.IsTrue(asyncResult.IsCompleted); Assert.IsTrue(asyncResult.AsyncWaitHandle.WaitOne(0)); Assert.AreEqual(string.Empty, cmd.Result); Assert.AreEqual("KILL", cmd.ExitSignal); Assert.IsNull(cmd.ExitStatus); } [TestMethod] public void Test_CancelAsync_Finished_Command() { using var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); client.Connect(); var testValue = Guid.NewGuid().ToString(); using var cmd = client.CreateCommand($"echo -n {testValue}"); var asyncResult = cmd.BeginExecute(); Assert.IsTrue(asyncResult.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))); cmd.CancelAsync(); // Should not throw Assert.AreEqual(testValue, cmd.EndExecute(asyncResult)); // Should not throw cmd.CancelAsync(); // Should not throw Assert.IsTrue(asyncResult.IsCompleted); Assert.AreEqual(testValue, cmd.Result); Assert.AreEqual(0, cmd.ExitStatus); Assert.IsNull(cmd.ExitSignal); } [TestMethod] [Timeout(5000)] public async Task Test_ExecuteAsync_CancellationToken() { using var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); client.Connect(); var testValue = Guid.NewGuid().ToString(); using var cmd = client.CreateCommand($"sleep 15s; echo {testValue}"); using CancellationTokenSource cts = new(); Task executeTask = cmd.ExecuteAsync(cts.Token); await cts.CancelAsync(); var tce = await Assert.ThrowsExceptionAsync(() => executeTask); Assert.AreSame(executeTask, tce.Task); Assert.AreEqual(cts.Token, tce.CancellationToken); Assert.AreEqual(string.Empty, cmd.Result); Assert.AreEqual("TERM", cmd.ExitSignal); Assert.IsNull(cmd.ExitStatus); } [TestMethod] public void Test_Execute_ExtendedOutputStream() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { #region Example SshCommand CreateCommand Execute ExtendedOutputStream client.Connect(); using var cmd = client.CreateCommand("echo 12345; echo 654321 >&2"); using var reader = new StreamReader(cmd.ExtendedOutputStream); Assert.AreEqual("12345\n", cmd.Execute()); Assert.AreEqual("654321\n", reader.ReadToEnd()); client.Disconnect(); #endregion } } [TestMethod] public void Test_Execute_Timeout() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand("sleep 10s"); cmd.CommandTimeout = TimeSpan.FromSeconds(2); Assert.ThrowsException(cmd.Execute); client.Disconnect(); } } [TestMethod] public async Task Test_ExecuteAsync_Timeout() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand("sleep 10s"); cmd.CommandTimeout = TimeSpan.FromSeconds(2); Task executeTask = cmd.ExecuteAsync(); Assert.IsTrue(((IAsyncResult)executeTask).AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3))); await Assert.ThrowsExceptionAsync(() => executeTask); client.Disconnect(); } } [TestMethod] [Timeout(15000)] public async Task Test_ExecuteAsync_Disconnect() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand("sleep 10s"); cmd.CommandTimeout = TimeSpan.FromSeconds(2); Task executeTask = cmd.ExecuteAsync(); client.Disconnect(); // Waiting for timeout is not optimal here, but better than hanging indefinitely. await Assert.ThrowsExceptionAsync(() => executeTask); } } [TestMethod] public void Test_Execute_InvalidCommand() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand(";"); cmd.Execute(); if (string.IsNullOrEmpty(cmd.Error)) { Assert.Fail("Operation should fail"); } Assert.IsTrue(cmd.ExitStatus > 0); client.Disconnect(); } } [TestMethod] public void Test_Execute_InvalidCommand_Then_Execute_ValidCommand() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand(";"); cmd.Execute(); if (string.IsNullOrEmpty(cmd.Error)) { Assert.Fail("Operation should fail"); } Assert.IsTrue(cmd.ExitStatus > 0); var result = ExecuteTestCommand(client); client.Disconnect(); Assert.IsTrue(result); } } [TestMethod] public void Test_Execute_Command_Reconnect_Execute_Command() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); var result = ExecuteTestCommand(client); Assert.IsTrue(result); client.Disconnect(); client.Connect(); result = ExecuteTestCommand(client); Assert.IsTrue(result); client.Disconnect(); } } [TestMethod] public void Test_Execute_Command_ExitStatus() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.RunCommand("exit 128"); Assert.AreEqual(128, cmd.ExitStatus); Assert.IsNull(cmd.ExitSignal); } } [TestMethod] public void Test_Execute_Command_Asynchronously() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var callbackCalled = new ManualResetEventSlim(); using var cmd = client.CreateCommand("sleep 2s; echo 'test'"); var asyncResult = cmd.BeginExecute(new AsyncCallback((s) => { callbackCalled.Set(); }), state: null); while (!asyncResult.IsCompleted) { Thread.Sleep(100); } Assert.IsTrue(asyncResult.AsyncWaitHandle.WaitOne(0)); cmd.EndExecute(asyncResult); Assert.AreEqual("test\n", cmd.Result); Assert.IsTrue(callbackCalled.Wait(TimeSpan.FromSeconds(1))); client.Disconnect(); } } [TestMethod] public void Test_Execute_Command_Asynchronously_With_Error() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand("sleep 2s; ;"); var asyncResult = cmd.BeginExecute(null, null); Assert.IsTrue(asyncResult.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))); cmd.EndExecute(asyncResult); Assert.IsFalse(string.IsNullOrEmpty(cmd.Error)); client.Disconnect(); } } [TestMethod] public void Test_Execute_Command_Asynchronously_With_Callback_On_Different_Thread() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); var currentThreadId = Thread.CurrentThread.ManagedThreadId; int callbackThreadId = 0; using var callbackCalled = new ManualResetEventSlim(); using var cmd = client.CreateCommand("sleep 2s; echo 'test'"); var asyncResult = cmd.BeginExecute(new AsyncCallback((s) => { callbackThreadId = Thread.CurrentThread.ManagedThreadId; callbackCalled.Set(); }), null); cmd.EndExecute(asyncResult); Assert.IsTrue(callbackCalled.Wait(TimeSpan.FromSeconds(1))); Assert.AreNotEqual(currentThreadId, callbackThreadId); client.Disconnect(); } } /// /// Tests for Issue 563. /// [WorkItem(563), TestMethod] public void Test_Execute_Command_Same_Object_Different_Commands() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand("echo 12345"); cmd.Execute(); Assert.AreEqual("12345\n", cmd.Result); cmd.Execute("echo 23456"); Assert.AreEqual("23456\n", cmd.Result); client.Disconnect(); } } [TestMethod] public void Test_Get_Result_Without_Execution() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand("ls -l"); Assert.AreEqual(string.Empty, cmd.Result); Assert.AreEqual(string.Empty, cmd.Error); client.Disconnect(); } } [WorkItem(703), TestMethod] public void Test_EndExecute_Before_BeginExecute() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); using var cmd = client.CreateCommand("ls -l"); Assert.ThrowsException(() => cmd.EndExecute(null)); client.Disconnect(); } } /// ///A test for BeginExecute /// [TestMethod()] public void BeginExecuteTest() { string expected = "123\n"; string result; using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { #region Example SshCommand CreateCommand BeginExecute IsCompleted EndExecute client.Connect(); using var cmd = client.CreateCommand("sleep 2s;echo 123"); // Perform long running task var asynch = cmd.BeginExecute(); Assert.IsTrue(asynch.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5))); result = cmd.EndExecute(asynch); client.Disconnect(); #endregion Assert.IsNotNull(asynch); Assert.AreEqual(expected, result); } } [TestMethod] public void Test_MultipleThread_100_MultipleConnections() { try { var options = new ParallelOptions() { MaxDegreeOfParallelism = 8 }; Parallel.For(0, 100, options, () => { var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); client.Connect(); return client; }, (int counter, ParallelLoopState pls, SshClient client) => { var result = ExecuteTestCommand(client); Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); Assert.IsTrue(result); return client; }, (SshClient client) => { client.Disconnect(); client.Dispose(); } ); } catch (Exception exp) { Assert.Fail(exp.ToString()); } } [TestMethod] public void Test_MultipleThread_100_MultipleSessions() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); Parallel.For(0, 100, (counter) => { var result = ExecuteTestCommand(client); Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); Assert.IsTrue(result); } ); client.Disconnect(); } } [TestMethod] public void Test_ExecuteAsync_Dispose_CommandFinishes() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { client.Connect(); var cmd = client.CreateCommand("sleep 5s"); var asyncResult = cmd.BeginExecute(null, null); cmd.Dispose(); Assert.IsTrue(asyncResult.AsyncWaitHandle.WaitOne(0)); Assert.ThrowsException(() => cmd.EndExecute(asyncResult)); } } private static bool ExecuteTestCommand(SshClient s) { var testValue = Guid.NewGuid().ToString(); var command = string.Format("echo -n {0}", testValue); using var cmd = s.CreateCommand(command); var result = cmd.Execute(); return result.Equals(testValue); } } }