From 145afbf21e5724c64ba8394fedccd26ed29b7f6f Mon Sep 17 00:00:00 2001 From: Hugh Bellamy Date: Mon, 12 Jun 2017 17:11:18 +0700 Subject: [PATCH 1/4] Add System.ComponentModel.EventBasedAsync tests --- .../tests/AsyncOperationFinalizerTests.cs | 71 +++++++++++++++++++ .../tests/BackgroundWorkerTests.cs | 22 ++++++ ...omponentModel.EventBasedAsync.Tests.csproj | 13 ++++ 3 files changed, 106 insertions(+) create mode 100644 src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs diff --git a/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs b/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs new file mode 100644 index 000000000000..f9c6e7f98f53 --- /dev/null +++ b/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Reflection; +using System.Threading; +using Xunit; + +namespace System.ComponentModel.Tests +{ + public class AsyncOperationFinalizerTests : RemoteExecutorTestBase + { + [Fact] + public void Finalizer_GetViaReflection_IsPresentForCompatability() + { + MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(finalizer); + } + + [Fact] + public void Finalizer_OperationCompleted_DoesNotCallOperationCompleted() + { + MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(finalizer); + + RemoteInvoke(() => + { + var tracker = new OperationCompletedTracker(); + AsyncOperationManager.SynchronizationContext = tracker; + AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); + + Assert.Equal(0, tracker.OperationCompletedCounter); + operation.OperationCompleted(); + Assert.Equal(1, tracker.OperationCompletedCounter); + + finalizer.Invoke(operation, null); + Assert.Equal(1, tracker.OperationCompletedCounter); + + return SuccessExitCode; + }).Dispose(); + } + + [Fact] + public void Finalizer_OperationCompleted_CompletesOperation() + { + MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(finalizer); + + RemoteInvoke(() => + { + var tracker = new OperationCompletedTracker(); + AsyncOperationManager.SynchronizationContext = tracker; + AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); + + Assert.Equal(0, tracker.OperationCompletedCounter); + finalizer.Invoke(operation, null); + Assert.Equal(1, tracker.OperationCompletedCounter); + + return SuccessExitCode; + }).Dispose(); + } + + public class OperationCompletedTracker : SynchronizationContext + { + public int OperationCompletedCounter { get; set; } + + public override void OperationCompleted() => OperationCompletedCounter++; + } + } +} diff --git a/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs b/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs index 24ec25b80aa6..d7f09fea8125 100644 --- a/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs +++ b/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs @@ -70,6 +70,18 @@ public void TestBackgroundWorkerBasic() } } + [Fact] + public void RunWorkerAsync_NoOnWorkHandler_SetsResultToNull() + { + var backgroundWorker = new BackgroundWorker { WorkerReportsProgress = true }; + backgroundWorker.RunWorkerCompleted += (sender, e) => + { + Assert.Null(e.Result); + Assert.False(backgroundWorker.IsBusy); + }; + backgroundWorker.RunWorkerAsync(); + } + #region TestCancelAsync private ManualResetEventSlim manualResetEvent3; @@ -283,6 +295,16 @@ public void TestReportProgressSync() Assert.Equal(expectedProgress, actualProgress); } + [Fact] + public void ReportProgress_NoProgressHandle_Nop() + { + var backgroundWorker = new BackgroundWorker { WorkerReportsProgress = true }; + foreach (int i in new int[] { 1, 2, 3, 4, 5 }) + { + backgroundWorker.ReportProgress(i); + } + } + [Fact] public void TestReportProgressWithWorkerReportsProgressFalse() { diff --git a/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj b/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj index 3a478941e4ee..a0817a77c911 100644 --- a/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj +++ b/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj @@ -12,6 +12,7 @@ + @@ -19,6 +20,18 @@ + + Common\System\Diagnostics\RemoteExecutorTestBase.cs + + + Common\System\IO\FileCleanupTestBase.cs + + + + + {69e46a6f-9966-45a5-8945-2559fe337827} + RemoteExecutorConsoleApp + \ No newline at end of file From 5c765f00d268fac0888502ea33be30b3f220616b Mon Sep 17 00:00:00 2001 From: Hugh Bellamy Date: Mon, 12 Jun 2017 19:12:30 +0700 Subject: [PATCH 2/4] Fix RemoteInvoke test failures --- .../tests/AsyncOperationFinalizerTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs b/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs index f9c6e7f98f53..6ecba195bf17 100644 --- a/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs +++ b/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs @@ -21,11 +21,11 @@ public void Finalizer_GetViaReflection_IsPresentForCompatability() [Fact] public void Finalizer_OperationCompleted_DoesNotCallOperationCompleted() { - MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(finalizer); - RemoteInvoke(() => { + MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(finalizer); + var tracker = new OperationCompletedTracker(); AsyncOperationManager.SynchronizationContext = tracker; AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); @@ -44,11 +44,11 @@ public void Finalizer_OperationCompleted_DoesNotCallOperationCompleted() [Fact] public void Finalizer_OperationCompleted_CompletesOperation() { - MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(finalizer); - RemoteInvoke(() => { + MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(finalizer); + var tracker = new OperationCompletedTracker(); AsyncOperationManager.SynchronizationContext = tracker; AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); From c2a746b8bf9fb29bcb0eb0ff36c1bf86e6c59692 Mon Sep 17 00:00:00 2001 From: Hugh Bellamy Date: Tue, 13 Jun 2017 09:05:18 +0700 Subject: [PATCH 3/4] Fix test failures potentially happpening after the test has finished --- .../tests/BackgroundWorkerTests.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs b/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs index d7f09fea8125..595f176ccc57 100644 --- a/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs +++ b/src/System.ComponentModel.EventBasedAsync/tests/BackgroundWorkerTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -74,12 +75,24 @@ public void TestBackgroundWorkerBasic() public void RunWorkerAsync_NoOnWorkHandler_SetsResultToNull() { var backgroundWorker = new BackgroundWorker { WorkerReportsProgress = true }; + bool isCompleted = false; backgroundWorker.RunWorkerCompleted += (sender, e) => { + isCompleted = true; Assert.Null(e.Result); Assert.False(backgroundWorker.IsBusy); }; backgroundWorker.RunWorkerAsync(); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + while (!isCompleted) + { + if (stopwatch.Elapsed > TimeSpan.FromSeconds(10)) + { + throw new Exception("The background worker never completed."); + } + } } #region TestCancelAsync From f142bc839ef09b8caafebe3c982347c519f12fcc Mon Sep 17 00:00:00 2001 From: Hugh Bellamy Date: Fri, 16 Jun 2017 18:51:29 +0700 Subject: [PATCH 4/4] Address PR feedback --- .../tests/AsyncOperationFinalizerTests.cs | 66 ++++++++++--------- ...omponentModel.EventBasedAsync.Tests.csproj | 6 -- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs b/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs index 6ecba195bf17..1a7b979f18bc 100644 --- a/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs +++ b/src/System.ComponentModel.EventBasedAsync/tests/AsyncOperationFinalizerTests.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Reflection; using System.Threading; using Xunit; @@ -11,61 +10,66 @@ namespace System.ComponentModel.Tests { public class AsyncOperationFinalizerTests : RemoteExecutorTestBase { - [Fact] - public void Finalizer_GetViaReflection_IsPresentForCompatability() - { - MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(finalizer); - } - [Fact] public void Finalizer_OperationCompleted_DoesNotCallOperationCompleted() { RemoteInvoke(() => { - MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(finalizer); + Completed(); - var tracker = new OperationCompletedTracker(); - AsyncOperationManager.SynchronizationContext = tracker; - AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); - - Assert.Equal(0, tracker.OperationCompletedCounter); - operation.OperationCompleted(); - Assert.Equal(1, tracker.OperationCompletedCounter); - - finalizer.Invoke(operation, null); - Assert.Equal(1, tracker.OperationCompletedCounter); + GC.Collect(); + GC.WaitForPendingFinalizers(); return SuccessExitCode; }).Dispose(); } + private void Completed() + { + // This is in a helper method to ensure the JIT doesn't artifically extend the lifetime of the operation. + var tracker = new OperationCompletedTracker(); + AsyncOperationManager.SynchronizationContext = tracker; + AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); + + Assert.False(tracker.OperationDidComplete); + operation.OperationCompleted(); + Assert.True(tracker.OperationDidComplete); + } + [Fact] - public void Finalizer_OperationCompleted_CompletesOperation() + public void Finalizer_OperationNotCompleted_CompletesOperation() { RemoteInvoke(() => { - MethodInfo finalizer = typeof(AsyncOperation).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); - Assert.NotNull(finalizer); - var tracker = new OperationCompletedTracker(); - AsyncOperationManager.SynchronizationContext = tracker; - AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); + NotCompleted(tracker); + + GC.Collect(); + GC.WaitForPendingFinalizers(); - Assert.Equal(0, tracker.OperationCompletedCounter); - finalizer.Invoke(operation, null); - Assert.Equal(1, tracker.OperationCompletedCounter); + Assert.True(tracker.OperationDidComplete); return SuccessExitCode; }).Dispose(); } + private void NotCompleted(OperationCompletedTracker tracker) + { + // This is in a helper method to ensure the JIT doesn't artifically extend the lifetime of the operation. + AsyncOperationManager.SynchronizationContext = tracker; + AsyncOperation operation = AsyncOperationManager.CreateOperation(new object()); + Assert.False(tracker.OperationDidComplete); + } + public class OperationCompletedTracker : SynchronizationContext { - public int OperationCompletedCounter { get; set; } + public bool OperationDidComplete { get; set; } - public override void OperationCompleted() => OperationCompletedCounter++; + public override void OperationCompleted() + { + Assert.False(OperationDidComplete); + OperationDidComplete = true; + } } } } diff --git a/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj b/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj index a0817a77c911..b4a20c142f18 100644 --- a/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj +++ b/src/System.ComponentModel.EventBasedAsync/tests/System.ComponentModel.EventBasedAsync.Tests.csproj @@ -20,12 +20,6 @@ - - Common\System\Diagnostics\RemoteExecutorTestBase.cs - - - Common\System\IO\FileCleanupTestBase.cs -