305f7f5a9c9305c3a5edae7c89249d6497ed5568
[appc.git] / appc-config / appc-config-adaptor / provider / src / test / java / org / onap / appc / ccadaptor / SshJcraftWrapperTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
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
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
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.
20  * 
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  * ============LICENSE_END=========================================================
23  */
24
25 package org.onap.appc.ccadaptor;
26
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.Matchers.eq;
37 import static org.mockito.Mockito.atLeastOnce;
38 import static org.mockito.Mockito.doThrow;
39 import static org.mockito.Mockito.inOrder;
40 import static org.mockito.Mockito.never;
41 import static org.mockito.Mockito.spy;
42 import static org.mockito.Mockito.times;
43 import static org.mockito.Mockito.verify;
44 import static org.mockito.Mockito.verifyNoMoreInteractions;
45
46 import com.jcraft.jsch.ChannelSftp;
47 import com.jcraft.jsch.ChannelShell;
48 import com.jcraft.jsch.ChannelSubsystem;
49 import com.jcraft.jsch.JSch;
50 import com.jcraft.jsch.JSchException;
51 import com.jcraft.jsch.Session;
52 import com.jcraft.jsch.SftpException;
53 import com.jcraft.jsch.UserInfo;
54 import java.io.File;
55 import java.io.FileNotFoundException;
56 import java.io.IOException;
57 import java.io.InputStream;
58 import java.io.OutputStream;
59 import java.net.URL;
60
61 import org.apache.commons.lang.StringUtils;
62 import org.junit.Assert;
63 import org.junit.Before;
64 import org.junit.Ignore;
65 import org.junit.Test;
66 import org.junit.runner.RunWith;
67 import org.mockito.InOrder;
68 import org.mockito.Mock;
69 import org.mockito.runners.MockitoJUnitRunner;
70 import org.apache.commons.io.IOUtils;
71
72 @RunWith(MockitoJUnitRunner.class)
73 public class SshJcraftWrapperTest {
74
75     private static final String USER = "username";
76     private static final String PASS = "pass";
77     private static final String HOST = "hostname";
78     private static final String SUBSYSTEM = "netconf";
79     private static final String PROMPT = "]]>]]>";
80     private static final String SEARCH_STR = "</rpc-reply>";
81     private static final String REMOTE_PATH = "/var/tmp/path/";
82     private static final String SOURCE_PATH = "/tmp/local/path/";
83     private static final String IO_EXCEPTION_MSG = "IOException should be thrown";
84     private static final int READ_TIMEOUT = 180_000;
85     private static final int PORT_NUM = 23;
86     private static final int SESSION_TIMEOUT = 30_000;
87     private static final int READ_INTERVAL_MS = 1;
88     private static final int READ_BUFFER_SIZE = 10;
89
90     private SshJcraftWrapper cut;
91     @Mock
92     private JSch jSchMock;
93     @Mock
94     private Session session;
95     @Mock
96     private ChannelShell channelShell;
97     @Mock
98     private ChannelSubsystem channelSubsystem;
99     @Mock
100     private InputStream channelIs;
101     @Mock
102     private OutputStream channelOs;
103     @Mock
104     private ChannelSftp channelSftp;
105
106     @Before
107     public void setUpTest() throws Exception {
108         InputStream is = IOUtils.toInputStream("test input stream:~#", "UTF-8");
109         given(channelShell.getInputStream()).willReturn(is);
110         given(channelSubsystem.getInputStream()).willReturn(is);
111         given(session.openChannel(SshJcraftWrapper.CHANNEL_SHELL_TYPE)).willReturn(channelShell);
112         given(session.openChannel(SshJcraftWrapper.CHANNEL_SUBSYSTEM_TYPE)).willReturn(channelSubsystem);
113         given(jSchMock.getSession(anyString(), anyString(), anyInt())).willReturn(session);
114         cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, READ_BUFFER_SIZE);
115     }
116
117     @Ignore
118     @Test
119     public void TestCheckIfReceivedStringMatchesDelimeter() {
120         SshJcraftWrapper wrapper = new SshJcraftWrapper();
121         wrapper.getTheDate();
122         boolean result = wrapper.checkIfReceivedStringMatchesDelimeter("#", "test#", "test#");
123         Assert.assertEquals(true, result);
124     }
125
126     @Ignore
127     @Test
128     public void testRemoveWhiteSpaceAndNewLineCharactersAroundString() {
129         SshJcraftWrapper wrapper = new SshJcraftWrapper();
130         String nameSpace = wrapper.removeWhiteSpaceAndNewLineCharactersAroundString("namespace ");
131         Assert.assertEquals("namespace", nameSpace);
132     }
133
134     @Ignore
135     @Test
136     public void testStripOffCmdFromRouterResponse() {
137         SshJcraftWrapper wrapper = new SshJcraftWrapper();
138         String result = wrapper.stripOffCmdFromRouterResponse("test\nsuccess");
139         Assert.assertEquals("success\n", result);
140     }
141
142     //@Test
143     public void testGetLastFewLinesOfFile() throws FileNotFoundException, IOException {
144         SshJcraftWrapper wrapper = new SshJcraftWrapper();
145         URL path = SshJcraftWrapperTest.class.getResource("Test");
146         File file = new File(path.getFile());
147         String value = wrapper.getLastFewLinesOfFile(file, 1);
148         Assert.assertEquals("\nTest data 3", value);
149     }
150
151     @Ignore
152     @Test(expected = Exception.class)
153     public void testSetRouterCommandType() throws IOException {
154         SshJcraftWrapper wrapper = new SshJcraftWrapper();
155         wrapper.setRouterCommandType("test");
156         wrapper.receiveUntil("test", 2, "test");
157     }
158
159     @Ignore
160     @Test
161     public void testValues() throws IOException {
162         SshJcraftWrapper wrapper = new SshJcraftWrapper();
163         wrapper.setEquipNameCode("testcode");
164         wrapper.setRouterCommandType("testcommand");
165         String equipName = wrapper.getEquipNameCode();
166         wrapper.getHostName();
167         wrapper.getPassWord();
168         wrapper.getRouterName();
169         wrapper.getUserName();
170         wrapper.getTheDate();
171         Assert.assertEquals("testcode", equipName);
172     }
173
174     @Ignore
175     @Test(expected = Exception.class)
176     public void testSetRouterCommandType2() throws IOException {
177         SshJcraftWrapper wrapper = new SshJcraftWrapper();
178         wrapper.appendToRouterFile("test", 2);
179         StringBuilder sb = new StringBuilder();
180         sb.append("test");
181         wrapper.appendToRouterFile("Test.txt", sb);
182         wrapper.receiveUntilBufferFlush(3, 4, "test");
183     }
184
185     @Ignore
186     @Test(expected = Exception.class)
187     public void testSetRouterCommandType3() throws IOException {
188         SshJcraftWrapper wrapper = new SshJcraftWrapper();
189         wrapper.checkIfReceivedStringMatchesDelimeter(3, "test");
190     }
191
192     //real jUnits
193     @Test(expected = IOException.class)
194     public void connect_shouldThrowIOException_whenJSchFails() throws Exception {
195         //given
196         given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
197
198         //when
199         cut.connect(HOST, USER, PASS);
200
201         //then
202         fail(IO_EXCEPTION_MSG);
203     }
204
205     @Test
206     public void connect_shouldSetVariables() throws Exception {
207         //when
208         cut.connect(HOST, USER, PASS);
209
210         //then
211         assertEquals(HOST, cut.getHostName());
212         assertEquals(HOST, cut.getRouterName());
213         assertEquals(USER, cut.getUserName());
214         assertEquals(PASS, cut.getPassWord());
215     }
216
217     @Test
218     public void connect_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
219         //given
220         InOrder inOrder = inOrder(session, channelShell);
221
222         //when
223         cut.connect(HOST, USER, PASS);
224
225         //then
226         verifySessionConfigurationOrderForChannelShellOpening(
227             inOrder, USER, HOST, PASS, SshJcraftWrapper.DEFAULT_PORT, SESSION_TIMEOUT);
228     }
229
230     @Test
231     public void connect_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception {
232         //given
233         doThrow(new JSchException()).when(session).setTimeout(anyInt());
234
235         //when
236         cut.connect(HOST, USER, PASS);
237
238         //then
239         verify(session).setTimeout(anyInt());
240     }
241
242     @Test(expected = IOException.class)
243     public void connect_withSubsystem_shouldThrowIOException_whenJSchFails() throws Exception {
244         //given
245         given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
246
247         //when
248         cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
249
250         //then
251         fail(IO_EXCEPTION_MSG);
252     }
253
254     @Test
255     public void connect_withSubsystem_shouldSetRouterName() throws Exception {
256         //when
257         cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
258
259         //then
260         assertEquals(HOST, cut.getRouterName());
261     }
262
263     @Test
264     public void connect_withSubsystem_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
265         //given
266         InOrder inOrder = inOrder(session, channelSubsystem);
267
268         //when
269         cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
270
271         //then
272         verify(jSchMock).getSession(USER, HOST, PORT_NUM);
273         inOrder.verify(session).setPassword(PASS);
274         inOrder.verify(session).setUserInfo(any(UserInfo.class));
275         inOrder.verify(session)
276             .setConfig(SshJcraftWrapper.STRICT_HOST_CHECK_KEY, SshJcraftWrapper.STRICT_HOST_CHECK_VALUE);
277         inOrder.verify(session).connect(SESSION_TIMEOUT);
278         inOrder.verify(session).setServerAliveCountMax(0);
279         inOrder.verify(session).openChannel(SshJcraftWrapper.CHANNEL_SUBSYSTEM_TYPE);
280         inOrder.verify(channelSubsystem).getInputStream();
281         inOrder.verify(channelSubsystem).connect(anyInt());
282         inOrder.verifyNoMoreInteractions();
283         verifyNoMoreInteractions(jSchMock);
284     }
285
286     @Test(expected = IOException.class)
287     public void connect_withPrompt_shouldThrowIOException_whenJSchFails() throws Exception {
288         //given
289         given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
290
291         //when
292         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
293
294         //then
295         fail(IO_EXCEPTION_MSG);
296     }
297
298     @Test
299     public void connect_withPrompt_shouldSetVariables() throws Exception {
300         //when
301         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
302
303         //then
304         assertEquals(HOST, cut.getHostName());
305         assertEquals(HOST, cut.getRouterName());
306         assertEquals(USER, cut.getUserName());
307         assertEquals(PASS, cut.getPassWord());
308     }
309
310     @Test
311     public void connect_withPrompt_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception {
312         //given
313         doThrow(new JSchException()).when(session).setTimeout(anyInt());
314
315         //when
316         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
317
318         //then
319         verify(session).setTimeout(anyInt());
320     }
321
322     @Test
323     public void connect_withPrompt_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
324         //given
325         InOrder inOrder = inOrder(session, channelShell);
326
327         //when
328         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT);
329
330         //then
331         verifySessionConfigurationOrderForChannelShellOpening(
332             inOrder, USER, HOST, PASS, SshJcraftWrapper.DEFAULT_PORT, SESSION_TIMEOUT);
333     }
334
335     @Test(expected = IOException.class)
336     public void connect_withPort_shouldThrowIOException_whenJSchFails() throws Exception {
337         //given
338         given(jSchMock.getSession(anyString(), anyString(), anyInt())).willThrow(new JSchException());
339
340         //when
341         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
342
343         //then
344         fail(IO_EXCEPTION_MSG);
345     }
346
347     @Test
348     public void connect_withPort_shouldSetVariables() throws Exception {
349         //when
350         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
351
352         //then
353         assertEquals(HOST, cut.getHostName());
354         assertEquals(HOST, cut.getRouterName());
355         assertEquals(USER, cut.getUserName());
356         assertEquals(PASS, cut.getPassWord());
357     }
358
359     @Test
360     public void connect_withPort_shouldFinishSuccessfully_whenExceptionThrownDuringReceivingPhase() throws Exception {
361         //given
362         doThrow(new JSchException()).when(session).setTimeout(anyInt());
363
364         //when
365         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
366
367         //then
368         verify(session).setTimeout(anyInt());
369     }
370
371     @Test
372     public void connect_withPort_shouldSetUpSessionWithProperInvocationOrder() throws Exception {
373         //given
374         InOrder inOrder = inOrder(session, channelShell);
375
376         //when
377         cut.connect(HOST, USER, PASS, PROMPT, SESSION_TIMEOUT, PORT_NUM);
378
379         //then
380         verifySessionConfigurationOrderForChannelShellOpening(inOrder, USER, HOST, PASS, PORT_NUM, SESSION_TIMEOUT);
381     }
382
383     private void verifySessionConfigurationOrderForChannelShellOpening(InOrder inOrder, String user, String host,
384         String pass, int port, int sessionTimeout) throws Exception {
385         verify(jSchMock).getSession(user, host, port);
386         inOrder.verify(session).setPassword(pass);
387         inOrder.verify(session).setUserInfo(any(UserInfo.class));
388         inOrder.verify(session)
389             .setConfig(SshJcraftWrapper.STRICT_HOST_CHECK_KEY, SshJcraftWrapper.STRICT_HOST_CHECK_VALUE);
390         inOrder.verify(session).connect(sessionTimeout);
391         inOrder.verify(session).setServerAliveCountMax(0);
392         inOrder.verify(session).openChannel(SshJcraftWrapper.CHANNEL_SHELL_TYPE);
393         inOrder.verify(channelShell).getInputStream();
394         inOrder.verify(channelShell).connect();
395         inOrder.verify(session).setTimeout(anyInt());
396         inOrder.verifyNoMoreInteractions();
397         verifyNoMoreInteractions(jSchMock);
398     }
399
400     @Test
401     public void closeConnection_shouldCloseReaderChannelAndSession_inAGivenOrder() throws Exception {
402         //given
403         provideConnectedSubsystemInstance();
404         InOrder inOrder = inOrder(channelIs, channelSubsystem, session);
405
406         //when
407         cut.closeConnection();
408
409         //then
410         inOrder.verify(channelIs).close();
411         inOrder.verify(channelSubsystem).disconnect();
412         inOrder.verify(session).disconnect();
413         inOrder.verifyNoMoreInteractions();
414     }
415
416     @Test
417     public void closeConnection_shouldCloseChannelAndSession_whenClosingReaderFails() throws Exception {
418         //given
419         doThrow(new IOException("failed to close reader")).when(channelIs).close();
420         provideConnectedSubsystemInstance();
421
422         //when
423         cut.closeConnection();
424
425         //then
426         verify(channelIs).close();
427         verify(channelSubsystem).disconnect();
428         verify(session).disconnect();
429     }
430
431     @Test
432     public void closeConnection_shouldBeIdempotent_whenRunOnNewInstance() throws Exception {
433         //given
434         assertFalse(cut.isConnected());
435
436         //when
437         cut.closeConnection();
438
439         //then
440         assertFalse(cut.isConnected());
441     }
442
443     @Test
444     public void closeConnection_shouldBeIdempotent_whenRunTwiceOnConnectedInstance() throws Exception {
445         //given
446         provideConnectedSubsystemInstance();
447
448         //when
449         cut.closeConnection();
450         cut.closeConnection();
451
452         //then
453         assertFalse(cut.isConnected());
454     }
455
456     @Test
457     public void closeConnection_shouldCloseResourcesOnce_whenRunTwiceOnConnectedInstance() throws Exception {
458         //given
459         provideConnectedSubsystemInstance();
460
461         //when
462         cut.closeConnection();
463         cut.closeConnection();
464
465         //then
466         verify(channelIs, times(1)).close();
467         verify(channelSubsystem, times(1)).disconnect();
468         verify(session, times(1)).disconnect();
469     }
470
471     private void provideConnectedSubsystemInstance() throws Exception {
472         given(channelSubsystem.getInputStream()).willReturn(channelIs);
473         cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
474         assertTrue(cut.isConnected());
475     }
476
477     //receiveUntil tests begin
478     @Test(expected = IllegalStateException.class)
479     public void receiveUntil_shouldThrowIllegalStateException_whenInstanceIsNotConnected() throws Exception {
480         //given
481         assertFalse(cut.isConnected());
482
483         //when
484         cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
485
486         //then
487         fail("IllegalStateException should be thrown");
488     }
489
490     @Test(expected = IllegalStateException.class)
491     public void receiveUntil_shouldThrowIllegalStateException_whenJschReaderStreamIsNotAvailable() throws Exception {
492         //given
493         provideConnectedSubsystemInstance();
494         given(channelIs.available()).willReturn(0);
495
496         //when
497         cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
498
499         //then
500         fail("IllegalStateException should be thrown");
501     }
502
503     @Test(expected = TimedOutException.class)
504     public void receiveUntil_shouldThrowTimedOutException_whenSessionFails() throws Exception {
505         //given
506         given(channelSubsystem.getInputStream()).willReturn(IOUtils.toInputStream("test input stream:~#", "UTF-8"));
507         cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
508         assertTrue(cut.isConnected());
509         doThrow(new JSchException("Session is not available")).when(session).setTimeout(anyInt());
510
511         //when
512         cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
513
514         //then
515         fail("TimedOutException should be thrown");
516     }
517
518     @Test(expected = TimedOutException.class)
519     public void receiveUntil_shouldThrowTimedOutException_whenReadFails() throws Exception {
520         //given
521         provideConnectedSubsystemInstance();
522         given(channelIs.available()).willReturn(1);
523         given(channelIs.read(any(), anyInt(), anyInt())).willThrow(new IOException("Could not read stream"));
524
525         //when
526         cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
527
528         //then
529         fail("TimedOutException should be thrown");
530     }
531
532     @Test(expected = TimedOutException.class)
533     public void receiveUntil_shouldThrowException_whenTimeoutIsReached() throws Exception {
534         //given
535         String streamContent = "test input stream:~#";
536         provideConnectedSubsystemInstanceWithStreamContent(streamContent);
537
538         //when
539         cut.receiveUntil(SEARCH_STR, -1000, " Some fake command\n");
540
541         //then
542         fail("TimedOutException should be thrown");
543     }
544
545     @Test(expected = TimedOutException.class)
546     public void receiveUntil_shouldThrowException_whenReachedEndOfStream_andCouldNotReadMoreBytes() throws Exception {
547         //given
548         provideConnectedSubsystemInstance();
549         given(channelIs.available()).willReturn(1);
550         given(channelIs.read(any(), anyInt(), anyInt())).willReturn(-1);
551
552         //when
553         cut.receiveUntil(SEARCH_STR, READ_TIMEOUT, "");
554
555         //then
556         fail("TimedOutException should be thrown");
557     }
558
559     @Test
560     public void receiveUntil_shouldReadUnderlyingStream_andStripOffFirstLine() throws Exception {
561         //given
562         String command = "Command" + SshJcraftWrapper.EOL;
563         String reply = "Reply" + SshJcraftWrapper.EOL;
564         String streamContent = command + reply + PROMPT;
565         provideConnectedSubsystemInstanceWithStreamContent(streamContent);
566
567         //when
568         String result = cut.receiveUntil(PROMPT, SESSION_TIMEOUT, command);
569
570         //then
571         assertEquals(reply + PROMPT, result);
572     }
573
574     @Test
575     public void receiveUntil_shouldReadUnderlyingStream_andReturnWholeReadString() throws Exception {
576         //given
577         String streamContent = "Command and Reply in just one line" + PROMPT;
578         provideConnectedSubsystemInstanceWithStreamContent(streamContent);
579
580         //when
581         String result = cut.receiveUntil(PROMPT, SESSION_TIMEOUT, streamContent);
582
583         //then
584         assertEquals(streamContent, result);
585     }
586
587     @Test
588     public void receiveUntil_shouldCutOffSpecialCharactersFromStream() throws Exception {
589         //given
590         char special1 = Character.UNASSIGNED;
591         char special2 = Character.ENCLOSING_MARK;
592         char special3 = Character.LINE_SEPARATOR;
593         char special4 = Character.MODIFIER_SYMBOL;
594         StringBuilder sb = new StringBuilder("Command");
595         sb.append(special1).append("With").append(special2).append("Special")
596             .append(special3).append("Characters").append(special4).append("Set").append(PROMPT);
597
598         provideConnectedSubsystemInstanceWithStreamContent(sb.toString());
599
600         //when
601         String result = cut.receiveUntil(PROMPT, SESSION_TIMEOUT, "");
602
603         //then
604         assertEquals("CommandWithSpecialCharactersSet" + PROMPT, result);
605     }
606
607     @Test
608     public void receiveUntil_shouldReadUnderlyingStream_untilCLIDelimiterFound_whenProperDelimiterSet()
609         throws Exception {
610         //given
611         String cliDelimiter = "#$";
612         String delimiters = PROMPT + SshJcraftWrapper.DELIMITERS_SEPARATOR + cliDelimiter;
613         String streamContent = "Command for CLI invocation #";
614         provideConnectedSubsystemInstanceWithStreamContent(streamContent);
615
616         //when
617         String result = cut.receiveUntil(delimiters, SESSION_TIMEOUT, streamContent);
618
619         //then
620         assertEquals(streamContent, result);
621     }
622
623     @Test
624     public void receiveUntil_shouldReadUnderlyingStream_untilCLIDelimiterFound_whenCLICommandSet() throws Exception {
625         //given
626         String streamContent = "Command for CLI invocation #";
627         provideConnectedSubsystemInstanceWithStreamContent(streamContent);
628         cut.setRouterCommandType("CLI");
629
630         //when
631         String result = cut.receiveUntil("", SESSION_TIMEOUT, streamContent);
632
633         //then
634         assertEquals(streamContent, result);
635     }
636
637     @Test
638     public void receiveUntil_shouldReadUnderlyingStream_untilCLIDelimiterFound_forShowConfigCommand() throws Exception {
639         //given
640         String streamContent = "show config\nconfig content#";
641         provideConnectedSubsystemInstanceWithStreamContent(streamContent);
642
643         //when
644         String result = cut.receiveUntil("#", SESSION_TIMEOUT, streamContent);
645
646         //then
647         assertEquals("config content#", result);
648     }
649
650     @Test
651     public void receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile_confirmFromFile()
652         throws Exception {
653         receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile();
654     }
655
656     @Test
657     public void receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile_confirmFromBuffer()
658         throws Exception {
659         //given
660         int biggerBufferSize = 32;
661         cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, biggerBufferSize);
662
663         receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile();
664     }
665
666     private void receiveUntil_shouldWriteOutputToRouterFile_whenReadingIOSXRswConfigFile() throws Exception {
667         //given
668         String routerName = "router";
669         String command = "RP/0/RP0/CPU0: " + routerName + " #IOS_XR_uploadedSwConfigCmd";
670         String configFileEnding = "\nXML>";
671         String streamContent = "Config file\ncontent" + configFileEnding;
672         provideConnectedSubsystemInstanceWithStreamContent(streamContent);
673
674         //when
675         String result = cut.receiveUntil("", SESSION_TIMEOUT, command);
676
677         //then
678         assertNull(result); //TO-DO: it would be better to return empty string in this situation
679         assertFileExist(routerName);
680
681         //after
682         teardownFile(routerName);
683     }
684
685     private void provideConnectedSubsystemInstanceWithStreamContent(String streamContent) throws Exception {
686         given(channelSubsystem.getInputStream()).willReturn(IOUtils.toInputStream(streamContent, "UTF-8"));
687         cut.connect(HOST, USER, PASS, SESSION_TIMEOUT, PORT_NUM, SUBSYSTEM);
688         assertTrue(cut.isConnected());
689     }
690
691     private void teardownFile(String routerName) {
692         File file = new File(routerName);
693         if (file.exists() && file.isFile()) {
694             file.delete();
695         }
696     }
697
698     private void assertFileExist(String fileName) {
699         File file = new File(fileName);
700         assertTrue(file.exists());
701         assertTrue(file.isFile());
702     }
703
704     @Test
705     public void send_withReceive_shouldWriteCommandToChannelOutputStream_andReturnReceivedCommand() throws Exception {
706         //given
707         String command = "sdc";
708         String delimiter = ":";
709         InOrder inOrder = inOrder(channelOs);
710         provideConnectedSubsystemInstanceWithStreamContent(command + delimiter);
711         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
712
713         //when
714         String result = cut.send(command, delimiter);
715
716         //then
717         verifySdcCommandSent(inOrder);
718         assertEquals(command + delimiter, result);
719     }
720
721     @Test
722     public void send_shouldWriteCommandToChannelOutputStream() throws Exception {
723         //given
724         String command = "sdc";
725         InOrder inOrder = inOrder(channelOs);
726         provideConnectedSubsystemInstance();
727         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
728
729         //when
730         cut.send(command);
731
732         //then
733         verifySdcCommandSent(inOrder);
734     }
735
736     private void verifySdcCommandSent(InOrder inOrder) throws IOException {
737         inOrder.verify(channelOs).write('s');
738         inOrder.verify(channelOs).write('d');
739         inOrder.verify(channelOs).write('c');
740         inOrder.verify(channelOs, atLeastOnce()).flush();
741         inOrder.verify(channelOs, atLeastOnce()).close();
742         inOrder.verifyNoMoreInteractions();
743     }
744
745     @Test
746     public void send_withReceive_shouldWriteCommandInChunksToChannelOutputStream_andReturnReceivedCommand()
747         throws Exception {
748         //given
749         cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, 1);
750         cut.setCharsChunkSize(1);
751         String command = "sdc";
752         String delimiter = ":";
753         int timeout = 9000;
754         provideConnectedSubsystemInstanceWithStreamContent(command + delimiter + SshJcraftWrapper.EOL);
755         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
756         InOrder inOrder = inOrder(channelOs, session);
757
758         //when
759         String result = cut.send(command, delimiter);
760
761         //then
762         verifySdcCommandSentInChunk(inOrder, timeout);
763         assertEquals(command + delimiter, result);
764     }
765
766     @Test
767     public void send_shouldWriteCommandInChunksToChannelOutputStream() throws Exception {
768         //given
769         cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, 1);
770         cut.setCharsChunkSize(1);
771         String command = "sdc";
772         int timeout = 9000;
773         provideConnectedSubsystemInstanceWithStreamContent(command + SshJcraftWrapper.EOL);
774         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
775         InOrder inOrder = inOrder(channelOs, session);
776
777         //when
778         cut.send(command);
779
780         //then
781         verifySdcCommandSentInChunk(inOrder, timeout);
782     }
783
784     private void verifySdcCommandSentInChunk(InOrder inOrder, int timeout) throws Exception {
785         inOrder.verify(channelOs).write('s');
786         inOrder.verify(channelOs).flush();
787         inOrder.verify(session).setTimeout(timeout);
788         inOrder.verify(channelOs).write('d');
789         inOrder.verify(channelOs).flush();
790         inOrder.verify(session).setTimeout(timeout);
791         inOrder.verify(channelOs).write('c');
792         inOrder.verify(channelOs).flush();
793         inOrder.verify(session).setTimeout(timeout);
794         inOrder.verify(channelOs, atLeastOnce()).flush();
795         inOrder.verify(channelOs, atLeastOnce()).close();
796         inOrder.verifyNoMoreInteractions();
797     }
798
799     @Test
800     public void send_withReceive_shouldReturnActualResult_whenTimeoutReached() throws Exception {
801         //given
802         cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, 1);
803         cut.setCharsChunkSize(1);
804         cut.setSessionTimeoutMs(-1);
805         String command = "sdc";
806         String delimiter = ":";
807         provideConnectedSubsystemInstanceWithStreamContent(command + SshJcraftWrapper.EOL);
808         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
809
810         //when
811         String result = cut.send(command, delimiter);
812
813         //then
814         assertEquals(StringUtils.EMPTY, result);
815     }
816
817     @Test
818     public void send_withReceive_shouldReturnActualResult_whenCouldNotSetSessionTimeout() throws Exception {
819         //given
820         cut = new SshJcraftWrapper(jSchMock, READ_INTERVAL_MS, 1);
821         cut.setCharsChunkSize(1);
822         String command = "sdc";
823         String delimiter = ":";
824         provideConnectedSubsystemInstanceWithStreamContent(command + SshJcraftWrapper.EOL);
825         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
826         doThrow(new JSchException("failed to set session timeout")).when(session).setTimeout(anyInt());
827
828         //when
829         String result = cut.send(command, delimiter);
830
831         //then
832         assertEquals(StringUtils.EMPTY, result);
833     }
834
835     @Test
836     public void sendChar_shouldWriteCharacterToChannelOutputStream() throws Exception {
837         //given
838         int charNum = 100;
839         provideConnectedSubsystemInstance();
840         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
841         InOrder inOrder = inOrder(channelOs);
842
843         //when
844         cut.sendChar(charNum);
845
846         //then
847         inOrder.verify(channelOs).write(charNum);
848         inOrder.verify(channelOs, atLeastOnce()).flush();
849         inOrder.verify(channelOs, atLeastOnce()).close();
850         inOrder.verifyNoMoreInteractions();
851     }
852
853     @Test(expected = IOException.class)
854     public void sendChar_shouldRethrowIOException_whenOccurs() throws Exception {
855         //given
856         int charNum = 100;
857         provideConnectedSubsystemInstance();
858         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
859         doThrow(new IOException()).when(channelOs).write(charNum);
860
861         //when
862         cut.sendChar(charNum);
863
864         //then
865         fail(IO_EXCEPTION_MSG);
866     }
867
868     @Test
869     public void send_withByteBuffer_shouldWriteBufferToChannelOutputStream() throws Exception {
870         //given
871         byte[] buffer = "Command".getBytes();
872         int offset = 5;
873         provideConnectedSubsystemInstance();
874         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
875         InOrder inOrder = inOrder(channelOs);
876
877         //when
878         cut.send(buffer, offset, buffer.length);
879
880         //then
881         inOrder.verify(channelOs).write(buffer, offset, buffer.length);
882         inOrder.verify(channelOs, atLeastOnce()).flush();
883         inOrder.verify(channelOs, atLeastOnce()).close();
884         inOrder.verifyNoMoreInteractions();
885     }
886
887     @Test(expected = IOException.class)
888     public void send_withByteBuffer_shouldRethrowIOException_whenOccurs() throws Exception {
889         //given
890         byte[] buffer = "Command".getBytes();
891         int offset = 5;
892         provideConnectedSubsystemInstance();
893         given(channelSubsystem.getOutputStream()).willReturn(channelOs);
894         doThrow(new IOException()).when(channelOs).write(buffer, offset, buffer.length);
895
896         //when
897         cut.send(buffer, offset, buffer.length);
898
899         //then
900         fail(IO_EXCEPTION_MSG);
901     }
902
903     @Test
904     public void getSftpConnection_shouldSetupSessionWithProperInvocationOrder() throws Exception {
905         //given
906         SshJcraftWrapper instance = spy(cut);
907         given(instance.openSftpChannel(session)).willReturn(channelSftp);
908         InOrder inOrder = inOrder(session, channelSftp, instance);
909
910         //when
911         ChannelSftp result = instance.getSftpConnection(HOST, USER, PASS);
912
913         //then
914         verify(jSchMock).getSession(USER, HOST, SshJcraftWrapper.DEFAULT_PORT);
915         inOrder.verify(session).setPassword(PASS);
916         inOrder.verify(session).setUserInfo(any(UserInfo.class));
917         inOrder.verify(session)
918             .setConfig(SshJcraftWrapper.STRICT_HOST_CHECK_KEY, SshJcraftWrapper.STRICT_HOST_CHECK_VALUE);
919         inOrder.verify(session).connect(SESSION_TIMEOUT);
920         inOrder.verify(instance).openSftpChannel(session);
921         inOrder.verify(channelSftp).connect();
922         inOrder.verifyNoMoreInteractions();
923         assertEquals(channelSftp, result);
924     }
925
926     @Test
927     public void sftp_get_shouldReadFromChannelInputStream_andCloseConnection() throws Exception {
928         //given
929         String streamContent = "test input stream content";
930         SshJcraftWrapper spyInstance = spy(cut);
931         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
932         given(channelSftp.get(REMOTE_PATH)).willReturn(IOUtils.toInputStream(streamContent, "UTF-8"));
933
934         //when
935         String result = spyInstance.get(REMOTE_PATH, HOST, USER, PASS);
936
937         //then
938         assertEquals(streamContent, result);
939         verify(channelSftp).disconnect();
940         verify(session).disconnect();
941     }
942
943     @Test(expected = IOException.class)
944     public void sftp_get_shouldThrowIOException_whenJschFails() throws Exception {
945         //given
946         SshJcraftWrapper spyInstance = spy(cut);
947         doThrow(new JSchException()).when(spyInstance).openSftpChannel(session);
948
949         //when
950         spyInstance.get(REMOTE_PATH, HOST, USER, PASS);
951
952         //then
953         fail(IO_EXCEPTION_MSG);
954     }
955
956     @Test(expected = IOException.class)
957     public void sftp_get_shouldThrowIOException_whenSftpOperationFails() throws Exception {
958         //given
959         SshJcraftWrapper spyInstance = spy(cut);
960         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
961         doThrow(new SftpException(0, "sftp error")).when(channelSftp).get(REMOTE_PATH);
962
963         //when
964         spyInstance.get(REMOTE_PATH, HOST, USER, PASS);
965
966         //then
967         fail(IO_EXCEPTION_MSG);
968     }
969
970     @Test
971     public void sftp_get_shouldCloseSessionAndChannel_whenExceptionOccursOnConnectedInstance() throws Exception {
972         //given
973         SshJcraftWrapper spyInstance = spy(cut);
974         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
975         doThrow(new SftpException(0, "sftp error")).when(channelSftp).get(REMOTE_PATH);
976         boolean ioException = false;
977
978         //when
979         try {
980             spyInstance.get(REMOTE_PATH, HOST, USER, PASS);
981         } catch (IOException e) {
982             ioException = true;
983         }
984
985         //then
986         assertTrue(ioException);
987         verify(channelSftp).disconnect();
988         verify(session).disconnect();
989     }
990
991     @Test
992     public void sftp_get_shouldSkipClosingSessionAndChannel_whenExceptionOccursOnNotConnectedInstance() throws Exception {
993         //given
994         doThrow(new JSchException()).when(jSchMock).getSession(anyString(), anyString(), anyInt());
995         boolean ioException = false;
996
997         //when
998         try {
999             cut.get(REMOTE_PATH, HOST, USER, PASS);
1000         } catch (IOException e) {
1001             ioException = true;
1002         }
1003
1004         //then
1005         assertTrue(ioException);
1006         verify(channelSftp, never()).disconnect();
1007         verify(session, never()).disconnect();
1008     }
1009
1010     @Test
1011     public void sftp_put_withIs_shouldRemoveOldFilesFromDestinationPath_andPutNewData() throws Exception {
1012         //given
1013         InputStream is = IOUtils.toInputStream("test input stream content", "UTF-8");
1014         SshJcraftWrapper spyInstance = spy(cut);
1015         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1016         InOrder inOrder = inOrder(channelSftp, session);
1017
1018         //when
1019         spyInstance.put(is, REMOTE_PATH, HOST, USER, PASS);
1020
1021         //then
1022         inOrder.verify(channelSftp).rm(REMOTE_PATH + "*");
1023         inOrder.verify(channelSftp).put(is, REMOTE_PATH, ChannelSftp.OVERWRITE);
1024         inOrder.verify(channelSftp).disconnect();
1025         inOrder.verify(session).disconnect();
1026         inOrder.verifyNoMoreInteractions();
1027     }
1028
1029     @Test
1030     public void sftp_put_withIs_shouldContinueInsertingNewData_whenFileNotFoundDuringRemoval() throws Exception {
1031         //given
1032         InputStream is = IOUtils.toInputStream("test input stream content", "UTF-8");
1033         SshJcraftWrapper spyInstance = spy(cut);
1034         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1035         doThrow(new SftpException(ChannelSftp.SSH_FX_NO_SUCH_FILE, "No such file/dir"))
1036             .when(channelSftp).rm(REMOTE_PATH + "*");
1037
1038         //when
1039         spyInstance.put(is, REMOTE_PATH, HOST, USER, PASS);
1040
1041         //then
1042         verify(channelSftp).rm(REMOTE_PATH + "*");
1043         verify(channelSftp).put(is, REMOTE_PATH, ChannelSftp.OVERWRITE);
1044     }
1045
1046     @Test(expected = IOException.class)
1047     public void sftp_put_withIs_shouldThrowIOException_whenSftpFails() throws Exception {
1048         //given
1049         InputStream is = IOUtils.toInputStream("test input stream content", "UTF-8");
1050         SshJcraftWrapper spyInstance = spy(cut);
1051         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1052         doThrow(new SftpException(ChannelSftp.SSH_FX_FAILURE, "general error"))
1053             .when(channelSftp).rm(anyString());
1054
1055         //when
1056         spyInstance.put(is, REMOTE_PATH, HOST, USER, PASS);
1057
1058         //then
1059         fail(IO_EXCEPTION_MSG);
1060     }
1061
1062     @Test(expected = IOException.class)
1063     public void sftp_put_withIs_shouldThrowIOException_whenJschFails() throws Exception {
1064         //given
1065         InputStream is = IOUtils.toInputStream("test input stream content", "UTF-8");
1066         SshJcraftWrapper spyInstance = spy(cut);
1067         doThrow(new JSchException()).when(spyInstance).openSftpChannel(session);
1068
1069         //when
1070         spyInstance.put(is, REMOTE_PATH, HOST, USER, PASS);
1071
1072         //then
1073         fail(IO_EXCEPTION_MSG);
1074     }
1075
1076     @Test
1077     public void sftp_put_withSourcePath_shouldPutSrcPathToDestinationPath_andDisconnectAfterwards() throws Exception {
1078         //given
1079         SshJcraftWrapper spyInstance = spy(cut);
1080         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1081
1082         //when
1083         spyInstance.put(SOURCE_PATH, REMOTE_PATH);
1084
1085         //then
1086         verify(channelSftp).put(SOURCE_PATH, REMOTE_PATH, ChannelSftp.OVERWRITE);
1087         verify(channelSftp).disconnect();
1088         verify(session).disconnect();
1089     }
1090
1091     @Test(expected = IOException.class)
1092     public void sftp_put_withSourcePath_shouldThrowIOException_whenSftpFails() throws Exception {
1093         //given
1094         SshJcraftWrapper spyInstance = spy(cut);
1095         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1096         doThrow(new SftpException(ChannelSftp.SSH_FX_FAILURE, "general error"))
1097             .when(channelSftp).put(anyString(), anyString(), anyInt());
1098
1099         //when
1100         spyInstance.put(SOURCE_PATH, REMOTE_PATH);
1101
1102         //then
1103         fail(IO_EXCEPTION_MSG);
1104     }
1105
1106     @Test(expected = IOException.class)
1107     public void sftp_put_withSourcePath_shouldThrowIOException_whenJschFails() throws Exception {
1108         //given
1109         SshJcraftWrapper spyInstance = spy(cut);
1110         doThrow(new JSchException()).when(spyInstance).openSftpChannel(session);
1111
1112         //when
1113         spyInstance.put(SOURCE_PATH, REMOTE_PATH);
1114
1115         //then
1116         fail(IO_EXCEPTION_MSG);
1117     }
1118
1119     @Test
1120     public void sftpPutStringData_shouldPutInputStreamToRemotePath() throws Exception {
1121         //given
1122         String inputData = "Test data";
1123         SshJcraftWrapper spyInstance = spy(cut);
1124         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1125
1126         //when
1127         spyInstance.sftpPutStringData(inputData, REMOTE_PATH);
1128
1129         //then
1130         verify(channelSftp).put(any(InputStream.class), eq(REMOTE_PATH), eq(ChannelSftp.OVERWRITE));
1131         verify(channelSftp).disconnect();
1132         verify(session).disconnect();
1133     }
1134
1135     @Test(expected = IOException.class)
1136     public void sftpPutStringData_shouldThrowIOException_whenJschFails() throws Exception {
1137         //given
1138         String inputData = "Test data";
1139         SshJcraftWrapper spyInstance = spy(cut);
1140         doThrow(new JSchException()).when(spyInstance).openSftpChannel(session);
1141
1142         //when
1143         spyInstance.sftpPutStringData(inputData, REMOTE_PATH);
1144
1145         //then
1146         fail(IO_EXCEPTION_MSG);
1147     }
1148
1149     @Test(expected = IOException.class)
1150     public void sftpPutStringData_shouldThrowIOException_whenSftpFails() throws Exception {
1151         //given
1152         String inputData = "Test data";
1153         SshJcraftWrapper spyInstance = spy(cut);
1154         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1155         doThrow(new SftpException(ChannelSftp.SSH_FX_FAILURE, "general error"))
1156             .when(channelSftp).put(any(InputStream.class), anyString(), anyInt());
1157
1158         //when
1159         spyInstance.sftpPutStringData(inputData, REMOTE_PATH);
1160
1161         //then
1162         fail(IO_EXCEPTION_MSG);
1163     }
1164
1165     @Test
1166     public void sftpGet_shouldReadFromChannelInputStream_withInstanceCredentials() throws Exception {
1167         //given
1168         String remoteStreamContent = "test input stream content";
1169         SshJcraftWrapper spyInstance = spy(cut);
1170         given(spyInstance.openSftpChannel(session)).willReturn(channelSftp);
1171         given(channelSftp.get(REMOTE_PATH)).willReturn(IOUtils.toInputStream(remoteStreamContent, "UTF-8"));
1172
1173         //when
1174         String result = spyInstance.sftpGet(REMOTE_PATH);
1175
1176         //then
1177         assertEquals(remoteStreamContent, result);
1178     }
1179 }