Skip to content

Commit af0845f

Browse files
authored
Made test of cancellation of engine execution more robust (#1984)
1 parent 1b0d5f8 commit af0845f

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

Jint.Tests/Runtime/ExecutionConstraintTests.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)