/* * Copyright (C) 2015 SoftIndex LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.datakernel.stream; import io.datakernel.eventloop.Eventloop; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; import static io.datakernel.eventloop.FatalErrorHandlers.rethrowOnAnyError; import static io.datakernel.stream.StreamStatus.*; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; public class StreamRewiringWithStatus { private Eventloop eventloop; private List<Integer> list; private Iterator<Integer> it; @Before public void before() { it = asList(1, 2, 3, 4, 5).iterator(); eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError()); list = new ArrayList<>(); } @Test public void testStartProducerReadyConsumerReady() { StreamConsumer<Integer> startStatusReadyConsumer = new TestConsumerOneByOne(eventloop); StreamProducer<Integer> startStatusReadyProducer = new TestProducerOfIterator(eventloop, it); startStatusReadyProducer.streamTo(startStatusReadyConsumer); eventloop.run(); assertEquals(asList(1, 2, 3, 4, 5), list); assertEquals(END_OF_STREAM, startStatusReadyProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusReadyConsumer.getConsumerStatus()); } @Test public void testStartProducerReadyConsumerSuspend() { StreamConsumer<Integer> startStatusSuspendConsumer = new TestConsumerOneByOne(eventloop) {{ suspend(); }}; StreamProducer<Integer> startStatusReadyProducer = new TestProducerOfIterator(eventloop, it); startStatusReadyProducer.streamTo(startStatusSuspendConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(SUSPENDED, startStatusReadyProducer.getProducerStatus()); assertEquals(SUSPENDED, startStatusSuspendConsumer.getConsumerStatus()); } @Test public void testStartProducerReadyConsumerEndOfStream() { StreamConsumer<Integer> startStatusEndConsumer = new TestConsumerOneByOne(eventloop) {{ onProducerEndOfStream(); }}; StreamProducer<Integer> startStatusReadyProducer = new TestProducerOfIterator(eventloop, it); startStatusReadyProducer.streamTo(startStatusEndConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusReadyProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusEndConsumer.getConsumerStatus()); } @Test public void testStartProducerReadyConsumerClosedWithError() { StreamConsumer<Integer> startStatusClosedWithErrorConsumer = new TestConsumerOneByOne(eventloop) {{ closeWithError(new Exception()); }}; StreamProducer<Integer> startStatusReadyProducer = new TestProducerOfIterator(eventloop, it); startStatusReadyProducer.streamTo(startStatusClosedWithErrorConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusReadyProducer.getProducerStatus()); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorConsumer.getConsumerStatus()); } //------------------------------------------------------------------------------------------------------------------ @Test public void testStartProducerSuspendConsumerReady() { StreamConsumer<Integer> startStatusReadyConsumer = new TestConsumerOneByOne(eventloop); StreamProducer<Integer> startStatusSuspendProducer = new TestProducerOfIterator(eventloop, it) {{ onConsumerSuspended(); }}; startStatusSuspendProducer.streamTo(startStatusReadyConsumer); eventloop.run(); assertEquals(asList(1, 2, 3, 4, 5), list); assertEquals(END_OF_STREAM, startStatusSuspendProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusReadyConsumer.getConsumerStatus()); } @Test public void testStartProducerSuspendConsumerSuspend() { StreamConsumer<Integer> startStatusSuspendConsumer = new TestConsumerOneByOne(eventloop) {{ suspend(); }}; StreamProducer<Integer> startStatusSuspendProducer = new TestProducerOfIterator(eventloop, it) {{ onConsumerSuspended(); }}; startStatusSuspendProducer.streamTo(startStatusSuspendConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(SUSPENDED, startStatusSuspendProducer.getProducerStatus()); assertEquals(SUSPENDED, startStatusSuspendConsumer.getConsumerStatus()); } @Test public void testStartProducerSuspendConsumerEndOfStream() { StreamConsumer<Integer> startStatusEndConsumer = new TestConsumerOneByOne(eventloop) {{ onProducerEndOfStream(); }}; StreamProducer<Integer> startStatusSuspendProducer = new TestProducerOfIterator(eventloop, it) {{ onConsumerSuspended(); }}; startStatusSuspendProducer.streamTo(startStatusEndConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusSuspendProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusEndConsumer.getConsumerStatus()); } @Test public void testStartProducerSuspendConsumerClosedWithError() { StreamConsumer<Integer> startStatusClosedWithErrorConsumer = new TestConsumerOneByOne(eventloop) {{ closeWithError(new Exception()); }}; StreamProducer<Integer> startStatusSuspendProducer = new TestProducerOfIterator(eventloop, it) {{ onConsumerSuspended(); }}; startStatusSuspendProducer.streamTo(startStatusClosedWithErrorConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusSuspendProducer.getProducerStatus()); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorConsumer.getConsumerStatus()); } //------------------------------------------------------------------------------------------------------------------ @Test public void testStartProducerEndOfStreamConsumerReady() { StreamConsumer<Integer> startStatusReadyConsumer = new TestConsumerOneByOne(eventloop); StreamProducer<Integer> startStatusEndProducer = new TestProducerOfIterator(eventloop, it) {{ sendEndOfStream(); }}; startStatusEndProducer.streamTo(startStatusReadyConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(END_OF_STREAM, startStatusEndProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusReadyConsumer.getConsumerStatus()); } @Test public void testStartProducerEndOfStreamConsumerSuspend() { StreamConsumer<Integer> startStatusSuspendConsumer = new TestConsumerOneByOne(eventloop) {{ suspend(); }}; StreamProducer<Integer> startStatusEndProducer = new TestProducerOfIterator(eventloop, it) {{ sendEndOfStream(); }}; startStatusEndProducer.streamTo(startStatusSuspendConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(END_OF_STREAM, startStatusEndProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusSuspendConsumer.getConsumerStatus()); } @Test public void testStartProducerEndOfStreamConsumerEndOfStream() { StreamConsumer<Integer> startStatusEndConsumer = new TestConsumerOneByOne(eventloop) {{ onProducerEndOfStream(); }}; StreamProducer<Integer> startStatusEndProducer = new TestProducerOfIterator(eventloop, it) {{ sendEndOfStream(); }}; startStatusEndProducer.streamTo(startStatusEndConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(END_OF_STREAM, startStatusEndProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusEndConsumer.getConsumerStatus()); } @Test public void testStartProducerEndOfStreamConsumerClosedWithError() { StreamConsumer<Integer> startStatusClosedWithErrorConsumer = new TestConsumerOneByOne(eventloop) {{ closeWithError(new Exception()); }}; StreamProducer<Integer> startStatusEndProducer = new TestProducerOfIterator(eventloop, it) {{ sendEndOfStream(); }}; startStatusEndProducer.streamTo(startStatusClosedWithErrorConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(END_OF_STREAM, startStatusEndProducer.getProducerStatus()); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorConsumer.getConsumerStatus()); } //------------------------------------------------------------------------------------------------------------------ @Test public void testStartCloseWithErrorConsumerReady() { StreamConsumer<Integer> startStatusReadyConsumer = new TestConsumerOneByOne(eventloop); StreamProducer<Integer> startStatusClosedWithErrorProducer = new TestProducerOfIterator(eventloop, it) {{ closeWithError(new Exception()); }}; startStatusClosedWithErrorProducer.streamTo(startStatusReadyConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorProducer.getProducerStatus()); assertEquals(CLOSED_WITH_ERROR, startStatusReadyConsumer.getConsumerStatus()); } @Test public void testStartCloseWithErrorConsumerSuspend() { StreamConsumer<Integer> startStatusSuspendConsumer = new TestConsumerOneByOne(eventloop) {{ suspend(); }}; StreamProducer<Integer> startStatusClosedWithErrorProducer = new TestProducerOfIterator(eventloop, it) {{ closeWithError(new Exception()); }}; startStatusClosedWithErrorProducer.streamTo(startStatusSuspendConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorProducer.getProducerStatus()); assertEquals(CLOSED_WITH_ERROR, startStatusSuspendConsumer.getConsumerStatus()); } @Test public void testStartCloseWithErrorConsumerEndOfStream() { StreamConsumer<Integer> startStatusEndConsumer = new TestConsumerOneByOne(eventloop) {{ onProducerEndOfStream(); }}; StreamProducer<Integer> startStatusClosedWithErrorProducer = new TestProducerOfIterator(eventloop, it) {{ closeWithError(new Exception()); }}; startStatusClosedWithErrorProducer.streamTo(startStatusEndConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorProducer.getProducerStatus()); assertEquals(END_OF_STREAM, startStatusEndConsumer.getConsumerStatus()); } @Test public void testStartCloseWithErrorConsumerClosedWithError() { StreamConsumer<Integer> startStatusClosedWithErrorConsumer = new TestConsumerOneByOne(eventloop) {{ closeWithError(new Exception()); }}; StreamProducer<Integer> startStatusClosedWithErrorProducer = new TestProducerOfIterator(eventloop, it) {{ closeWithError(new Exception()); }}; startStatusClosedWithErrorProducer.streamTo(startStatusClosedWithErrorConsumer); eventloop.run(); assertEquals(Collections.emptyList(), list); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorProducer.getProducerStatus()); assertEquals(CLOSED_WITH_ERROR, startStatusClosedWithErrorConsumer.getConsumerStatus()); } //------------------------------------------------------------------------------------------------------------------ private class TestConsumerOneByOne extends AbstractStreamConsumer<Integer> { protected TestConsumerOneByOne(Eventloop eventloop) { super(eventloop); } @Override public StreamDataReceiver<Integer> getDataReceiver() { return new StreamDataReceiver<Integer>() { @Override public void onData(Integer item) { list.add(item); suspend(); eventloop.post(new Runnable() { @Override public void run() { resume(); } }); } }; } } private class TestProducerOfIterator extends AbstractStreamProducer<Integer> { private final Iterator<Integer> iterator; private boolean sendEndOfStream = true; public TestProducerOfIterator(Eventloop eventloop, Iterator<Integer> iterator) { this(eventloop, iterator, true); } public TestProducerOfIterator(Eventloop eventloop, Iterator<Integer> iterator, boolean sendEndOfStream) { super(eventloop); this.iterator = checkNotNull(iterator); this.sendEndOfStream = sendEndOfStream; } @Override protected void doProduce() { for (; ; ) { if (!iterator.hasNext()) break; if (!isStatusReady()) return; Integer item = iterator.next(); send(item); } if (sendEndOfStream) sendEndOfStream(); } @Override protected void onStarted() { produce(); } @Override protected void onResumed() { resumeProduce(); } } }