2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * =============================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 * ============LICENSE_END=========================================================
25 package org.onap.appc.ccadaptor;
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertTrue;
30 import static org.junit.Assert.assertFalse;
31 import static org.junit.Assert.fail;
32 import static org.mockito.BDDMockito.given;
33 import static org.mockito.Matchers.any;
34 import static org.mockito.Matchers.anyInt;
35 import static org.mockito.Matchers.anyString;
36 import static org.mockito.Mockito.doThrow;
37 import static org.mockito.Mockito.inOrder;
38 import static org.mockito.Mockito.times;
39 import static org.mockito.Mockito.verify;
40 import static org.mockito.Mockito.verifyNoMoreInteractions;
42 import com.jcraft.jsch.ChannelShell;
43 import com.jcraft.jsch.ChannelSubsystem;
44 import com.jcraft.jsch.JSch;
45 import com.jcraft.jsch.JSchException;
46 import com.jcraft.jsch.Session;
47 import com.jcraft.jsch.UserInfo;
49 import java.io.FileNotFoundException;
50 import java.io.IOException;
51 import java.io.InputStream;
54 import org.junit.Assert;
55 import org.junit.Before;
56 import org.junit.Ignore;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.mockito.InOrder;
60 import org.mockito.Mock;
61 import org.mockito.runners.MockitoJUnitRunner;
62 import org.apache.commons.io.IOUtils;
64 @RunWith(MockitoJUnitRunner.class)
65 public class SshJcraftWrapperTest {
67 private static final String USER = "username";
68 private static final String PASS = "pass";
69 private static final String HOST = "hostname";
70 private static final String SUBSYSTEM = "netconf";
71 private static final String PROMPT = "]]>]]>";
72 private static final String SEARCH_STR = "</rpc-reply>";
73 private static final int READ_TIMEOUT = 180_000;
74 private static final int PORT_NUM = 23;
75 private static final int SESSION_TIMEOUT = 30_000;
76 private static final int READ_INTERVAL_MS = 1;
77 private static final int READ_BUFFER_SIZE = 10;
79 private SshJcraftWrapper cut;
81 private JSch jSchMock;
83 private Session session;
85 private ChannelShell channelShell;
87 private ChannelSubsystem channelSubsystem;
89 private InputStream channelIs;
92 public void setUpTest() throws Exception {
93 InputStream is = IOUtils.toInputStream("test input stream:~#", "UTF-8");
94 given(channelShell.getInputStream()).willReturn(is);
95 given(channelSubsystem.getInputStream()).willReturn(is);
96 given(session.openChannel(SshJcraftWrapper.CHANNEL_SHELL_TYPE)).willReturn(channelShell);
97 given(session.openChannel(SshJcraftWrapper.CHANNEL_SUBSYSTEM_TYPE)).willReturn(channelSubsystem);
98 given(jSchMock.getSession(anyString(), anyString(), anyInt())).willReturn(session);
99 cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, READ_BUFFER_SIZE);
104 public void TestCheckIfReceivedStringMatchesDelimeter(){
105 SshJcraftWrapper wrapper = new SshJcraftWrapper();
106 wrapper.getTheDate();
107 boolean result = wrapper.checkIfReceivedStringMatchesDelimeter("#", "test#", "test#");
108 Assert.assertEquals(true, result);
113 public void testRemoveWhiteSpaceAndNewLineCharactersAroundString(){
114 SshJcraftWrapper wrapper = new SshJcraftWrapper();
115 String nameSpace = wrapper.removeWhiteSpaceAndNewLineCharactersAroundString("namespace ");
116 Assert.assertEquals("namespace", nameSpace);
121 public void testStripOffCmdFromRouterResponse(){
122 SshJcraftWrapper wrapper = new SshJcraftWrapper();
123 String result = wrapper.stripOffCmdFromRouterResponse("test\nsuccess");
124 Assert.assertEquals("success\n", result);
128 public void testGetLastFewLinesOfFile() throws FileNotFoundException, IOException{
129 SshJcraftWrapper wrapper = new SshJcraftWrapper();
130 URL path = SshJcraftWrapperTest.class.getResource("Test");
131 File file = new File(path.getFile());
132 String value = wrapper.getLastFewLinesOfFile(file,1);
133 Assert.assertEquals("\nTest data 3", value);
137 @Test(expected=Exception.class)
138 public void testSetRouterCommandType() throws IOException{
139 SshJcraftWrapper wrapper = new SshJcraftWrapper();
140 wrapper.setRouterCommandType("test");
141 wrapper.receiveUntil("test", 2, "test");
146 public void testValues() throws IOException{
147 SshJcraftWrapper wrapper = new SshJcraftWrapper();
148 wrapper.setEquipNameCode("testcode");
149 wrapper.setRouterCommandType("testcommand");
150 String equipName = wrapper.getEquipNameCode();
151 wrapper.getHostName();
152 wrapper.getPassWord();
153 wrapper.getRouterName();
154 wrapper.getUserName();
155 wrapper.getTheDate();
156 Assert.assertEquals("testcode", equipName);
160 @Test(expected=Exception.class)
161 public void testSetRouterCommandType2() throws IOException{
162 SshJcraftWrapper wrapper = new SshJcraftWrapper();
163 wrapper.appendToRouterFile("test", 2);
164 StringBuilder sb = new StringBuilder();
166 wrapper.appendToRouterFile("Test.txt", sb);
167 wrapper.receiveUntilBufferFlush(3, 4, "test");
171 @Test(expected=Exception.class)
172 public void testSetRouterCommandType3() throws IOException{
173 SshJcraftWrapper wrapper = new SshJcraftWrapper();
174 wrapper.checkIfReceivedStringMatchesDelimeter(3, "test");
178 @Test(expected = IOException.class)
179 public void connect_shouldThrowIOException_whenJSchFails() throws Exception {
181 given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
184 cut.connect(HOST, USER, PASS);
187 fail("IOException should be thrown");
191 public void connect_shouldSetVariables() throws Exception {
193 cut.connect(HOST, USER, PASS);
196 assertEquals(HOST, cut.getHostName());
197 assertEquals(HOST, cut.getRouterName());
198 assertEquals(USER, cut.getUserName());
199 assertEquals(PASS, cut.getPassWord());
203 public void connect_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
205 InOrder inOrder = inOrder(session, channelShell);
208 cut.connect(HOST, USER, PASS);
211 verifySessionConfigurationOrderForChannelShellOpenning(
212 inOrder, USER, HOST, PASS, SshJcraftWrapper.DEFAULT_PORT, SESSION_TIMEOUT);
216 public void connect_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception {
218 doThrow(new JSchException()).when(session).setTimeout(anyInt());
221 cut.connect(HOST, USER, PASS);
224 verify(session).setTimeout(anyInt());
227 @Test(expected = IOException.class)
228 public void connect_withSubsystem_shouldThrowIOException_whenJSchFails() throws Exception {
230 given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
233 cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
236 fail("IOException should be thrown");
240 public void connect_withSubsystem_shouldSetRouterName() throws Exception {
242 cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
245 assertEquals(HOST, cut.getRouterName());
249 public void connect_withSubsystem_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
251 InOrder inOrder = inOrder(session, channelSubsystem);
254 cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
257 verify(jSchMock).getSession(USER, HOST, PORT_NUM);
258 inOrder.verify(session).setPassword(PASS);
259 inOrder.verify(session).setUserInfo(any(UserInfo.class));
260 inOrder.verify(session).setConfig(SshJcraftWrapper.STRICT_HOST_CHECK_KEY, SshJcraftWrapper.STRICT_HOST_CHECK_VALUE);
261 inOrder.verify(session).connect(SESSION_TIMEOUT);
262 inOrder.verify(session).setServerAliveCountMax(0);
263 inOrder.verify(session).openChannel(SshJcraftWrapper.CHANNEL_SUBSYSTEM_TYPE);
264 inOrder.verify(channelSubsystem).getInputStream();
265 inOrder.verify(channelSubsystem).connect(anyInt());
266 inOrder.verifyNoMoreInteractions();
267 verifyNoMoreInteractions(jSchMock);
270 @Test(expected = IOException.class)
271 public void connect_withPrompt_shouldThrowIOException_whenJSchFails() throws Exception {
273 given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
276 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
279 fail("IOException should be thrown");
283 public void connect_withPrompt_shouldSetVariables() throws Exception {
285 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
288 assertEquals(HOST, cut.getHostName());
289 assertEquals(HOST, cut.getRouterName());
290 assertEquals(USER, cut.getUserName());
291 assertEquals(PASS, cut.getPassWord());
295 public void connect_withPrompt_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception {
297 doThrow(new JSchException()).when(session).setTimeout(anyInt());
300 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
303 verify(session).setTimeout(anyInt());
307 public void connect_withPrompt_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
309 InOrder inOrder = inOrder(session, channelShell);
312 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
315 verifySessionConfigurationOrderForChannelShellOpenning(
316 inOrder, USER, HOST, PASS, SshJcraftWrapper.DEFAULT_PORT, SESSION_TIMEOUT);
319 @Test(expected = IOException.class)
320 public void connect_withPort_shouldThrowIOException_whenJSchFails() throws Exception {
322 given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
325 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
328 fail("IOException should be thrown");
332 public void connect_withPort_shouldSetVariables() throws Exception {
334 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
337 assertEquals(HOST, cut.getHostName());
338 assertEquals(HOST, cut.getRouterName());
339 assertEquals(USER, cut.getUserName());
340 assertEquals(PASS, cut.getPassWord());
344 public void connect_withPort_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception {
346 doThrow(new JSchException()).when(session).setTimeout(anyInt());
349 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
352 verify(session).setTimeout(anyInt());
356 public void connect_withPort_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
358 InOrder inOrder = inOrder(session, channelShell);
361 cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
364 verifySessionConfigurationOrderForChannelShellOpenning(inOrder, USER, HOST, PASS, PORT_NUM, SESSION_TIMEOUT);
367 private void verifySessionConfigurationOrderForChannelShellOpenning(InOrder inOrder, String user, String host, String pass, int port, int sessionTimeout) throws Exception {
368 verify(jSchMock).getSession(user, host, port);
369 inOrder.verify(session).setPassword(pass);
370 inOrder.verify(session).setUserInfo(any(UserInfo.class));
371 inOrder.verify(session).setConfig(SshJcraftWrapper.STRICT_HOST_CHECK_KEY, SshJcraftWrapper.STRICT_HOST_CHECK_VALUE);
372 inOrder.verify(session).connect(sessionTimeout);
373 inOrder.verify(session).setServerAliveCountMax(0);
374 inOrder.verify(session).openChannel(SshJcraftWrapper.CHANNEL_SHELL_TYPE);
375 inOrder.verify(channelShell).getInputStream();
376 inOrder.verify(channelShell).connect();
377 inOrder.verify(session).setTimeout(anyInt());
378 inOrder.verifyNoMoreInteractions();
379 verifyNoMoreInteractions(jSchMock);
383 public void closeConnection_shouldCloseReaderChannelAndSession_inAGivenOrder() throws Exception {
385 provideConnectedSubsystemInstance();
386 InOrder inOrder = inOrder(channelIs, channelSubsystem, session);
389 cut.closeConnection();
392 inOrder.verify(channelIs).close();
393 inOrder.verify(channelSubsystem).disconnect();
394 inOrder.verify(session).disconnect();
395 inOrder.verifyNoMoreInteractions();
399 public void closeConnection_shouldCloseChannelAndSession_whenClosingReaderFails() throws Exception {
401 doThrow(new IOException("failed to close reader")).when(channelIs).close();
402 provideConnectedSubsystemInstance();
405 cut.closeConnection();
408 verify(channelIs).close();
409 verify(channelSubsystem).disconnect();
410 verify(session).disconnect();
414 public void closeConnection_shouldBeIdempotent_whenRunOnNewInstance() throws Exception {
416 assertFalse(cut.isConnected());
419 cut.closeConnection();
422 assertFalse(cut.isConnected());
426 public void closeConnection_shouldBeIdempotent_whenRunTwiceOnConnectedInstance() throws Exception {
428 provideConnectedSubsystemInstance();
431 cut.closeConnection();
432 cut.closeConnection();
435 assertFalse(cut.isConnected());
439 public void closeConnection_shouldCloseResourcesOnce_whenRunTwiceOnConnectedInstance() throws Exception {
441 provideConnectedSubsystemInstance();
444 cut.closeConnection();
445 cut.closeConnection();
448 verify(channelIs, times(1)).close();
449 verify(channelSubsystem, times(1)).disconnect();
450 verify(session, times(1)).disconnect();
453 private void provideConnectedSubsystemInstance() throws Exception {
454 given(channelSubsystem.getInputStream()).willReturn(channelIs);
455 cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
456 assertTrue(cut.isConnected());
459 //receiveUntil tests begin
460 @Test(expected = IllegalStateException.class)
461 public void receiveUntil_shouldThrowIllegalStateException_whenInstanceIsNotConnected() throws Exception {
463 assertFalse(cut.isConnected());
466 cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
469 fail("IllegalStateException should be thrown");
472 @Test(expected = IllegalStateException.class)
473 public void receiveUntil_shouldThrowIllegalStateException_whenJschReaderStreamIsNotAvailable() throws Exception {
475 provideConnectedSubsystemInstance();
476 given(channelIs.available()).willReturn(0);
479 cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
482 fail("IllegalStateException should be thrown");
485 @Test(expected = TimedOutException.class)
486 public void receiveUntil_shouldThrowTimedOutException_whenSessionFails() throws Exception {
488 given(channelSubsystem.getInputStream()).willReturn(IOUtils.toInputStream("test input stream:~#", "UTF-8"));
489 cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
490 assertTrue(cut.isConnected());
491 doThrow(new JSchException("Session is not available")).when(session).setTimeout(anyInt());
494 cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
497 fail("TimedOutException should be thrown");
500 @Test(expected = TimedOutException.class)
501 public void receiveUntil_shouldThrowTimedOutException_whenReadFails() throws Exception {
503 provideConnectedSubsystemInstance();
504 given(channelIs.available()).willReturn(1);
505 given(channelIs.read(any(), anyInt(), anyInt())).willThrow(new IOException("Could not read stream"));
508 cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
511 fail("TimedOutException should be thrown");
514 @Test(expected = TimedOutException.class)
515 public void receiveUntil_shouldThrowException_whenTimeoutIsReached() throws Exception {
517 String streamContent = "test input stream:~#";
518 provideConnectedSubsystemInstanceWithStreamContent(streamContent);
521 cut.receiveUntil(SEARCH_STR, -1000, " Some fake command\n");
524 fail("TimedOutException should be thrown");
527 @Test(expected = TimedOutException.class)
528 public void receiveUntil_shouldThrowException_whenReachedEndOfStream_andCouldNotReadMoreBytes() throws Exception {
530 provideConnectedSubsystemInstance();
531 given(channelIs.available()).willReturn(1);
532 given(channelIs.read(any(), anyInt(), anyInt())).willReturn(-1);
535 cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
538 fail("TimedOutException should be thrown");
542 public void receiveUntil_shouldReadUnderlyingStream_andStripOffFirstLine() throws Exception {
544 String command = "Command"+SshJcraftWrapper.EOL;
545 String reply = "Reply"+SshJcraftWrapper.EOL;
546 String streamContent = command+reply+PROMPT;
547 provideConnectedSubsystemInstanceWithStreamContent(streamContent);
550 String result = cut.receiveUntil(PROMPT, SESSION_TIMEOUT, command);
553 assertEquals(reply+PROMPT, result);
557 public void receiveUntil_shouldReadUnderlyingStream_andReturnWholeReadString() throws Exception {
559 String streamContent = "Command and Reply in just one line"+PROMPT;
560 provideConnectedSubsystemInstanceWithStreamContent(streamContent);
563 String result = cut.receiveUntil(PROMPT, SESSION_TIMEOUT, streamContent);
566 assertEquals(streamContent, result);
570 public void receiveUntil_shouldCutOffSpecialCharactersFromStream() throws Exception {
572 char special1 = Character.UNASSIGNED;
573 char special2 = Character.ENCLOSING_MARK;
574 char special3 = Character.LINE_SEPARATOR;
575 char special4 = Character.MODIFIER_SYMBOL;
576 StringBuilder sb = new StringBuilder("Command");
577 sb.append(special1).append("With").append(special2).append("Special")
578 .append(special3).append("Characters").append(special4).append("Set").append(PROMPT);
580 provideConnectedSubsystemInstanceWithStreamContent(sb.toString());
583 String result = cut.receiveUntil(PROMPT, SESSION_TIMEOUT, "");
586 assertEquals("CommandWithSpecialCharactersSet"+PROMPT, result);
590 public void receiveUntil_shouldReadUnderlyingStream_untilCLIDelimiterFound_whenProperDelimiterSet() throws Exception {
592 String cliDelimiter = "#$";
593 String delimiters = PROMPT+SshJcraftWrapper.DELIMITERS_SEPARATOR+cliDelimiter;
594 String streamContent = "Command for CLI invocation #";
595 provideConnectedSubsystemInstanceWithStreamContent(streamContent);
598 String result = cut.receiveUntil(delimiters, SESSION_TIMEOUT, streamContent);
601 assertEquals(streamContent, result);
605 public void receiveUntil_shouldReadUnderlyingStream_untilCLIDelimiterFound_whenCLICommandSet() throws Exception {
607 String streamContent = "Command for CLI invocation #";
608 provideConnectedSubsystemInstanceWithStreamContent(streamContent);
609 cut.setRouterCommandType("CLI");
612 String result = cut.receiveUntil("", SESSION_TIMEOUT, streamContent);
615 assertEquals(streamContent, result);
619 public void receiveUntil_shouldReadUnderlyingStream_untilCLIDelimiterFound_forShowConfigCommand() throws Exception {
621 String streamContent = "show config\nconfig content#";
622 provideConnectedSubsystemInstanceWithStreamContent(streamContent);
625 String result = cut.receiveUntil("#", SESSION_TIMEOUT, streamContent);
628 assertEquals("config content#", result);
632 public void receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile_confirmFromFile() throws Exception {
633 receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile();
637 public void receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile_confirmFromBuffer() throws Exception {
639 int biggerBufferSize = 32;
640 cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, biggerBufferSize);
642 receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile();
645 private void receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile() throws Exception {
647 String routerName = "router";
648 String command = "RP/0/RP0/CPU0: "+routerName+" #IOS_XR_uploadedSwConfigCmd";
649 String configFileEnding = "\nXML>";
650 String streamContent = "Config file\ncontent"+configFileEnding;
651 provideConnectedSubsystemInstanceWithStreamContent(streamContent);
654 String result = cut.receiveUntil("", SESSION_TIMEOUT, command);
657 assertNull(result); //TO-DO: it would be better to return empty string in this situation
658 assertFileExist(routerName);
661 teardownFile(routerName);
664 private void provideConnectedSubsystemInstanceWithStreamContent( String streamContent) throws Exception {
665 given(channelSubsystem.getInputStream()).willReturn(IOUtils.toInputStream(streamContent, "UTF-8"));
666 cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
667 assertTrue(cut.isConnected());
670 private void teardownFile(String routerName) {
671 File file = new File(routerName);
672 if(file.exists() && file.isFile()) {
677 private void assertFileExist(String fileName) {
678 File file = new File(fileName);
679 assertTrue(file.exists());
680 assertTrue(file.isFile());