* 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.netconf.callhome.protocol;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyString;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPipeline;
+import io.netty.channel.DefaultChannelPipeline;
import io.netty.channel.EventLoopGroup;
-import java.io.IOException;
import java.net.InetSocketAddress;
import java.security.PublicKey;
-import org.apache.sshd.ClientChannel;
-import org.apache.sshd.ClientChannel.Streaming;
-import org.apache.sshd.ClientSession;
-import org.apache.sshd.client.channel.ChannelSubsystem;
-import org.apache.sshd.client.future.OpenFuture;
-import org.apache.sshd.client.session.ClientSessionImpl;
-import org.apache.sshd.common.KeyExchange;
-import org.apache.sshd.common.Session.AttributeKey;
-import org.apache.sshd.common.future.SshFutureListener;
-import org.apache.sshd.common.io.IoInputStream;
-import org.apache.sshd.common.io.IoOutputStream;
-import org.apache.sshd.common.io.IoReadFuture;
-import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.util.Buffer;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
-import org.mockito.Mockito;
+import org.opendaylight.netconf.callhome.protocol.CallHomeSessionContext.Factory;
import org.opendaylight.netconf.client.NetconfClientSessionListener;
import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory;
+import org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfClientSessionImpl;
+import org.opendaylight.netconf.shaded.sshd.client.channel.ChannelSubsystem;
+import org.opendaylight.netconf.shaded.sshd.client.channel.ClientChannel;
+import org.opendaylight.netconf.shaded.sshd.client.future.OpenFuture;
+import org.opendaylight.netconf.shaded.sshd.common.AttributeRepository.AttributeKey;
+import org.opendaylight.netconf.shaded.sshd.common.channel.StreamingChannel;
+import org.opendaylight.netconf.shaded.sshd.common.future.SshFutureListener;
+import org.opendaylight.netconf.shaded.sshd.common.io.IoInputStream;
+import org.opendaylight.netconf.shaded.sshd.common.io.IoOutputStream;
+import org.opendaylight.netconf.shaded.sshd.common.io.IoReadFuture;
+import org.opendaylight.netconf.shaded.sshd.common.io.IoSession;
+import org.opendaylight.netconf.shaded.sshd.common.kex.KeyExchange;
+import org.opendaylight.netconf.shaded.sshd.common.util.buffer.Buffer;
public class CallHomeSessionContextTest {
- private ClientSessionImpl mockSession;
+ private NetconfClientSessionImpl mockSession;
private CallHomeAuthorization mockAuth;
private ClientChannel mockChannel;
- private InetSocketAddress address;
-
- private ReverseSshChannelInitializer mockChannelInitializer;
- private CallHomeNetconfSubsystemListener subListener;
private EventLoopGroup mockNettyGroup;
- private CallHomeSessionContext.Factory realFactory;
+ private Factory realFactory;
private CallHomeSessionContext instance;
- private NetconfClientSessionNegotiatorFactory mockNegotiatior;
@Before
public void setup() {
- mockSession = mock(ClientSessionImpl.class);
+ mockSession = mock(NetconfClientSessionImpl.class);
mockAuth = mock(CallHomeAuthorization.class);
mockChannel = mock(ClientChannel.class);
- address = mock(InetSocketAddress.class);
- mockNegotiatior = mock(NetconfClientSessionNegotiatorFactory.class);
- subListener = mock(CallHomeNetconfSubsystemListener.class);
+ final var mockNegotiatior = mock(NetconfClientSessionNegotiatorFactory.class);
+ final var subListener = mock(CallHomeNetconfSubsystemListener.class);
mockNettyGroup = mock(EventLoopGroup.class);
-
- realFactory = new CallHomeSessionContext.Factory(mockNettyGroup, mockNegotiatior, subListener);
-
-
-
- KeyExchange kexMock = Mockito.mock(KeyExchange.class);
- Mockito.doReturn(kexMock).when(mockSession).getKex();
-
- PublicKey keyMock = Mockito.mock(PublicKey.class);
- Mockito.doReturn(keyMock).when(kexMock).getServerKey();
- IoReadFuture mockFuture = mock(IoReadFuture.class);
- IoInputStream mockIn = mock(IoInputStream.class);
- Mockito.doReturn(mockFuture).when(mockIn).read(any(Buffer.class));
- IoOutputStream mockOut = mock(IoOutputStream.class);
-
- Mockito.doReturn(mockIn).when(mockChannel).getAsyncOut();
- Mockito.doReturn(mockOut).when(mockChannel).getAsyncIn();
-
- Mockito.doReturn(true).when(mockAuth).isServerAllowed();
-
- IoSession ioSession = mock(IoSession.class);
- Mockito.doReturn(ioSession).when(mockSession).getIoSession();
- Mockito.doReturn(address).when(ioSession).getRemoteAddress();
- Mockito.doReturn(null).when(mockSession).setAttribute(any(AttributeKey.class), any());
- Mockito.doReturn(null).when(mockSession).getAttribute(any(AttributeKey.class));
- Mockito.doReturn("testSession").when(mockSession).toString();
-
- Mockito.doNothing().when(mockAuth).applyTo(mockSession);
- Mockito.doReturn("test").when(mockAuth).getSessionName();
+ realFactory = new Factory(mockNettyGroup, mockNegotiatior, subListener);
+
+ final var kexMock = mock(KeyExchange.class);
+ doReturn(kexMock).when(mockSession).getKex();
+ final var keyMock = mock(PublicKey.class);
+ doReturn(keyMock).when(mockSession).getServerKey();
+
+ final var mockFuture = mock(IoReadFuture.class);
+ final var mockIn = mock(IoInputStream.class);
+ doReturn(mockFuture).when(mockIn).read(any(Buffer.class));
+ final var mockOut = mock(IoOutputStream.class);
+ doReturn(mockIn).when(mockChannel).getAsyncOut();
+ doReturn(mockOut).when(mockChannel).getAsyncIn();
+
+ final var ioSession = mock(IoSession.class);
+ doReturn(ioSession).when(mockSession).getIoSession();
+ final var address = mock(InetSocketAddress.class);
+ doReturn(address).when(ioSession).getRemoteAddress();
+ doReturn(null).when(mockSession).setAttribute(any(AttributeKey.class), any());
+ doReturn(null).when(mockSession).getAttribute(any(AttributeKey.class));
+ doReturn("testSession").when(mockSession).toString();
+
+ doReturn(true).when(mockAuth).isServerAllowed();
+ doNothing().when(mockAuth).applyTo(mockSession);
+ doReturn("test").when(mockAuth).getSessionName();
}
@Test
public void theContextShouldBeSettableAndRetrievableAsASessionAttribute() {
- // redo instance below because previous constructor happened too early to capture behavior
- instance = realFactory.createIfNotExists(mockSession, mockAuth, address);
// when
- CallHomeSessionContext.getFrom(mockSession);
+ instance = realFactory.createIfNotExists(mockSession, mockAuth);
// then
+ assertNotNull(instance);
verify(mockSession, times(1)).setAttribute(CallHomeSessionContext.SESSION_KEY, instance);
+ verify(mockSession, times(0)).getAttribute(any());
+
+ // when
+ CallHomeSessionContext.getFrom(mockSession);
+ // then
verify(mockSession, times(1)).getAttribute(CallHomeSessionContext.SESSION_KEY);
}
@Test
- public void anAuthorizeActionShouldApplyToTheBoundSession() throws IOException {
- instance = realFactory.createIfNotExists(mockSession, mockAuth, address);
+ public void anAuthorizeActionShouldApplyToTheBoundSession() throws Exception {
+ instance = realFactory.createIfNotExists(mockSession, mockAuth);
// when
- Mockito.doReturn(null).when(mockSession).auth();
+ doReturn(null).when(mockSession).auth();
instance.authorize();
// then
verify(mockAuth, times(1)).applyTo(mockSession);
}
@Test
- public void creatingAChannelSuccessfullyShouldResultInAnAttachedListener() throws IOException {
+ public void creatingAChannelSuccessfullyShouldResultInAnAttachedListener() throws Exception {
// given
- OpenFuture mockFuture = mock(OpenFuture.class);
- ChannelSubsystem mockChannel = mock(ChannelSubsystem.class);
- Mockito.doReturn(mockFuture).when(mockChannel).open();
- Mockito.doReturn(mockChannel).when(mockSession).createSubsystemChannel(anyString());
-
- Mockito.doReturn(null).when(mockFuture).addListener(any(SshFutureListener.class));
- Mockito.doNothing().when(mockChannel).setStreaming(any(Streaming.class));
- instance = realFactory.createIfNotExists(mockSession, mockAuth, address);
+ final var mockFuture = mock(OpenFuture.class);
+ final var mockChannelSubsystem = mock(ChannelSubsystem.class);
+ doReturn(mockFuture).when(mockChannelSubsystem).open();
+ doReturn(mockChannelSubsystem).when(mockSession).createSubsystemChannel(anyString(),
+ any(DefaultChannelPipeline.class));
+
+ doReturn(null).when(mockFuture).addListener(any(SshFutureListener.class));
+ doNothing().when(mockChannelSubsystem).setStreaming(any(StreamingChannel.Streaming.class));
+ instance = realFactory.createIfNotExists(mockSession, mockAuth);
// when
instance.openNetconfChannel();
// then
verify(mockFuture, times(1)).addListener(any(SshFutureListener.class));
}
- static class TestableContext extends CallHomeSessionContext {
- MinaSshNettyChannel minaMock;
-
- public TestableContext(ClientSession sshSession, CallHomeAuthorization authorization, InetSocketAddress address,
- CallHomeSessionContext.Factory factory, MinaSshNettyChannel minaMock) {
- super(sshSession, authorization, address, factory);
- this.minaMock = minaMock;
- }
-
- @Override
- protected MinaSshNettyChannel newMinaSshNettyChannel(ClientChannel netconfChannel) {
- return minaMock;
- }
- }
-
- @Ignore
@Test
- public void openingTheChannelSuccessfullyShouldFireActiveChannel() {
+ public void openingTheChannelSuccessfullyNotifyTheChannelListener() {
// given
- MinaSshNettyChannel mockMinaChannel = mock(MinaSshNettyChannel.class);
- CallHomeSessionContext.Factory mockFactory = mock(CallHomeSessionContext.Factory.class);
+ final var mockListener = mock(CallHomeNetconfSubsystemListener.class);
+ doNothing().when(mockListener).onNetconfSubsystemOpened(any(CallHomeProtocolSessionContext.class),
+ any(CallHomeChannelActivator.class));
+
+ final var mockChanFuture = mock(ChannelFuture.class);
+ doReturn(mockChanFuture).when(mockNettyGroup).register(any(Channel.class));
- ChannelFuture mockChanFuture = mock(ChannelFuture.class);
- Mockito.doReturn(mockChanFuture).when(mockNettyGroup).register(any(Channel.class));
+ final var mockFactory = mock(Factory.class);
+ doReturn(mockNettyGroup).when(mockFactory).getNettyGroup();
+ final var mockChannelInitializer = mock(ReverseSshChannelInitializer.class);
+ doReturn(mockChannelInitializer).when(mockFactory)
+ .getChannelInitializer(any(NetconfClientSessionListener.class));
+ doReturn(mockListener).when(mockFactory).getChannelOpenListener();
- Mockito.doReturn(mockNettyGroup).when(mockFactory).getNettyGroup();
- Mockito.doReturn(mockChannelInitializer).when(mockFactory)
- .getChannelInitializer(any(NetconfClientSessionListener.class));
+ final var mockPipeline = mock(ChannelPipeline.class);
+ final var mockMinaChannel = mock(MinaSshNettyChannel.class);
+ doReturn(mockPipeline).when(mockMinaChannel).pipeline();
- ChannelPipeline mockPipeline = mock(ChannelPipeline.class);
- Mockito.doReturn(mockPipeline).when(mockMinaChannel).pipeline();
+ final var mockFuture = mock(OpenFuture.class);
+ doReturn(true).when(mockFuture).isOpened();
- OpenFuture mockFuture = mock(OpenFuture.class);
- Mockito.doReturn(true).when(mockFuture).isOpened();
+ instance = spy(new CallHomeSessionContext(mockSession, mockAuth, mockFactory));
+ doReturn(mockMinaChannel).when(instance).newMinaSshNettyChannel();
+ final var listener = instance.newSshFutureListener(mockChannel, mockMinaChannel);
- instance = new TestableContext(mockSession, mockAuth, address, mockFactory, mockMinaChannel);
- SshFutureListener<OpenFuture> listener = instance.newSshFutureListener(mockChannel);
// when
listener.operationComplete(mockFuture);
// then
- verify(mockPipeline, times(1)).fireChannelActive();
+ verify(mockListener, times(1)).onNetconfSubsystemOpened(any(CallHomeProtocolSessionContext.class),
+ any(CallHomeChannelActivator.class));
}
@Test
- @Ignore
public void failureToOpenTheChannelShouldCauseTheSessionToClose() {
// given
- SshFutureListener<OpenFuture> listener = instance.newSshFutureListener(mockChannel);
- OpenFuture mockFuture = mock(OpenFuture.class);
- Mockito.doReturn(false).when(mockFuture).isOpened();
- Mockito.doReturn(new RuntimeException("test")).when(mockFuture).getException();
+ instance = realFactory.createIfNotExists(mockSession, mockAuth);
+ final var mockFuture = mock(OpenFuture.class);
+ doReturn(false).when(mockFuture).isOpened();
+ doReturn(new RuntimeException("test")).when(mockFuture).getException();
+ doReturn(null).when(mockSession).close(anyBoolean());
+
// when
+ final var listener = instance.newSshFutureListener(mockChannel, null);
listener.operationComplete(mockFuture);
// then
+ // You'll see an error message logged to the console - it is expected.
verify(mockSession, times(1)).close(anyBoolean());
}
+
+ @Test
+ public void theContextConstructorShouldNotModifySession() {
+ instance = new CallHomeSessionContext(mockSession, mockAuth, realFactory);
+ verify(mockSession, times(0)).setAttribute(any(), any());
+ assertNull(CallHomeSessionContext.getFrom(mockSession));
+ }
}