Improve Test coverage of DFC
[nonrtric/plt/ranpm.git] / datafilecollector / src / test / java / org / oran / datafile / ftp / SftpClientTest.java
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2023 Nordix Foundation. All rights reserved.
4  * Copyright (C) 2020 Nokia. All rights reserved.
5  * ===============================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
7  * except in compliance with the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software distributed under the
12  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific language governing permissions
14  * and limitations under the License.
15  * ============LICENSE_END========================================================================
16  */
17
18 package org.oran.datafile.ftp;
19
20 import static org.assertj.core.api.Assertions.assertThatThrownBy;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.mockito.ArgumentMatchers.anyInt;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.Mockito.doReturn;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.spy;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.verifyNoMoreInteractions;
30 import static org.mockito.Mockito.when;
31
32 import com.jcraft.jsch.ChannelSftp;
33 import com.jcraft.jsch.JSch;
34 import com.jcraft.jsch.JSchException;
35 import com.jcraft.jsch.Session;
36 import com.jcraft.jsch.SftpException;
37
38 import java.nio.file.Paths;
39
40 import org.junit.jupiter.api.Test;
41 import org.junit.jupiter.api.extension.ExtendWith;
42 import org.mockito.Mock;
43 import org.mockito.junit.jupiter.MockitoExtension;
44 import org.oran.datafile.configuration.SftpConfig;
45 import org.oran.datafile.exceptions.DatafileTaskException;
46 import org.oran.datafile.exceptions.NonRetryableDatafileTaskException;
47 import org.oran.datafile.model.FileServerData;
48
49 @ExtendWith(MockitoExtension.class)
50 class SftpClientTest {
51
52     private static final String HOST = "127.0.0.1";
53     private static final int SFTP_PORT = 1021;
54     private static final String USERNAME = "bob";
55     private static final String PASSWORD = "123";
56
57     @Mock
58     private JSch jschMock;
59
60     @Mock
61     private Session sessionMock;
62
63     @Mock
64     private ChannelSftp channelMock;
65
66     @Test
67     void openWithPort_success() throws Exception {
68         FileServerData expectedFileServerData = FileServerData.builder() //
69             .serverAddress(HOST) //
70             .userId(USERNAME) //
71             .password(PASSWORD) //
72             .port(SFTP_PORT) //
73             .build();
74
75         SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
76
77         doReturn(jschMock).when(sftpClientSpy).createJsch();
78         when(jschMock.getSession(anyString(), anyString(), anyInt())).thenReturn(sessionMock);
79         when(sessionMock.openChannel(anyString())).thenReturn(channelMock);
80
81         sftpClientSpy.open();
82
83         verify(jschMock).getSession(USERNAME, HOST, SFTP_PORT);
84         verify(sessionMock).setConfig("StrictHostKeyChecking", "no");
85         verify(sessionMock).setPassword(PASSWORD);
86         verify(sessionMock).connect();
87         verify(sessionMock).openChannel("sftp");
88         verifyNoMoreInteractions(sessionMock);
89
90         verify(channelMock).connect();
91         verifyNoMoreInteractions(channelMock);
92     }
93
94     @Test
95     void openWithoutPort_success() throws Exception {
96         FileServerData expectedFileServerData = FileServerData.builder() //
97             .serverAddress(HOST) //
98             .userId(USERNAME) //
99             .password(PASSWORD) //
100             .port(null) //
101             .build();
102
103         SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
104
105         doReturn(jschMock).when(sftpClientSpy).createJsch();
106         when(jschMock.getSession(anyString(), anyString(), anyInt())).thenReturn(sessionMock);
107         when(sessionMock.openChannel(anyString())).thenReturn(channelMock);
108
109         sftpClientSpy.open();
110
111         verify(jschMock).getSession(USERNAME, HOST, 22);
112     }
113
114     @Test
115     void open_throwsExceptionWithRetry() throws Exception {
116         FileServerData expectedFileServerData = FileServerData.builder() //
117             .serverAddress(HOST) //
118             .userId(USERNAME) //
119             .password(PASSWORD) //
120             .port(SFTP_PORT) //
121             .build();
122
123         SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
124
125         doReturn(jschMock).when(sftpClientSpy).createJsch();
126         when(jschMock.getSession(anyString(), anyString(), anyInt())).thenThrow(new JSchException("Failed"));
127
128         DatafileTaskException exception = assertThrows(DatafileTaskException.class, () -> sftpClientSpy.open());
129         assertEquals("Could not open Sftp client. com.jcraft.jsch.JSchException: Failed", exception.getMessage());
130     }
131
132     @Test
133     void openAuthFail_throwsExceptionWithoutRetry() throws Exception {
134         FileServerData expectedFileServerData = FileServerData.builder() //
135             .serverAddress(HOST) //
136             .userId(USERNAME) //
137             .password(PASSWORD) //
138             .port(SFTP_PORT) //
139             .build();
140
141         SftpClient sftpClientSpy = spy(new SftpClient(expectedFileServerData, createSampleSftpClientSettings()));
142
143         doReturn(jschMock).when(sftpClientSpy).createJsch();
144         when(jschMock.getSession(anyString(), anyString(), anyInt())).thenThrow(new JSchException("Auth fail"));
145
146         NonRetryableDatafileTaskException exception =
147             assertThrows(NonRetryableDatafileTaskException.class, () -> sftpClientSpy.open());
148         assertEquals(
149             "Could not open Sftp client, no retry attempts will be done. com.jcraft.jsch.JSchException: Auth fail",
150             exception.getMessage());
151     }
152
153     @SuppressWarnings("resource")
154     @Test
155     void collectFile_success() throws DatafileTaskException, SftpException {
156         FileServerData expectedFileServerData = FileServerData.builder() //
157             .serverAddress(HOST) //
158             .userId(USERNAME) //
159             .password(PASSWORD) //
160             .port(SFTP_PORT) //
161             .build();
162         SftpClient sftpClient = new SftpClient(expectedFileServerData, createSampleSftpClientSettings());
163
164         sftpClient.sftpChannel = channelMock;
165
166         sftpClient.collectFile("remote.xml", Paths.get("local.xml"));
167
168         verify(channelMock).get("remote.xml", "local.xml");
169         verifyNoMoreInteractions(channelMock);
170     }
171
172     @Test
173     void collectFile_throwsExceptionWithRetry() throws SftpException {
174         FileServerData expectedFileServerData = FileServerData.builder() //
175             .serverAddress(HOST) //
176             .userId(USERNAME) //
177             .password(PASSWORD) //
178             .port(SFTP_PORT) //
179             .build();
180
181         try (SftpClient sftpClient = new SftpClient(expectedFileServerData, createSampleSftpClientSettings())) {
182             sftpClient.sftpChannel = channelMock;
183             doThrow(new SftpException(ChannelSftp.SSH_FX_BAD_MESSAGE, "Failed")).when(channelMock).get(anyString(),
184                 anyString());
185
186             assertThatThrownBy(() -> sftpClient.collectFile("remoteFile", Paths.get("localFile")))
187                 .isInstanceOf(DatafileTaskException.class).hasMessageStartingWith("Unable to get file from xNF. ")
188                 .hasMessageContaining(HOST);
189         }
190     }
191
192     @Test
193     void collectFileFileMissing_throwsExceptionWithoutRetry() throws SftpException {
194         FileServerData expectedFileServerData = FileServerData.builder() //
195             .serverAddress(HOST) //
196             .userId(USERNAME) //
197             .password(PASSWORD) //
198             .port(SFTP_PORT) //
199             .build();
200
201         try (SftpClient sftpClient = new SftpClient(expectedFileServerData, createSampleSftpClientSettings())) {
202             sftpClient.sftpChannel = channelMock;
203             doThrow(new SftpException(ChannelSftp.SSH_FX_NO_SUCH_FILE, "Failed")).when(channelMock).get(anyString(),
204                 anyString());
205
206             assertThatThrownBy(() -> sftpClient.collectFile("remoteFile", Paths.get("localFile")))
207                 .isInstanceOf(NonRetryableDatafileTaskException.class)
208                 .hasMessageStartingWith("Unable to get file from xNF. No retry attempts will be done")
209                 .hasMessageContaining("" + SFTP_PORT);
210         }
211     }
212
213     @Test
214     void close_success() {
215         SftpClient sftpClient = new SftpClient(null, createSampleSftpClientSettings());
216
217         sftpClient.session = sessionMock;
218         sftpClient.sftpChannel = channelMock;
219
220         sftpClient.close();
221
222         verify(sessionMock).disconnect();
223         verifyNoMoreInteractions(sessionMock);
224
225         verify(channelMock).exit();;
226         verifyNoMoreInteractions(channelMock);
227     }
228
229     private SftpClientSettings createSampleSftpClientSettings() {
230         return new SftpClientSettings(createSampleSftpConfigNoStrictHostChecking());
231     }
232
233     private SftpConfig createSampleSftpConfigNoStrictHostChecking() {
234         return SftpConfig.builder() //
235             .strictHostKeyChecking(false).knownHostsFilePath("N/A").build();
236     }
237
238 }