/* * Copyright (c) 2013-2015, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.strands.channels.reactivestreams; import co.paralleluniverse.fibers.Fiber; import co.paralleluniverse.fibers.SuspendExecution; import co.paralleluniverse.strands.Strand; import co.paralleluniverse.strands.SuspendableAction2; import co.paralleluniverse.strands.SuspendableRunnable; import co.paralleluniverse.strands.channels.Channel; import co.paralleluniverse.strands.channels.Channels; import co.paralleluniverse.strands.channels.Channels.OverflowPolicy; import co.paralleluniverse.strands.channels.ReceivePort; import co.paralleluniverse.strands.channels.SendPort; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import org.reactivestreams.Processor; import org.reactivestreams.Publisher; import org.testng.annotations.*; import static org.testng.Assert.*; public class TwoSidedTest { private static final long ELEMENTS = 10000; private final int buffer; private final OverflowPolicy overflowPolicy; private final boolean batch; @Factory(dataProvider = "params") public TwoSidedTest(int buffer, OverflowPolicy overflowPolicy, boolean batch) { this.buffer = buffer; this.overflowPolicy = overflowPolicy; this.batch = batch; } @DataProvider(name = "params") public static Object[][] data() { return new Object[][]{ {5, OverflowPolicy.THROW, false}, // {5, OverflowPolicy.THROW, true}, {5, OverflowPolicy.BLOCK, false}, // {5, OverflowPolicy.BLOCK, true}, {-1, OverflowPolicy.THROW, false}, // {-1, OverflowPolicy.THROW, true}, // {5, OverflowPolicy.DISPLACE, false}, // {5, OverflowPolicy.DISPLACE, true}, {1, OverflowPolicy.BLOCK, false}, // {1, OverflowPolicy.BLOCK, true} }; } @Test public void twoSidedTest() throws Exception { // Publisher final Channel<Integer> publisherChannel = Channels.newChannel(random() ? 0 : 5, OverflowPolicy.BLOCK); final Strand publisherStrand = new Fiber<Void>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { for (long i = 0; i < ELEMENTS; i++) publisherChannel.send((int) (i % 1000)); publisherChannel.close(); } }).start(); final Publisher publisher = ReactiveStreams.toPublisher(publisherChannel); // Subscriber final ReceivePort<Integer> subscriberChannel = ReactiveStreams.subscribe(buffer, overflowPolicy, publisher); final Strand subscriberStrand = new Fiber<Void>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { long count = 0; for (;;) { Integer x = subscriberChannel.receive(); if (x == null) break; assertEquals(count % 1000, x.longValue()); count++; } subscriberChannel.close(); assertEquals(ELEMENTS, count); } }).start(); subscriberStrand.join(5, TimeUnit.SECONDS); publisherStrand.join(5, TimeUnit.SECONDS); } @Test public void twoSidedTestWithProcessor() throws Exception { // Publisher final Channel<Integer> publisherChannel = Channels.newChannel(random() ? 0 : 5, OverflowPolicy.BLOCK); final Strand publisherStrand = new Fiber<Void>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { for (long i = 0; i < ELEMENTS; i++) publisherChannel.send((int) (i % 1000)); publisherChannel.close(); } }).start(); final Publisher<Integer> publisher = ReactiveStreams.toPublisher(publisherChannel); // Processor final Processor<Integer, Integer> processor = ReactiveStreams.toProcessor(5, OverflowPolicy.BLOCK, new SuspendableAction2<ReceivePort<Integer>, SendPort<Integer>>() { @Override public void call(ReceivePort<Integer> in, SendPort<Integer> out) throws SuspendExecution, InterruptedException { long count = 0; for (Integer element; ((element = in.receive()) != null); count++) { out.send(element * 10); out.send(element * 100); // Fiber.sleep(1); // just for fun assertTrue(count < ELEMENTS); } assertEquals(ELEMENTS, count); out.close(); } }); publisher.subscribe(processor); // Subscriber final ReceivePort<Integer> subscriberChannel = ReactiveStreams.subscribe(buffer, overflowPolicy, processor); final Strand subscriberStrand = new Fiber<Void>(new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { long count = 0; for (;;) { Integer x = subscriberChannel.receive(); if (x == null) break; assertTrue(x % 10 == 0); if (count % 2 != 0) assertTrue(x % 100 == 0); count++; } subscriberChannel.close(); assertEquals(ELEMENTS * 2, count); } }).start(); subscriberStrand.join(5, TimeUnit.SECONDS); publisherStrand.join(5, TimeUnit.SECONDS); } private boolean random() { return ThreadLocalRandom.current().nextBoolean(); } }