View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * 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
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs2.provider.ftp;
18  
19  import java.io.IOException;
20  import java.net.URL;
21  import java.time.Duration;
22  
23  import org.apache.commons.vfs2.AbstractProviderTestCase;
24  import org.apache.commons.vfs2.AbstractProviderTestConfig;
25  import org.apache.commons.vfs2.FileObject;
26  import org.apache.commons.vfs2.FileSystemManager;
27  import org.apache.commons.vfs2.FileSystemOptions;
28  import org.apache.commons.vfs2.ProviderTestSuite;
29  import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
30  import org.apache.ftpserver.FtpServer;
31  import org.apache.ftpserver.FtpServerFactory;
32  import org.apache.ftpserver.command.CommandFactory;
33  import org.apache.ftpserver.ftplet.FileSystemFactory;
34  import org.apache.ftpserver.ftplet.FtpException;
35  import org.apache.ftpserver.ftplet.UserManager;
36  import org.apache.ftpserver.listener.ListenerFactory;
37  import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
38  import org.apache.ftpserver.usermanager.impl.BaseUser;
39  import org.junit.Assert;
40  
41  import junit.framework.Test;
42  
43  /**
44   * Tests for FTP file systems.
45   */
46  public class FtpProviderTestCase extends AbstractProviderTestConfig {
47  
48      private static int SocketPort;
49  
50      /**
51       * Use %40 for @ in URLs
52       */
53      private static String ConnectionUri;
54  
55      private static FtpServer Server;
56  
57      private static final String TEST_URI = "test.ftp.uri";
58  
59      private static final String USER_PROPS_RES = "org.apache.ftpserver/users.properties";
60  
61      static String getConnectionUri() {
62          return ConnectionUri;
63      }
64  
65      static int getSocketPort() {
66          return SocketPort;
67      }
68  
69      private static String getSystemTestUriOverride() {
70          return System.getProperty(TEST_URI);
71      }
72  
73      /**
74       * Creates and starts an embedded Apache FTP Server (MINA).
75       *
76       * @param rootDirectory the local FTP server rootDirectory.
77       * @param fileSystemFactory optional local FTP server FileSystemFactory.
78       * @param commandFactory FTP server command factory.
79       * @throws FtpException
80       */
81      static void setUpClass(final String rootDirectory, final FileSystemFactory fileSystemFactory,
82          final CommandFactory commandFactory) throws FtpException {
83          if (Server != null) {
84              return;
85          }
86          final FtpServerFactory serverFactory = new FtpServerFactory();
87          final PropertiesUserManagerFactory propertiesUserManagerFactory = new PropertiesUserManagerFactory();
88          final URL userPropsResource = ClassLoader.getSystemClassLoader().getResource(USER_PROPS_RES);
89          Assert.assertNotNull(USER_PROPS_RES, userPropsResource);
90          propertiesUserManagerFactory.setUrl(userPropsResource);
91          final UserManager userManager = propertiesUserManagerFactory.createUserManager();
92          final BaseUser user = (BaseUser) userManager.getUserByName("test");
93          // Pickup the home dir value at runtime even though we have it set in the user prop file
94          // The user prop file requires the "homedirectory" to be set
95          user.setHomeDirectory(rootDirectory);
96          userManager.save(user);
97          serverFactory.setUserManager(userManager);
98          if (fileSystemFactory != null) {
99              serverFactory.setFileSystem(fileSystemFactory);
100         }
101         if (commandFactory != null) {
102             serverFactory.setCommandFactory(commandFactory);
103         }
104         final ListenerFactory factory = new ListenerFactory();
105         // set the port of the listener
106         factory.setPort(0);
107 
108         // replace the default listener
109         serverFactory.addListener("default", factory.createListener());
110 
111         // start the server
112         Server = serverFactory.createServer();
113         Server.start();
114         SocketPort = ((org.apache.ftpserver.impl.DefaultFtpServer) Server).getListener("default").getPort();
115         ConnectionUri = "ftp://test:test@localhost:" + SocketPort;
116     }
117 
118     /**
119      * Creates the test suite for the FTP file system.
120      */
121     public static Test suite() throws Exception {
122         return suite(new FtpProviderTestCase());
123     }
124 
125     /**
126      * Creates the test suite for subclasses of the FTP file system.
127      */
128     protected static Test suite(final FtpProviderTestCase testCase,
129         final Class<? extends AbstractProviderTestCase>... testClasses) throws Exception {
130         return new ProviderTestSuite(testCase) {
131 
132             @Override
133             protected void addBaseTests() throws Exception {
134                 if (testClasses.length == 0) {
135                     super.addBaseTests();
136                 } else {
137                     for (final Class<?> test : testClasses) {
138                         addTests(test);
139                     }
140                 }
141             }
142 
143             @Override
144             protected void setUp() throws Exception {
145                 if (getSystemTestUriOverride() == null) {
146                     setUpClass(testCase.getFtpRootDir(), testCase.getFtpFileSystem(), testCase.getCommandFactory());
147                 }
148                 super.setUp();
149             }
150 
151             @Override
152             protected void tearDown() throws Exception {
153                 try {
154                     // This will report running threads of the FTP server.
155                     // However, shutting down the FTP server first will always
156                     // report an exception closing the manager, because the
157                     // server is already down
158                     super.tearDown();
159                 } finally {
160                     tearDownClass();
161                 }
162             }
163         };
164     }
165 
166     /**
167      * Stops the embedded Apache FTP Server (MINA).
168      */
169     static void tearDownClass() {
170         if (Server != null) {
171             Server.stop();
172             Server = null;
173         }
174     }
175 
176     private final boolean mdtmLastModifiedTime;
177 
178     public FtpProviderTestCase() {
179         this(false);
180     }
181 
182     public FtpProviderTestCase(final boolean mdtmLastModifiedTime) {
183         this.mdtmLastModifiedTime = mdtmLastModifiedTime;
184     }
185 
186     /**
187      * Returns the base folder for tests. You can override the DEFAULT_URI by using the system property name defined by
188      * TEST_URI.
189      */
190     @Override
191     public FileObject getBaseTestFolder(final FileSystemManager manager) throws Exception {
192         String uri = getSystemTestUriOverride();
193         if (uri == null) {
194             uri = ConnectionUri;
195         }
196         final FileSystemOptions options = new FileSystemOptions();
197         final FtpFileSystemConfigBuilder builder = FtpFileSystemConfigBuilder.getInstance();
198         init(builder, options);
199         return manager.resolveFile(uri, options);
200     }
201 
202     /**
203      * Gets the FTP server command factory. Defaults to null for no override.
204      *
205      * @return the FTP server command factory or null.
206      */
207     protected CommandFactory getCommandFactory() {
208         return null;
209     }
210 
211     /**
212      * Gets option file system factory for local FTP server.
213      */
214     protected FileSystemFactory getFtpFileSystem() throws IOException {
215         // use default
216         return null;
217     }
218 
219     /**
220      * Gets the root of the local FTP Server file system.
221      */
222     protected String getFtpRootDir() {
223         return getTestDirectory();
224     }
225 
226     /**
227      * Gets the setting for UserDirIsRoot. Defaults to false.
228      */
229     protected boolean getUserDirIsRoot() {
230         return false;
231     }
232 
233     protected void init(final FtpFileSystemConfigBuilder builder, final FileSystemOptions options) {
234         builder.setUserDirIsRoot(options, getUserDirIsRoot());
235         builder.setPassiveMode(options, true);
236         // FtpFileType.BINARY is the default
237         builder.setFileType(options, FtpFileType.BINARY);
238         builder.setConnectTimeout(options, Duration.ofSeconds(10));
239         builder.setControlEncoding(options, "UTF-8");
240         builder.setControlKeepAliveReplyTimeout(options, Duration.ofSeconds(35));
241         builder.setControlKeepAliveTimeout(options, Duration.ofSeconds(30));
242         builder.setMdtmLastModifiedTime(options, mdtmLastModifiedTime);
243     }
244 
245     /**
246      * Prepares the file system manager.
247      */
248     @Override
249     public void prepare(final DefaultFileSystemManager manager) throws Exception {
250         manager.addProvider("ftp", new FtpFileProvider());
251     }
252 }