/* * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.openflowjava.protocol.impl.core.connection; import com.google.common.util.concurrent.FutureCallback; import javax.annotation.Nullable; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueException; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.MultipartRequestFlags; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowModInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessageBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketOutInputBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@link OutboundQueueEntry} class test */ @RunWith(MockitoJUnitRunner.class) public class OutboundQueueEntryTest { private static final Logger LOG = LoggerFactory.getLogger(OutboundQueueEntryTest.class); private static final short VERSION = (short) 13; private static final long VALUE = 1L; private Integer failCounter = 0; @Mock private OfHeader ofHeader; @Mock private FutureCallback<OfHeader> futureCallback; private final OutboundQueueEntry outboundQueueEntry = new OutboundQueueEntry(); private final OfHeader barrierInput = new BarrierInputBuilder().setVersion(VERSION).setXid(VALUE).build(); private final OfHeader packetOutInput = new PacketOutInputBuilder().setVersion(VERSION).setXid(VALUE).build(); private final OfHeader multipartReplyMessage = new MultipartReplyMessageBuilder().setVersion(VERSION).setXid(VALUE).setFlags(new MultipartRequestFlags(false)).build(); private final OfHeader flowModInput = new FlowModInputBuilder().setVersion(VERSION).setXid(VALUE).build(); private final OfHeader flowRemoved = new FlowRemovedMessageBuilder().setVersion(VERSION).setXid(VALUE).build(); @Test public void commit() throws Exception { outboundQueueEntry.commit(ofHeader, futureCallback); Assert.assertTrue(outboundQueueEntry.isCommitted()); Assert.assertFalse(outboundQueueEntry.isCompleted()); Assert.assertFalse(outboundQueueEntry.isBarrier()); } @Test public void reset() throws Exception { outboundQueueEntry.commit(ofHeader, futureCallback); Assert.assertTrue(outboundQueueEntry.isCommitted()); outboundQueueEntry.reset(); Assert.assertFalse(outboundQueueEntry.isCommitted()); } @Test public void isBarrier() throws Exception { outboundQueueEntry.commit(barrierInput, futureCallback); Assert.assertTrue(outboundQueueEntry.isBarrier()); } @Test public void takeMessage() throws Exception { outboundQueueEntry.commit(packetOutInput, futureCallback); outboundQueueEntry.takeMessage(); Mockito.verify(futureCallback).onSuccess(Mockito.<OfHeader>any()); } @Test public void complete() throws Exception { final boolean result = outboundQueueEntry.complete(multipartReplyMessage); Assert.assertTrue(result); Assert.assertTrue(outboundQueueEntry.isCompleted()); } @Test(expected = IllegalStateException.class) public void completeTwice() throws Exception { outboundQueueEntry.complete(multipartReplyMessage); outboundQueueEntry.complete(multipartReplyMessage); } @Test public void fail() throws Exception { outboundQueueEntry.commit(ofHeader, futureCallback); outboundQueueEntry.fail(null); Mockito.verify(futureCallback).onFailure(Mockito.<OutboundQueueException>any()); } private Integer increaseFailCounter() { return ++this.failCounter; } @Test public void test() throws Exception { final FutureCallback<OfHeader> result = new FutureCallback<OfHeader>() { @Override public void onSuccess(@Nullable OfHeader ofHeader) { LOG.info("onSuccess: xid: {}", ofHeader.getXid()); } @Override public void onFailure(Throwable throwable) { LOG.info("onFailure! Error: {}", throwable); LOG.info("Failure called {} time", increaseFailCounter()); } }; /** This scenario creates entry with XID 1 then commit it, fail it and again commit it */ /** Simulates behavior when entry is committed after fail */ /** It shouldn't be in state completed and still have callback, it can consume all threads in thread pool */ /** Entry but no callback */ outboundQueueEntry.commit(flowModInput, null); /** Failed entry for whatever reason */ outboundQueueEntry.fail(null); /** Commit the same entry adding callback */ outboundQueueEntry.commit(flowModInput, result); Assert.assertTrue(outboundQueueEntry.isCompleted()); Assert.assertTrue(outboundQueueEntry.isCommitted()); /** This is check that no callback is in entry stuck */ Assert.assertFalse(outboundQueueEntry.hasCallback()); Assert.assertTrue(this.failCounter == 1); } }