Ejemplo n.º 1
0
        public async Task Await_TaskCompletesOnNonDefaultSyncCtx_ContinuesOnDefaultSyncCtx()
        {
            await Task.Run(async delegate // escape xunit's sync context
            {
                Assert.Null(SynchronizationContext.Current);
                Assert.Same(TaskScheduler.Default, TaskScheduler.Current);

                var ctx     = new ValidateCorrectContextSynchronizationContext();
                var tcs     = new TaskCompletionSource <bool>();
                var ignored = Task.Delay(1).ContinueWith(_ =>
                {
                    SynchronizationContext orig = SynchronizationContext.Current;
                    SynchronizationContext.SetSynchronizationContext(ctx);
                    try
                    {
                        tcs.SetResult(true);
                    }
                    finally
                    {
                        SynchronizationContext.SetSynchronizationContext(orig);
                    }
                }, TaskScheduler.Default);
                await tcs.Task;

                Assert.Null(SynchronizationContext.Current);
                Assert.Same(TaskScheduler.Default, TaskScheduler.Current);
            });
        }
Ejemplo n.º 2
0
 public static async Task AsyncMethod_Yields_ReturnsToCorrectSynchronizationContext()
 {
     var sc = new ValidateCorrectContextSynchronizationContext ();
     SynchronizationContext.SetSynchronizationContext(sc);
     await Task.Yield();
     Assert.Equal(1, sc.PostCount);
 }
Ejemplo n.º 3
0
        public static void OnCompleted_CompletesInAnotherSynchronizationContext(bool generic, bool? continueOnCapturedContext)
        {
            SynchronizationContext origCtx = SynchronizationContext.Current;
            try
            {
                // Create a context that tracks operations, and set it as current
                var validateCtx = new ValidateCorrectContextSynchronizationContext();
                Assert.Equal(0, validateCtx.PostCount);
                SynchronizationContext.SetSynchronizationContext(validateCtx);

                // Create a not-completed task and get an awaiter for it
                var mres = new ManualResetEventSlim();
                var tcs = new TaskCompletionSource<object>();

                // Hook up a callback
                bool postedInContext = false;
                Action callback = () =>
                {
                    postedInContext = ValidateCorrectContextSynchronizationContext.IsPostedInContext;
                    mres.Set();
                };
                if (generic)
                {
                    if (continueOnCapturedContext.HasValue) tcs.Task.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
                    else tcs.Task.GetAwaiter().OnCompleted(callback);
                }
                else
                {
                    if (continueOnCapturedContext.HasValue) ((Task)tcs.Task).ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
                    else ((Task)tcs.Task).GetAwaiter().OnCompleted(callback);
                }
                Assert.False(mres.IsSet, "Callback should not yet have run.");

                // Complete the task in another context and wait for the callback to run
                Task.Run(() => tcs.SetResult(null));
                mres.Wait();

                // Validate the callback ran and in the correct context
                bool shouldHavePosted = !continueOnCapturedContext.HasValue || continueOnCapturedContext.Value;
                Assert.Equal(shouldHavePosted ? 1 : 0, validateCtx.PostCount);
                Assert.Equal(shouldHavePosted, postedInContext);
            }
            finally
            {
                // Reset back to the original context
                SynchronizationContext.SetSynchronizationContext(origCtx);
            }
        }
Ejemplo n.º 4
0
        public static void OnCompleted_CompletesInAnotherSynchronizationContext(bool generic, bool?continueOnCapturedContext)
        {
            SynchronizationContext origCtx = SynchronizationContext.Current;

            try
            {
                // Create a context that tracks operations, and set it as current
                var validateCtx = new ValidateCorrectContextSynchronizationContext();
                Assert.Equal(0, validateCtx.PostCount);
                SynchronizationContext.SetSynchronizationContext(validateCtx);

                // Create a not-completed task and get an awaiter for it
                var mres = new ManualResetEventSlim();
                var tcs  = new TaskCompletionSource <object>();

                // Hook up a callback
                bool   postedInContext = false;
                Action callback        = () =>
                {
                    postedInContext = ValidateCorrectContextSynchronizationContext.t_isPostedInContext;
                    mres.Set();
                };
                if (generic)
                {
                    if (continueOnCapturedContext.HasValue)
                    {
                        tcs.Task.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
                    }
                    else
                    {
                        tcs.Task.GetAwaiter().OnCompleted(callback);
                    }
                }
                else
                {
                    if (continueOnCapturedContext.HasValue)
                    {
                        ((Task)tcs.Task).ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
                    }
                    else
                    {
                        ((Task)tcs.Task).GetAwaiter().OnCompleted(callback);
                    }
                }
                Assert.False(mres.IsSet, "Callback should not yet have run.");

                // Complete the task in another context and wait for the callback to run
                Task.Run(() => tcs.SetResult(null));
                mres.Wait();

                // Validate the callback ran and in the correct context
                bool shouldHavePosted = !continueOnCapturedContext.HasValue || continueOnCapturedContext.Value;
                Assert.Equal(shouldHavePosted ? 1 : 0, validateCtx.PostCount);
                Assert.Equal(shouldHavePosted, postedInContext);
            }
            finally
            {
                // Reset back to the original context
                SynchronizationContext.SetSynchronizationContext(origCtx);
            }
        }
Ejemplo n.º 5
0
        public static void RunAsyncTaskAwaiterTests()
        {
            var completed = new TaskCompletionSource<string>();
            Task task = completed.Task;
            Task<string> taskOfString = completed.Task;
            completed.SetResult("42");

            {
                // IsCompleted/OnCompleted on a non-completed Task with SyncContext and completes the task in another context
                var vccsc = new ValidateCorrectContextSynchronizationContext();
                SynchronizationContext.SetSynchronizationContext(vccsc);
                ManualResetEventSlim mres = new ManualResetEventSlim();
                var tcs = new TaskCompletionSource<object>();
                int result = 1;
                var awaiter = ((Task)tcs.Task).GetAwaiter();
                Assert.False(awaiter.IsCompleted, "     > FAILURE. Awaiter on non-completed task should not be IsCompleted");
                awaiter.OnCompleted(() =>
                {
                    Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext, "     > FAILURE. Continuation should be running in captured sync context.");
                    result = 2;
                    mres.Set();
                });
                Assert.True(result == 1, "     > FAILURE. Await continuation should not run until task completes.");
                Task.Run(delegate { tcs.SetResult(null); });
                mres.Wait();
                awaiter.GetResult();
                Assert.True(result == 2, "     > FAILURE. Await continuation should have completed.");
                Assert.True(vccsc.PostCount == 1, "     > FAILURE. Await continuation should have posted to the target context.");
                SynchronizationContext.SetSynchronizationContext(null);
            }

            {
                // IsCompleted/OnCompleted on a non-completed Task with TaskScheduler and completes the task in another context
                var quwi = new QUWITaskScheduler();
                RunWithSchedulerAsCurrent(quwi, delegate
                {
                    ManualResetEventSlim mres = new ManualResetEventSlim();
                    var tcs = new TaskCompletionSource<object>();
                    int result = 1;
                    var awaiter = ((Task)tcs.Task).GetAwaiter();
                    Assert.False(awaiter.IsCompleted, "     > FAILURE. Awaiter on non-completed task should not be IsCompleted");
                    awaiter.OnCompleted(() =>
                    {
                        Assert.True(TaskScheduler.Current == quwi, "     > FAILURE. Continuation should be running in task scheduler.");
                        result = 2;
                        mres.Set();
                    });
                    Assert.True(result == 1, "     > FAILURE. Await continuation should not run until task completes.");
                    Task.Run(delegate { tcs.SetResult(null); });
                    mres.Wait();
                    awaiter.GetResult();
                    Assert.True(result == 2, "     > FAILURE. Await continuation should have completed.");
                });
            }

            {
                // Configured IsCompleted/OnCompleted on a non-completed Task with SyncContext
                for (int iter = 0; iter < 2; iter++)
                {
                    Task.Factory.StartNew(() =>
                    {
                        bool continueOnCapturedContext = iter == 0;
                        SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
                        ManualResetEventSlim mres = new ManualResetEventSlim();
                        var tcs = new TaskCompletionSource<object>();
                        int result = 1;
                        var awaiter = ((Task)tcs.Task).ConfigureAwait(continueOnCapturedContext).GetAwaiter();
                        Assert.False(awaiter.IsCompleted, "     > FAILURE. Configured awaiter on non-completed task should not be IsCompleted");
                        awaiter.OnCompleted(() =>
                        {
                            Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext == continueOnCapturedContext,
                            "     > FAILURE. Continuation should have been posted to context iff continueOnCapturedContext == true.");
                            //
                            //    Assert.True(Environment.StackTrace.Contains("SetResult") != continueOnCapturedContext,
                            //    "     > FAILURE. Continuation should have been executed synchronously iff continueOnCapturedContext == false.");
                            result = 2;
                            mres.Set();
                        });
                        Assert.True(result == 1, "     > FAILURE. Await continuation should not have run before task completed.");
                        Task.Factory.StartNew(() => tcs.SetResult(null));
                        mres.Wait();
                        awaiter.GetResult();
                        Assert.True(result == 2, "     > FAILURE. Await continuation should now have completed.");
                        SynchronizationContext.SetSynchronizationContext(null);
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Wait();
                }
            }

            {
                // IsCompleted/OnCompleted on a non-completed Task<TResult> with SyncContext and completes the task in another context
                var vccsc = new ValidateCorrectContextSynchronizationContext();
                SynchronizationContext.SetSynchronizationContext(vccsc);
                var mres = new ManualResetEventSlim();
                var tcs = new TaskCompletionSource<object>();
                int result = 1;
                var awaiter = ((Task<object>)tcs.Task).GetAwaiter();
                Assert.False(awaiter.IsCompleted, "     > FAILURE. Awaiter on non-completed Task<TResult> should not be IsCompleted");
                awaiter.OnCompleted(() =>
                {
                    Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext, "     > FAILURE. Await continuation should have posted to target context");
                    result = 2;
                    mres.Set();
                });
                Assert.True(result == 1, "     > FAILURE. Await continuation should not have run before task completed.");
                Task.Run(delegate { tcs.SetResult(null); });
                mres.Wait();
                awaiter.GetResult();
                Assert.True(result == 2, "     > FAILURE. Await continuation should now have completed.");
                Assert.True(vccsc.PostCount == 1, "     > FAILURE. Await continuation should have posted to the target context");
                SynchronizationContext.SetSynchronizationContext(null);
            }

            {
                // Configured IsCompleted/OnCompleted on a non-completed Task<TResult> with SyncContext
                for (int iter = 0; iter < 2; iter++)
                {
                    Task.Factory.StartNew(() =>
                    {
                        bool continueOnCapturedContext = iter == 0;
                        SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
                        var mres = new ManualResetEventSlim();
                        var tcs = new TaskCompletionSource<object>();
                        int result = 1;
                        var awaiter = tcs.Task.ConfigureAwait(continueOnCapturedContext).GetAwaiter();
                        Assert.False(awaiter.IsCompleted, "     > FAILURE. Configured awaiter on non-completed Task<TResult> should not be IsCompleted");
                        awaiter.OnCompleted(() =>
                        {
                            Assert.True(
                               ValidateCorrectContextSynchronizationContext.IsPostedInContext == continueOnCapturedContext,
                               "     > FAILURE. Await continuation should have posted to target context iff continueOnCapturedContext == true");
                            // Assert.True(
                            //    Environment.StackTrace.Contains("SetResult") != continueOnCapturedContext,
                            //    "     > FAILURE. Await continuation should have executed inline iff continueOnCapturedContext == false");
                            result = 2;
                            mres.Set();
                        });
                        Assert.True(result == 1, "     > FAILURE. Await continuation should not have run before task completed.");
                        Task.Factory.StartNew(() => tcs.SetResult(null));
                        mres.Wait();
                        awaiter.GetResult();
                        Assert.True(result == 2, "     > FAILURE. Await continuation should now have completed.");
                        SynchronizationContext.SetSynchronizationContext(null);
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Wait();
                }
            }

            {
                // Validate successful GetResult
                task.GetAwaiter().GetResult();
                task.ConfigureAwait(false).GetAwaiter().GetResult();
                task.ConfigureAwait(true).GetAwaiter().GetResult();

                Assert.Equal(taskOfString.GetAwaiter().GetResult(), "42");
                Assert.Equal(taskOfString.ConfigureAwait(false).GetAwaiter().GetResult(), "42");
                Assert.Equal(taskOfString.ConfigureAwait(true).GetAwaiter().GetResult(), "42");
            }

            {
                // Validate GetResult blocks until completion
                var tcs = new TaskCompletionSource<bool>();

                // Kick off tasks that should all block
                var t1 = Task.Factory.StartNew(() => tcs.Task.GetAwaiter().GetResult());
                var t2 = Task.Factory.StartNew(() => ((Task)tcs.Task).GetAwaiter().GetResult());
                var t3 = Task.Factory.StartNew(() => tcs.Task.ConfigureAwait(false).GetAwaiter().GetResult());
                var t4 = Task.Factory.StartNew(() => ((Task)tcs.Task).ConfigureAwait(false).GetAwaiter().GetResult());
                var allTasks = new Task[] { t1, t2, t3, t4 };

                // Wait with timeout should return false
                bool waitCompleted;
                try
                {
                    waitCompleted = Task.WaitAll(allTasks, 4000);
                    Assert.False(waitCompleted, "     > Expected tasks to not be completed");
                }
                catch (Exception exc)
                {
                    Assert.True(false, string.Format("     > Did not expect an exception: " + exc));
                }

                // Now complete the tasks
                tcs.SetResult(true);

                // All tasks should complete successfully
                waitCompleted = Task.WaitAll(allTasks, 4000);
                Assert.True(waitCompleted,
                    "After completion, excepted all GetResult calls to completed successfully");
                foreach (var taskToCheck in allTasks)
                {
                    Assert.True(taskToCheck.Status == TaskStatus.RanToCompletion, "Task was not run to completion. Excepted all GetResult calls to completed successfully");
                }
            }
        }
Ejemplo n.º 6
0
        public static void RunAsyncTaskAwaiterTests()
        {
            var           completed    = new TaskCompletionSource <string>();
            Task          task         = completed.Task;
            Task <string> taskOfString = completed.Task;

            completed.SetResult("42");

            {
                // IsCompleted/OnCompleted on a non-completed Task with SyncContext and completes the task in another context
                var vccsc = new ValidateCorrectContextSynchronizationContext();
                SynchronizationContext.SetSynchronizationContext(vccsc);
                ManualResetEventSlim mres = new ManualResetEventSlim();
                var tcs     = new TaskCompletionSource <object>();
                int result  = 1;
                var awaiter = ((Task)tcs.Task).GetAwaiter();
                Assert.False(awaiter.IsCompleted, "     > FAILURE. Awaiter on non-completed task should not be IsCompleted");
                awaiter.OnCompleted(() =>
                {
                    Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext, "     > FAILURE. Continuation should be running in captured sync context.");
                    result = 2;
                    mres.Set();
                });
                Assert.True(result == 1, "     > FAILURE. Await continuation should not run until task completes.");
                Task.Run(delegate { tcs.SetResult(null); });
                mres.Wait();
                awaiter.GetResult();
                Assert.True(result == 2, "     > FAILURE. Await continuation should have completed.");
                Assert.True(vccsc.PostCount == 1, "     > FAILURE. Await continuation should have posted to the target context.");
                SynchronizationContext.SetSynchronizationContext(null);
            }

            {
                // IsCompleted/OnCompleted on a non-completed Task with TaskScheduler and completes the task in another context
                var quwi = new QUWITaskScheduler();
                RunWithSchedulerAsCurrent(quwi, delegate
                {
                    ManualResetEventSlim mres = new ManualResetEventSlim();
                    var tcs     = new TaskCompletionSource <object>();
                    int result  = 1;
                    var awaiter = ((Task)tcs.Task).GetAwaiter();
                    Assert.False(awaiter.IsCompleted, "     > FAILURE. Awaiter on non-completed task should not be IsCompleted");
                    awaiter.OnCompleted(() =>
                    {
                        Assert.True(TaskScheduler.Current == quwi, "     > FAILURE. Continuation should be running in task scheduler.");
                        result = 2;
                        mres.Set();
                    });
                    Assert.True(result == 1, "     > FAILURE. Await continuation should not run until task completes.");
                    Task.Run(delegate { tcs.SetResult(null); });
                    mres.Wait();
                    awaiter.GetResult();
                    Assert.True(result == 2, "     > FAILURE. Await continuation should have completed.");
                });
            }

            {
                // Configured IsCompleted/OnCompleted on a non-completed Task with SyncContext
                for (int iter = 0; iter < 2; iter++)
                {
                    Task.Factory.StartNew(() =>
                    {
                        bool continueOnCapturedContext = iter == 0;
                        SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
                        ManualResetEventSlim mres = new ManualResetEventSlim();
                        var tcs     = new TaskCompletionSource <object>();
                        int result  = 1;
                        var awaiter = ((Task)tcs.Task).ConfigureAwait(continueOnCapturedContext).GetAwaiter();
                        Assert.False(awaiter.IsCompleted, "     > FAILURE. Configured awaiter on non-completed task should not be IsCompleted");
                        awaiter.OnCompleted(() =>
                        {
                            Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext == continueOnCapturedContext,
                                        "     > FAILURE. Continuation should have been posted to context iff continueOnCapturedContext == true.");
                            //
                            //    Assert.True(Environment.StackTrace.Contains("SetResult") != continueOnCapturedContext,
                            //    "     > FAILURE. Continuation should have been executed synchronously iff continueOnCapturedContext == false.");
                            result = 2;
                            mres.Set();
                        });
                        Assert.True(result == 1, "     > FAILURE. Await continuation should not have run before task completed.");
                        Task.Factory.StartNew(() => tcs.SetResult(null));
                        mres.Wait();
                        awaiter.GetResult();
                        Assert.True(result == 2, "     > FAILURE. Await continuation should now have completed.");
                        SynchronizationContext.SetSynchronizationContext(null);
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Wait();
                }
            }

            {
                // IsCompleted/OnCompleted on a non-completed Task<TResult> with SyncContext and completes the task in another context
                var vccsc = new ValidateCorrectContextSynchronizationContext();
                SynchronizationContext.SetSynchronizationContext(vccsc);
                var mres    = new ManualResetEventSlim();
                var tcs     = new TaskCompletionSource <object>();
                int result  = 1;
                var awaiter = ((Task <object>)tcs.Task).GetAwaiter();
                Assert.False(awaiter.IsCompleted, "     > FAILURE. Awaiter on non-completed Task<TResult> should not be IsCompleted");
                awaiter.OnCompleted(() =>
                {
                    Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext, "     > FAILURE. Await continuation should have posted to target context");
                    result = 2;
                    mres.Set();
                });
                Assert.True(result == 1, "     > FAILURE. Await continuation should not have run before task completed.");
                Task.Run(delegate { tcs.SetResult(null); });
                mres.Wait();
                awaiter.GetResult();
                Assert.True(result == 2, "     > FAILURE. Await continuation should now have completed.");
                Assert.True(vccsc.PostCount == 1, "     > FAILURE. Await continuation should have posted to the target context");
                SynchronizationContext.SetSynchronizationContext(null);
            }

            {
                // Configured IsCompleted/OnCompleted on a non-completed Task<TResult> with SyncContext
                for (int iter = 0; iter < 2; iter++)
                {
                    Task.Factory.StartNew(() =>
                    {
                        bool continueOnCapturedContext = iter == 0;
                        SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
                        var mres    = new ManualResetEventSlim();
                        var tcs     = new TaskCompletionSource <object>();
                        int result  = 1;
                        var awaiter = tcs.Task.ConfigureAwait(continueOnCapturedContext).GetAwaiter();
                        Assert.False(awaiter.IsCompleted, "     > FAILURE. Configured awaiter on non-completed Task<TResult> should not be IsCompleted");
                        awaiter.OnCompleted(() =>
                        {
                            Assert.True(
                                ValidateCorrectContextSynchronizationContext.IsPostedInContext == continueOnCapturedContext,
                                "     > FAILURE. Await continuation should have posted to target context iff continueOnCapturedContext == true");
                            // Assert.True(
                            //    Environment.StackTrace.Contains("SetResult") != continueOnCapturedContext,
                            //    "     > FAILURE. Await continuation should have executed inline iff continueOnCapturedContext == false");
                            result = 2;
                            mres.Set();
                        });
                        Assert.True(result == 1, "     > FAILURE. Await continuation should not have run before task completed.");
                        Task.Factory.StartNew(() => tcs.SetResult(null));
                        mres.Wait();
                        awaiter.GetResult();
                        Assert.True(result == 2, "     > FAILURE. Await continuation should now have completed.");
                        SynchronizationContext.SetSynchronizationContext(null);
                    }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Wait();
                }
            }

            {
                // Validate successful GetResult
                task.GetAwaiter().GetResult();
                task.ConfigureAwait(false).GetAwaiter().GetResult();
                task.ConfigureAwait(true).GetAwaiter().GetResult();

                Assert.Equal(taskOfString.GetAwaiter().GetResult(), "42");
                Assert.Equal(taskOfString.ConfigureAwait(false).GetAwaiter().GetResult(), "42");
                Assert.Equal(taskOfString.ConfigureAwait(true).GetAwaiter().GetResult(), "42");
            }

            {
                // Validate GetResult blocks until completion
                var tcs = new TaskCompletionSource <bool>();

                // Kick off tasks that should all block
                var t1       = Task.Factory.StartNew(() => tcs.Task.GetAwaiter().GetResult());
                var t2       = Task.Factory.StartNew(() => ((Task)tcs.Task).GetAwaiter().GetResult());
                var t3       = Task.Factory.StartNew(() => tcs.Task.ConfigureAwait(false).GetAwaiter().GetResult());
                var t4       = Task.Factory.StartNew(() => ((Task)tcs.Task).ConfigureAwait(false).GetAwaiter().GetResult());
                var allTasks = new Task[] { t1, t2, t3, t4 };

                // Wait with timeout should return false
                bool waitCompleted;
                try
                {
                    waitCompleted = Task.WaitAll(allTasks, 4000);
                    Assert.False(waitCompleted, "     > Expected tasks to not be completed");
                }
                catch (Exception exc)
                {
                    Assert.True(false, string.Format("     > Did not expect an exception: " + exc));
                }

                // Now complete the tasks
                tcs.SetResult(true);

                // All tasks should complete successfully
                waitCompleted = Task.WaitAll(allTasks, 4000);
                Assert.True(waitCompleted,
                            "After completion, excepted all GetResult calls to completed successfully");
                foreach (var taskToCheck in allTasks)
                {
                    Assert.True(taskToCheck.Status == TaskStatus.RanToCompletion, "Task was not run to completion. Excepted all GetResult calls to completed successfully");
                }
            }
        }