Merge "fix failure during connecting device when channelActive happens later than...
authorJakub Morvay <jakub.morvay@gmail.com>
Thu, 12 Apr 2018 14:20:59 +0000 (14:20 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 12 Apr 2018 14:20:59 +0000 (14:20 +0000)
1  2 
netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java
netconf/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorTest.java

index 3212754c26a435e8b6ffff2d005f5d6211d50264,0b456f447f8ce33be11239ec8901dcffe0a041aa..69dc1059b5535f8914c95c966b69e9ccaa451b68
@@@ -12,7 -12,6 +12,7 @@@ import com.google.common.base.Strings
  import com.google.common.collect.ImmutableSet;
  import com.google.common.collect.Interner;
  import com.google.common.collect.Interners;
 +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  import io.netty.channel.Channel;
  import io.netty.channel.ChannelFuture;
  import io.netty.channel.ChannelFutureListener;
@@@ -23,12 -22,12 +23,12 @@@ import io.netty.util.concurrent.Promise
  import java.util.Set;
  import javax.xml.xpath.XPathConstants;
  import javax.xml.xpath.XPathExpression;
 -import org.opendaylight.controller.config.util.xml.XmlUtil;
  import org.opendaylight.netconf.api.NetconfClientSessionPreferences;
  import org.opendaylight.netconf.api.NetconfDocumentedException;
  import org.opendaylight.netconf.api.NetconfMessage;
  import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
  import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
 +import org.opendaylight.netconf.api.xml.XmlUtil;
  import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer;
  import org.opendaylight.netconf.nettyutil.AbstractNetconfSessionNegotiator;
  import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
@@@ -64,18 -63,28 +64,29 @@@ public class NetconfClientSessionNegoti
          super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
      }
  
+     @SuppressWarnings("checkstyle:IllegalCatch")
      @Override
 +    @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
      protected void handleMessage(final NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
+         if (!ifNegotiatedAlready()) {
+             LOG.debug("Server hello message received, starting negotiation on channel {}", channel);
+             try {
+                 startNegotiation();
+             } catch (final Exception e) {
+                 LOG.warn("Unexpected negotiation failure", e);
+                 negotiationFailed(e);
+                 return;
+             }
+         }
          final NetconfClientSession session = getSessionForHelloMessage(netconfMessage);
          replaceHelloMessageInboundHandler(session);
  
          // If exi should be used, try to initiate exi communication
          // Call negotiationSuccessFul after exi negotiation is finished successfully or not
 -        if (shouldUseExi(netconfMessage)) {
 +        final NetconfMessage startExiMessage = sessionPreferences.getStartExiMessage();
 +        if (shouldUseExi(netconfMessage) && startExiMessage instanceof NetconfStartExiMessage) {
              LOG.debug("Netconf session {} should use exi.", session);
 -            NetconfStartExiMessage startExiMessage = (NetconfStartExiMessage) sessionPreferences.getStartExiMessage();
 -            tryToInitiateExi(session, startExiMessage);
 +            tryToInitiateExi(session, (NetconfStartExiMessage) startExiMessage);
          } else {
              // Exi is not supported, release session immediately
              LOG.debug("Netconf session {} isn't capable of using exi.", session);
          });
      }
  
 +    @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
      private boolean shouldUseExi(final NetconfHelloMessage helloMsg) {
          return containsExi10Capability(helloMsg.getDocument())
                  && containsExi10Capability(sessionPreferences.getHelloMessage().getDocument());
              }
          }
  
 -        return Long.valueOf(textContent);
 +        return Long.parseLong(textContent);
      }
  
      private static String getSessionIdWithXPath(final Document doc, final XPathExpression sessionIdXPath) {
index 874b0a17bacba21355500d063951589d2ba03494,12d4322ea081ba6625bb6fb3fde55a57f5495856..7b84cb0be481ae9ff77e7706a40923774718e704
@@@ -23,12 -23,12 +23,12 @@@ import static org.mockito.Mockito.verif
  import com.google.common.base.Optional;
  import com.google.common.collect.ImmutableSet;
  import io.netty.channel.Channel;
 -import io.netty.channel.ChannelFuture;
  import io.netty.channel.ChannelHandler;
  import io.netty.channel.ChannelHandlerContext;
  import io.netty.channel.ChannelInboundHandlerAdapter;
  import io.netty.channel.ChannelPipeline;
  import io.netty.channel.ChannelProgressivePromise;
 +import io.netty.channel.ChannelPromise;
  import io.netty.channel.EventLoop;
  import io.netty.handler.ssl.SslHandler;
  import io.netty.util.HashedWheelTimer;
@@@ -40,11 -40,13 +40,11 @@@ import java.util.Set
  import org.junit.Before;
  import org.junit.Test;
  import org.mockito.internal.util.collections.Sets;
 -import org.mockito.invocation.InvocationOnMock;
 -import org.mockito.stubbing.Answer;
 -import org.opendaylight.controller.config.util.xml.XmlUtil;
  import org.opendaylight.netconf.api.NetconfClientSessionPreferences;
 +import org.opendaylight.netconf.api.NetconfDocumentedException;
  import org.opendaylight.netconf.api.NetconfMessage;
  import org.opendaylight.netconf.api.messages.NetconfHelloMessage;
 -import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 +import org.opendaylight.netconf.api.xml.XmlUtil;
  import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
  import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToHelloMessageDecoder;
  import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToMessageDecoder;
@@@ -58,13 -60,14 +58,13 @@@ public class NetconfClientSessionNegoti
  
      private NetconfHelloMessage helloMessage;
      private ChannelPipeline pipeline;
 -    private ChannelFuture future;
 +    private ChannelPromise future;
      private Channel channel;
      private ChannelInboundHandlerAdapter channelInboundHandlerAdapter;
  
      @Before
      public void setUp() throws Exception {
 -        helloMessage = NetconfHelloMessage.createClientHello(Sets.newSet("exi:1.0"), Optional
 -                .<NetconfHelloMessageAdditionalHeader>absent());
 +        helloMessage = NetconfHelloMessage.createClientHello(Sets.newSet("exi:1.0"), Optional.absent());
          pipeline = mockChannelPipeline();
          future = mockChannelFuture();
          channel = mockChannel();
          Channel ret = mock(Channel.class);
          ChannelHandler channelHandler = mockChannelHandler();
          doReturn("").when(ret).toString();
 +        doReturn(future).when(ret).newPromise();
          doReturn(future).when(ret).close();
          doReturn(future).when(ret).writeAndFlush(anyObject());
 +        doReturn(future).when(ret).writeAndFlush(anyObject(), anyObject());
          doReturn(true).when(ret).isOpen();
          doReturn(pipeline).when(ret).pipeline();
          doReturn("").when(pipeline).toString();
@@@ -92,8 -93,8 +92,8 @@@
          return ret;
      }
  
 -    private static ChannelFuture mockChannelFuture() {
 -        ChannelFuture future = mock(ChannelFuture.class);
 +    private static ChannelPromise mockChannelFuture() {
 +        ChannelPromise future = mock(ChannelPromise.class);
          doReturn(future).when(future).addListener(any(GenericFutureListener.class));
          return future;
      }
      private void mockEventLoop() {
          final EventLoop eventLoop = mock(EventLoop.class);
          doReturn(eventLoop).when(channel).eventLoop();
 -        doAnswer(new Answer<Void>() {
 -            @Override
 -            public Void answer(InvocationOnMock invocation) throws Throwable {
 -                final Object[] args = invocation.getArguments();
 -                final Runnable runnable = (Runnable) args[0];
 -                runnable.run();
 -                return null;
 -            }
 +        doAnswer(invocation -> {
 +            invocation.getArgumentAt(0, Runnable.class).run();
 +            return null;
          }).when(eventLoop).execute(any(Runnable.class));
      }
  
          return new NetconfClientSessionNegotiator(preferences, promise, channel, timer, sessionListener, timeout);
      }
  
 -    private NetconfHelloMessage createHelloMsg(final String name) throws Exception {
 +    private static NetconfHelloMessage createHelloMsg(final String name) throws Exception {
          final InputStream stream = NetconfClientSessionNegotiatorTest.class.getResourceAsStream(name);
          final Document doc = XmlUtil.readXmlToDocument(stream);
  
          return new NetconfHelloMessage(doc);
      }
  
 -    private Set<String> createCapabilities(String name) throws Exception {
 +    private static Set<String> createCapabilities(final String name) throws Exception {
          NetconfHelloMessage hello = createHelloMsg(name);
  
          return ImmutableSet.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(hello.getDocument()));
      }
  
      @Test
 -    public void testNetconfClientSessionNegotiator() throws Exception {
 +    public void testNetconfClientSessionNegotiator() throws NetconfDocumentedException {
          Promise<NetconfClientSession> promise = mock(Promise.class);
          doReturn(promise).when(promise).setSuccess(anyObject());
          NetconfClientSessionNegotiator negotiator = createNetconfClientSessionNegotiator(promise, null);
          verify(promise).setSuccess(anyObject());
      }
  
+     @Test
+     public void testNegotiatorWhenChannelActiveHappenAfterHandleMessage() throws Exception {
+         Promise promise = mock(Promise.class);
+         doReturn(false).when(promise).isDone();
+         doReturn(promise).when(promise).setSuccess(anyObject());
+         NetconfClientSessionNegotiator negotiator = createNetconfClientSessionNegotiator(promise, null);
+         Set<String> caps = Sets.newSet("a", "b");
+         NetconfHelloMessage helloServerMessage = NetconfHelloMessage.createServerHello(caps, 10);
+         negotiator.handleMessage(helloServerMessage);
+         negotiator.channelActive(null);
+         verify(promise).setSuccess(anyObject());
+     }
      @Test
      public void testNetconfClientSessionNegotiatorWithEXI() throws Exception {
          Promise<NetconfClientSession> promise = mock(Promise.class);
          Set<String> caps = Sets.newSet("exi:1.0");
          NetconfHelloMessage message = NetconfHelloMessage.createServerHello(caps, 10);
  
 -        doAnswer(new Answer<Object>() {
 -            @Override
 -            public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
 -                channelInboundHandlerAdapter = ((ChannelInboundHandlerAdapter) invocationOnMock.getArguments()[2]);
 -                return null;
 -            }
 +        doAnswer(invocationOnMock -> {
 +            channelInboundHandlerAdapter = (ChannelInboundHandlerAdapter) invocationOnMock.getArguments()[2];
 +            return null;
          }).when(pipeline).addAfter(anyString(), anyString(), any(ChannelHandler.class));
  
          ChannelHandlerContext handlerContext = mock(ChannelHandlerContext.class);