2 * ============LICENSE_START======================================================================
3 * Copyright (C) 2018-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 except
7 * in compliance with the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software distributed under the License
12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13 * or implied. See the License for the specific language governing permissions and limitations under
15 * ============LICENSE_END========================================================================
18 package org.oran.datafile.ftp;
20 import static org.assertj.core.api.Assertions.assertThatThrownBy;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.Mockito.doReturn;
23 import static org.mockito.Mockito.doThrow;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.spy;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.verifyNoMoreInteractions;
29 import static org.mockito.Mockito.when;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.OutputStream;
34 import java.nio.file.Path;
35 import java.nio.file.Paths;
37 import javax.net.ssl.KeyManager;
38 import javax.net.ssl.TrustManager;
40 import org.apache.commons.net.ftp.FTP;
41 import org.apache.commons.net.ftp.FTPSClient;
42 import org.junit.jupiter.api.BeforeEach;
43 import org.junit.jupiter.api.Test;
44 import org.mockito.ArgumentMatchers;
45 import org.oran.datafile.commons.FileServerData;
46 import org.springframework.http.HttpStatus;
48 public class FtpesClientTest {
50 private static final String REMOTE_FILE_PATH = "/dir/sample.txt";
51 private static final Path LOCAL_FILE_PATH = Paths.get("target/sample.txt");
52 private static final String XNF_ADDRESS = "127.0.0.1";
53 private static final int PORT = 8021;
54 private static final String FTP_KEY_PATH = "ftpKeyPath";
55 private static final String FTP_KEY_PASSWORD = "ftpKeyPassword";
56 private static final Path TRUSTED_CA_PATH = Paths.get("trustedCaPath");
57 private static final String TRUSTED_CA_PASSWORD = "trustedCaPassword";
59 private static final String USERNAME = "bob";
60 private static final String PASSWORD = "123";
62 private FTPSClient ftpsClientMock = mock(FTPSClient.class);
63 private KeyManager keyManagerMock = mock(KeyManager.class);
64 private TrustManager trustManagerMock = mock(TrustManager.class);
65 private InputStream inputStreamMock = mock(InputStream.class);
66 private OutputStream outputStreamMock = mock(OutputStream.class);
68 FtpesClient clientUnderTestSpy;
70 private FileServerData createFileServerData() {
71 return FileServerData.builder() //
72 .serverAddress(XNF_ADDRESS) //
73 .userId(USERNAME).password(PASSWORD) //
79 protected void setUp() throws Exception {
80 clientUnderTestSpy = spy(new FtpesClient(createFileServerData(), Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD,
81 TRUSTED_CA_PATH, TRUSTED_CA_PASSWORD));
82 clientUnderTestSpy.realFtpsClient = ftpsClientMock;
85 private void verifyFtpsClientMock_openOk() throws Exception {
86 doReturn(outputStreamMock).when(clientUnderTestSpy).createOutputStream(LOCAL_FILE_PATH);
88 when(ftpsClientMock.retrieveFile(ArgumentMatchers.eq(REMOTE_FILE_PATH),
89 ArgumentMatchers.any(OutputStream.class))).thenReturn(true);
90 verify(ftpsClientMock).setNeedClientAuth(true);
91 verify(ftpsClientMock).setKeyManager(keyManagerMock);
92 verify(ftpsClientMock).setTrustManager(trustManagerMock);
93 verify(ftpsClientMock).connect(XNF_ADDRESS, PORT);
94 verify(ftpsClientMock).login(USERNAME, PASSWORD);
95 verify(ftpsClientMock).getReplyCode();
96 verify(ftpsClientMock, times(1)).enterLocalPassiveMode();
97 verify(ftpsClientMock).execPBSZ(0);
98 verify(ftpsClientMock).execPROT("P");
99 verify(ftpsClientMock).setFileType(FTP.BINARY_FILE_TYPE);
100 verify(ftpsClientMock).setBufferSize(1024 * 1024);
104 public void collectFile_allOk() throws Exception {
106 doReturn(keyManagerMock).when(clientUnderTestSpy).getKeyManager(Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD);
107 doReturn(trustManagerMock).when(clientUnderTestSpy).getTrustManager(TRUSTED_CA_PATH, TRUSTED_CA_PASSWORD);
108 doReturn(outputStreamMock).when(clientUnderTestSpy).createOutputStream(LOCAL_FILE_PATH);
109 doReturn(true).when(ftpsClientMock).login(USERNAME, PASSWORD);
110 doReturn(HttpStatus.OK.value()).when(ftpsClientMock).getReplyCode();
112 clientUnderTestSpy.open();
114 doReturn(true).when(ftpsClientMock).retrieveFile(REMOTE_FILE_PATH, outputStreamMock);
115 clientUnderTestSpy.collectFile(REMOTE_FILE_PATH, LOCAL_FILE_PATH);
117 doReturn(true).when(ftpsClientMock).isConnected();
118 clientUnderTestSpy.close();
120 verifyFtpsClientMock_openOk();
121 verify(ftpsClientMock, times(1)).isConnected();
122 verify(ftpsClientMock, times(1)).logout();
123 verify(ftpsClientMock, times(1)).disconnect();
124 verify(ftpsClientMock, times(1)).retrieveFile(ArgumentMatchers.eq(REMOTE_FILE_PATH), any());
125 verifyNoMoreInteractions(ftpsClientMock);
129 public void collectFileFaultyOwnKey_shouldFail() throws Exception {
131 doReturn(outputStreamMock).when(clientUnderTestSpy).createOutputStream(LOCAL_FILE_PATH);
132 assertThatThrownBy(() -> clientUnderTestSpy.open())
133 .hasMessageContaining("Could not open connection: java.io.FileNotFoundException:");
135 verify(ftpsClientMock).setNeedClientAuth(true);
137 doReturn(false).when(ftpsClientMock).isConnected();
138 clientUnderTestSpy.close();
139 verify(ftpsClientMock).isConnected();
140 verifyNoMoreInteractions(ftpsClientMock);
144 public void collectFileFaultTrustedCA_shouldFail_no_trustedCA_file() throws Exception {
146 doReturn(keyManagerMock).when(clientUnderTestSpy).getKeyManager(Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD);
147 doThrow(new IOException("problem")).when(clientUnderTestSpy).createInputStream(TRUSTED_CA_PATH);
149 assertThatThrownBy(() -> clientUnderTestSpy.open())
150 .hasMessage("Could not open connection: java.io.IOException: problem");
154 public void collectFileFaultTrustedCA_shouldFail_empty_trustedCA_file() throws Exception {
156 doReturn(keyManagerMock).when(clientUnderTestSpy).getKeyManager(Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD);
157 doReturn(inputStreamMock).when(clientUnderTestSpy).createInputStream(TRUSTED_CA_PATH);
159 assertThatThrownBy(() -> clientUnderTestSpy.open())
160 .hasMessage("Could not open connection: java.io.EOFException");
164 public void collectFileFaultyLogin_shouldFail() throws Exception {
166 doReturn(keyManagerMock).when(clientUnderTestSpy).getKeyManager(Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD);
167 doReturn(trustManagerMock).when(clientUnderTestSpy).getTrustManager(TRUSTED_CA_PATH, TRUSTED_CA_PASSWORD);
168 doReturn(outputStreamMock).when(clientUnderTestSpy).createOutputStream(LOCAL_FILE_PATH);
169 doReturn(false).when(ftpsClientMock).login(USERNAME, PASSWORD);
171 assertThatThrownBy(() -> clientUnderTestSpy.open()).hasMessage("Unable to log in to xNF. 127.0.0.1");
173 verify(ftpsClientMock).setNeedClientAuth(true);
174 verify(ftpsClientMock).setKeyManager(keyManagerMock);
175 verify(ftpsClientMock).setTrustManager(trustManagerMock);
176 verify(ftpsClientMock).connect(XNF_ADDRESS, PORT);
177 verify(ftpsClientMock).login(USERNAME, PASSWORD);
181 public void collectFileBadRequestResponse_shouldFail() throws Exception {
182 doReturn(keyManagerMock).when(clientUnderTestSpy).getKeyManager(Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD);
183 doReturn(trustManagerMock).when(clientUnderTestSpy).getTrustManager(TRUSTED_CA_PATH, TRUSTED_CA_PASSWORD);
184 doReturn(outputStreamMock).when(clientUnderTestSpy).createOutputStream(LOCAL_FILE_PATH);
185 doReturn(true).when(ftpsClientMock).login(USERNAME, PASSWORD);
186 doReturn(503).when(ftpsClientMock).getReplyCode();
188 assertThatThrownBy(() -> clientUnderTestSpy.open())
189 .hasMessage("Unable to connect to xNF. 127.0.0.1 xNF reply code: 503");
191 verify(ftpsClientMock).setNeedClientAuth(true);
192 verify(ftpsClientMock).setKeyManager(keyManagerMock);
193 verify(ftpsClientMock).setTrustManager(trustManagerMock);
194 verify(ftpsClientMock).connect(XNF_ADDRESS, PORT);
195 verify(ftpsClientMock).login(USERNAME, PASSWORD);
196 verify(ftpsClientMock, times(2)).getReplyCode();
197 verifyNoMoreInteractions(ftpsClientMock);
201 public void collectFile_shouldFail() throws Exception {
202 doReturn(keyManagerMock).when(clientUnderTestSpy).getKeyManager(Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD);
203 doReturn(trustManagerMock).when(clientUnderTestSpy).getTrustManager(TRUSTED_CA_PATH, TRUSTED_CA_PASSWORD);
204 doReturn(outputStreamMock).when(clientUnderTestSpy).createOutputStream(LOCAL_FILE_PATH);
205 doReturn(true).when(ftpsClientMock).login(USERNAME, PASSWORD);
206 doReturn(HttpStatus.OK.value()).when(ftpsClientMock).getReplyCode();
207 clientUnderTestSpy.open();
209 doReturn(false).when(ftpsClientMock).retrieveFile(REMOTE_FILE_PATH, outputStreamMock);
211 assertThatThrownBy(() -> clientUnderTestSpy.collectFile(REMOTE_FILE_PATH, LOCAL_FILE_PATH))
212 .hasMessageContaining(REMOTE_FILE_PATH).hasMessageContaining("No retry");
214 verifyFtpsClientMock_openOk();
215 verify(ftpsClientMock, times(1)).retrieveFile(ArgumentMatchers.eq(REMOTE_FILE_PATH), any());
216 verifyNoMoreInteractions(ftpsClientMock);
220 public void collectFile_shouldFail_ioexception() throws Exception {
221 doReturn(keyManagerMock).when(clientUnderTestSpy).getKeyManager(Paths.get(FTP_KEY_PATH), FTP_KEY_PASSWORD);
222 doReturn(trustManagerMock).when(clientUnderTestSpy).getTrustManager(TRUSTED_CA_PATH, TRUSTED_CA_PASSWORD);
223 doReturn(outputStreamMock).when(clientUnderTestSpy).createOutputStream(LOCAL_FILE_PATH);
224 doReturn(true).when(ftpsClientMock).login(USERNAME, PASSWORD);
225 doReturn(HttpStatus.OK.value()).when(ftpsClientMock).getReplyCode();
226 clientUnderTestSpy.open();
227 when(ftpsClientMock.isConnected()).thenReturn(false);
229 doThrow(new IOException("problem")).when(ftpsClientMock).retrieveFile(REMOTE_FILE_PATH, outputStreamMock);
231 assertThatThrownBy(() -> clientUnderTestSpy.collectFile(REMOTE_FILE_PATH, LOCAL_FILE_PATH))
232 .hasMessage("Could not fetch file: java.io.IOException: problem");
234 verifyFtpsClientMock_openOk();
235 verify(ftpsClientMock, times(1)).retrieveFile(ArgumentMatchers.eq(REMOTE_FILE_PATH), any());
236 verifyNoMoreInteractions(ftpsClientMock);