< Summary

Class:Azure.Identity.ProcessRunner
Assembly:Azure.Identity
File(s):C:\Git\azure-sdk-for-net\sdk\identity\Azure.Identity\src\ProcessRunner.cs
Covered lines:48
Uncovered lines:3
Coverable lines:51
Total lines:136
Line coverage:94.1% (48 of 51)
Covered branches:14
Total branches:18
Branch coverage:77.7% (14 of 18)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-77.78%50%
RunAsync()-100%100%
Run()-100%100%
StartProcess()-100%83.33%
HandleExit()-100%100%
HandleCancel()-90%75%
TrySetResult(...)-100%100%
TrySetCanceled()-100%100%
TrySetException(...)-100%100%
DisposeProcess()-100%50%

File(s)

C:\Git\azure-sdk-for-net\sdk\identity\Azure.Identity\src\ProcessRunner.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Threading;
 6using System.Threading.Tasks;
 7
 8namespace Azure.Identity
 9{
 10#pragma warning disable CA1001 // Types that own disposable fields should be disposable. Disposing of _process and _ctRe
 11    internal sealed class ProcessRunner
 12#pragma warning restore CA1001 // Types that own disposable fields should be disposable
 13    {
 14        private readonly IProcess _process;
 15        private readonly TimeSpan _timeout;
 16        private readonly TaskCompletionSource<string> _tcs;
 17        private readonly CancellationToken _cancellationToken;
 18        private readonly CancellationTokenSource _timeoutCts;
 19        private CancellationTokenRegistration _ctRegistration;
 20
 18821        public ProcessRunner(IProcess process, TimeSpan timeout, CancellationToken cancellationToken)
 22        {
 18823            _process = process;
 18824            _timeout = timeout;
 18825            _tcs = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
 26
 18827            if (timeout.TotalMilliseconds >= 0)
 28            {
 18829                _timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 18830                _cancellationToken = _timeoutCts.Token;
 31            }
 32            else
 33            {
 034                _cancellationToken = cancellationToken;
 35            }
 036        }
 37
 38        public Task<string> RunAsync()
 39        {
 9440            StartProcess();
 9441            return _tcs.Task;
 42        }
 43
 44        public string Run()
 45        {
 9446            StartProcess();
 47#pragma warning disable AZC0102 // Do not use GetAwaiter().GetResult().
 9448            return _tcs.Task.GetAwaiter().GetResult();
 49#pragma warning restore AZC0102 // Do not use GetAwaiter().GetResult().
 50        }
 51
 52        private void StartProcess()
 53        {
 18854            if (TrySetCanceled() || _tcs.Task.IsCompleted)
 55            {
 856                return;
 57            }
 58
 33859            _process.Exited += (o, e) => HandleExit();
 60
 18061            _process.StartInfo.UseShellExecute = false;
 18062            _process.StartInfo.RedirectStandardOutput = true;
 18063            _process.StartInfo.RedirectStandardError = true;
 64
 18065            _timeoutCts?.CancelAfter(_timeout);
 66
 18067            _process.Start();
 18068            _ctRegistration = _cancellationToken.Register(HandleCancel, false);
 18069        }
 70
 71        private void HandleExit()
 72        {
 15873            if (_process.ExitCode == 0)
 74            {
 10675                TrySetResult(_process.StandardOutput.ReadToEnd());
 76            }
 77            else
 78            {
 5279                TrySetException(new InvalidOperationException(_process.StandardError.ReadToEnd()));
 80            }
 5281        }
 82
 83        private void HandleCancel()
 84        {
 2285            if (_tcs.Task.IsCompleted)
 86            {
 087                return;
 88            }
 89
 2290            if (!_process.HasExited)
 91            {
 92                try
 93                {
 2294                    _process.Kill();
 1895                }
 496                catch (Exception ex)
 97                {
 498                    TrySetException(ex);
 499                    return;
 100                }
 101            }
 102
 18103            TrySetCanceled();
 22104        }
 105
 106        private void TrySetResult(string result)
 107        {
 106108            DisposeProcess();
 106109            _tcs.TrySetResult(result);
 106110        }
 111
 112        private bool TrySetCanceled()
 113        {
 206114            if (_cancellationToken.IsCancellationRequested)
 115            {
 26116                DisposeProcess();
 26117                _tcs.TrySetCanceled(_cancellationToken);
 118            }
 119
 206120            return _cancellationToken.IsCancellationRequested;
 121        }
 122
 123        private void TrySetException(Exception exception)
 124        {
 56125            DisposeProcess();
 56126            _tcs.TrySetException(exception);
 56127        }
 128
 129        private void DisposeProcess()
 130        {
 188131            _process.Dispose();
 188132            _ctRegistration.Dispose();
 188133            _timeoutCts?.Dispose();
 188134        }
 135    }
 136}