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); }
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)); } } }
public async Task TestNonGreedyReleasingFailsAtCompletion() { var joinBlock = new JoinBlock <int, int>(new GroupingDataflowBlockOptions { Greedy = false }); var source = new DelegatePropagator <int, int> { ReserveMessageDelegate = (header, target) => true, ReleaseMessageDelegate = delegate { throw new FormatException(); } }; joinBlock.Target1.OfferMessage(new DataflowMessageHeader(1), 1, source, consumeToAccept: true); joinBlock.Complete(); await Assert.ThrowsAsync <FormatException>(() => joinBlock.Completion); }
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); }
public async Task TestReleasingFailsAtCompletion() { var bb = new BufferBlock <int>(new DataflowBlockOptions { BoundedCapacity = 1 }); bb.Post(1); var source = new DelegatePropagator <int, int> { ReserveMessageDelegate = (header, target) => true, ReleaseMessageDelegate = delegate { throw new FormatException(); } }; ((ITargetBlock <int>)bb).OfferMessage(new DataflowMessageHeader(1), 1, source, consumeToAccept: false); bb.Complete(); Assert.Equal(expected: 1, actual: bb.Receive()); await Assert.ThrowsAsync <FormatException>(() => bb.Completion); }
internal static async Task TestReserveAndRelease <T>( IReceivableSourceBlock <T> block, bool reservationIsTargetSpecific = true) { var tcs = new TaskCompletionSource <bool>(); // Offer the message to a target and wait until it's postponed var offeredMessage = default(DataflowMessageHeader); var target = new DelegatePropagator <T, T> { OfferMessageDelegate = (messageHeader, value, source, consumeToAccept) => { offeredMessage = messageHeader; tcs.TrySetResult(true); return(DataflowMessageStatus.Postponed); } }; block.LinkTo(target); await tcs.Task; Assert.False(block.ReserveMessage(new DataflowMessageHeader(-99), target)); // reserving a different message should fail Assert.True(block.ReserveMessage(offeredMessage, target)); // reserve the message Assert.False(block.ReserveMessage(new DataflowMessageHeader(-99), target)); // reserving a different message should still fail if (reservationIsTargetSpecific) { Assert.False(block.ReserveMessage(offeredMessage, DataflowBlock.NullTarget <T>())); // another block tries to reserve the message Assert.Throws <InvalidOperationException>(() => block.ReleaseReservation(offeredMessage, DataflowBlock.NullTarget <T>())); // another block tries to release the message } T item; Assert.Equal(expected: !reservationIsTargetSpecific, actual: block.TryReceive(out item)); // anyone tries to receive Assert.Throws <InvalidOperationException>(() => block.ReleaseReservation(new DataflowMessageHeader(-42), target)); // anyone tries to release a reservation on a different message block.ReleaseReservation(offeredMessage, target); // release the reservation Assert.True(block.TryReceive(out item)); // now receiving should work }
internal static async Task TestOfferMessage_AcceptsViaLinking <T>(ITargetBlock <T> target, int messages = 3) { var src = new BufferBlock <T>(); var stingySource = new DelegatePropagator <T, T> { ConsumeMessageDelegate = (DataflowMessageHeader _, ITargetBlock <T> __, out bool messageConsumed) => { messageConsumed = false; return(default(T)); } }; Assert.Equal( expected: DataflowMessageStatus.NotAvailable, actual: target.OfferMessage(new DataflowMessageHeader(1), default(T), stingySource, consumeToAccept: true)); src.PostRange(1, messages + 1, i => default(T)); Assert.Equal(expected: messages, actual: src.Count); src.LinkTo(target); src.Complete(); await src.Completion; }
public async Task TestNonGreedyConsumingFailsWhileJoining() { var joinBlock = new JoinBlock <int, int>(new GroupingDataflowBlockOptions { Greedy = false }); var source1 = new DelegatePropagator <int, int> { ReserveMessageDelegate = (header, target) => true, ConsumeMessageDelegate = delegate(DataflowMessageHeader messageHeader, ITargetBlock <int> target, out bool messageConsumed) { throw new FormatException(); } }; joinBlock.Target1.OfferMessage(new DataflowMessageHeader(1), 1, source1, consumeToAccept: true); var source2 = new BufferBlock <int>(); source2.Post(2); source2.LinkTo(joinBlock.Target2); await Assert.ThrowsAsync <FormatException>(() => joinBlock.Completion); }
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 } }
internal static async Task TestReserveAndConsume <T>( ISourceBlock <T> block, bool reservationIsTargetSpecific = true) { bool consumed; block.ConsumeMessage(new DataflowMessageHeader(-99), new ActionBlock <T>(i => { }), out consumed); Assert.False(consumed); var tcs = new TaskCompletionSource <bool>(); var offeredMessage = default(DataflowMessageHeader); var target = new DelegatePropagator <T, T> { OfferMessageDelegate = (messageHeader, value, source, consumeToAccept) => { offeredMessage = messageHeader; tcs.TrySetResult(true); return(DataflowMessageStatus.Postponed); } }; block.LinkTo(target); await tcs.Task; Assert.True(block.ReserveMessage(offeredMessage, target)); // reserve the message if (reservationIsTargetSpecific) { block.ConsumeMessage(offeredMessage, new ActionBlock <T>(delegate { }), out consumed); // different target tries to consume Assert.False(consumed); } block.ConsumeMessage(new DataflowMessageHeader(-99), target, out consumed); // right target, wrong message Assert.False(consumed); block.ConsumeMessage(offeredMessage, target, out consumed); // right target, right message Assert.True(consumed); }