Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit b7e3ee9

Browse files
committed
Improve and Clean Up TaskAPMTest
Separate out the test cases into four distinct methods, which were already isolated from each other in the original test case. Lower some of the spinning time in the tasks to reduce the run-time significantly (wait duration did not seem significant to the test). Although they now take around 8 seconds total on my machine, they are still too slow to be inner-loop tests. I've also added some additional assertions into the tests to make failures more diagnosable.
1 parent 4f8a814 commit b7e3ee9

File tree

1 file changed

+99
-96
lines changed

1 file changed

+99
-96
lines changed

src/System.Threading.Tasks/tests/Task/TaskAPMTest.cs

Lines changed: 99 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
55
//
66
// Test class that verifies the integration with APM (Task => APM) section 2.5.11 in the TPL spec
7+
// "Asynchronous Programming Model", or the "Begin/End" pattern
78
//
89
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
910

@@ -18,101 +19,120 @@ namespace System.Threading.Tasks.Tests
1819
/// <summary>
1920
/// A class that implements the APM pattern to ensure that TPL can support APM patttern
2021
/// </summary>
21-
public sealed class TaskAPMTest
22+
public sealed class TaskAPMTests : IDisposable
2223
{
2324
/// <summary>
2425
/// Used to indicate whether to test TPL's Task or Future functionality for the APM pattern
2526
/// </summary>
26-
private readonly bool _hasReturnType;
27+
private bool _hasReturnType;
2728

2829
/// <summary>
2930
/// Used to synchornize between Main thread and async thread, by blocking the main thread until
3031
/// the thread that invokes the TaskCompleted method via AsyncCallback finishes
3132
/// </summary>
32-
private ManualResetEvent _mre;
33+
private ManualResetEvent _mre = new ManualResetEvent(false);
3334

34-
private const int INTINPUT = 1000; // the input to the LongTask<int>.DoTask/BeginDoTask
3535
/// <summary>
36-
/// The constant that defines the amount time to spinwait (to simulate work) in the LongTask class
36+
/// The input value to LongTask<int>.DoTask/BeginDoTask
3737
/// </summary>
38-
private const int LongTaskSeconds = 5;
38+
private const int IntInput = 1000;
3939

4040
/// <summary>
41-
/// Ctor that reads the XML testcase and sets the boolean to indicate whether to test Task or Future
42-
/// functionality
41+
/// The constant that defines the amount time to spinwait (to simulate work) in the LongTask class
4342
/// </summary>
44-
/// <param name="hasReturnType"></param>
45-
public TaskAPMTest(bool hasReturnType)
43+
private const int LongTaskMilliseconds = 1000;
44+
45+
[Theory]
46+
[OuterLoop]
47+
[InlineData(true)]
48+
[InlineData(false)]
49+
public void WaitUntilCompleteTechnique(bool hasReturnType)
4650
{
4751
_hasReturnType = hasReturnType;
48-
_mre = new ManualResetEvent(false);
52+
53+
LongTask longTask;
54+
if (_hasReturnType)
55+
longTask = new LongTask<int>(LongTaskMilliseconds);
56+
else
57+
longTask = new LongTask(LongTaskMilliseconds);
58+
59+
// Prove that the Wait-until-done technique works
60+
IAsyncResult asyncResult = longTask.BeginDoTask(null, null);
61+
longTask.EndDoTask(asyncResult);
62+
63+
AssertTaskCompleted(asyncResult);
64+
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
4965
}
5066

51-
/// <summary>
52-
/// Method that tests that the four APM patterns works
53-
/// </summary>
54-
/// <returns></returns>
55-
internal void RealRun()
67+
[Theory]
68+
[OuterLoop]
69+
[InlineData(true)]
70+
[InlineData(false)]
71+
public void PollUntilCompleteTechnique(bool hasReturnType)
5672
{
57-
IAsyncResult ar;
73+
_hasReturnType = hasReturnType;
5874

59-
LongTask lt = null;
75+
LongTask longTask;
6076
if (_hasReturnType)
61-
lt = new LongTask<int>(LongTaskSeconds);
77+
longTask = new LongTask<int>(LongTaskMilliseconds);
6278
else
63-
lt = new LongTask(LongTaskSeconds);
64-
65-
//1. Prove that the Wait-until-done technique works
66-
ar = lt.BeginDoTask(null, null);
67-
lt.EndDoTask(ar);
68-
// verify task completed
69-
if (!VerifyTaskCompleted(ar))
70-
Assert.True(false, string.Format("Wait-until-done: Task is not completed"));
79+
longTask = new LongTask(LongTaskMilliseconds);
7180

72-
Debug.WriteLine("Wait-until-Done -- Task completed");
73-
74-
//2. Prove that the Polling technique works
75-
ar = lt.BeginDoTask(null, null);
76-
while (!ar.IsCompleted)
81+
IAsyncResult asyncResult = longTask.BeginDoTask(null, null);
82+
while (!asyncResult.IsCompleted)
7783
{
78-
Task delay = Task.Delay(1000);
79-
delay.Wait();
80-
//Thread.Sleep(1000);
84+
Task.Delay(300).Wait();
8185
}
82-
// verify task completed
83-
if (!VerifyTaskCompleted(ar))
84-
Assert.True(false, string.Format("Polling: Task is not completed"));
85-
86-
Debug.WriteLine("Polling -- Task completed");
8786

88-
//3. Prove the AsyncWaitHandle works
89-
ar = lt.BeginDoTask(null, null);
90-
ar.AsyncWaitHandle.WaitOne();
91-
// verify task completed
92-
if (!VerifyTaskCompleted(ar))
93-
Assert.True(false, string.Format("wait via AsyncWaitHandle: Task is not completed"));
87+
AssertTaskCompleted(asyncResult);
88+
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
89+
}
9490

95-
Debug.WriteLine("Wait on AsyncWaitHandle -- Task completed");
91+
[Theory]
92+
[OuterLoop]
93+
[InlineData(true)]
94+
[InlineData(false)]
95+
public void WaitOnAsyncWaitHandleTechnique(bool hasReturnType)
96+
{
97+
_hasReturnType = hasReturnType;
9698

97-
//4. Prove that the Callback technique works
99+
LongTask longTask;
98100
if (_hasReturnType)
99-
ar = ((LongTask<int>)lt).BeginDoTask(INTINPUT, TaskCompleted, lt);
101+
longTask = new LongTask<int>(LongTaskMilliseconds);
100102
else
101-
ar = lt.BeginDoTask(TaskCompleted, lt);
103+
longTask = new LongTask(LongTaskMilliseconds);
102104

103-
_mre.WaitOne(); //Block the main thread until async thread finishes executing the call back
104-
// verify task completed
105-
if (!VerifyTaskCompleted(ar))
106-
Assert.True(false, string.Format("Callback: Task is not completed"));
105+
IAsyncResult asyncResult = longTask.BeginDoTask(null, null);
106+
asyncResult.AsyncWaitHandle.WaitOne();
107107

108-
Debug.WriteLine("Callback -- Task completed");
109-
//reaching this point means that the test didnt encounter any crashes or hangs.
110-
//So set the test as passed by returning true
111-
Assert.False(ar.CompletedSynchronously, "Should not have completed synchronously.");
108+
AssertTaskCompleted(asyncResult);
109+
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
110+
}
112111

112+
[Theory]
113+
[OuterLoop]
114+
[InlineData(true)]
115+
[InlineData(false)]
116+
public void CallbackTechnique(bool hasReturnType)
117+
{
118+
_hasReturnType = hasReturnType;
113119

114-
// Cleanup
115-
_mre.Dispose();
120+
LongTask longTask;
121+
if (_hasReturnType)
122+
longTask = new LongTask<int>(LongTaskMilliseconds);
123+
else
124+
longTask = new LongTask(LongTaskMilliseconds);
125+
126+
IAsyncResult asyncResult;
127+
if (_hasReturnType)
128+
asyncResult = ((LongTask<int>)longTask).BeginDoTask(IntInput, TaskCompleted, longTask);
129+
else
130+
asyncResult = longTask.BeginDoTask(TaskCompleted, longTask);
131+
132+
_mre.WaitOne(); //Block the main thread until async thread finishes executing the call back
133+
134+
AssertTaskCompleted(asyncResult);
135+
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
116136
}
117137

118138
/// <summary>
@@ -125,8 +145,8 @@ private void TaskCompleted(IAsyncResult ar)
125145
{
126146
LongTask<int> lt = (LongTask<int>)ar.AsyncState;
127147
int retValue = lt.EndDoTask(ar);
128-
if (retValue != INTINPUT)
129-
Assert.True(false, string.Format("Mismatch: Return = {0} vs Expect = {1}", retValue, INTINPUT));
148+
if (retValue != IntInput)
149+
Assert.True(false, string.Format("Mismatch: Return = {0} vs Expect = {1}", retValue, IntInput));
130150
}
131151
else
132152
{
@@ -138,33 +158,17 @@ private void TaskCompleted(IAsyncResult ar)
138158
}
139159

140160
/// <summary>
141-
/// Verify the IAsyncResult represent a completed Task
161+
/// Assert that the IAsyncResult represent a completed Task
142162
/// </summary>
143-
/// <param name="ar"></param>
144-
/// <returns></returns>
145-
private bool VerifyTaskCompleted(IAsyncResult ar)
146-
{
147-
return ar.IsCompleted &&
148-
((Task)ar).Status == TaskStatus.RanToCompletion; // assume no exception thrown
149-
}
150-
}
151-
152-
public static class TaskAPMTestCases
153-
{
154-
[Fact]
155-
[OuterLoop]
156-
public static void TaskAPMTest0()
163+
private void AssertTaskCompleted(IAsyncResult ar)
157164
{
158-
TaskAPMTest test = new TaskAPMTest(false);
159-
test.RealRun();
165+
Assert.True(ar.IsCompleted);
166+
Assert.Equal(TaskStatus.RanToCompletion, ((Task)ar).Status);
160167
}
161168

162-
[Fact]
163-
[OuterLoop]
164-
public static void TaskAPMTest1()
169+
public void Dispose()
165170
{
166-
TaskAPMTest test = new TaskAPMTest(true);
167-
test.RealRun();
171+
_mre.Dispose();
168172
}
169173
}
170174

@@ -173,20 +177,19 @@ public static void TaskAPMTest1()
173177
/// </summary>
174178
public class LongTask
175179
{
176-
//Used to store the amount time to perform spinWait
177-
protected readonly Int32 _ms; // Milliseconds;
180+
// Amount of time to SpinWait, in milliseconds.
181+
protected readonly Int32 _msWaitDuration;
178182

179-
public LongTask(Int32 seconds)
183+
public LongTask(Int32 milliseconds)
180184
{
181-
_ms = seconds * 1000;
185+
_msWaitDuration = milliseconds;
182186
}
183187

184188
// Synchronous version of time-consuming method
185189
public void DoTask()
186190
{
187191
// Simulate time-consuming task
188-
SpinWait.SpinUntil(() => false, _ms);
189-
//Thread.SpinWait(_ms);
192+
SpinWait.SpinUntil(() => false, _msWaitDuration);
190193
}
191194

192195
// Asynchronous version of time-consuming method (Begin part)
@@ -208,7 +211,7 @@ public IAsyncResult BeginDoTask(AsyncCallback callback, Object state)
208211
});
209212
}
210213

211-
return task; // Return the IAsyncResult to the caller
214+
return task; // Return the IAsyncResult to the caller
212215
}
213216

214217
// Asynchronous version of time-consuming method (End part)
@@ -226,16 +229,16 @@ public void EndDoTask(IAsyncResult asyncResult)
226229
/// </summary>
227230
public sealed class LongTask<T> : LongTask
228231
{
229-
public LongTask(Int32 seconds)
230-
: base(seconds)
232+
public LongTask(Int32 milliseconds)
233+
: base(milliseconds)
231234
{
232235
}
233236

234237
// Synchronous version of time-consuming method
235238
public T DoTask(T input)
236239
{
237-
SpinWait.SpinUntil(() => false, _ms); // Simulate time-consuming task
238-
return input; // Return some result, for now, just return the input
240+
SpinWait.SpinUntil(() => false, _msWaitDuration); // Simulate time-consuming task
241+
return input; // Return some result, for now, just return the input
239242
}
240243

241244
public IAsyncResult BeginDoTask(T input, AsyncCallback callback, Object state)
@@ -253,7 +256,7 @@ public IAsyncResult BeginDoTask(T input, AsyncCallback callback, Object state)
253256
callback(task);
254257
});
255258

256-
return task; // Return the IAsyncResult to the caller
259+
return task; // Return the IAsyncResult to the caller
257260
}
258261

259262
// Asynchronous version of time-consuming method (End part)

0 commit comments

Comments
 (0)