/** * Copyright 2007-2015, Kaazing Corporation. All rights reserved. * * 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 org.kaazing.k3po.driver.internal.netty.channel; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jmock.integration.junit4.JUnitRuleMockery; import org.junit.Rule; import org.junit.Test; import org.kaazing.k3po.driver.internal.jmock.Expectations; /** * Convenience class that simply overRides toString to not print out the channel * to facilitate easier testing (no regex's needed, simple string comparison) * */ public class CompositeChannelFutureTest { @Rule public final JUnitRuleMockery context = new JUnitRuleMockery(); private final Channel channel = context.mock(Channel.class); @Test public void shouldBeSucceededAfterConstructionWithAllKidsSucceeded() throws Exception { final ChannelFuture future1 = context.mock(ChannelFuture.class, "future1"); final ChannelFuture future2 = context.mock(ChannelFuture.class, "future2"); Collection<ChannelFuture> futures = Arrays.asList(future1, future2); context.checking(new Expectations() { { oneOf(future1).addListener(with(any(ChannelFutureListener.class))); will(callChannelFutureListener(future1)); oneOf(future2).addListener(with(any(ChannelFutureListener.class))); will(callChannelFutureListener(future2)); oneOf(future1).isSuccess(); will(returnValue(true)); oneOf(future1).isCancelled(); will(returnValue(false)); oneOf(future2).isSuccess(); will(returnValue(true)); oneOf(future2).isCancelled(); will(returnValue(false)); } }); CompositeChannelFuture<ChannelFuture> composite = new CompositeChannelFuture<ChannelFuture>(channel, futures); assertTrue(composite.isSuccess()); } @Test public void shouldBeSucceededAfterConstructionWithKidsSucceededAndCancelled() throws Exception { final ChannelFuture future1 = context.mock(ChannelFuture.class, "future1"); final ChannelFuture future2 = context.mock(ChannelFuture.class, "future2"); Collection<ChannelFuture> futures = Arrays.asList(future1, future2); context.checking(new Expectations() { { oneOf(future1).addListener(with(any(ChannelFutureListener.class))); will(callChannelFutureListener(future1)); oneOf(future2).addListener(with(any(ChannelFutureListener.class))); will(callChannelFutureListener(future2)); oneOf(future1).isSuccess(); will(returnValue(true)); oneOf(future1).isCancelled(); will(returnValue(false)); oneOf(future2).isSuccess(); will(returnValue(false)); oneOf(future2).isCancelled(); will(returnValue(true)); } }); CompositeChannelFuture<ChannelFuture> composite = new CompositeChannelFuture<ChannelFuture>(channel, futures); assertTrue(composite.isDone()); assertTrue(composite.isSuccess()); assertFalse(composite.isCancelled()); } @Test public void shouldBeFailedAfterConstructionWithAllKidsDoneOneFailed() throws Exception { final ChannelFuture future1 = context.mock(ChannelFuture.class, "future1"); final ChannelFuture future2 = context.mock(ChannelFuture.class, "future2"); Collection<ChannelFuture> futures = Arrays.asList(future1, future2); final Exception exception = new Exception("Test exception"); context.checking(new Expectations() { { oneOf(future1).addListener(with(any(ChannelFutureListener.class))); will(callChannelFutureListener(future1)); oneOf(future2).addListener(with(any(ChannelFutureListener.class))); will(callChannelFutureListener(future2)); oneOf(future1).isSuccess(); will(returnValue(true)); oneOf(future1).isCancelled(); will(returnValue(false)); oneOf(future1).getCause(); oneOf(future2).isSuccess(); will(returnValue(false)); oneOf(future2).isCancelled(); will(returnValue(false)); oneOf(future2).getCause(); will(returnValue(exception)); } }); CompositeChannelFuture<ChannelFuture> composite = new CompositeChannelFuture<ChannelFuture>(channel, futures); assertTrue(composite.isDone()); assertSame(exception, composite.getCause()); } @Test public void shouldSucceedOnlyWhenAllKidsHaveSucceeded() throws Exception { final ChannelFuture future1 = context.mock(ChannelFuture.class, "future1"); final ChannelFuture future2 = context.mock(ChannelFuture.class, "future2"); Collection<ChannelFuture> futures = Arrays.asList(future1, future2); final ChannelFutureListener testListener = context.mock(ChannelFutureListener.class, "testListener"); final List<ChannelFutureListener> listeners = new ArrayList<ChannelFutureListener>(); context.checking(new Expectations() { { oneOf(future1).addListener(with(any(ChannelFutureListener.class))); will(saveParameter(0, listeners)); oneOf(future2).addListener(with(any(ChannelFutureListener.class))); will(saveParameter(0, listeners)); } }); CompositeChannelFuture<ChannelFuture> composite = new CompositeChannelFuture<ChannelFuture>(channel, futures); context.assertIsSatisfied(); composite.addListener(testListener); context.checking(new Expectations() { { oneOf(future1).isDone(); will(returnValue(false)); } }); assertFalse(composite.isDone()); context.assertIsSatisfied(); context.checking(new Expectations() { { oneOf(future1).isSuccess(); will(returnValue(true)); oneOf(future1).isCancelled(); will(returnValue(false)); } }); listeners.get(0).operationComplete(future1); context.assertIsSatisfied(); context.checking(new Expectations() { { oneOf(future1).isDone(); will(returnValue(true)); oneOf(future2).isDone(); will(returnValue(false)); } }); assertFalse(composite.isDone()); context.assertIsSatisfied(); context.checking(new Expectations() { { oneOf(future2).isSuccess(); will(returnValue(true)); oneOf(future2).isCancelled(); will(returnValue(false)); oneOf(testListener).operationComplete(with(composite)); } }); listeners.get(1).operationComplete(future2); assertTrue(composite.isSuccess()); } @Test public void shouldFailOnlyWhenAllKidsHaveCompleted() throws Exception { final ChannelFuture future1 = context.mock(ChannelFuture.class, "future1"); final ChannelFuture future2 = context.mock(ChannelFuture.class, "future2"); Collection<ChannelFuture> futures = Arrays.asList(future1, future2); final ChannelFutureListener testListener = context.mock(ChannelFutureListener.class, "testListener"); final List<ChannelFutureListener> listeners = new ArrayList<ChannelFutureListener>(); final Exception testException = new Exception("test exception"); context.checking(new Expectations() { { oneOf(future1).addListener(with(any(ChannelFutureListener.class))); will(saveParameter(0, listeners)); oneOf(future2).addListener(with(any(ChannelFutureListener.class))); will(saveParameter(0, listeners)); } }); CompositeChannelFuture<ChannelFuture> composite = new CompositeChannelFuture<ChannelFuture>(channel, futures); context.assertIsSatisfied(); composite.addListener(testListener); context.checking(new Expectations() { { oneOf(future1).isDone(); will(returnValue(false)); } }); assertFalse(composite.isDone()); context.checking(new Expectations() { { oneOf(future1).isSuccess(); will(returnValue(false)); oneOf(future1).isCancelled(); will(returnValue(false)); oneOf(future1).getCause(); will(returnValue(testException)); } }); listeners.get(0).operationComplete(future1); context.checking(new Expectations() { { oneOf(future1).isDone(); will(returnValue(true)); oneOf(future2).isDone(); will(returnValue(false)); } }); assertFalse(composite.isDone()); context.checking(new Expectations() { { oneOf(future2).isSuccess(); will(returnValue(true)); oneOf(future2).isCancelled(); will(returnValue(false)); oneOf(testListener).operationComplete(with(composite)); } }); listeners.get(1).operationComplete(future2); assertTrue(composite.isDone()); assertSame(testException, composite.getCause()); } @Test public void shouldFailFast() throws Exception { final ChannelFuture future1 = context.mock(ChannelFuture.class, "future1"); final ChannelFuture future2 = context.mock(ChannelFuture.class, "future2"); Collection<ChannelFuture> futures = Arrays.asList(future1, future2); final ChannelFutureListener testListener = context.mock(ChannelFutureListener.class, "testListener"); final List<ChannelFutureListener> listeners = new ArrayList<ChannelFutureListener>(); final Exception testException = new Exception("test exception"); context.checking(new Expectations() { { oneOf(future1).addListener(with(any(ChannelFutureListener.class))); will(saveParameter(0, listeners)); oneOf(future2).addListener(with(any(ChannelFutureListener.class))); will(saveParameter(0, listeners)); } }); CompositeChannelFuture<ChannelFuture> composite = new CompositeChannelFuture<ChannelFuture>(channel, futures, true); composite.addListener(testListener); context.checking(new Expectations() { { oneOf(future1).isDone(); will(returnValue(false)); } }); assertFalse(composite.isDone()); context.checking(new Expectations() { { oneOf(future1).isSuccess(); will(returnValue(false)); oneOf(future1).isCancelled(); will(returnValue(false)); oneOf(future1).getCause(); will(returnValue(testException)); oneOf(testListener).operationComplete(with(composite)); } }); listeners.get(0).operationComplete(future1); assertTrue(composite.isDone()); assertSame(testException, composite.getCause()); } @Test public void toStringShouldBeHelpful() throws Exception { final ChannelFuture success = context.mock(ChannelFuture.class, "success"); final ChannelFuture cancelled = context.mock(ChannelFuture.class, "cancelled"); final ChannelFuture incomplete = context.mock(ChannelFuture.class, "incomplete"); final ChannelFuture failed = context.mock(ChannelFuture.class, "failed"); Collection<ChannelFuture> futures = Arrays.asList(success, cancelled, incomplete, failed); final Exception testException = new Exception("test exception"); context.checking(new Expectations() { { oneOf(success).addListener(with(any(ChannelFutureListener.class))); oneOf(cancelled).addListener(with(any(ChannelFutureListener.class))); oneOf(incomplete).addListener(with(any(ChannelFutureListener.class))); oneOf(failed).addListener(with(any(ChannelFutureListener.class))); allowing(success).isDone(); will(returnValue(true)); allowing(success).isSuccess(); will(returnValue(true)); allowing(success).getCause(); allowing(cancelled).isDone(); will(returnValue(true)); allowing(cancelled).isSuccess(); will(returnValue(false)); allowing(cancelled).isCancelled(); will(returnValue(true)); allowing(cancelled).getCause(); allowing(incomplete).isDone(); will(returnValue(false)); allowing(incomplete).isSuccess(); will(returnValue(false)); allowing(incomplete).isCancelled(); will(returnValue(false)); allowing(incomplete).getCause(); allowing(failed).isDone(); will(returnValue(true)); allowing(failed).isSuccess(); will(returnValue(false)); allowing(failed).isCancelled(); will(returnValue(false)); allowing(failed).getCause(); will(returnValue(testException)); } }); CompositeChannelFuture<ChannelFuture> composite = new CompositeChannelFuture<ChannelFuture>(channel, futures, true); assertFalse(composite.isDone()); //System.out.println(composite.toString()); assertTrue(composite.toString().matches( "(?s).*success.*success.*cancelled.*cancelled.*incomplete.*incomplete.*failed.*failed.*test exception.*")); } }