PageRenderTime 35ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/test/System.Web.Http.Test/Common/TaskHelpersTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 574 lines | 440 code | 110 blank | 24 comment | 5 complexity | bb5152447ae9756010d7c0e8b4c1fdef MD5 | raw file
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using Microsoft.TestCommon;
  4. using Xunit;
  5. using Assert = Microsoft.TestCommon.AssertEx;
  6. namespace System.Threading.Tasks
  7. {
  8. public class TaskHelpersTest
  9. {
  10. // -----------------------------------------------------------------
  11. // TaskHelpers.Canceled
  12. [Fact]
  13. public void Canceled_ReturnsCanceledTask()
  14. {
  15. Task result = TaskHelpers.Canceled();
  16. Assert.NotNull(result);
  17. Assert.True(result.IsCanceled);
  18. }
  19. // -----------------------------------------------------------------
  20. // TaskHelpers.Canceled<T>
  21. [Fact]
  22. public void Canceled_Generic_ReturnsCanceledTask()
  23. {
  24. Task<string> result = TaskHelpers.Canceled<string>();
  25. Assert.NotNull(result);
  26. Assert.True(result.IsCanceled);
  27. }
  28. // -----------------------------------------------------------------
  29. // TaskHelpers.Completed
  30. [Fact]
  31. public void Completed_ReturnsCompletedTask()
  32. {
  33. Task result = TaskHelpers.Completed();
  34. Assert.NotNull(result);
  35. Assert.Equal(TaskStatus.RanToCompletion, result.Status);
  36. }
  37. // -----------------------------------------------------------------
  38. // TaskHelpers.FromError
  39. [Fact]
  40. public void FromError_ReturnsFaultedTaskWithGivenException()
  41. {
  42. var exception = new Exception();
  43. Task result = TaskHelpers.FromError(exception);
  44. Assert.NotNull(result);
  45. Assert.True(result.IsFaulted);
  46. Assert.Same(exception, result.Exception.InnerException);
  47. }
  48. // -----------------------------------------------------------------
  49. // TaskHelpers.FromError<T>
  50. [Fact]
  51. public void FromError_Generic_ReturnsFaultedTaskWithGivenException()
  52. {
  53. var exception = new Exception();
  54. Task<string> result = TaskHelpers.FromError<string>(exception);
  55. Assert.NotNull(result);
  56. Assert.True(result.IsFaulted);
  57. Assert.Same(exception, result.Exception.InnerException);
  58. }
  59. // -----------------------------------------------------------------
  60. // TaskHelpers.FromErrors
  61. [Fact]
  62. public void FromErrors_ReturnsFaultedTaskWithGivenExceptions()
  63. {
  64. var exceptions = new[] { new Exception(), new InvalidOperationException() };
  65. Task result = TaskHelpers.FromErrors(exceptions);
  66. Assert.NotNull(result);
  67. Assert.True(result.IsFaulted);
  68. Assert.Equal(exceptions, result.Exception.InnerExceptions.ToArray());
  69. }
  70. // -----------------------------------------------------------------
  71. // TaskHelpers.FromErrors<T>
  72. [Fact]
  73. public void FromErrors_Generic_ReturnsFaultedTaskWithGivenExceptions()
  74. {
  75. var exceptions = new[] { new Exception(), new InvalidOperationException() };
  76. Task<string> result = TaskHelpers.FromErrors<string>(exceptions);
  77. Assert.NotNull(result);
  78. Assert.True(result.IsFaulted);
  79. Assert.Equal(exceptions, result.Exception.InnerExceptions.ToArray());
  80. }
  81. // -----------------------------------------------------------------
  82. // TaskHelpers.FromResult<T>
  83. [Fact]
  84. public void FromResult_ReturnsCompletedTaskWithGivenResult()
  85. {
  86. string s = "ABC";
  87. Task<string> result = TaskHelpers.FromResult(s);
  88. Assert.NotNull(result);
  89. Assert.True(result.Status == TaskStatus.RanToCompletion);
  90. Assert.Same(s, result.Result);
  91. }
  92. // -----------------------------------------------------------------
  93. // Task TaskHelpers.Iterate(IEnumerable<Task>)
  94. [Fact]
  95. public void Iterate_NonGeneric_IfProvidedEnumerationContainsNullValue_ReturnsFaultedTaskWithNullReferenceException()
  96. {
  97. List<string> log = new List<string>();
  98. var result = TaskHelpers.Iterate(NullTaskEnumerable(log));
  99. Assert.NotNull(result);
  100. result.WaitUntilCompleted();
  101. Assert.Equal(TaskStatus.Faulted, result.Status);
  102. Assert.IsType<NullReferenceException>(result.Exception.GetBaseException());
  103. }
  104. private static IEnumerable<Task> NullTaskEnumerable(List<string> log)
  105. {
  106. log.Add("first");
  107. yield return null;
  108. log.Add("second");
  109. }
  110. [Fact]
  111. public void Iterate_NonGeneric_IfProvidedEnumerationThrowsException_ReturnsFaultedTask()
  112. {
  113. List<string> log = new List<string>();
  114. Exception exception = new Exception();
  115. var result = TaskHelpers.Iterate(ThrowingTaskEnumerable(exception, log));
  116. Assert.NotNull(result);
  117. result.WaitUntilCompleted();
  118. Assert.Equal(TaskStatus.Faulted, result.Status);
  119. Assert.Same(exception, result.Exception.InnerException);
  120. Assert.Equal(new[] { "first" }, log.ToArray());
  121. }
  122. private static IEnumerable<Task> ThrowingTaskEnumerable(Exception e, List<string> log)
  123. {
  124. log.Add("first");
  125. bool a = true; // work around unreachable code warning
  126. if (a) throw e;
  127. log.Add("second");
  128. yield return null;
  129. }
  130. [Fact]
  131. public void Iterate_NonGeneric_IfProvidedEnumerableExecutesCancellingTask_ReturnsCanceledTaskAndHaltsEnumeration()
  132. {
  133. List<string> log = new List<string>();
  134. var result = TaskHelpers.Iterate(CanceledTaskEnumerable(log));
  135. Assert.NotNull(result);
  136. result.WaitUntilCompleted();
  137. Assert.Equal(TaskStatus.Canceled, result.Status);
  138. Assert.Equal(new[] { "first" }, log.ToArray());
  139. }
  140. private static IEnumerable<Task> CanceledTaskEnumerable(List<string> log)
  141. {
  142. log.Add("first");
  143. yield return TaskHelpers.Canceled();
  144. log.Add("second");
  145. }
  146. [Fact]
  147. public void Iterate_NonGeneric_IfProvidedEnumerableExecutesFaultingTask_ReturnsCanceledTaskAndHaltsEnumeration()
  148. {
  149. List<string> log = new List<string>();
  150. Exception exception = new Exception();
  151. var result = TaskHelpers.Iterate(FaultedTaskEnumerable(exception, log));
  152. Assert.NotNull(result);
  153. result.WaitUntilCompleted();
  154. Assert.Equal(TaskStatus.Faulted, result.Status);
  155. Assert.Same(exception, result.Exception.InnerException);
  156. Assert.Equal(new[] { "first" }, log.ToArray());
  157. }
  158. private static IEnumerable<Task> FaultedTaskEnumerable(Exception e, List<string> log)
  159. {
  160. log.Add("first");
  161. yield return TaskHelpers.FromError(e);
  162. log.Add("second");
  163. }
  164. [Fact]
  165. public void Iterate_NonGeneric_ExecutesNextTaskOnlyAfterPreviousTaskSucceeded()
  166. {
  167. List<string> log = new List<string>();
  168. var result = TaskHelpers.Iterate(SuccessTaskEnumerable(log));
  169. Assert.NotNull(result);
  170. result.WaitUntilCompleted();
  171. Assert.Equal(TaskStatus.RanToCompletion, result.Status);
  172. Assert.Equal(
  173. new[] { "first", "Executing first task. Log size: 1", "second", "Executing second task. Log size: 3" },
  174. log.ToArray());
  175. }
  176. private static IEnumerable<Task> SuccessTaskEnumerable(List<string> log)
  177. {
  178. log.Add("first");
  179. yield return Task.Factory.StartNew(() => log.Add("Executing first task. Log size: " + log.Count));
  180. log.Add("second");
  181. yield return Task.Factory.StartNew(() => log.Add("Executing second task. Log size: " + log.Count));
  182. }
  183. [Fact]
  184. public void Iterate_NonGeneric_TasksRunSequentiallyRegardlessOfExecutionTime()
  185. {
  186. List<string> log = new List<string>();
  187. Task task = TaskHelpers.Iterate(TasksWithVaryingDelays(log, 100, 1, 50, 2));
  188. task.WaitUntilCompleted();
  189. Assert.Equal(TaskStatus.RanToCompletion, task.Status);
  190. Assert.Equal(new[] { "ENTER: 100", "EXIT: 100", "ENTER: 1", "EXIT: 1", "ENTER: 50", "EXIT: 50", "ENTER: 2", "EXIT: 2" }, log);
  191. }
  192. private static IEnumerable<Task> TasksWithVaryingDelays(List<string> log, params int[] delays)
  193. {
  194. foreach (int delay in delays)
  195. yield return Task.Factory.StartNew(timeToSleep =>
  196. {
  197. log.Add("ENTER: " + timeToSleep);
  198. Thread.Sleep((int)timeToSleep);
  199. log.Add("EXIT: " + timeToSleep);
  200. }, delay);
  201. }
  202. [Fact]
  203. public void Iterate_NonGeneric_StopsTaskIterationIfCancellationWasRequested()
  204. {
  205. List<string> log = new List<string>();
  206. CancellationTokenSource cts = new CancellationTokenSource();
  207. var result = TaskHelpers.Iterate(CancelingTaskEnumerable(log, cts), cts.Token);
  208. Assert.NotNull(result);
  209. result.WaitUntilCompleted();
  210. Assert.Equal(TaskStatus.Canceled, result.Status);
  211. Assert.Equal(
  212. new[] { "first", "Executing first task. Log size: 1" },
  213. log.ToArray());
  214. }
  215. private static IEnumerable<Task> CancelingTaskEnumerable(List<string> log, CancellationTokenSource cts)
  216. {
  217. log.Add("first");
  218. yield return Task.Factory.StartNew(() =>
  219. {
  220. log.Add("Executing first task. Log size: " + log.Count);
  221. cts.Cancel();
  222. });
  223. log.Add("second");
  224. yield return Task.Factory.StartNew(() =>
  225. {
  226. log.Add("Executing second task. Log size: " + log.Count);
  227. });
  228. }
  229. [Fact, PreserveSyncContext]
  230. public Task Iterate_NonGeneric_IteratorRunsInSynchronizationContext()
  231. {
  232. ThreadPoolSyncContext sc = new ThreadPoolSyncContext();
  233. SynchronizationContext.SetSynchronizationContext(sc);
  234. return TaskHelpers.Iterate(SyncContextVerifyingEnumerable(sc)).Then(() =>
  235. {
  236. Assert.Same(sc, SynchronizationContext.Current);
  237. });
  238. }
  239. private static IEnumerable<Task> SyncContextVerifyingEnumerable(SynchronizationContext sc)
  240. {
  241. for (int i = 0; i < 10; i++)
  242. {
  243. Assert.Same(sc, SynchronizationContext.Current);
  244. yield return TaskHelpers.Completed();
  245. }
  246. }
  247. // -----------------------------------------------------------------
  248. // Task<IEnumerable<T>> TaskHelpers.Iterate(IEnumerable<Task<T>>)
  249. [Fact]
  250. public void Iterate_Generic_IfProvidedEnumerationContainsNullValue_ReturnsFaultedTaskWithNullReferenceException()
  251. {
  252. List<string> log = new List<string>();
  253. Task<IEnumerable<object>> result = TaskHelpers.Iterate(NullTaskEnumerable_Generic(log));
  254. Assert.NotNull(result);
  255. result.WaitUntilCompleted();
  256. Assert.Equal(TaskStatus.Faulted, result.Status);
  257. Assert.IsType<NullReferenceException>(result.Exception.GetBaseException());
  258. }
  259. private static IEnumerable<Task<object>> NullTaskEnumerable_Generic(List<string> log)
  260. {
  261. log.Add("first");
  262. yield return null;
  263. log.Add("second");
  264. }
  265. [Fact]
  266. public void Iterate_Generic_IfProvidedEnumerationThrowsException_ReturnsFaultedTask()
  267. {
  268. List<string> log = new List<string>();
  269. Exception exception = new Exception();
  270. Task<IEnumerable<object>> result = TaskHelpers.Iterate(ThrowingTaskEnumerable_Generic(exception, log));
  271. Assert.NotNull(result);
  272. result.WaitUntilCompleted();
  273. Assert.Equal(TaskStatus.Faulted, result.Status);
  274. Assert.Same(exception, result.Exception.InnerException);
  275. Assert.Equal(new[] { "first" }, log.ToArray());
  276. }
  277. private static IEnumerable<Task<object>> ThrowingTaskEnumerable_Generic(Exception e, List<string> log)
  278. {
  279. log.Add("first");
  280. bool a = true; // work around unreachable code warning
  281. if (a) throw e;
  282. log.Add("second");
  283. yield return null;
  284. }
  285. [Fact]
  286. public void Iterate_Generic_IfProvidedEnumerableExecutesCancellingTask_ReturnsCanceledTaskAndHaltsEnumeration()
  287. {
  288. List<string> log = new List<string>();
  289. Task<IEnumerable<object>> result = TaskHelpers.Iterate(CanceledTaskEnumerable_Generic(log));
  290. Assert.NotNull(result);
  291. result.WaitUntilCompleted();
  292. Assert.Equal(TaskStatus.Canceled, result.Status);
  293. Assert.Equal(new[] { "first" }, log.ToArray());
  294. }
  295. private static IEnumerable<Task<object>> CanceledTaskEnumerable_Generic(List<string> log)
  296. {
  297. log.Add("first");
  298. yield return TaskHelpers.Canceled<object>();
  299. log.Add("second");
  300. }
  301. [Fact]
  302. public void Iterate_Generic_IfProvidedEnumerableExecutesFaultingTask_ReturnsCanceledTaskAndHaltsEnumeration()
  303. {
  304. List<string> log = new List<string>();
  305. Exception exception = new Exception();
  306. Task<IEnumerable<object>> result = TaskHelpers.Iterate(FaultedTaskEnumerable_Generic(exception, log));
  307. Assert.NotNull(result);
  308. result.WaitUntilCompleted();
  309. Assert.Equal(TaskStatus.Faulted, result.Status);
  310. Assert.Same(exception, result.Exception.InnerException);
  311. Assert.Equal(new[] { "first" }, log.ToArray());
  312. }
  313. private static IEnumerable<Task<object>> FaultedTaskEnumerable_Generic(Exception e, List<string> log)
  314. {
  315. log.Add("first");
  316. yield return TaskHelpers.FromError<object>(e);
  317. log.Add("second");
  318. }
  319. [Fact]
  320. public void Iterate_Generic_ExecutesNextTaskOnlyAfterPreviousTaskSucceeded()
  321. {
  322. Task<IEnumerable<int>> result = TaskHelpers.Iterate(SuccessTaskEnumerable_Generic());
  323. Assert.NotNull(result);
  324. result.WaitUntilCompleted();
  325. Assert.Equal(TaskStatus.RanToCompletion, result.Status);
  326. Assert.Equal(new[] { 42, 2112 }, result.Result);
  327. }
  328. private static IEnumerable<Task<int>> SuccessTaskEnumerable_Generic()
  329. {
  330. yield return Task.Factory.StartNew(() => 42);
  331. yield return Task.Factory.StartNew(() => 2112);
  332. }
  333. [Fact]
  334. public void Iterate_Generic_TasksRunSequentiallyRegardlessOfExecutionTime()
  335. {
  336. List<string> log = new List<string>();
  337. Task<IEnumerable<object>> task = TaskHelpers.Iterate(TasksWithVaryingDelays_Generic(log, 100, 1, 50, 2));
  338. task.WaitUntilCompleted();
  339. Assert.Equal(TaskStatus.RanToCompletion, task.Status);
  340. Assert.Equal(new[] { "ENTER: 100", "EXIT: 100", "ENTER: 1", "EXIT: 1", "ENTER: 50", "EXIT: 50", "ENTER: 2", "EXIT: 2" }, log);
  341. }
  342. private static IEnumerable<Task<object>> TasksWithVaryingDelays_Generic(List<string> log, params int[] delays)
  343. {
  344. foreach (int delay in delays)
  345. yield return Task.Factory.StartNew(timeToSleep =>
  346. {
  347. log.Add("ENTER: " + timeToSleep);
  348. Thread.Sleep((int)timeToSleep);
  349. log.Add("EXIT: " + timeToSleep);
  350. return (object)null;
  351. }, delay);
  352. }
  353. [Fact]
  354. public void Iterate_Generic_StopsTaskIterationIfCancellationWasRequested()
  355. {
  356. List<string> log = new List<string>();
  357. CancellationTokenSource cts = new CancellationTokenSource();
  358. var result = TaskHelpers.Iterate(CancelingTaskEnumerable_Generic(log, cts), cts.Token);
  359. Assert.NotNull(result);
  360. result.WaitUntilCompleted();
  361. Assert.Equal(TaskStatus.Canceled, result.Status);
  362. Assert.Equal(
  363. new[] { "first", "Executing first task. Log size: 1" },
  364. log.ToArray());
  365. }
  366. private static IEnumerable<Task<object>> CancelingTaskEnumerable_Generic(List<string> log, CancellationTokenSource cts)
  367. {
  368. log.Add("first");
  369. yield return Task.Factory.StartNew(() =>
  370. {
  371. log.Add("Executing first task. Log size: " + log.Count);
  372. cts.Cancel();
  373. return (object)null;
  374. });
  375. log.Add("second");
  376. yield return Task.Factory.StartNew(() =>
  377. {
  378. log.Add("Executing second task. Log size: " + log.Count);
  379. return (object)null;
  380. });
  381. }
  382. [Fact, PreserveSyncContext]
  383. public Task Iterate_Generic_IteratorRunsInSynchronizationContext()
  384. {
  385. ThreadPoolSyncContext sc = new ThreadPoolSyncContext();
  386. SynchronizationContext.SetSynchronizationContext(sc);
  387. return TaskHelpers.Iterate(SyncContextVerifyingEnumerable_Generic(sc)).Then(result =>
  388. {
  389. Assert.Same(sc, SynchronizationContext.Current);
  390. Assert.Equal(new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, result);
  391. });
  392. }
  393. private static IEnumerable<Task<int>> SyncContextVerifyingEnumerable_Generic(SynchronizationContext sc)
  394. {
  395. for (int i = 0; i < 10; i++)
  396. {
  397. Assert.Same(sc, SynchronizationContext.Current);
  398. yield return TaskHelpers.FromResult(i);
  399. }
  400. }
  401. // -----------------------------------------------------------------
  402. // TaskHelpers.TrySetFromTask<T>
  403. [Fact]
  404. public void TrySetFromTask_IfSourceTaskIsCanceled_CancelsTaskCompletionSource()
  405. {
  406. TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
  407. Task canceledTask = TaskHelpers.Canceled<object>();
  408. tcs.TrySetFromTask(canceledTask);
  409. Assert.Equal(TaskStatus.Canceled, tcs.Task.Status);
  410. }
  411. [Fact]
  412. public void TrySetFromTask_IfSourceTaskIsFaulted_FaultsTaskCompletionSource()
  413. {
  414. TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
  415. Exception exception = new Exception();
  416. Task faultedTask = TaskHelpers.FromError<object>(exception);
  417. tcs.TrySetFromTask(faultedTask);
  418. Assert.Equal(TaskStatus.Faulted, tcs.Task.Status);
  419. Assert.Same(exception, tcs.Task.Exception.InnerException);
  420. }
  421. [Fact]
  422. public void TrySetFromTask_IfSourceTaskIsSuccessfulAndOfSameResultType_SucceedsTaskCompletionSourceAndSetsResult()
  423. {
  424. TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
  425. Task<string> successfulTask = TaskHelpers.FromResult("abc");
  426. tcs.TrySetFromTask(successfulTask);
  427. Assert.Equal(TaskStatus.RanToCompletion, tcs.Task.Status);
  428. Assert.Equal("abc", tcs.Task.Result);
  429. }
  430. [Fact]
  431. public void TrySetFromTask_IfSourceTaskIsSuccessfulAndOfDifferentResultType_SucceedsTaskCompletionSourceAndSetsDefaultValueAsResult()
  432. {
  433. TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
  434. Task<object> successfulTask = TaskHelpers.FromResult(new object());
  435. tcs.TrySetFromTask(successfulTask);
  436. Assert.Equal(TaskStatus.RanToCompletion, tcs.Task.Status);
  437. Assert.Equal(null, tcs.Task.Result);
  438. }
  439. // -----------------------------------------------------------------
  440. // TaskHelpers.RunSynchronously
  441. [Fact]
  442. public void RunSynchronously_Executes_Action()
  443. {
  444. bool wasRun = false;
  445. Task t = TaskHelpers.RunSynchronously(() => { wasRun = true; });
  446. t.WaitUntilCompleted();
  447. Assert.True(wasRun);
  448. }
  449. [Fact]
  450. public void RunSynchronously_Captures_Exception_In_AggregateException()
  451. {
  452. Task t = TaskHelpers.RunSynchronously(() => { throw new InvalidOperationException(); });
  453. Assert.Throws<InvalidOperationException>(() => t.Wait());
  454. }
  455. [Fact]
  456. public void RunSynchronously_Cancels()
  457. {
  458. CancellationTokenSource cts = new CancellationTokenSource();
  459. cts.Cancel();
  460. Task t = TaskHelpers.RunSynchronously(() => { throw new InvalidOperationException(); }, cts.Token);
  461. Assert.Throws<TaskCanceledException>(() => t.Wait());
  462. }
  463. }
  464. }