2 * ============LICENSE_START======================================================================
3 * Copyright (C) 2020 Nokia. All rights reserved.
4 * ===============================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software distributed under the
11 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12 * either express or implied. See the License for the specific language governing permissions
13 * and limitations under the License.
14 * ============LICENSE_END========================================================================
17 package org.onap.dcaegen2.collectors.datafile.ftp;
19 import static org.assertj.core.api.Assertions.assertThatThrownBy;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertThrows;
22 import static org.mockito.ArgumentMatchers.anyInt;
23 import static org.mockito.ArgumentMatchers.anyString;
24 import static org.mockito.Mockito.doReturn;
25 import static org.mockito.Mockito.doThrow;
26 import static org.mockito.Mockito.spy;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.verifyNoMoreInteractions;
29 import static org.mockito.Mockito.when;
31 import com.jcraft.jsch.ChannelSftp;
32 import com.jcraft.jsch.JSch;
33 import com.jcraft.jsch.JSchException;
34 import com.jcraft.jsch.Session;
35 import com.jcraft.jsch.SftpException;
37 import java.nio.file.Paths;
39 import org.junit.jupiter.api.Test;
40 import org.junit.jupiter.api.extension.ExtendWith;
41 import org.mockito.Mock;
42 import org.mockito.junit.jupiter.MockitoExtension;
43 import org.onap.dcaegen2.collectors.datafile.commons.FileServerData;
44 import org.onap.dcaegen2.collectors.datafile.configuration.SftpConfig;
45 import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException;
46 import org.onap.dcaegen2.collectors.datafile.exceptions.NonRetryableDatafileTaskException;
48 @ExtendWith(MockitoExtension.class)
49 public class SftpClientTest {
51 private static final String HOST = "127.0.0.1";
52 private static final int SFTP_PORT = 1021;
53 private static final String USERNAME = "bob";
54 private static final String PASSWORD = "123";
57 private JSch jschMock;
60 private Session sessionMock;
63 private ChannelSftp channelMock;
66 public void openWithPort_success() throws Exception {
67 FileServerData expectedFileServerData = FileServerData.builder() //
68 .serverAddress(HOST) //
70 .password(PASSWORD) //
74 SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
76 doReturn(jschMock).when(sftpClientSpy).createJsch();
77 when(jschMock.getSession(anyString(), anyString(), anyInt())).thenReturn(sessionMock);
78 when(sessionMock.openChannel(anyString())).thenReturn(channelMock);
82 verify(jschMock).getSession(USERNAME, HOST, SFTP_PORT);
83 verify(sessionMock).setConfig("StrictHostKeyChecking", "no");
84 verify(sessionMock).setPassword(PASSWORD);
85 verify(sessionMock).connect();
86 verify(sessionMock).openChannel("sftp");
87 verifyNoMoreInteractions(sessionMock);
89 verify(channelMock).connect();
90 verifyNoMoreInteractions(channelMock);
94 public void openWithoutPort_success() throws Exception {
95 FileServerData expectedFileServerData = FileServerData.builder() //
96 .serverAddress(HOST) //
98 .password(PASSWORD) //
102 SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
104 doReturn(jschMock).when(sftpClientSpy).createJsch();
105 when(jschMock.getSession(anyString(), anyString(), anyInt())).thenReturn(sessionMock);
106 when(sessionMock.openChannel(anyString())).thenReturn(channelMock);
108 sftpClientSpy.open();
110 verify(jschMock).getSession(USERNAME, HOST, 22);
114 public void open_throwsExceptionWithRetry() throws Exception {
115 FileServerData expectedFileServerData = FileServerData.builder() //
116 .serverAddress(HOST) //
118 .password(PASSWORD) //
122 SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
124 doReturn(jschMock).when(sftpClientSpy).createJsch();
125 when(jschMock.getSession(anyString(), anyString(), anyInt())).thenThrow(new JSchException("Failed"));
127 DatafileTaskException exception = assertThrows(DatafileTaskException.class, () -> sftpClientSpy.open());
128 assertEquals("Could not open Sftp client. com.jcraft.jsch.JSchException: Failed", exception.getMessage());
132 public void openAuthFail_throwsExceptionWithoutRetry() throws Exception {
133 FileServerData expectedFileServerData = FileServerData.builder() //
134 .serverAddress(HOST) //
136 .password(PASSWORD) //
140 SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
142 doReturn(jschMock).when(sftpClientSpy).createJsch();
143 when(jschMock.getSession(anyString(), anyString(), anyInt())).thenThrow(new JSchException("Auth fail"));
145 NonRetryableDatafileTaskException exception =
146 assertThrows(NonRetryableDatafileTaskException.class, () -> sftpClientSpy.open());
148 "Could not open Sftp client, no retry attempts will be done. com.jcraft.jsch.JSchException: Auth fail",
149 exception.getMessage());
152 @SuppressWarnings("resource")
154 public void collectFile_success() throws DatafileTaskException, SftpException {
155 FileServerData expectedFileServerData = FileServerData.builder() //
156 .serverAddress(HOST) //
158 .password(PASSWORD) //
161 SftpClient sftpClient = new SftpClient(expectedFileServerData, createSampleSftpClientSettings());
163 sftpClient.sftpChannel = channelMock;
165 sftpClient.collectFile("remote.xml", Paths.get("local.xml"));
167 verify(channelMock).get("remote.xml", "local.xml");
168 verifyNoMoreInteractions(channelMock);
172 public void collectFile_throwsExceptionWithRetry() throws SftpException {
173 FileServerData expectedFileServerData = FileServerData.builder() //
174 .serverAddress(HOST) //
176 .password(PASSWORD) //
180 try (SftpClient sftpClient = new SftpClient(expectedFileServerData, createSampleSftpClientSettings())) {
181 sftpClient.sftpChannel = channelMock;
182 doThrow(new SftpException(ChannelSftp.SSH_FX_BAD_MESSAGE, "Failed")).when(channelMock).get(anyString(),
185 assertThatThrownBy(() -> sftpClient.collectFile("remoteFile", Paths.get("localFile")))
186 .isInstanceOf(DatafileTaskException.class).hasMessageStartingWith("Unable to get file from xNF. ")
187 .hasMessageContaining(HOST);
192 public void collectFileFileMissing_throwsExceptionWithoutRetry() throws SftpException {
193 FileServerData expectedFileServerData = FileServerData.builder() //
194 .serverAddress(HOST) //
196 .password(PASSWORD) //
200 try (SftpClient sftpClient = new SftpClient(expectedFileServerData, createSampleSftpClientSettings())) {
201 sftpClient.sftpChannel = channelMock;
202 doThrow(new SftpException(ChannelSftp.SSH_FX_NO_SUCH_FILE, "Failed")).when(channelMock).get(anyString(),
205 assertThatThrownBy(() -> sftpClient.collectFile("remoteFile", Paths.get("localFile")))
206 .isInstanceOf(NonRetryableDatafileTaskException.class)
207 .hasMessageStartingWith("Unable to get file from xNF. No retry attempts will be done")
208 .hasMessageContaining("" + SFTP_PORT);
213 public void close_success() {
214 SftpClient sftpClient = new SftpClient(null, createSampleSftpClientSettings());
216 sftpClient.session = sessionMock;
217 sftpClient.sftpChannel = channelMock;
221 verify(sessionMock).disconnect();
222 verifyNoMoreInteractions(sessionMock);
224 verify(channelMock).exit();;
225 verifyNoMoreInteractions(channelMock);
228 private SftpClientSettings createSampleSftpClientSettings() {
229 return new SftpClientSettings(createSampleSftpConfigNoStrictHostChecking());
232 private SftpConfig createSampleSftpConfigNoStrictHostChecking() {
233 return SftpConfig.builder() //
234 .strictHostKeyChecking(false).knownHostsFilePath("N/A").build();