public async Task TestSendAsync_ConsumeCanceled()
        {
            var cts = new CancellationTokenSource();
            DelegatePropagator<int, int> target = null;
            target = new DelegatePropagator<int, int>
            {
                OfferMessageDelegate = delegate(DataflowMessageHeader header, int value, ISourceBlock<int> source, bool consumeToAccept) {
                    if (source == null)
                    {
                        return DataflowMessageStatus.Declined;
                    }

                    Assert.True(consumeToAccept);
                    cts.Cancel();

                    bool consumed;
                    int consumedMessage = source.ConsumeMessage(header, target, out consumed);
                    Assert.False(consumed);
                    Assert.Equal(expected: 0, actual: consumedMessage);
                    return DataflowMessageStatus.Postponed; // should really be NotAvailable, but doing so causes an (expected) assert in the product code
                }
            };
            Task<bool> send = target.SendAsync(42, cts.Token);
            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => send);
        }
 public async Task TestSendAsync_FaultyTarget()
 {
     var target = new DelegatePropagator<int, int>
     {
         OfferMessageDelegate = (header, value, source, consumeToAccept) => {
             if (source == null)
                 return DataflowMessageStatus.Declined;
             throw new FormatException();
         }
     };
     await Assert.ThrowsAsync<FormatException>(() => target.SendAsync(1));
 }
        public void TestSendAsync_BehavesAsGoodSource()
        {
            ISourceBlock<int> sendSource = null;
            ITargetBlock<int> capturingTarget = new DelegatePropagator<int, int>
            {
                OfferMessageDelegate = delegate(DataflowMessageHeader header, int value, ISourceBlock<int> source, bool consumeToAccept) {
                    if (source == null)
                    {
                        return DataflowMessageStatus.Declined;
                    }
                    sendSource = source;
                    return DataflowMessageStatus.Postponed;
                }
            };

            Task<bool> sendTask = capturingTarget.SendAsync(42);
            Assert.False(sendTask.IsCompleted);
            Assert.NotNull(sendSource);

            DataflowTestHelpers.TestConsumeReserveReleaseArgumentsExceptions(sendSource);
            Assert.Throws<NotSupportedException>(() => sendSource.LinkTo(DataflowBlock.NullTarget<int>()));
            Assert.Throws<NotSupportedException>(() => sendSource.Fault(new Exception()));
            Assert.Throws<NotSupportedException>(() => sendSource.Complete());
        }
        public async Task TestSendAsync_Canceled()
        {
            CancellationTokenSource cts;
            var bb = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });

            Task<bool> t = bb.SendAsync(1, new CancellationToken(canceled: true));
            Assert.True(t.IsCanceled);

            t = bb.SendAsync(2, new CancellationToken(canceled: false));
            Assert.True(t.IsCompleted);
            Assert.True(t.Result);

            cts = new CancellationTokenSource();
            t = bb.SendAsync(3, cts.Token);
            Assert.False(t.IsCompleted);
            cts.Cancel();
            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t);

            Assert.Equal(expected: 2, actual: await bb.ReceiveAsync());
            bb.Complete();
            await bb.Completion;

            foreach (bool withCancellation in DataflowTestHelpers.BooleanValues)
            {
                var target = new DelegatePropagator<int, int>();
                target.OfferMessageDelegate = (messageHeader, messageValue, source, consumeToAccept) => {
                    if (source == null)
                        return DataflowMessageStatus.Declined;

                    Assert.Equal(expected: withCancellation, actual: consumeToAccept);
                    if (consumeToAccept)
                    {
                        Assert.NotNull(source);
                        bool consumed;
                        source.ConsumeMessage(messageHeader, target, out consumed);
                        Assert.True(consumed);
                    }
                    return DataflowMessageStatus.Accepted;
                };

                t = withCancellation ?
                    target.SendAsync(1, new CancellationTokenSource().Token) :
                    target.SendAsync(2);
                Assert.True(await t);
            }
        }
        public async Task TestSendAsync_ReserveRelease()
        {
            bool alreadyReservedReleased = false;

            foreach (bool withCancellation in DataflowTestHelpers.BooleanValues)
            {
                var cts = new CancellationTokenSource();

                DelegatePropagator<int, int> target = new DelegatePropagator<int, int>();
                target.OfferMessageDelegate = (messageHeader, messageValue, source, consumeToAccept) => {
                    Assert.True(messageHeader.IsValid);
                    Assert.Equal(expected: 42, actual: messageValue);

                    if (source == null)
                    {
                        return DataflowMessageStatus.Declined;
                    }

                    Assert.Equal(expected: withCancellation, actual: consumeToAccept);

                    if (!alreadyReservedReleased)
                    {
                        alreadyReservedReleased = true;
                        Task.Run(() => {
                            Assert.True(source.ReserveMessage(messageHeader, target));
                            if (withCancellation)
                                cts.Cancel();
                            source.ReleaseReservation(messageHeader, target);
                        });
                        return DataflowMessageStatus.Postponed;
                    }
                    else
                    {
                        return DataflowMessageStatus.Accepted;
                    }
                };

                if (withCancellation)
                {
                    await Assert.ThrowsAnyAsync<OperationCanceledException>(() => target.SendAsync(42, cts.Token));
                }
                else
                {
                    Assert.True(await target.SendAsync(42));
                }
            }
        }
        public async Task TestNullTarget_OfferMessage()
        {
            DataflowTestHelpers.TestOfferMessage_ArgumentValidation(DataflowBlock.NullTarget<int>());
            DataflowTestHelpers.TestOfferMessage_AcceptsDataDirectly(DataflowBlock.NullTarget<string>());
            await DataflowTestHelpers.TestOfferMessage_AcceptsViaLinking(DataflowBlock.NullTarget<double>());

            // Test OfferMessage(consumeToAccept: false)
            Assert.Equal(
                expected: DataflowMessageStatus.Accepted,
                actual: DataflowBlock.NullTarget<double>().OfferMessage(new DataflowMessageHeader(1), 3.14, null, consumeToAccept: false));

            // Test OfferMessage(consumeToAccept: true)
            long consumedId = -1;
            DataflowBlock.NullTarget<int>().OfferMessage(new DataflowMessageHeader(42), 84, new DelegatePropagator<int, int>()
            {
                ConsumeMessageDelegate = delegate(DataflowMessageHeader messageHeader, ITargetBlock<int> target, out bool messageConsumed) {
                    consumedId = messageHeader.Id;
                    messageConsumed = true;
                    return 0;
                }
            }, consumeToAccept: true);
            Assert.Equal(expected: 42, actual: consumedId);

            // Test bad source
            Assert.Throws<InvalidOperationException>(() => {
                var target = DataflowBlock.NullTarget<int>();
                DataflowBlock.NullTarget<int>().OfferMessage(new DataflowMessageHeader(42), 84, new DelegatePropagator<int, int>()
                {
                    ConsumeMessageDelegate = delegate(DataflowMessageHeader _, ITargetBlock<int> __, out bool ___) {
                        throw new InvalidOperationException();
                    }
                }, consumeToAccept: true);
                Assert.True(target.Post(42));
            });

            // Test message no longer available
            var stingySource = new DelegatePropagator<int, int>
            {
                ConsumeMessageDelegate = (DataflowMessageHeader messageHeader, ITargetBlock<int> target, out bool messageConsumed) => {
                    messageConsumed = false;
                    return 0;
                }
            };
            Assert.Equal(
                expected: DataflowMessageStatus.NotAvailable,
                actual: DataflowBlock.NullTarget<int>().OfferMessage(
                    new DataflowMessageHeader(1), 1, stingySource, consumeToAccept: true));
        }
        public async Task TestLinkTo_DoubleLinking_ValidPropagator()
        {
            bool tested = false;
            var tcs = new TaskCompletionSource<bool>();

            // Link a source to a target
            var source = new BufferBlock<int>();
            DelegatePropagator<int, int> target = null;
            target = new DelegatePropagator<int, int>
            {
                OfferMessageDelegate = (header, value, nopPropagator, consumeToAccept) =>
                {
                    if (!tested) // just run once; the release below could trigger an addition offering
                    {
                        // Make sure the nop propagator's Completion object is the same as that of the source
                        Assert.Same(expected: source.Completion, actual: nopPropagator.Completion);

                        // Make sure we can reserve and release through the propagator
                        Assert.True(nopPropagator.ReserveMessage(header, target));
                        nopPropagator.ReleaseReservation(header, target);

                        // Make sure its LinkTo doesn't work; that wouldn't make sense
                        Assert.Throws<NotSupportedException>(() => nopPropagator.LinkTo(DataflowBlock.NullTarget<int>(), new DataflowLinkOptions()));
                    }
                    return DataflowMessageStatus.Accepted;
                },
                CompleteDelegate = () => tcs.SetResult(true)
            };

            // Link from the source to the target, ensuring that we do so via a nop propagator
            using (source.LinkTo(target))
            {
                source.LinkTo(target, new DataflowLinkOptions { PropagateCompletion = true });
            }

            // Now put data in the source that it can propagator through the nop link
            source.Post(42);
            source.Complete();

            // Wait for everything to shut down.
            await source.Completion;
            await tcs.Task;
        }
 public async Task TestOutputAvailableAsync_FaultySource()
 {
     var source = new DelegatePropagator<int, int>
     {
         LinkToDelegate = delegate { throw new InvalidCastException(); }
     };
     var t = source.OutputAvailableAsync();
     await Assert.ThrowsAsync<InvalidCastException>(() => t);
 }
예제 #9
0
        public async Task TestReleaseOnReserveException()
        {
            foreach (bool linkBadFirst in DataflowTestHelpers.BooleanValues)
            {
                var goodSource = new BufferBlock<int>();
                goodSource.Post(1);

                DelegatePropagator<int, int> badSource = null;
                badSource = new DelegatePropagator<int, int>
                {
                    LinkToDelegate = (target, options) => {
                        target.OfferMessage(new DataflowMessageHeader(1), 2, badSource, consumeToAccept: true);
                        return new DelegateDisposable();
                    },
                    ReserveMessageDelegate = delegate { throw new InvalidCastException(); }
                };

                var batch = new BatchBlock<int>(2, new GroupingDataflowBlockOptions { Greedy = false });

                if (linkBadFirst) // Each linking will offer a message
                {
                    badSource.LinkTo(batch);
                    goodSource.LinkTo(batch);
                }
                else
                {
                    goodSource.LinkTo(batch);
                    badSource.LinkTo(batch);
                }

                await Assert.ThrowsAnyAsync<InvalidCastException>(() => batch.Completion);

                int item;
                Assert.True(goodSource.TryReceive(out item)); // The good message must not be Reserved
            }
        }
예제 #10
0
        public async Task TestNonGreedyFailedConsume()
        {
            foreach (bool exceptionalConsume in DataflowTestHelpers.BooleanValues)
            foreach (bool linkGoodFirst in DataflowTestHelpers.BooleanValues)
            {
                const int BatchSize = 2;
                var bb = new BatchBlock<int>(BatchSize, new GroupingDataflowBlockOptions { Greedy = false });

                var goodSource = new BufferBlock<int>();
                Assert.True(goodSource.Post(1));

                if (linkGoodFirst)
                {
                    goodSource.LinkTo(bb);
                }

                var badSource = new DelegatePropagator<int, int>
                {
                    ReserveMessageDelegate = delegate { return true; },
                    ConsumeMessageDelegate = delegate(DataflowMessageHeader header, ITargetBlock<int> target, out bool messageConsumed) {
                        if (exceptionalConsume)
                        {
                            throw new FormatException(); // throw when attempting to consume reserved message
                        }
                        else
                        {
                            messageConsumed = false; // fail when attempting to consume reserved message
                            return 0;
                        }
                    }
                };
                Assert.Equal(
                    expected: DataflowMessageStatus.Postponed,
                    actual: ((ITargetBlock<int>)bb).OfferMessage(new DataflowMessageHeader(2), 2, badSource, consumeToAccept: true));

                if (!linkGoodFirst)
                {
                    goodSource.LinkTo(bb);
                }

                await (exceptionalConsume ?
                    (Task)Assert.ThrowsAsync<FormatException>(() => bb.Completion) :
                    (Task)Assert.ThrowsAsync<InvalidOperationException>(() => bb.Completion));
            }
        }
예제 #11
0
        public async Task TestReleasingFailsAtCompletion()
        {
            // Create a bounded block that's filled
            var bb = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });
            bb.Post(1);

            // Create a source that will throw an exception when a message is released,
            // which should happen when the buffer block drops any postponed messages
            var source = new DelegatePropagator<int, int>
            {
                ReserveMessageDelegate = (header, target) => true,
                ReleaseMessageDelegate = delegate { throw new FormatException(); }
            };

            // Offer a message from the source. It'll be postponed.
            ((ITargetBlock<int>)bb).OfferMessage(new DataflowMessageHeader(1), 1, source, consumeToAccept: false);

            // Mark the block as complete.  This should cause the block to reserve/release any postponed messages,
            // which will cause the block to fault.
            bb.Complete();
            await Assert.ThrowsAsync<FormatException>(() => bb.Completion);
        }
예제 #12
0
 public async Task TestFaultySource()
 {
     var bb = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 1 });
     bb.Post(1);
     var source = new DelegatePropagator<int, int> {
         ConsumeMessageDelegate = delegate(DataflowMessageHeader messageHeader, ITargetBlock<int> target, out bool messageConsumed) {
             throw new FormatException();
         }
     };
     Assert.Equal(
         expected: DataflowMessageStatus.Postponed,
         actual: ((ITargetBlock<int>)bb).OfferMessage(new DataflowMessageHeader(1), 2, source, true));
     Assert.Equal(expected: 1, actual: bb.Receive());
     await Assert.ThrowsAsync<FormatException>(() => bb.Completion);
 }