How to use KillAsync method of PuppeteerSharp.States.KillingState class

Best Puppeteer-sharp code snippet using PuppeteerSharp.States.KillingState.KillAsync

Run Puppeteer-sharp automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

KillingState.cs

Source: KillingState.cs Github

copy
1using System;
2using System.Threading.Tasks;
3
4namespace PuppeteerSharp.States
5{
6    internal class KillingState : State
7    {
8        public KillingState(StateManager stateManager) : base(stateManager)
9        {
10        }
11
12        public override async Task EnterFromAsync(LauncherBase p, State fromState, TimeSpan timeout)
13        {
14            if (!StateManager.TryEnter(p, fromState, this))
15            {
16                // Delegate KillAsync to current state, because it has already changed since
17                // transition to this state was initiated.
18                await StateManager.CurrentState.KillAsync(p).ConfigureAwait(false);
19            }
20
21            try
22            {
23                if (!p.Process.HasExited)
24                {
25                    p.Process.Kill();
26                }
27            }
28            catch (InvalidOperationException)
29            {
30                // Ignore
31                return;
32            }
33
34            await WaitForExitAsync(p).ConfigureAwait(false);
35        }
36
37        public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => WaitForExitAsync(p);
38
39        public override Task KillAsync(LauncherBase p) => WaitForExitAsync(p);
40    }
41}
42
Full Screen

StartedState.cs

Source: StartedState.cs Github

copy
1using System;
2using System.Threading.Tasks;
3
4namespace PuppeteerSharp.States
5{
6    internal class StartedState : State
7    {
8        public StartedState(StateManager stateManager) : base(stateManager)
9        {
10        }
11
12        public override Task EnterFromAsync(LauncherBase p, State fromState, TimeSpan timeout)
13        {
14            StateManager.TryEnter(p, fromState, this);
15            return Task.CompletedTask;
16        }
17
18        public override Task StartAsync(LauncherBase p) => Task.CompletedTask;
19
20        public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => new ExitingState(StateManager).EnterFromAsync(p, this, timeout);
21
22        public override Task KillAsync(LauncherBase p) => new KillingState(StateManager).EnterFromAsync(p, this);
23    }
24}
25
Full Screen

LauncherBase.cs

Source: LauncherBase.cs Github

copy
1using PuppeteerSharp.Helpers;
2using System;
3using System.Collections;
4using System.Collections.Generic;
5using System.Diagnostics;
6using System.Text;
7using System.Text.RegularExpressions;
8using System.Threading;
9using System.Threading.Tasks;
10
11namespace PuppeteerSharp
12{
13    /// <summary>
14    /// Represents a Base process and any associated temporary user data directory that have created
15    /// by Puppeteer and therefore must be cleaned up when no longer needed.
16    /// </summary>
17    public class LauncherBase : IDisposable
18    {
19
20        #region Instance fields
21
22        private readonly LaunchOptions _options;
23        private readonly TaskCompletionSource<string> _startCompletionSource = new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
24        private readonly TaskCompletionSource<bool> _exitCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
25        private State _currentState = State.Initial;
26
27        #endregion
28
29        #region Constructor
30
31        /// <summary>
32        /// Creates a new <see cref="LauncherBase"/> instance.
33        /// </summary>
34        /// <param name="executable">Full path of executable.</param>
35        /// <param name="options">Options for launching Base.</param>
36        /// <param name="loggerFactory">Logger factory</param>
37        public LauncherBase(string executable, LaunchOptions options)
38        {
39            _options = options;
40
41            Process = new Process
42            {
43                EnableRaisingEvents = true
44            };
45            Process.StartInfo.UseShellExecute = false;
46            Process.StartInfo.FileName = executable;
47            Process.StartInfo.RedirectStandardError = true;
48
49            SetEnvVariables(Process.StartInfo.Environment, options.Env, Environment.GetEnvironmentVariables());
50
51            if (options.DumpIO)
52            {
53                Process.ErrorDataReceived += (sender, e) => Console.Error.WriteLine(e.Data);
54            }
55        }
56
57        #endregion
58
59        #region Dispose
60
61        /// <summary>
62        /// Finalizer.
63        /// </summary>
64        ~LauncherBase()
65        {
66            Dispose(false);
67        }
68
69        /// <inheritdoc />
70        public void Dispose()
71        {
72            Dispose(true);
73            GC.SuppressFinalize(this);
74        }
75
76        /// <summary>
77        /// Disposes Base process and any temporary user directory.
78        /// </summary>
79        /// <param name="disposing">Indicates whether disposal was initiated by <see cref="Dispose()"/> operation.</param>
80        protected virtual void Dispose(bool disposing) => _currentState.Dispose(this);
81
82        #endregion
83
84        #region Properties
85
86        /// <summary>
87        /// Gets Base process details.
88        /// </summary>
89        public Process Process { get; }
90
91        /// <summary>
92        /// Gets Base endpoint.
93        /// </summary>
94        public string EndPoint => _startCompletionSource.Task.IsCompleted
95            ? _startCompletionSource.Task.Result
96            : null;
97
98        /// <summary>
99        /// Indicates whether Base process is exiting.
100        /// </summary>
101        public bool IsExiting => _currentState.IsExiting;
102
103        /// <summary>
104        /// Indicates whether Base process has exited.
105        /// </summary>
106        public bool HasExited => _currentState.IsExited;
107
108        internal TempDirectory TempUserDataDir { get; set; }
109
110        /// <summary>
111        /// Gets Base process current state.
112        /// </summary>
113        protected State CurrentState { get => _currentState; }
114
115        #endregion
116
117        #region Public methods
118
119        /// <summary>
120        /// Asynchronously starts Base process.
121        /// </summary>
122        /// <returns></returns>
123        public Task StartAsync() => _currentState.StartAsync(this);
124
125        /// <summary>
126        /// Asynchronously waits for graceful Base process exit within a given timeout period.
127        /// Kills the Base process if it has not exited within this period.
128        /// </summary>
129        /// <param name="timeout">The maximum waiting time for a graceful process exit.</param>
130        /// <returns></returns>
131        public Task EnsureExitAsync(TimeSpan? timeout) => timeout.HasValue
132            ? _currentState.ExitAsync(this, timeout.Value)
133            : _currentState.KillAsync(this);
134
135        /// <summary>
136        /// Asynchronously kills Base process.
137        /// </summary>
138        /// <returns></returns>
139        public Task KillAsync() => _currentState.KillAsync(this);
140
141        /// <summary>
142        /// Waits for Base process exit within a given timeout.
143        /// </summary>
144        /// <param name="timeout">The maximum wait period.</param>
145        /// <returns><c>true</c> if Base process has exited within the given <paramref name="timeout"/>,
146        /// or <c>false</c> otherwise.</returns>
147        public async Task<bool> WaitForExitAsync(TimeSpan? timeout)
148        {
149            if (timeout.HasValue)
150            {
151                bool taskCompleted = true;
152                await _exitCompletionSource.Task.WithTimeout(
153                    () =>
154                    {
155                        taskCompleted = false;
156                    }, timeout.Value).ConfigureAwait(false);
157                return taskCompleted;
158            }
159
160            await _exitCompletionSource.Task.ConfigureAwait(false);
161            return true;
162        }
163
164        #endregion
165
166        #region Private methods
167
168        /// <summary>
169        /// Set Env Variables
170        /// </summary>
171        /// <param name="environment">The environment.</param>
172        /// <param name="customEnv">The customEnv.</param>
173        /// <param name="realEnv">The realEnv.</param>
174        protected static void SetEnvVariables(IDictionary<string, string> environment, IDictionary<string, string> customEnv, IDictionary realEnv)
175        {
176            foreach (DictionaryEntry item in realEnv)
177            {
178                environment[item.Key.ToString()] = item.Value.ToString();
179            }
180
181            if (customEnv != null)
182            {
183                foreach (var item in customEnv)
184                {
185                    environment[item.Key] = item.Value;
186                }
187            }
188        }
189
190        #endregion
191
192        #region State machine
193
194        /// <summary>
195        /// Represents state machine for Base process instances. The happy path runs along the
196        /// following state transitions: <see cref="Initial"/>
197        /// -> <see cref="Starting"/>
198        /// -> <see cref="Started"/>
199        /// -> <see cref="Exiting"/>
200        /// -> <see cref="Exited"/>.
201        /// -> <see cref="Disposed"/>.
202        /// </summary>
203        /// <remarks>
204        /// <para>
205        /// This state machine implements the following state transitions:
206        /// <code>
207        /// State     Event              Target State Action
208        /// ======== =================== ============ ==========================================================
209        /// Initial  --StartAsync------> Starting     Start process and wait for endpoint
210        /// Initial  --ExitAsync-------> Exited       Cleanup temp user data
211        /// Initial  --KillAsync-------> Exited       Cleanup temp user data
212        /// Initial  --Dispose---------> Disposed     Cleanup temp user data
213        /// Starting --StartAsync------> Starting     -
214        /// Starting --ExitAsync-------> Exiting      Wait for process exit
215        /// Starting --KillAsync-------> Killing      Kill process
216        /// Starting --Dispose---------> Disposed     Kill process; Cleanup temp user data;  throw ObjectDisposedException on outstanding async operations;
217        /// Starting --endpoint ready--> Started      Complete StartAsync successfully; Log process start
218        /// Starting --process exit----> Exited       Complete StartAsync with exception; Cleanup temp user data
219        /// Started  --StartAsync------> Started      -
220        /// Started  --EnsureExitAsync-> Exiting      Start exit timer; Log process exit
221        /// Started  --KillAsync-------> Killing      Kill process; Log process exit
222        /// Started  --Dispose---------> Disposed     Kill process; Log process exit; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;
223        /// Started  --process exit----> Exited       Log process exit; Cleanup temp user data
224        /// Exiting  --StartAsync------> Exiting      - (StartAsync throws InvalidOperationException)
225        /// Exiting  --ExitAsync-------> Exiting      -
226        /// Exiting  --KillAsync-------> Killing      Kill process
227        /// Exiting  --Dispose---------> Disposed     Kill process; Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;
228        /// Exiting  --exit timeout----> Killing      Kill process
229        /// Exiting  --process exit----> Exited       Cleanup temp user data; complete outstanding async operations;
230        /// Killing  --StartAsync------> Killing      - (StartAsync throws InvalidOperationException)
231        /// Killing  --KillAsync-------> Killing      -
232        /// Killing  --Dispose---------> Disposed     Cleanup temp user data; throw ObjectDisposedException on outstanding async operations;
233        /// Killing  --process exit----> Exited       Cleanup temp user data; complete outstanding async operations;
234        /// Exited   --StartAsync------> Killing      - (StartAsync throws InvalidOperationException)
235        /// Exited   --KillAsync-------> Exited       -
236        /// Exited   --Dispose---------> Disposed     -
237        /// Disposed --StartAsync------> Disposed     -
238        /// Disposed --KillAsync-------> Disposed     -
239        /// Disposed --Dispose---------> Disposed     -
240        /// </code>
241        /// </para>
242        /// </remarks>
243        protected abstract class State
244        {
245            #region Predefined states
246
247            /// <summary>
248            /// Set initial state.
249            /// </summary>
250            public static readonly State Initial = new InitialState();
251            private static readonly StartingState Starting = new StartingState();
252            private static readonly StartedState Started = new StartedState();
253            private static readonly ExitingState Exiting = new ExitingState();
254            private static readonly KillingState Killing = new KillingState();
255            private static readonly ExitedState Exited = new ExitedState();
256            private static readonly DisposedState Disposed = new DisposedState();
257
258            #endregion
259
260            #region Properties
261
262            /// <summary>
263            /// Get If process exists.
264            /// </summary>
265            public bool IsExiting => this == Killing || this == Exiting;
266            /// <summary>
267            /// Get If process is exited.
268            /// </summary>
269            public bool IsExited => this == Exited || this == Disposed;
270
271            #endregion
272
273            #region Methods
274
275            /// <summary>
276            /// Attempts thread-safe transitions from a given state to this state.
277            /// </summary>
278            /// <param name="p">The Base process</param>
279            /// <param name="fromState">The state from which state transition takes place</param>
280            /// <returns>Returns <c>true</c> if transition is successful, or <c>false</c> if transition
281            /// cannot be made because current state does not equal <paramref name="fromState"/>.</returns>
282            protected bool TryEnter(LauncherBase p, State fromState)
283            {
284                if (Interlocked.CompareExchange(ref p._currentState, this, fromState) == fromState)
285                {
286                    fromState.Leave(p);
287                    return true;
288                }
289
290                return false;
291            }
292
293            /// <summary>
294            /// Notifies that state machine is about to transition to another state.
295            /// </summary>
296            /// <param name="p">The Base process</param>
297            protected virtual void Leave(LauncherBase p)
298            {
299            }
300
301            /// <summary>
302            /// Handles process start request.
303            /// </summary>
304            /// <param name="p">The Base process</param>
305            /// <returns></returns>
306            public virtual Task StartAsync(LauncherBase p) => Task.FromException(InvalidOperation("start"));
307
308            /// <summary>
309            /// Handles process exit request.
310            /// </summary>
311            /// <param name="p">The Base process</param>
312            /// <param name="timeout">The maximum waiting time for a graceful process exit.</param>
313            /// <returns></returns>
314            public virtual Task ExitAsync(LauncherBase p, TimeSpan timeout) => Task.FromException(InvalidOperation("exit"));
315
316            /// <summary>
317            /// Handles process kill request.
318            /// </summary>
319            /// <param name="p">The Base process</param>
320            /// <returns></returns>
321            public virtual Task KillAsync(LauncherBase p) => Task.FromException(InvalidOperation("kill"));
322
323            /// <summary>
324            /// Handles wait for process exit request.
325            /// </summary>
326            /// <param name="p">The Base process</param>
327            /// <returns></returns>
328            public virtual Task WaitForExitAsync(LauncherBase p) => p._exitCompletionSource.Task;
329
330            /// <summary>
331            /// Handles disposal of process and temporary user directory
332            /// </summary>
333            /// <param name="p"></param>
334            public virtual void Dispose(LauncherBase p) => Disposed.EnterFrom(p, this);
335
336            /// <inheritdoc />
337            public override string ToString()
338            {
339                string name = GetType().Name;
340                return name.Substring(0, name.Length - "State".Length);
341            }
342
343            private Exception InvalidOperation(string operationName)
344                => new InvalidOperationException($"Cannot {operationName} in state {this}");
345
346            /// <summary>
347            /// Kills process if it is still alive.
348            /// </summary>
349            /// <param name="p"></param>
350            private static void Kill(LauncherBase p)
351            {
352                try
353                {
354                    if (!p.Process.HasExited)
355                    {
356                        p.Process.Kill();
357                    }
358                }
359                catch (InvalidOperationException)
360                {
361                    // Ignore
362                }
363            }
364
365            #endregion
366
367            #region Concrete state classes
368
369            private class InitialState : State
370            {
371                public override Task StartAsync(LauncherBase p) => Starting.EnterFromAsync(p, this);
372
373                public override Task ExitAsync(LauncherBase p, TimeSpan timeout)
374                {
375                    Exited.EnterFrom(p, this);
376                    return Task.CompletedTask;
377                }
378
379                public override Task KillAsync(LauncherBase p)
380                {
381                    Exited.EnterFrom(p, this);
382                    return Task.CompletedTask;
383                }
384
385                public override Task WaitForExitAsync(LauncherBase p) => Task.FromException(InvalidOperation("wait for exit"));
386            }
387
388            private class StartingState : State
389            {
390                public Task EnterFromAsync(LauncherBase p, State fromState)
391                {
392                    if (!TryEnter(p, fromState))
393                    {
394                        // Delegate StartAsync to current state, because it has already changed since
395                        // transition to this state was initiated.
396                        return p._currentState.StartAsync(p);
397                    }
398
399                    return StartCoreAsync(p);
400                }
401
402                public override Task StartAsync(LauncherBase p) => p._startCompletionSource.Task;
403
404                public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => Exiting.EnterFromAsync(p, this, timeout);
405
406                public override Task KillAsync(LauncherBase p) => Killing.EnterFromAsync(p, this);
407
408                public override void Dispose(LauncherBase p)
409                {
410                    p._startCompletionSource.TrySetException(new ObjectDisposedException(p.ToString()));
411                    base.Dispose(p);
412                }
413
414                private async Task StartCoreAsync(LauncherBase p)
415                {
416                    var output = new StringBuilder();
417
418                    void OnProcessDataReceivedWhileStarting(object sender, DataReceivedEventArgs e)
419                    {
420                        if (e.Data != null)
421                        {
422                            output.AppendLine(e.Data);
423                            var match = Regex.Match(e.Data, "^DevTools listening on (ws:\\/\\/.*)");
424                            if (match.Success)
425                            {
426                                p._startCompletionSource.TrySetResult(match.Groups[1].Value);
427                            }
428                        }
429                    }
430
431                    void OnProcessExitedWhileStarting(object sender, EventArgs e)
432                        => p._startCompletionSource.TrySetException(new ProcessException($"Failed to launch Base! {output}"));
433                    void OnProcessExited(object sender, EventArgs e) => Exited.EnterFrom(p, p._currentState);
434
435                    p.Process.ErrorDataReceived += OnProcessDataReceivedWhileStarting;
436                    p.Process.Exited += OnProcessExitedWhileStarting;
437                    p.Process.Exited += OnProcessExited;
438                    CancellationTokenSource cts = null;
439                    try
440                    {
441                        p.Process.Start();
442                        await Started.EnterFromAsync(p, this).ConfigureAwait(false);
443
444                        p.Process.BeginErrorReadLine();
445
446                        int timeout = p._options.Timeout;
447                        if (timeout > 0)
448                        {
449                            cts = new CancellationTokenSource(timeout);
450                            cts.Token.Register(() => p._startCompletionSource.TrySetException(
451                                new ProcessException($"Timed out after {timeout} ms while trying to connect to Base!")));
452                        }
453
454                        try
455                        {
456                            await p._startCompletionSource.Task.ConfigureAwait(false);
457                            await Started.EnterFromAsync(p, this).ConfigureAwait(false);
458                        }
459                        catch
460                        {
461                            await Killing.EnterFromAsync(p, this).ConfigureAwait(false);
462                            throw;
463                        }
464                    }
465                    finally
466                    {
467                        cts?.Dispose();
468                        p.Process.Exited -= OnProcessExitedWhileStarting;
469                        p.Process.ErrorDataReceived -= OnProcessDataReceivedWhileStarting;
470                    }
471                }
472            }
473
474            private class StartedState : State
475            {
476                public Task EnterFromAsync(LauncherBase p, State fromState)
477                {
478                    if (TryEnter(p, fromState))
479                    {
480                    }
481
482                    return Task.CompletedTask;
483                }
484
485                protected override void Leave(LauncherBase p) { }
486
487                public override Task StartAsync(LauncherBase p) => Task.CompletedTask;
488
489                public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => Exiting.EnterFromAsync(p, this, timeout);
490
491                public override Task KillAsync(LauncherBase p) => Killing.EnterFromAsync(p, this);
492            }
493
494            private class ExitingState : State
495            {
496                public Task EnterFromAsync(LauncherBase p, State fromState, TimeSpan timeout)
497                    => !TryEnter(p, fromState) ? p._currentState.ExitAsync(p, timeout) : ExitAsync(p, timeout);
498
499                public override async Task ExitAsync(LauncherBase p, TimeSpan timeout)
500                {
501                    var waitForExitTask = WaitForExitAsync(p);
502                    await waitForExitTask.WithTimeout(
503                        async () =>
504                        {
505                            await Killing.EnterFromAsync(p, this).ConfigureAwait(false);
506                            await waitForExitTask.ConfigureAwait(false);
507                        },
508                        timeout,
509                        CancellationToken.None).ConfigureAwait(false);
510                }
511
512                public override Task KillAsync(LauncherBase p) => Killing.EnterFromAsync(p, this);
513            }
514
515            private class KillingState : State
516            {
517                public async Task EnterFromAsync(LauncherBase p, State fromState)
518                {
519                    if (!TryEnter(p, fromState))
520                    {
521                        // Delegate KillAsync to current state, because it has already changed since
522                        // transition to this state was initiated.
523                        await p._currentState.KillAsync(p).ConfigureAwait(false);
524                    }
525
526                    try
527                    {
528                        if (!p.Process.HasExited)
529                        {
530                            p.Process.Kill();
531                        }
532                    }
533                    catch (InvalidOperationException)
534                    {
535                        // Ignore
536                        return;
537                    }
538
539                    await WaitForExitAsync(p).ConfigureAwait(false);
540                }
541
542                public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => WaitForExitAsync(p);
543
544                public override Task KillAsync(LauncherBase p) => WaitForExitAsync(p);
545            }
546
547            private class ExitedState : State
548            {
549                public void EnterFrom(LauncherBase p, State fromState)
550                {
551                    while (!TryEnter(p, fromState))
552                    {
553                        // Current state has changed since transition to this state was requested.
554                        // Therefore retry transition to this state from the current state. This ensures
555                        // that Leave() operation of current state is properly called.
556                        fromState = p._currentState;
557                        if (fromState == this)
558                        {
559                            return;
560                        }
561                    }
562
563                    p._exitCompletionSource.TrySetResult(true);
564                    p.TempUserDataDir?.Dispose();
565                }
566
567                public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => Task.CompletedTask;
568
569                public override Task KillAsync(LauncherBase p) => Task.CompletedTask;
570
571                public override Task WaitForExitAsync(LauncherBase p) => Task.CompletedTask;
572            }
573
574            private class DisposedState : State
575            {
576                public void EnterFrom(LauncherBase p, State fromState)
577                {
578                    if (!TryEnter(p, fromState))
579                    {
580                        // Delegate Dispose to current state, because it has already changed since
581                        // transition to this state was initiated.
582                        p._currentState.Dispose(p);
583                    }
584                    else if (fromState != Exited)
585                    {
586                        Kill(p);
587
588                        p._exitCompletionSource.TrySetException(new ObjectDisposedException(p.ToString()));
589                        p.TempUserDataDir?.Dispose();
590                    }
591                }
592
593                public override Task StartAsync(LauncherBase p) => throw new ObjectDisposedException(p.ToString());
594
595                public override Task ExitAsync(LauncherBase p, TimeSpan timeout) => throw new ObjectDisposedException(p.ToString());
596
597                public override Task KillAsync(LauncherBase p) => throw new ObjectDisposedException(p.ToString());
598
599                public override void Dispose(LauncherBase p)
600                {
601                    // Nothing to do
602                }
603            }
604
605            #endregion
606        }
607
608        #endregion
609    }
610}
611
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Most used method in KillingState

Trigger KillAsync code on LambdaTest Cloud Grid

Execute automation tests with KillAsync on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)