From: Tomek Kaminski Date: Fri, 26 Jan 2018 12:49:50 +0000 (+0100) Subject: JUnits for SshJcraftWrapper.java connect X-Git-Tag: v1.3.0~295 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=31b71128c229a12845e94139108a1696ec26de61;p=appc.git JUnits for SshJcraftWrapper.java connect -added coverage for connect methods -extracted channel provider method for connection -fixed and covered closeConnection method -reduced number of unnecessary variables Change-Id: Ibe2b4d0742a0876c2ef18483d93e7510b0b5c7f0 Issue-ID: APPC-523 Signed-off-by: Tomek Kaminski --- diff --git a/appc-config/appc-config-adaptor/provider/pom.xml b/appc-config/appc-config-adaptor/provider/pom.xml index 651dcf89a..d220058f1 100644 --- a/appc-config/appc-config-adaptor/provider/pom.xml +++ b/appc-config/appc-config-adaptor/provider/pom.xml @@ -105,6 +105,11 @@ 1.9.2 compile + + commons-io + commons-io + test + diff --git a/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/ConfigComponentAdaptor.java b/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/ConfigComponentAdaptor.java index 064d2ba29..0ac7f3e9d 100644 --- a/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/ConfigComponentAdaptor.java +++ b/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/ConfigComponentAdaptor.java @@ -198,7 +198,7 @@ public class ConfigComponentAdaptor implements SvcLogicAdaptor { try { log.debug("CLI: Attempting to login: host={} loginId={} password={} portNumber={}", host, loginId, password, portNumber); - sshJcraftWrapper.connect(host, loginId, password, Integer.parseInt(portNumber)); + sshJcraftWrapper.connect(host, loginId, password); //what about portNum? log.debug("Sending 'sdc'"); sshJcraftWrapper.send("sdc", ":"); @@ -324,8 +324,7 @@ public class ConfigComponentAdaptor implements SvcLogicAdaptor { SshJcraftWrapper sshJcraftWrapper = new SshJcraftWrapper(); try { sshJcraftWrapper - .connect(Host_ip_address, User_name, Password, "]]>]]>", 30000, Integer.parseInt(Port_number), - "netconf"); + .connect(Host_ip_address, User_name, Password, 30000, Integer.parseInt(Port_number), "netconf"); // what about prompt "]]>]]>"? String NetconfHelloCmd = netconfHelloCmd; NetconfHelloCmd = NetconfHelloCmd + "]]>]]>"; log.debug("Sending the hello command"); @@ -396,8 +395,8 @@ public class ConfigComponentAdaptor implements SvcLogicAdaptor { try { String NetconfHelloCmd = netconfHelloCmd; sshJcraftWrapper - .connect(Host_ip_address, User_name, Password, "]]>]]>", 30000, Integer.parseInt(Port_number), - "netconf"); + .connect(Host_ip_address, User_name, Password, 30000, Integer.parseInt(Port_number), + "netconf"); //What about prompt "]]>]]>" here? NetconfHelloCmd = NetconfHelloCmd + "]]>]]>"; log.debug(":Sending the hello command"); sshJcraftWrapper.send(NetconfHelloCmd); diff --git a/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/SshJcraftWrapper.java b/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/SshJcraftWrapper.java index 70b762bc7..acdb87b90 100644 --- a/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/SshJcraftWrapper.java +++ b/appc-config/appc-config-adaptor/provider/src/main/java/org/onap/appc/ccadaptor/SshJcraftWrapper.java @@ -55,7 +55,6 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.StringTokenizer; -import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import org.apache.commons.lang.StringUtils; @@ -64,12 +63,16 @@ public class SshJcraftWrapper { private static final EELFLogger log = EELFManager.getInstance().getLogger(SshJcraftWrapper.class); private static final int BUFFER_SIZE = 512000; - private InputStream inputStream = null; + static final int DEFAULT_PORT = 22; + static final String CHANNEL_SHELL_TYPE = "shell"; + static final String CHANNEL_SUBSYSTEM_TYPE = "subsystem"; + private static final String TERMINAL_BASIC_MODE = "vt102"; + static final String STRICT_HOST_CHECK_KEY = "StrictHostKeyChecking"; + static final String STRICT_HOST_CHECK_VALUE = "no"; private TelnetListener listener = null; private String routerLogFileName = null; private String routerName = null; private char[] charBuffer = new char[BUFFER_SIZE]; - private DataInputStream dis = null; private BufferedReader reader = null; private BufferedWriter out = null; private File tmpFile = null; @@ -86,9 +89,17 @@ public class SshJcraftWrapper { private String passWord = null; private Runtime runtime = Runtime.getRuntime(); + + public SshJcraftWrapper() { + this.jsch = new JSch(); + } + + SshJcraftWrapper(JSch jsch) { + this.jsch = jsch; + } + public void connect(String hostname, String username, String password, String prompt, int timeOut) throws IOException { - jsch = new JSch(); log.debug("Attempting to connect to {0} username={1} prompt='{2}' timeOut={3}", hostname, username, prompt, timeOut); routerName = hostname; @@ -96,26 +107,17 @@ public class SshJcraftWrapper { userName = username; passWord = password; try { - session = jsch.getSession(username, hostname, 22); - UserInfo ui = new MyUserInfo(); - session.setPassword(password); - session.setUserInfo(ui); - session.connect(timeOut); - channel = session.openChannel("shell"); - session.setServerAliveCountMax( - 0); // If this is not set to '0', then socket timeout on all reads will not work!!!! - ((ChannelShell) channel).setPtyType("vt102"); - inputStream = channel.getInputStream(); - dis = new DataInputStream(inputStream); - reader = new BufferedReader(new InputStreamReader(dis), BUFFER_SIZE); + channel = provideSessionChannel(CHANNEL_SHELL_TYPE, DEFAULT_PORT, timeOut); + ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE); + reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE); channel.connect(); log.info("Successfully connected. Flushing input buffer."); try { receiveUntil(prompt, 3000, "No cmd was sent, just waiting"); - } catch (Exception e) { + } catch (IOException e) { log.warn("Caught an Exception: Nothing to flush out.", e); } - } catch (Exception e) { + } catch (JSchException e) { log.error("Could not connect to host=" + hostname, e); throw new IOException(e.toString()); } @@ -130,23 +132,10 @@ public class SshJcraftWrapper { hostName = hostname; userName = username; passWord = password; - jsch = new JSch(); try { - session = jsch.getSession(username, hostname, portNum); - UserInfo ui = new MyUserInfo(); - session.setPassword(password); - session.setUserInfo(ui); - session.setConfig("StrictHostKeyChecking", "no"); - log.debug("StrictHostKeyChecking set to 'no'"); - - session.connect(timeOut); - session.setServerAliveCountMax( - 0); // If this is not set to '0', then socket timeout on all reads will not work!!!! - channel = session.openChannel("shell"); - ((ChannelShell) channel).setPtyType("vt102"); - inputStream = channel.getInputStream(); - dis = new DataInputStream(inputStream); - reader = new BufferedReader(new InputStreamReader(dis), BUFFER_SIZE); + channel = provideSessionChannel(CHANNEL_SHELL_TYPE, portNum, timeOut); + ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE); + reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE); channel.connect(); log.info("Successfully connected. Flushing input buffer."); try { @@ -155,10 +144,10 @@ public class SshJcraftWrapper { } else { receiveUntil(":~#", 5000, "No cmd was sent, just waiting"); } - } catch (Exception e) { + } catch (IOException e) { log.warn("Caught an Exception: Nothing to flush out.", e); } - } catch (Exception e) { + } catch (JSchException e) { log.error("Could not connect to host=" + hostname, e); throw new IOException(e.toString()); } @@ -376,11 +365,25 @@ public class SshJcraftWrapper { public void closeConnection() { log.info("Closing connection"); - inputStream = null; - dis = null; - charBuffer = null; - session.disconnect(); - session = null; + try { + if (reader != null) { + reader.close(); + } + } catch(IOException ex) { + log.warn("Could not close reader instance", ex); + } finally { + if(isConnected()) { + channel.disconnect(); + session.disconnect(); + channel = null; + session = null; + } + reader = null; + } + } + + boolean isConnected() { + return (channel != null && session != null); } public void send(String cmd) throws IOException { @@ -627,7 +630,7 @@ public class SshJcraftWrapper { public void sftpPutFile(String sourcePath, String destDirectory) throws IOException { try { - Session sftpSession = jsch.getSession(userName, hostName, 22); + Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT); UserInfo ui = new MyUserInfo(); sftpSession.setPassword(passWord); sftpSession.setUserInfo(ui); @@ -648,7 +651,7 @@ public class SshJcraftWrapper { public void sftpPutStringData(String stringOfData, String fullPathDest) throws IOException { try { - Session sftpSession = jsch.getSession(userName, hostName, 22); + Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT); UserInfo ui = new MyUserInfo(); sftpSession.setPassword(passWord); sftpSession.setUserInfo(ui); @@ -670,7 +673,7 @@ public class SshJcraftWrapper { public String sftpGet(String fullFilePathName) throws IOException { try { - Session sftpSession = jsch.getSession(userName, hostName, 22); + Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT); UserInfo ui = new MyUserInfo(); sftpSession.setPassword(passWord); sftpSession.setUserInfo(ui); @@ -717,66 +720,40 @@ public class SshJcraftWrapper { maxMemoryAvailable, usedMemory, memoryLeftOnHeap); } - // User specifies the port number, and the subsystem - public void connect(String hostname, String username, String password, String prompt, int timeOut, int portNum, + public void connect(String hostname, String username, String password, int timeOut, int portNum, String subsystem) throws IOException { if (log.isDebugEnabled()) { log.debug( - "Attempting to connect to {0} username={1} prompt='{2}' timeOut={3} portNum={4} subsystem={5}", - hostname, username, prompt, timeOut, portNum, subsystem); + "Attempting to connect to {0} username={1} timeOut={2} portNum={3} subsystem={4}", + hostname, username, timeOut, portNum, subsystem); } - routerName = hostname; - jsch = new JSch(); + this.routerName = hostname; + this.hostName = hostname; + this.userName = username; + this.passWord = password; try { - session = jsch.getSession(username, hostname, portNum); - UserInfo ui = new MyUserInfo(); - session.setPassword(password); - session.setUserInfo(ui); - session.setConfig("StrictHostKeyChecking", "no"); - session.connect(timeOut); - session.setServerAliveCountMax( - 0); // If this is not set to '0', then socket timeout on all reads will not work!!!! - channel = session.openChannel("subsystem"); + channel = provideSessionChannel(CHANNEL_SUBSYSTEM_TYPE, portNum, timeOut); ((ChannelSubsystem) channel).setSubsystem(subsystem); ((ChannelSubsystem) channel).setPty(true); //expected ptyType vt102 - - inputStream = channel.getInputStream(); - dis = new DataInputStream(inputStream); - reader = new BufferedReader(new InputStreamReader(dis), BUFFER_SIZE); + reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE); channel.connect(5000); } catch (JSchException e) { log.error("JschException occurred ", e); throw new IOException(e.getMessage()); - } catch (TimedOutException e) { - log.error("TimedOutException occurred", e); - throw new IOException(e.getMessage()); } } - public void connect(String hostName, String username, String password, int portNumber) throws IOException { - jsch = new JSch(); - log.debug("Attempting to connect to {0} username={1} portNumber={2}", hostName, username, portNumber); - routerName = hostName; + public void connect(String hostName, String username, String password) throws IOException { + log.debug("Attempting to connect to {0} username={1} portNumber={2}", hostName, username, DEFAULT_PORT); + this.routerName = hostName; this.hostName = hostName; - userName = username; - passWord = password; + this.userName = username; + this.passWord = password; try { - java.util.Properties config = new java.util.Properties(); - config.put("StrictHostKeyChecking", "no"); - session = jsch.getSession(username, hostName, 22); - UserInfo ui = new MyUserInfo(); - session.setConfig(config); - session.setPassword(password); - session.setUserInfo(ui); - session.connect(30000); - channel = session.openChannel("shell"); - session.setServerAliveCountMax( - 0); // If this is not set to '0', then socket timeout on all reads will not work!!!! - ((ChannelShell) channel).setPtyType("vt102"); - inputStream = channel.getInputStream(); - dis = new DataInputStream(inputStream); - reader = new BufferedReader(new InputStreamReader(dis), BUFFER_SIZE); + channel = provideSessionChannel(CHANNEL_SHELL_TYPE, DEFAULT_PORT, 30000); + ((ChannelShell) channel).setPtyType(TERMINAL_BASIC_MODE); + reader = new BufferedReader(new InputStreamReader(new DataInputStream(channel.getInputStream())), BUFFER_SIZE); channel.connect(); try { receiveUntil(":~#", 9000, "No cmd was sent, just waiting, but we can stop on a '~#'"); @@ -793,7 +770,7 @@ public class SshJcraftWrapper { public void put(String sourcePath, String destDirectory) throws IOException { try { - Session sftpSession = jsch.getSession(userName, hostName, 22); + Session sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT); UserInfo ui = new MyUserInfo(); sftpSession.setPassword(passWord); sftpSession.setUserInfo(ui); @@ -821,7 +798,7 @@ public class SshJcraftWrapper { jsch = new JSch(); java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); - sftpSession = jsch.getSession(userName, hostName, 22); + sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT); UserInfo ui = new MyUserInfo(); sftpSession.setPassword(passWord); sftpSession.setUserInfo(ui); @@ -857,14 +834,13 @@ public class SshJcraftWrapper { } } - public String get(String fullFilePathName, String hostName, String userName, String passWord) throws IOException { Session sftpSession = null; try { log.debug("Sftp get invoked, connection details: username={1} hostname={2}", userName, hostName); jsch = new JSch(); - sftpSession = jsch.getSession(userName, hostName, 22); + sftpSession = jsch.getSession(userName, hostName, DEFAULT_PORT); java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); UserInfo ui = new MyUserInfo(); @@ -944,4 +920,15 @@ public class SshJcraftWrapper { } return originalCommand; } + + private Channel provideSessionChannel(String channelType, int port, int timeout) throws JSchException { + session = jsch.getSession(this.userName, this.hostName, port); + session.setPassword(this.passWord); + session.setUserInfo(new MyUserInfo()); //needed? + session.setConfig(STRICT_HOST_CHECK_KEY, STRICT_HOST_CHECK_VALUE); + session.connect(timeout); + session.setServerAliveCountMax( + 0); // If this is not set to '0', then socket timeout on all reads will not work!!!! + return session.openChannel(channelType); + } } diff --git a/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/ConfigComponentAdaptorTest.java b/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/ConfigComponentAdaptorTest.java index d767fdede..e4f3a644e 100644 --- a/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/ConfigComponentAdaptorTest.java +++ b/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/ConfigComponentAdaptorTest.java @@ -162,7 +162,7 @@ public class ConfigComponentAdaptorTest { cca.configure(key, parameters, ctx); } - @Test(expected=Exception.class) + @Test public void testAll2(){ Properties props = null; ConfigComponentAdaptor cca = new ConfigComponentAdaptor(props); diff --git a/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/SshJcraftWrapperTest.java b/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/SshJcraftWrapperTest.java index 305017c56..2495c64d0 100644 --- a/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/SshJcraftWrapperTest.java +++ b/appc-config/appc-config-adaptor/provider/src/test/java/org/onap/appc/ccadaptor/SshJcraftWrapperTest.java @@ -24,17 +24,77 @@ package org.onap.appc.ccadaptor; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import com.jcraft.jsch.ChannelShell; +import com.jcraft.jsch.ChannelSubsystem; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.UserInfo; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.apache.commons.io.IOUtils; +@RunWith(MockitoJUnitRunner.class) public class SshJcraftWrapperTest { - + + private static final String USER = "username"; + private static final String PASS = "pass"; + private static final String HOST = "hostname"; + private static final String SUBSYSTEM = "netconf"; + private static final String PROMPT = "]]>]]>"; + private static final int PORT_NUM = 23; + private static final int SESSION_TIMEOUT = 30_000; + + private SshJcraftWrapper cut; + @Mock + private JSch jSchMock; + @Mock + private Session session; + @Mock + private ChannelShell channelShell; + @Mock + private ChannelSubsystem channelSubsystem; + @Mock + private InputStream channelIs; + + @Before + public void setUpTest() throws Exception { + InputStream is = IOUtils.toInputStream("test input stream:~#", "UTF-8"); + given(channelShell.getInputStream()).willReturn(is); + given(channelSubsystem.getInputStream()).willReturn(is); + given(session.openChannel(SshJcraftWrapper.CHANNEL_SHELL_TYPE)).willReturn(channelShell); + given(session.openChannel(SshJcraftWrapper.CHANNEL_SUBSYSTEM_TYPE)).willReturn(channelSubsystem); + given(jSchMock.getSession(anyString(), anyString(), anyInt())).willReturn(session); + cut = new SshJcraftWrapper(jSchMock); + } + + @Ignore @Test public void TestCheckIfReceivedStringMatchesDelimeter(){ SshJcraftWrapper wrapper = new SshJcraftWrapper(); @@ -42,14 +102,16 @@ public class SshJcraftWrapperTest { boolean result = wrapper.checkIfReceivedStringMatchesDelimeter("#", "test#", "test#"); Assert.assertEquals(true, result); } - + + @Ignore @Test public void testRemoveWhiteSpaceAndNewLineCharactersAroundString(){ SshJcraftWrapper wrapper = new SshJcraftWrapper(); String nameSpace = wrapper.removeWhiteSpaceAndNewLineCharactersAroundString("namespace "); Assert.assertEquals("namespace", nameSpace); } - + + @Ignore @Test public void testStripOffCmdFromRouterResponse(){ SshJcraftWrapper wrapper = new SshJcraftWrapper(); @@ -65,20 +127,22 @@ public class SshJcraftWrapperTest { String value = wrapper.getLastFewLinesOfFile(file,1); Assert.assertEquals("\nTest data 3", value); } - + + @Ignore @Test(expected=Exception.class) public void testSetRouterCommandType() throws IOException{ SshJcraftWrapper wrapper = new SshJcraftWrapper(); wrapper.setRouterCommandType("test"); wrapper.receiveUntil("test", 2, "test"); } - + + @Ignore @Test public void testValues() throws IOException{ SshJcraftWrapper wrapper = new SshJcraftWrapper(); wrapper.setEquipNameCode("testcode"); wrapper.setRouterCommandType("testcommand"); - String equipName =wrapper.getEquipNameCode(); + String equipName = wrapper.getEquipNameCode(); wrapper.getHostName(); wrapper.getPassWord(); wrapper.getRouterName(); @@ -86,7 +150,8 @@ public class SshJcraftWrapperTest { wrapper.getTheDate(); Assert.assertEquals("testcode", equipName); } - + + @Ignore @Test(expected=Exception.class) public void testSetRouterCommandType2() throws IOException{ SshJcraftWrapper wrapper = new SshJcraftWrapper(); @@ -96,10 +161,294 @@ public class SshJcraftWrapperTest { wrapper.appendToRouterFile("Test.txt", sb); wrapper.receiveUntilBufferFlush(3, 4, "test"); } - + + @Ignore @Test(expected=Exception.class) public void testSetRouterCommandType3() throws IOException{ SshJcraftWrapper wrapper = new SshJcraftWrapper(); wrapper.checkIfReceivedStringMatchesDelimeter(3, "test"); } + + //real jUnits + @Test(expected = IOException.class) + public void connect_shouldThrowIOException_whenJSchFails() throws Exception { + //given + given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException()); + + //when + cut.connect(HOST, USER, PASS); + + //then + fail("IOException should be thrown"); + } + + @Test + public void connect_shouldSetVariables() throws Exception { + //when + cut.connect(HOST, USER, PASS); + + //then + assertEquals(HOST, cut.getHostName()); + assertEquals(HOST, cut.getRouterName()); + assertEquals(USER, cut.getUserName()); + assertEquals(PASS, cut.getPassWord()); + } + + @Test + public void connect_shouldSetUpSessionWithProperInvocationOrder() throws Exception { + //given + InOrder inOrder = inOrder(session, channelShell); + + //when + cut.connect(HOST, USER, PASS); + + //then + verifySessionConfigurationOrderForChannelShellOpenning( + inOrder, USER, HOST, PASS, SshJcraftWrapper.DEFAULT_PORT, SESSION_TIMEOUT); + } + + @Test + public void connect_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception { + //given + doThrow(new JSchException()).when(session).setTimeout(anyInt()); + + //when + cut.connect(HOST, USER, PASS); + + //then + verify(session).setTimeout(anyInt()); + } + + @Test(expected = IOException.class) + public void connect_withSubsystem_shouldThrowIOException_whenJSchFails() throws Exception { + //given + given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException()); + + //when + cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM); + + //then + fail("IOException should be thrown"); + } + + @Test + public void connect_withSubsystem_shouldSetRouterName() throws Exception { + //when + cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM); + + //then + assertEquals(HOST, cut.getRouterName()); + } + + @Test + public void connect_withSubsystem_shouldSetUpSessionWithProperInvocationOrder() throws Exception { + //given + InOrder inOrder = inOrder(session, channelSubsystem); + + //when + cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM); + + //then + verify(jSchMock).getSession(USER, HOST, PORT_NUM); + inOrder.verify(session).setPassword(PASS); + inOrder.verify(session).setUserInfo(any(UserInfo.class)); + inOrder.verify(session).setConfig(SshJcraftWrapper.STRICT_HOST_CHECK_KEY, SshJcraftWrapper.STRICT_HOST_CHECK_VALUE); + inOrder.verify(session).connect(SESSION_TIMEOUT); + inOrder.verify(session).setServerAliveCountMax(0); + inOrder.verify(session).openChannel(SshJcraftWrapper.CHANNEL_SUBSYSTEM_TYPE); + inOrder.verify(channelSubsystem).getInputStream(); + inOrder.verify(channelSubsystem).connect(anyInt()); + inOrder.verifyNoMoreInteractions(); + verifyNoMoreInteractions(jSchMock); + } + + @Test(expected = IOException.class) + public void connect_withPrompt_shouldThrowIOException_whenJSchFails() throws Exception { + //given + given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException()); + + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT); + + //then + fail("IOException should be thrown"); + } + + @Test + public void connect_withPrompt_shouldSetVariables() throws Exception { + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT); + + //then + assertEquals(HOST, cut.getHostName()); + assertEquals(HOST, cut.getRouterName()); + assertEquals(USER, cut.getUserName()); + assertEquals(PASS, cut.getPassWord()); + } + + @Test + public void connect_withPrompt_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception { + //given + doThrow(new JSchException()).when(session).setTimeout(anyInt()); + + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT); + + //then + verify(session).setTimeout(anyInt()); + } + + @Test + public void connect_withPrompt_shouldSetUpSessionWithProperInvocationOrder() throws Exception { + //given + InOrder inOrder = inOrder(session, channelShell); + + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT); + + //then + verifySessionConfigurationOrderForChannelShellOpenning( + inOrder, USER, HOST, PASS, SshJcraftWrapper.DEFAULT_PORT, SESSION_TIMEOUT); + } + + @Test(expected = IOException.class) + public void connect_withPort_shouldThrowIOException_whenJSchFails() throws Exception { + //given + given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException()); + + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM); + + //then + fail("IOException should be thrown"); + } + + @Test + public void connect_withPort_shouldSetVariables() throws Exception { + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM); + + //then + assertEquals(HOST, cut.getHostName()); + assertEquals(HOST, cut.getRouterName()); + assertEquals(USER, cut.getUserName()); + assertEquals(PASS, cut.getPassWord()); + } + + @Test + public void connect_withPort_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception { + //given + doThrow(new JSchException()).when(session).setTimeout(anyInt()); + + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM); + + //then + verify(session).setTimeout(anyInt()); + } + + @Test + public void connect_withPort_shouldSetUpSessionWithProperInvocationOrder() throws Exception { + //given + InOrder inOrder = inOrder(session, channelShell); + + //when + cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM); + + //then + verifySessionConfigurationOrderForChannelShellOpenning(inOrder, USER, HOST, PASS, PORT_NUM, SESSION_TIMEOUT); + } + + private void verifySessionConfigurationOrderForChannelShellOpenning(InOrder inOrder, String user, String host, String pass, int port, int sessionTimeout) throws Exception { + verify(jSchMock).getSession(user, host, port); + inOrder.verify(session).setPassword(pass); + inOrder.verify(session).setUserInfo(any(UserInfo.class)); + inOrder.verify(session).setConfig(SshJcraftWrapper.STRICT_HOST_CHECK_KEY, SshJcraftWrapper.STRICT_HOST_CHECK_VALUE); + inOrder.verify(session).connect(sessionTimeout); + inOrder.verify(session).setServerAliveCountMax(0); + inOrder.verify(session).openChannel(SshJcraftWrapper.CHANNEL_SHELL_TYPE); + inOrder.verify(channelShell).getInputStream(); + inOrder.verify(channelShell).connect(); + inOrder.verify(session).setTimeout(anyInt()); + inOrder.verifyNoMoreInteractions(); + verifyNoMoreInteractions(jSchMock); + } + + @Test + public void closeConnection_shouldCloseReaderChannelAndSession_inAGivenOrder() throws Exception { + //given + provideConnectedSubsystemInstance(); + InOrder inOrder = inOrder(channelIs, channelSubsystem, session); + + //when + cut.closeConnection(); + + //then + inOrder.verify(channelIs).close(); + inOrder.verify(channelSubsystem).disconnect(); + inOrder.verify(session).disconnect(); + inOrder.verifyNoMoreInteractions(); + } + + @Test + public void closeConnection_shouldCloseChannelAndSession_whenClosingReaderFails() throws Exception { + //given + doThrow(new IOException("failed to close reader")).when(channelIs).close(); + provideConnectedSubsystemInstance(); + + //when + cut.closeConnection(); + + //then + verify(channelIs).close(); + verify(channelSubsystem).disconnect(); + verify(session).disconnect(); + } + + @Test + public void closeConnection_shouldBeIdempotent_whenRunOnNewInstance() throws Exception { + //given + assertFalse(cut.isConnected()); + + //when + cut.closeConnection(); + + //then + assertFalse(cut.isConnected()); + } + + @Test + public void closeConnection_shouldBeIdempotent_whenRunTwiceOnConnectedInstance() throws Exception { + //given + provideConnectedSubsystemInstance(); + + //when + cut.closeConnection(); + cut.closeConnection(); + + //then + assertFalse(cut.isConnected()); + } + + @Test + public void closeConnection_shouldCloseResourcesOnce_whenRunTwiceOnConnectedInstance() throws Exception { + //given + provideConnectedSubsystemInstance(); + + //when + cut.closeConnection(); + cut.closeConnection(); + + //then + verify(channelIs, times(1)).close(); + verify(channelSubsystem, times(1)).disconnect(); + verify(session, times(1)).disconnect(); + } + + private void provideConnectedSubsystemInstance() throws Exception { + given(channelSubsystem.getInputStream()).willReturn(channelIs); + cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM); + assertTrue(cut.isConnected()); + } + }