public async Task TestOrdering_Async_OrderedDisabled(bool trustedEnumeration) { // If ordering were enabled, this test would hang. var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded, EnsureOrdered = false }; var tasks = new TaskCompletionSource <IEnumerable <int> > [10]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = new TaskCompletionSource <IEnumerable <int> >(); } var tb = new TransformManyBlock <int, int>(i => tasks[i].Task, options); tb.PostRange(0, tasks.Length); for (int i = tasks.Length - 1; i >= 0; i--) { tasks[i].SetResult(trustedEnumeration ? new[] { i } : Enumerable.Repeat(i, 1)); Assert.Equal(expected: i, actual: await tb.ReceiveAsync()); } tb.Complete(); await tb.Completion; }
public async Task TestLinkToOptionsAsyncEnumerable() { const int Messages = 1; foreach (bool append in DataflowTestHelpers.BooleanValues) { var tb = new TransformManyBlock <int, int>(DataflowTestHelpers.ToAsyncEnumerable); var values = new int[Messages]; var targets = new ActionBlock <int> [Messages]; for (int i = 0; i < Messages; i++) { int slot = i; targets[i] = new ActionBlock <int>(item => values[slot] = item); tb.LinkTo(targets[i], new DataflowLinkOptions { MaxMessages = 1, Append = append }); } tb.PostRange(0, Messages); tb.Complete(); await tb.Completion; for (int i = 0; i < Messages; i++) { Assert.Equal( expected: append ? i : Messages - i - 1, actual: values[i]); } } }
public async Task TestNullTasksIgnored() { foreach (int dop in new[] { DataflowBlockOptions.Unbounded, 1, 2 }) { var tb = new TransformManyBlock <int, int>(i => { if ((i % 2) == 0) { return(null); } return(Task.Run(() => (IEnumerable <int>) new[] { i })); }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = dop }); const int Iters = 100; tb.PostRange(0, Iters); tb.Complete(); for (int i = 0; i < Iters; i++) { if ((i % 2) != 0) { Assert.Equal(expected: i, actual: await tb.ReceiveAsync()); } } await tb.Completion; } }
[InlineData(2, 1, false)] // no force ordered, but dop == 1, so it doesn't matter public async Task TestOrdering_Async_OrderedEnabled(int mmpt, int dop, bool?EnsureOrdered) { const int iters = 1000; var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = dop, MaxMessagesPerTask = mmpt }; if (EnsureOrdered == null) { Assert.True(options.EnsureOrdered); } else { options.EnsureOrdered = EnsureOrdered.Value; } var tb = new TransformManyBlock <int, int>(i => Task.FromResult(Enumerable.Repeat(i, 1)), options); tb.PostRange(0, iters); for (int i = 0; i < iters; i++) { Assert.Equal(expected: i, actual: await tb.ReceiveAsync()); } tb.Complete(); await tb.Completion; }
public async Task TestFaultingAndCancellation() { foreach (bool fault in DataflowTestHelpers.BooleanValues) { var cts = new CancellationTokenSource(); var tb = new TransformManyBlock <int, int>(DataflowTestHelpers.ToEnumerable, new ExecutionDataflowBlockOptions { CancellationToken = cts.Token }); tb.PostRange(0, 4); Assert.Equal(expected: 0, actual: await tb.ReceiveAsync()); Assert.Equal(expected: 1, actual: await tb.ReceiveAsync()); if (fault) { Assert.Throws <ArgumentNullException>(() => ((IDataflowBlock)tb).Fault(null)); ((IDataflowBlock)tb).Fault(new InvalidCastException()); await Assert.ThrowsAsync <InvalidCastException>(() => tb.Completion); } else { cts.Cancel(); await Assert.ThrowsAnyAsync <OperationCanceledException>(() => tb.Completion); } Assert.Equal(expected: 0, actual: tb.InputCount); Assert.Equal(expected: 0, actual: tb.OutputCount); } }
public async Task TestCancellationExceptionsIgnored() { foreach (bool sync in DataflowTestHelpers.BooleanValues) { Func <int, IEnumerable <int> > body = i => { if ((i % 2) == 0) { throw new OperationCanceledException(); } return(new[] { i }); }; TransformManyBlock <int, int> t = sync ? new TransformManyBlock <int, int>(body) : new TransformManyBlock <int, int>(async i => await Task.Run(() => body(i))); t.PostRange(0, 2); t.Complete(); for (int i = 0; i < 2; i++) { if ((i % 2) != 0) { Assert.Equal(expected: i, actual: await t.ReceiveAsync()); } } await t.Completion; } }
private static TransformManyBlock <int, int> ConstructTransformManyWithNMessages(int messagesCount) { var block = new TransformManyBlock <int, int>(i => new int[] { i }); block.PostRange(0, messagesCount); SpinWait.SpinUntil(() => block.OutputCount == messagesCount); // spin until messages available return(block); }
public async Task TestReceivesAsyncEnumerable() { for (int test = 0; test < 2; test++) { var tb = new TransformManyBlock <int, int>(i => AsyncEnumerable.Repeat(i * 2, 1)); tb.PostRange(0, 5); for (int i = 0; i < 5; i++) { Assert.Equal(expected: i * 2, actual: await tb.ReceiveAsync()); } Assert.False(tb.TryReceive(out _)); Assert.False(tb.TryReceiveAll(out _)); } }
[OuterLoop] // spins waiting for a condition to be true, though it should happen very quickly public async Task TestCount() { var tb = new TransformManyBlock <int, int>(DataflowTestHelpers.ToEnumerable); Assert.Equal(expected: 0, actual: tb.InputCount); Assert.Equal(expected: 0, actual: tb.OutputCount); tb.PostRange(1, 11); await Task.Run(() => SpinWait.SpinUntil(() => tb.OutputCount == 10)); for (int i = 10; i > 0; i--) { int item; Assert.True(tb.TryReceive(out item)); Assert.Equal(expected: 11 - i, actual: item); Assert.Equal(expected: i - 1, actual: tb.OutputCount); } }
public async Task TransformManyEnumerableToAction() { var data = new[] { 1 }; var tm = new TransformManyBlock <int, int>(i => data); int completedCount = 0; var c = new ActionBlock <int>(i => completedCount++); tm.LinkTo(c, new DataflowLinkOptions { PropagateCompletion = true }); tm.PostRange(0, Iterations); tm.Complete(); await c.Completion; Assert.Equal(expected: Iterations, actual: completedCount); }
public async Task TransformManyEnumerableToAction() { var data = new[] { 1 }; var tm = new TransformManyBlock<int, int>(i => data); int completedCount = 0; var c = new ActionBlock<int>(i => completedCount++); tm.LinkTo(c, new DataflowLinkOptions { PropagateCompletion = true }); tm.PostRange(0, Iterations); tm.Complete(); await c.Completion; Assert.Equal(expected: Iterations, actual: completedCount); }
public async Task TestOrdering_Async_OrderedDisabled(bool trustedEnumeration) { // If ordering were enabled, this test would hang. var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded, EnsureOrdered = false }; var tasks = new TaskCompletionSource<IEnumerable<int>>[10]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = new TaskCompletionSource<IEnumerable<int>>(); } var tb = new TransformManyBlock<int, int>(i => tasks[i].Task, options); tb.PostRange(0, tasks.Length); for (int i = tasks.Length - 1; i >= 0; i--) { tasks[i].SetResult(trustedEnumeration ? new[] { i } : Enumerable.Repeat(i, 1)); Assert.Equal(expected: i, actual: await tb.ReceiveAsync()); } tb.Complete(); await tb.Completion; }
[InlineData(2, 1, false)] // no force ordered, but dop == 1, so it doesn't matter public async Task TestOrdering_Async_OrderedEnabled(int mmpt, int dop, bool? EnsureOrdered) { const int iters = 1000; var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = dop, MaxMessagesPerTask = mmpt }; if (EnsureOrdered == null) { Assert.True(options.EnsureOrdered); } else { options.EnsureOrdered = EnsureOrdered.Value; } var tb = new TransformManyBlock<int, int>(i => Task.FromResult(Enumerable.Repeat(i, 1)), options); tb.PostRange(0, iters); for (int i = 0; i < iters; i++) { Assert.Equal(expected: i, actual: await tb.ReceiveAsync()); } tb.Complete(); await tb.Completion; }
public async Task TestNullTasksIgnored() { foreach (int dop in new[] { DataflowBlockOptions.Unbounded, 1, 2 }) { var tb = new TransformManyBlock<int, int>(i => { if ((i % 2) == 0) return null; return Task.Run(() => (IEnumerable<int>)new[] { i }); }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = dop }); const int Iters = 100; tb.PostRange(0, Iters); tb.Complete(); for (int i = 0; i < Iters; i++) { if ((i % 2) != 0) { Assert.Equal(expected: i, actual: await tb.ReceiveAsync()); } } await tb.Completion; } }
public async Task TestFaultingAndCancellation() { foreach (bool fault in DataflowTestHelpers.BooleanValues) { var cts = new CancellationTokenSource(); var tb = new TransformManyBlock<int, int>(DataflowTestHelpers.ToEnumerable, new ExecutionDataflowBlockOptions { CancellationToken = cts.Token }); tb.PostRange(0, 4); Assert.Equal(expected: 0, actual: await tb.ReceiveAsync()); Assert.Equal(expected: 1, actual: await tb.ReceiveAsync()); if (fault) { Assert.Throws<ArgumentNullException>(() => ((IDataflowBlock)tb).Fault(null)); ((IDataflowBlock)tb).Fault(new InvalidCastException()); await Assert.ThrowsAsync<InvalidCastException>(() => tb.Completion); } else { cts.Cancel(); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => tb.Completion); } Assert.Equal(expected: 0, actual: tb.InputCount); Assert.Equal(expected: 0, actual: tb.OutputCount); } }
[OuterLoop] // spins waiting for a condition to be true, though it should happen very quickly public async Task TestCount() { var tb = new TransformManyBlock<int, int>(DataflowTestHelpers.ToEnumerable); Assert.Equal(expected: 0, actual: tb.InputCount); Assert.Equal(expected: 0, actual: tb.OutputCount); tb.PostRange(1, 11); await Task.Run(() => SpinWait.SpinUntil(() => tb.OutputCount == 10)); for (int i = 10; i > 0; i--) { int item; Assert.True(tb.TryReceive(out item)); Assert.Equal(expected: 11 - i, actual: item); Assert.Equal(expected: i - 1, actual: tb.OutputCount); } }