Пример #1
0
        public void WaitForExitPollsAllowsExecutableToContinueAfterTimeoutIfCpuActivity()
        {
            // Arrange
            var idleTimeout = TimeSpan.MinValue;
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            int num = 10, cpu = 0;
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(() => --num == 0);
            process.Setup(f => f.GetTotalProcessorTime(It.IsAny<ITracer>()))
                   .Returns(() => TimeSpan.FromSeconds(++cpu))
                   .Verifiable();
            process.Setup(f => f.WaitUntilEOF())
                   .Verifiable();
            tracer.Setup(t => t.Trace(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
                  .Verifiable();

            // Act
            idleManager.WaitForExit(process.Object);

            // Assert
            process.Verify();
            Assert.Equal(0, num);
        }
Пример #2
0
        public CommandResult ExecuteCommand(string command, string workingDirectory)
        {
            var idleManager = new IdleManager(_settings.GetCommandIdleTimeout(), _tracer);
            var result = new CommandResult();

            int exitCode = 0;
            var outputBuilder = new StringBuilder();
            var errorBuilder = new StringBuilder();

            Action<CommandEvent> handler = args =>
            {
                idleManager.UpdateActivity();
                switch (args.EventType)
                {
                    case CommandEventType.Output:
                        outputBuilder.AppendLine(args.Data);
                        break;
                    case CommandEventType.Error:
                        errorBuilder.AppendLine(args.Data);
                        break;
                    case CommandEventType.Complete:
                        exitCode = args.ExitCode;
                        break;
                    default:
                        break;
                }
            };

            try
            {
                // Code reuse is good
                CommandEvent += handler;

                ExecuteCommandAsync(command, workingDirectory);
            }
            finally
            {
                CommandEvent -= handler;
            }

            idleManager.WaitForExit(_executingProcess);

            result.Output = outputBuilder.ToString();
            result.Error = errorBuilder.ToString();
            result.ExitCode = exitCode;

            return result;
        }
Пример #3
0
        public void WaitForExitWaitsForEOFPriorToExiting()
        {
            // Arrange
            var idleTimeout = DeploymentSettingsExtension.DefaultCommandIdleTimeout;
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(true)
                   .Verifiable();
            process.Setup(f => f.WaitUntilEOF())
                   .Verifiable();

            // Act
            idleManager.WaitForExit(process.Object);

            // Assert
            process.Verify();
        }
Пример #4
0
        public void WaitForExitPollsAllowsExecutableToContinueAfterTimeoutIfIOActivity()
        {
            // Arrange
            var idleTimeout = TimeSpan.MinValue;
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            int num = 10;
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(() =>
                    {
                        if (--num == 0)
                        {
                            return true;
                        }
                        else
                        {
                            Thread.Sleep(10);
                            idleManager.UpdateActivity();
                            return false;
                        }
                    });
            process.Setup(f => f.WaitUntilEOF())
                   .Verifiable();

            // Act
            idleManager.WaitForExit(process.Object);

            // Assert
            process.Verify();
            Assert.Equal(0, num);
        }
Пример #5
0
        private static async Task CopyStreamAsync(Stream from, Stream to, IdleManager idleManager, CancellationToken cancellationToken, bool closeAfterCopy = false)
        {
            try
            {
                byte[] bytes = new byte[1024];
                int    read  = 0;
                while ((read = await from.ReadAsync(bytes, 0, bytes.Length, cancellationToken)) != 0)
                {
                    idleManager.UpdateActivity();
                    await to.WriteAsync(bytes, 0, read, cancellationToken);
                }

                idleManager.UpdateActivity();
            }
            finally
            {
                // this is needed specifically for input stream
                // in order to tell executable that the input is done
                if (closeAfterCopy)
                {
                    to.Close();
                }
            }
        }
Пример #6
0
        // This is pure async process execution
        public async Task<int> ExecuteAsync(ITracer tracer, string arguments, Stream output, Stream error, Stream input = null, IdleManager idleManager = null)
        {
            using (GetProcessStep(tracer, arguments))
            {
                using (Process process = CreateProcess(arguments))
                {
                    var wrapper = new ProcessWrapper(process);

                    int exitCode = await wrapper.Start(output, error, input, idleManager ?? new IdleManager(IdleTimeout, tracer));

                    tracer.TraceProcessExitCode(process);

                    return exitCode;
                }
            }
        }
Пример #7
0
        private Tuple<string, string> ExecuteInternal(ITracer tracer, Func<string, bool> onWriteOutput, Func<string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            var cmdArguments = String.Format(arguments, args);
            var errorBuffer = new StringBuilder();
            var outputBuffer = new StringBuilder();
            var idleManager = new IdleManager(IdleTimeout, tracer);
            var outputStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteOutput(data))
                    {
                        outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);
            var errorStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteError(data))
                    {
                        errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);

            int exitCode;
            try
            {
                // common execute
                exitCode = Task.Run(() => ExecuteAsync(tracer, cmdArguments, outputStream, errorStream, idleManager: idleManager)).Result;
            }
            catch (AggregateException ex)
            {
                foreach (var inner in ex.Flatten().InnerExceptions)
                {
                    onWriteError(inner.Message);
                }
                throw;
            }
            catch (Exception ex)
            {
                onWriteError(ex.Message);
                throw;
            }
            finally
            {
                // flush out last buffer if any
                outputStream.Dispose();
                errorStream.Dispose();
            }

            string output = outputBuffer.ToString().Trim();
            string error = errorBuffer.ToString().Trim();

            if (exitCode != 0)
            {
                throw new CommandLineException(Path, cmdArguments, !String.IsNullOrEmpty(error) ? error : output)
                {
                    ExitCode = exitCode,
                    Output = output,
                    Error = error
                };
            }

            return Tuple.Create(output, error);
        }
Пример #8
0
        public Tuple <string, string> Execute(ITracer tracer, Func <string, bool> onWriteOutput, Func <string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                Process process = CreateProcess(arguments, args);
                process.EnableRaisingEvents = true;

                var errorBuffer  = new StringBuilder();
                var outputBuffer = new StringBuilder();

                var idleManager = new IdleManager(IdleTimeout, tracer);
                process.OutputDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteOutput(e.Data))
                        {
                            outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteError(e.Data))
                        {
                            errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                try
                {
                    idleManager.WaitForExit(process);
                }
                catch (Exception ex)
                {
                    onWriteError(ex.Message);
                    throw;
                }

                tracer.TraceProcessExitCode(process);

                string output = outputBuffer.ToString().Trim();
                string error  = errorBuffer.ToString().Trim();

                if (process.ExitCode != 0)
                {
                    string text = String.IsNullOrEmpty(error) ? output : error;

                    throw new CommandLineException(Path, process.StartInfo.Arguments, text)
                          {
                              ExitCode = process.ExitCode,
                              Output   = output,
                              Error    = error
                          };
                }

                return(Tuple.Create(output, error));
            }
        }
Пример #9
0
        private Tuple <string, string> ExecuteInternal(ITracer tracer, Func <string, bool> onWriteOutput, Func <string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            var cmdArguments = String.Format(arguments, args);
            var errorBuffer  = new StringBuilder();
            var outputBuffer = new StringBuilder();
            var idleManager  = new IdleManager(IdleTimeout, tracer);
            var outputStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteOutput(data))
                    {
                        outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);
            var errorStream = new AsyncStreamWriter(data =>
            {
                idleManager.UpdateActivity();
                if (data != null)
                {
                    if (onWriteError(data))
                    {
                        errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(data)));
                    }
                }
            }, Encoding ?? Console.OutputEncoding);

            int exitCode;

            try
            {
                // common execute
                exitCode = Task.Run(() => ExecuteAsync(tracer, cmdArguments, outputStream, errorStream, idleManager: idleManager)).Result;
            }
            catch (AggregateException ex)
            {
                foreach (var inner in ex.Flatten().InnerExceptions)
                {
                    onWriteError(inner.Message);
                }
                throw;
            }
            catch (Exception ex)
            {
                onWriteError(ex.Message);
                throw;
            }
            finally
            {
                // flush out last buffer if any
                outputStream.Dispose();
                errorStream.Dispose();
            }

            string output = outputBuffer.ToString().Trim();
            string error  = errorBuffer.ToString().Trim();

            if (exitCode != 0)
            {
                throw new CommandLineException(Path, cmdArguments, error)
                      {
                          ExitCode = exitCode,
                          Output   = output,
                          Error    = error
                      };
            }

            return(Tuple.Create(output, error));
        }
Пример #10
0
        public async Task ProcesStartBasicTests()
        {
            var tracer = Mock.Of<ITracer>();
            var process = new Mock<IProcess>();
            var idleManager = new IdleManager(TimeSpan.MaxValue, tracer);

            var expectedExitCode = 10;
            var input = "this is input";
            var output = "this is output";
            var error = "this is error";
            var inputBuffer = new byte[1024];

            var actualOutput = new MemoryStream();
            var actualError = new MemoryStream();
            var actualInput = new MemoryStream(inputBuffer);

            var expectedInput = new MemoryStream();
            var bytes = Encoding.UTF8.GetBytes(input);
            expectedInput.Write(bytes, 0, bytes.Length);
            expectedInput.Position = 0;

            var expectedOutput = new MemoryStream();
            bytes = Encoding.UTF8.GetBytes(output);
            expectedOutput.Write(bytes, 0, bytes.Length);
            expectedOutput.Position = 0;

            var expectedError = new MemoryStream();
            bytes = Encoding.UTF8.GetBytes(error);
            expectedError.Write(bytes, 0, bytes.Length);
            expectedError.Position = 0;

            // Setup
            process.SetupGet(p => p.StandardInput)
                   .Returns(new StreamWriter(actualInput));
            process.SetupGet(p => p.StandardOutput)
                   .Returns(new StreamReader(expectedOutput));
            process.SetupGet(p => p.StandardError)
                   .Returns(new StreamReader(expectedError));
            process.SetupGet(p => p.ExitCode)
                   .Returns(expectedExitCode);
            process.Setup(p => p.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(true);

            // Test
            int actualExitCode = await process.Object.Start(tracer, actualOutput, actualError, expectedInput, idleManager);

            // Assert
            Assert.Equal(expectedExitCode, actualExitCode);
            Assert.Throws<ObjectDisposedException>(() => actualInput.Length);
            Assert.Equal(input, Encoding.UTF8.GetString(inputBuffer, 0, input.Length));
            Assert.Equal(output, Encoding.UTF8.GetString(actualOutput.GetBuffer(), 0, (int)actualOutput.Length));
            Assert.Equal(error, Encoding.UTF8.GetString(actualError.GetBuffer(), 0, (int)actualError.Length));
        }
Пример #11
0
        public static async Task <int> Start(this IProcess process, ITracer tracer, Stream output, Stream error, Stream input = null, IdleManager idleManager = null)
        {
            var cancellationTokenSource = new CancellationTokenSource();

            process.Start();

            var tasks = new List <Task>();

            if (input != null)
            {
                tasks.Add(CopyStreamAsync(input, process.StandardInput.BaseStream, idleManager, cancellationTokenSource.Token, closeAfterCopy: true));
            }

            tasks.Add(CopyStreamAsync(process.StandardOutput.BaseStream, output, idleManager, cancellationTokenSource.Token));
            tasks.Add(CopyStreamAsync(process.StandardError.BaseStream, error, idleManager, cancellationTokenSource.Token));

            idleManager.WaitForExit(process);

            // Process has exited, draining the stdout and stderr
            await FlushAllAsync(process, tracer, idleManager, cancellationTokenSource, tasks);

            return(process.ExitCode);
        }
Пример #12
0
        private static async Task CopyStreamAsync(Stream from, Stream to, IdleManager idleManager, CancellationToken cancellationToken, bool closeAfterCopy = false)
        {
            try
            {
                byte[] bytes = new byte[1024];
                int read = 0;
                while ((read = await from.ReadAsync(bytes, 0, bytes.Length, cancellationToken)) != 0)
                {
                    idleManager.UpdateActivity();
                    await to.WriteAsync(bytes, 0, read, cancellationToken);
                }

                idleManager.UpdateActivity();
            }
            finally
            {
                // this is needed specifically for input stream
                // in order to tell executable that the input is done
                if (closeAfterCopy)
                {
                    to.Close();
                }
            }
        }
Пример #13
0
        public void WaitForExitPollsKillsProcessIfProcessorTimeDoesNotChangeAndNotUpdated()
        {
            // Arrange
            var tracer = new Mock<ITracer>(MockBehavior.Strict);
            DateTime startTime = DateTime.UtcNow;
            TimeSpan idleTimeout = TimeSpan.FromMilliseconds(100);
            var idleManager = new IdleManager(idleTimeout, tracer.Object);
            var process = new Mock<IProcess>(MockBehavior.Strict);

            // Setup
            process.SetupGet(f => f.Name)
                   .Returns("Test-Process");
            process.SetupGet(f => f.Arguments)
                   .Returns("");
            process.Setup(f => f.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(() => { Thread.Sleep(10); return false; });
            process.Setup(f => f.GetTotalProcessorTime(It.IsAny<ITracer>()))
                   .Returns(TimeSpan.Zero);
            process.Setup(f => f.Kill(tracer.Object))
                   .Verifiable();
            tracer.Setup(t => t.Trace(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
                  .Verifiable();

            // Act
            var ex = Assert.Throws<CommandLineException>(() => idleManager.WaitForExit(process.Object));

            // Assert
            process.Verify();

            Assert.True(DateTime.UtcNow - startTime >= idleTimeout);
            Assert.Contains("Command 'Test-Process ' aborted due to no output and CPU activity for", ex.Message);
        }
Пример #14
0
        // This is pure async process execution
        public async Task <int> ExecuteAsync(ITracer tracer, string arguments, Stream output, Stream error, Stream input = null, IdleManager idleManager = null)
        {
            using (GetProcessStep(tracer, arguments))
            {
                using (Process process = CreateProcess(arguments))
                {
                    var wrapper = new ProcessWrapper(process);

                    int exitCode = await wrapper.Start(tracer, output, error, input, idleManager ?? new IdleManager(IdleTimeout, tracer));

                    tracer.TraceProcessExitCode(process);

                    return(exitCode);
                }
            }
        }
Пример #15
0
        // this is used exclusive in git sever scenario
        public void Execute(ITracer tracer, Stream input, Stream output, string arguments, params object[] args)
        {
            var cmdArguments = String.Format(arguments, args);
            var errorStream = new MemoryStream();
            var idleManager = new IdleManager(IdleTimeout, tracer, output);

            // common execute
            int exitCode = Task.Run(() => ExecuteAsync(tracer, cmdArguments, output, errorStream, input, idleManager)).Result;

            string error = GetString(errorStream);
            if (exitCode != 0)
            {
                throw new CommandLineException(Path, cmdArguments, error)
                {
                    ExitCode = exitCode,
                    Error = error
                };
            }
        }
Пример #16
0
        public static async Task<int> Start(this IProcess process, ITracer tracer, Stream output, Stream error, Stream input = null, IdleManager idleManager = null)
        {
            var cancellationTokenSource = new CancellationTokenSource();

            process.Start();

            var tasks = new List<Task>();

            if (input != null)
            {
                tasks.Add(CopyStreamAsync(input, process.StandardInput.BaseStream, idleManager, cancellationTokenSource.Token, closeAfterCopy: true));
            }

            tasks.Add(CopyStreamAsync(process.StandardOutput.BaseStream, output, idleManager, cancellationTokenSource.Token));
            tasks.Add(CopyStreamAsync(process.StandardError.BaseStream, error, idleManager, cancellationTokenSource.Token));

            idleManager.WaitForExit(process);

            // Process has exited, draining the stdout and stderr
            await FlushAllAsync(process, tracer, idleManager, cancellationTokenSource, tasks);

            return process.ExitCode;
        }
Пример #17
0
        public void Execute(ITracer tracer, Stream input, Stream output, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                var process = CreateProcess(arguments, args);
                process.Start();

                var idleManager = new IdleManager(Path, IdleTimeout, tracer);
                Func<StreamReader, string> reader = (StreamReader streamReader) => streamReader.ReadToEnd();
                Action<Stream, Stream, bool> copyStream = (Stream from, Stream to, bool closeAfterCopy) =>
                {
                    try
                    {
                        byte[] bytes = new byte[1024];
                        int read = 0;
                        while ((read = from.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            idleManager.UpdateActivity();
                            to.Write(bytes, 0, read);
                        }

                        idleManager.UpdateActivity();
                        if (closeAfterCopy)
                        {
                            to.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        tracer.TraceError(ex);
                    }
                };

                IAsyncResult errorReader = reader.BeginInvoke(process.StandardError, null, null);
                IAsyncResult inputResult = null;

                if (input != null)
                {
                    // Copy into the input stream, and close it to tell the exe it can process it
                    inputResult = copyStream.BeginInvoke(input,
                                                         process.StandardInput.BaseStream,
                                                         true,
                                                         null,
                                                         null);
                }

                // Copy the exe's output into the output stream
                IAsyncResult outputResult = copyStream.BeginInvoke(process.StandardOutput.BaseStream,
                                                                   output,
                                                                   false,
                                                                   null,
                                                                   null);

                idleManager.WaitForExit(process);

                // Wait for the input operation to complete
                if (inputResult != null)
                {
                    inputResult.AsyncWaitHandle.WaitOne();
                }

                // Wait for the output operation to be complete
                outputResult.AsyncWaitHandle.WaitOne();

                string error = reader.EndInvoke(errorReader);

                tracer.Trace("Process dump", new Dictionary<string, string>
                {
                    { "exitCode", process.ExitCode.ToString() },
                    { "type", "processOutput" }
                });

                if (process.ExitCode != 0)
                {
                    throw new CommandLineException(error)
                    {
                        ExitCode = process.ExitCode,
                        Error = error
                    };
                }
            }
        }
Пример #18
0
        private static async Task FlushAllAsync(IProcess process, ITracer tracer, IdleManager idleManager, CancellationTokenSource cancellationTokenSource, IEnumerable<Task> tasks)
        {
            var prevActivity = DateTime.MinValue;
            while (true)
            {
                // Wait for either delay or io tasks
                var delay = Task.Delay(StandardOutputDrainTimeout, cancellationTokenSource.Token);
                var stdio = Task.WhenAll(tasks);
                var completed = await Task.WhenAny(stdio, delay);

                // if delay commpleted first (meaning timeout), check if activity and continue to wait
                if (completed == delay)
                {
                    var lastActivity = idleManager.LastActivity;
                    if (lastActivity != prevActivity)
                    {
                        prevActivity = lastActivity;
                        continue;
                    }
                }

                // clean up all pending tasks by cancelling them
                // this is important so we don't have runaway tasks
                cancellationTokenSource.Cancel();

                // in case of stdoutput/err have no activity within given time
                // we force close all streams
                if (completed == delay)
                {
                    // TODO, suwatch: MDS Kudu SiteExtension
                    using (tracer.Step("Flush stdio and stderr have no activity within given time"))
                    {
                        bool exited = process.HasExited;

                        SafeCloseStream(process.StandardOutput.BaseStream);
                        SafeCloseStream(process.StandardError.BaseStream);

                        // this means no activity within given time
                        // and process has not exited
                        if (!exited)
                        {
                            throw new TimeoutException("Timeout draining standard input, output and error!");
                        }
                    }
                }

                // happy path
                break;
            }
        }
Пример #19
0
        public Tuple<string, string> Execute(ITracer tracer, Func<string, bool> onWriteOutput, Func<string, bool> onWriteError, Encoding encoding, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                Process process = CreateProcess(arguments, args);
                process.EnableRaisingEvents = true;

                var errorBuffer = new StringBuilder();
                var outputBuffer = new StringBuilder();

                var idleManager = new IdleManager(Path, IdleTimeout, tracer);
                process.OutputDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteOutput(e.Data))
                        {
                            outputBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    idleManager.UpdateActivity();
                    if (e.Data != null)
                    {
                        if (onWriteError(e.Data))
                        {
                            errorBuffer.AppendLine(Encoding.UTF8.GetString(encoding.GetBytes(e.Data)));
                        }
                    }
                };

                process.Start();

                process.BeginErrorReadLine();
                process.BeginOutputReadLine();

                try
                {
                    idleManager.WaitForExit(process);
                }
                catch (Exception ex)
                {
                    onWriteError(ex.Message);
                    throw;
                }

                tracer.Trace("Process dump", new Dictionary<string, string>
                {
                    { "exitCode", process.ExitCode.ToString() },
                    { "type", "processOutput" }
                });

                string output = outputBuffer.ToString().Trim();
                string error = errorBuffer.ToString().Trim();

                if (process.ExitCode != 0)
                {
                    string text = String.IsNullOrEmpty(error) ? output : error;

                    throw new CommandLineException(text)
                    {
                        ExitCode = process.ExitCode,
                        Output = output,
                        Error = error
                    };
                }

                return Tuple.Create(output, error);
            }
        }
Пример #20
0
        public Tuple<string, string> Execute(string arguments, params object[] args)
#endif
        {

#if !SITEMANAGEMENT
            using (GetProcessStep(tracer, arguments, args))
            {
#endif
                var process = CreateProcess(arguments, args);
                process.Start();

#if !SITEMANAGEMENT
                var idleManager = new IdleManager(Path, IdleTimeout, tracer);
#else
                var idleManager = new IdleManager();
#endif
                Func<StreamReader, string> reader = (StreamReader streamReader) =>
                {
                    var strb = new StringBuilder();
                    char[] buffer = new char[1024];
                    int read;
                    while ((read = streamReader.ReadBlock(buffer, 0, buffer.Length)) != 0)
                    {
                        idleManager.UpdateActivity();
                        strb.Append(buffer, 0, read);
                    }
                    idleManager.UpdateActivity();
                    return strb.ToString();
                };

                IAsyncResult outputReader = reader.BeginInvoke(process.StandardOutput, null, null);
                IAsyncResult errorReader = reader.BeginInvoke(process.StandardError, null, null);

                process.StandardInput.Close();

                idleManager.WaitForExit(process);

                string output = reader.EndInvoke(outputReader);
                string error = reader.EndInvoke(errorReader);

#if !SITEMANAGEMENT
                tracer.Trace("Process dump", new Dictionary<string, string>
                {
                    { "exitCode", process.ExitCode.ToString() },
                    { "type", "processOutput" }
                });
#endif

                // Sometimes, we get an exit code of 1 even when the command succeeds (e.g. with 'git reset .').
                // So also make sure there is an error string
                if (process.ExitCode != 0)
                {
                    string text = String.IsNullOrEmpty(error) ? output : error;

                    throw new CommandLineException(text)
                    {
                        ExitCode = process.ExitCode,
                        Output = output,
                        Error = error
                    };
                }

                return Tuple.Create(output, error);

#if !SITEMANAGEMENT
            }
#endif
        }
Пример #21
0
        public void Execute(ITracer tracer, Stream input, Stream output, string arguments, params object[] args)
        {
            using (GetProcessStep(tracer, arguments, args))
            {
                var process = CreateProcess(arguments, args);
                process.Start();

                var idleManager = new IdleManager(IdleTimeout, tracer, output);
                Func <StreamReader, string>   reader     = (StreamReader streamReader) => streamReader.ReadToEnd();
                Action <Stream, Stream, bool> copyStream = (Stream from, Stream to, bool closeAfterCopy) =>
                {
                    try
                    {
                        byte[] bytes      = new byte[1024];
                        int    read       = 0;
                        bool   writeError = false;
                        while ((read = from.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            idleManager.UpdateActivity();
                            try
                            {
                                if (!writeError)
                                {
                                    to.Write(bytes, 0, read);
                                }
                            }
                            catch (Exception ex)
                            {
                                writeError = true;
                                tracer.TraceError(ex);
                            }
                        }

                        idleManager.UpdateActivity();
                        if (closeAfterCopy)
                        {
                            to.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        tracer.TraceError(ex);
                    }
                };

                IAsyncResult errorReader = reader.BeginInvoke(process.StandardError, null, null);
                IAsyncResult inputResult = null;

                if (input != null)
                {
                    // Copy into the input stream, and close it to tell the exe it can process it
                    inputResult = copyStream.BeginInvoke(input,
                                                         process.StandardInput.BaseStream,
                                                         true,
                                                         null,
                                                         null);
                }

                // Copy the exe's output into the output stream
                IAsyncResult outputResult = copyStream.BeginInvoke(process.StandardOutput.BaseStream,
                                                                   output,
                                                                   false,
                                                                   null,
                                                                   null);

                idleManager.WaitForExit(process);

                // Wait for the input operation to complete
                if (inputResult != null)
                {
                    inputResult.AsyncWaitHandle.WaitOne();
                }

                // Wait for the output operation to be complete
                outputResult.AsyncWaitHandle.WaitOne();

                string error = reader.EndInvoke(errorReader);

                tracer.TraceProcessExitCode(process);

                if (process.ExitCode != 0)
                {
                    throw new CommandLineException(Path, process.StartInfo.Arguments, error)
                          {
                              ExitCode = process.ExitCode,
                              Error    = error
                          };
                }
            }
        }
Пример #22
0
        public async Task ProcesOutputBlockedTests()
        {
            var tracer = Mock.Of<ITracer>();
            var process = new Mock<IProcess>();
            var idleManager = new IdleManager(TimeSpan.MaxValue, tracer);
            var output = new Mock<Stream>(MockBehavior.Strict);
            CancellationToken cancellationToken;

            // Setup
            output.SetupGet(o => o.CanRead)
                  .Returns(true);
            output.Setup(o => o.ReadAsync(It.IsAny<byte[]>(), 0, It.IsAny<int>(), It.IsAny<CancellationToken>()))
                  .Callback((byte[] buffer, int offset, int count, CancellationToken token) => { cancellationToken = token; })
                  .Returns(async () =>
                  {
                      await Task.Delay(5000, cancellationToken);
                      return 0;
                  });
            process.SetupGet(p => p.StandardInput)
                   .Returns(new StreamWriter(new MemoryStream()));
            process.SetupGet(p => p.StandardOutput)
                   .Returns(new StreamReader(output.Object));
            process.SetupGet(p => p.StandardError)
                   .Returns(new StreamReader(new MemoryStream()));
            process.Setup(p => p.WaitForExit(It.IsAny<TimeSpan>()))
                   .Returns(true);

            var timeout = ProcessExtensions.StandardOutputDrainTimeout;
            try
            {
                // Speedup the test
                ProcessExtensions.StandardOutputDrainTimeout = TimeSpan.FromSeconds(1);

                // Test
                await process.Object.Start(tracer, new MemoryStream(), new MemoryStream(), null, idleManager);

                throw new InvalidOperationException("Should not reach here!");
            }
            catch (TimeoutException)
            {
                // No-op
            }
            finally
            {
                ProcessExtensions.StandardOutputDrainTimeout = timeout;
            }
        }
Пример #23
0
        private static async Task FlushAllAsync(IdleManager idleManager, CancellationTokenSource cancellationTokenSource, IEnumerable<Task> tasks)
        {
            var prevActivity = DateTime.MinValue;
            while (true)
            {
                // Wait for either delay or io tasks
                var delay = Task.Delay(StandardOutputDrainTimeout, cancellationTokenSource.Token);
                var stdio = Task.WhenAll(tasks);
                var completed = await Task.WhenAny(stdio, delay);

                // if delay commpleted first (meaning timeout), check if activity and continue to wait
                if (completed == delay)
                {
                    var lastActivity = idleManager.LastActivity;
                    if (lastActivity != prevActivity)
                    {
                        prevActivity = lastActivity;
                        continue;
                    }
                }

                // clean up all pending tasks by cancelling them
                // this is important so we don't have runaway tasks
                cancellationTokenSource.Cancel();

                try
                {
                    // get result of stdio flush
                    await stdio;

                    break;
                }
                catch (TaskCanceledException)
                {
                    // expected since we cancelled all tasks
                }

                // this means no activity within given time
                if (completed != stdio)
                {
                    throw new TimeoutException("Timeout draining standard input, output and error!");
                }

                // happy path
                break;
            }
        }