internal static bool TestBoundingJoin3 <TInput>(JoinBlock <TInput, TInput, TInput> join, bool greedy) { Console.WriteLine("* TestBoundingJoin3 {0} ({1})", join.GetType().Name, greedy ? "greedy" : "non-greedy"); bool passed = true; bool localPassed = true; int i; var send1 = new Task <bool> [3 * BOUNDED_CAPACITY]; var send2 = new Task <bool> [3]; // Send messages up to the bounding capacity for (i = 0; localPassed && i < BOUNDED_CAPACITY; i++) { // All should be accepted immediately in greedy mode send1[i] = join.Target1.SendAsync(default(TInput)); send1[BOUNDED_CAPACITY + i] = join.Target2.SendAsync(default(TInput)); send1[2 * BOUNDED_CAPACITY + i] = join.Target3.SendAsync(default(TInput)); if (greedy) { localPassed = send1[i].Wait(0) && send1[i].Result && send1[BOUNDED_CAPACITY + i].Wait(0) && send1[BOUNDED_CAPACITY + i].Result && send1[2 * BOUNDED_CAPACITY + i].Wait(0) && send1[2 * BOUNDED_CAPACITY + i].Result; } } // In non-greedy mode, all should be accepted afterwards if (!greedy) { localPassed = Task.WaitAll(send1, COMPLETE_TIMEOUT); } passed &= localPassed; Assert.True(localPassed, string.Format("FAILED to send up to capacity ({0}) at iteration {1}", BOUNDED_CAPACITY, i)); // Send one more message to each target - it should be postponed (not consumed) send2[0] = join.Target1.SendAsync(default(TInput)); send2[1] = join.Target2.SendAsync(default(TInput)); send2[2] = join.Target3.SendAsync(default(TInput)); localPassed = !Task.WaitAll(send2, NOT_COMPLETED_TIMEOUT); passed &= localPassed; Assert.True(localPassed, "FAILED to postpone the excess message"); // Unblock at least one message Tuple <TInput, TInput, TInput> item; join.TryReceive(out item); // Now the excess items should be consumed localPassed = send2[0].Wait(COMPLETE_TIMEOUT); passed &= localPassed; Assert.True(localPassed, "FAILED to consume the excess message after unblocking"); return(passed); }