@@ -35,18 +35,38 @@ public void ShouldThrowExecutionCanceled()
3535        Assert . Throws < ExecutionCanceledException > ( 
3636            ( )  => 
3737            { 
38-                 using  ( var  tcs  =  new  CancellationTokenSource ( ) ) 
38+                 using  ( var  cts  =  new  CancellationTokenSource ( ) ) 
3939                using  ( var  waitHandle  =  new  ManualResetEvent ( false ) ) 
40+                 using  ( var  cancellationTokenSet  =  new  ManualResetEvent ( initialState :  false ) ) 
4041                { 
41-                     var  engine  =  new  Engine ( cfg =>  cfg . CancellationToken ( tcs . Token ) ) ; 
42- 
43-                     ThreadPool . QueueUserWorkItem ( state => 
42+                     var  engine  =  new  Engine ( cfg =>  cfg . CancellationToken ( cts . Token ) ) ; 
43+ 
44+                     /* 
45+                      * To ensure that the action "threadPoolAction" has actually been called by the ThreadPool 
46+                      * (which can happen very late, depending on the ThreadPool usage, etc.), the 
47+                      * "cancellationTokenSet" event will be an indicator for that. 
48+                      * 
49+                      * 1. The "cancellationTokenSet" will be set after the "cts" has been cancelled. 
50+                      * 2. Within the JS, the "test" code will only start as soon as the "cancellationTokenSet" 
51+                      *    event will be set. 
52+                      * 3. The cancellationToken and its source has not been used on purpose for this test to 
53+                      *    not mix "test infrastructure" and "test code". 
54+                      * 4. To verify that this test still works under heavy load, you can add 
55+                      *    a "Thread.Sleep(10000)" call anywhere within the "threadPoolAction" action. 
56+                      */ 
57+ 
58+                     WaitCallback  threadPoolAction  =  _ => 
4459                    { 
4560                        waitHandle . WaitOne ( ) ; 
46-                         tcs . Cancel ( ) ; 
47-                     } ) ; 
61+                         cts . Cancel ( ) ; 
62+                         cancellationTokenSet . Set ( ) ; 
63+                     } ; 
64+                     ThreadPool . QueueUserWorkItem ( threadPoolAction ) ; 
4865
4966                    engine . SetValue ( "waitHandle" ,  waitHandle ) ; 
67+                     engine . SetValue ( "waitForTokenToBeSet" ,  new  Action ( ( )  =>  cancellationTokenSet . WaitOne ( ) ) ) ; 
68+                     engine . SetValue ( "mustNotBeCalled" ,  new  Action ( ( )  => 
69+                         throw  new  InvalidOperationException ( "A cancellation of the script execution has been requested, but the script did continue to run." ) ) ) ; 
5070                    engine . Evaluate ( @" 
5171                            function sleep(millisecondsTimeout) { 
5272                                var totalMilliseconds = new Date().getTime() + millisecondsTimeout; 
@@ -56,11 +76,16 @@ function sleep(millisecondsTimeout) {
5676
5777                            sleep(100); 
5878                            waitHandle.Set(); 
79+                             waitForTokenToBeSet(); 
80+ 
81+                             // Now it is ensured that the cancellationToken has been cancelled.  
82+                             // The following JS code execution should get aborted by the engine. 
5983                            sleep(1000); 
6084                            sleep(1000); 
6185                            sleep(1000); 
6286                            sleep(1000); 
6387                            sleep(1000); 
88+                             mustNotBeCalled(); 
6489                        " ) ; 
6590                } 
6691            } 
@@ -376,4 +401,4 @@ public void Log(string logMessage)
376401            Console . WriteLine ( logMessage ) ; 
377402        } 
378403    } 
379- } 
404+ } 
0 commit comments