summaryrefslogtreecommitdiff
path: root/tags/2.5/src/site/apt/fakeftpserver-getting-started.apt
diff options
context:
space:
mode:
Diffstat (limited to 'tags/2.5/src/site/apt/fakeftpserver-getting-started.apt')
-rw-r--r--tags/2.5/src/site/apt/fakeftpserver-getting-started.apt449
1 files changed, 449 insertions, 0 deletions
diff --git a/tags/2.5/src/site/apt/fakeftpserver-getting-started.apt b/tags/2.5/src/site/apt/fakeftpserver-getting-started.apt
new file mode 100644
index 0000000..c342978
--- /dev/null
+++ b/tags/2.5/src/site/apt/fakeftpserver-getting-started.apt
@@ -0,0 +1,449 @@
+ --------------------------------------------------
+ FakeFtpServer Getting Started
+ --------------------------------------------------
+
+FakeFtpServer - Getting Started
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ <<FakeFtpServer>> is a "fake" implementation of an FTP server. It provides a high-level abstraction for
+ an FTP Server and is suitable for most testing and simulation scenarios. You define a virtual filesystem
+ (internal, in-memory) containing an arbitrary set of files and directories. These files and directories can
+ (optionally) have associated access permissions. You also configure a set of one or more user accounts that
+ control which users can login to the FTP server, and their home (default) directories. The user account is
+ also used when assigning file and directory ownership for new files.
+
+ <<FakeFtpServer>> processes FTP client requests and responds with reply codes and reply messages
+ consistent with its configured file system and user accounts, including file and directory permissions,
+ if they have been configured.
+
+ See the {{{./fakeftpserver-features.html}FakeFtpServer Features and Limitations}} page for more information on
+ which features and scenarios are supported.
+
+ In general the steps for setting up and starting the <<<FakeFtpServer>>> are:
+
+ * Create a new <<<FakeFtpServer>>> instance, and optionally set the server control port (use a value of 0
+ to automatically choose a free port number).
+
+ * Create and configure a <<<FileSystem>>>, and attach to the <<<FakeFtpServer>>> instance.
+
+ * Create and configure one or more <<<UserAccount>>> objects and attach to the <<<FakeFtpServer>>> instance.
+
+ []
+
+ Here is an example showing configuration and starting of an <<FakeFtpServer>> with a single user
+ account and a (simulated) Windows file system, defining a directory containing two files.
+
++------------------------------------------------------------------------------
+FakeFtpServer fakeFtpServer = new FakeFtpServer();
+fakeFtpServer.addUserAccount(new UserAccount("user", "password", "c:\\data"));
+
+FileSystem fileSystem = new WindowsFakeFileSystem();
+fileSystem.add(new DirectoryEntry("c:\\data"));
+fileSystem.add(new FileEntry("c:\\data\\file1.txt", "abcdef 1234567890"));
+fileSystem.add(new FileEntry("c:\\data\\run.exe"));
+fakeFtpServer.setFileSystem(fileSystem);
+
+fakeFtpServer.start();
++------------------------------------------------------------------------------
+
+ If you are running on a system where the default port (21) is already in use or cannot be bound
+ from a user process (such as Unix), you probably need to use a different server control port. Use the
+ <<<FakeFtpServer.setServerControlPort(int serverControlPort)>>> method to use a different port
+ number. If you specify a value of <<<0>>>, then the server will use a free port number. Then call
+ <<<getServerControlPort()>>> AFTER calling <<<start()>>> has been called to determine the actual port
+ number being used. Or, you can pass in a specific port number, such as 9187.
+
+ <<FakeFtpServer>> can be fully configured programmatically or within the
+ {{{http://www.springframework.org/}Spring Framework}} or other dependency-injection container.
+ The {{{#Example}Example Test Using FakeFtpServer}} below illustrates programmatic configuration of
+ <<<FakeFtpServer>>>. Alternatively, the {{{#Spring}Configuration}} section later on illustrates how to use
+ the <Spring Framework> to configure a <<<FakeFtpServer>>> instance.
+
+* {Example} Test Using FakeFtpServer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This section includes a simplified example of FTP client code to be tested, and a JUnit
+ test for it that programmatically configures and uses <<FakeFtpServer>>.
+
+** FTP Client Code
+~~~~~~~~~~~~~~~~~~
+
+ The following <<<RemoteFile>>> class includes a <<<readFile()>>> method that retrieves a remote
+ ASCII file and returns its contents as a String. This class uses the <<<FTPClient>>> from the
+ {{{http://commons.apache.org/net/}Apache Commons Net}} framework.
+
++------------------------------------------------------------------------------
+public class RemoteFile {
+
+ public static final String USERNAME = "user";
+ public static final String PASSWORD = "password";
+
+ private String server;
+ private int port;
+
+ public String readFile(String filename) throws IOException {
+
+ FTPClient ftpClient = new FTPClient();
+ ftpClient.connect(server, port);
+ ftpClient.login(USERNAME, PASSWORD);
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ boolean success = ftpClient.retrieveFile(filename, outputStream);
+ ftpClient.disconnect();
+
+ if (!success) {
+ throw new IOException("Retrieve file failed: " + filename);
+ }
+ return outputStream.toString();
+ }
+
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ // Other methods ...
+}
++------------------------------------------------------------------------------
+
+** JUnit Test For FTP Client Code Using FakeFtpServer
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The following <<<RemoteFileTest>>> class includes a couple of JUnit tests that use
+ <<FakeFtpServer>>.
+
++------------------------------------------------------------------------------
+import org.mockftpserver.fake.filesystem.FileEntry;
+import org.mockftpserver.fake.filesystem.FileSystem;
+import org.mockftpserver.fake.filesystem.UnixFakeFileSystem;
+import org.mockftpserver.fake.FakeFtpServer;
+import org.mockftpserver.fake.UserAccount;
+import org.mockftpserver.stub.example.RemoteFile;
+import org.mockftpserver.test.AbstractTest;
+import java.io.IOException;
+import java.util.List;
+
+public class RemoteFileTest extends AbstractTest {
+
+ private static final String HOME_DIR = "/";
+ private static final String FILE = "/dir/sample.txt";
+ private static final String CONTENTS = "abcdef 1234567890";
+
+ private RemoteFile remoteFile;
+ private FakeFtpServer fakeFtpServer;
+
+ public void testReadFile() throws Exception {
+ String contents = remoteFile.readFile(FILE);
+ assertEquals("contents", CONTENTS, contents);
+ }
+
+ public void testReadFileThrowsException() {
+ try {
+ remoteFile.readFile("NoSuchFile.txt");
+ fail("Expected IOException");
+ }
+ catch (IOException expected) {
+ // Expected this
+ }
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ fakeFtpServer = new FakeFtpServer();
+ fakeFtpServer.setServerControlPort(0); // use any free port
+
+ FileSystem fileSystem = new UnixFakeFileSystem();
+ fileSystem.add(new FileEntry(FILE, CONTENTS));
+ fakeFtpServer.setFileSystem(fileSystem);
+
+ UserAccount userAccount = new UserAccount(RemoteFile.USERNAME, RemoteFile.PASSWORD, HOME_DIR);
+ fakeFtpServer.addUserAccount(userAccount);
+
+ fakeFtpServer.start();
+ int port = fakeFtpServer.getServerControlPort();
+
+ remoteFile = new RemoteFile();
+ remoteFile.setServer("localhost");
+ remoteFile.setPort(port);
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ fakeFtpServer.stop();
+ }
+}
++------------------------------------------------------------------------------
+
+ Things to note about the above test:
+
+ * The <<<FakeFtpServer>>> instance is created and started in the <<<setUp()>>> method and
+ stopped in the <<<tearDown()>>> method, to ensure that it is stopped, even if the test fails.
+
+ * The server control port is set to 0 using <<<fakeFtpServer.setServerControlPort(PORT)>>>.
+ This means it will dynamically choose a free port. This is necessary if you are running on a
+ system where the default port (21) is already in use or cannot be bound from a user process (such as Unix).
+
+ * The <<<UnixFakeFileSystem>>> filesystem is configured and attached to the <<<FakeFtpServer>>> instance
+ in the <<<setUp()>>> method. That includes creating a predefined <<<"/dir/sample.txt">>> file with the
+ specified file contents. The <<<UnixFakeFileSystem>>> has a <<<createParentDirectoriesAutomatically>>>
+ attribute, which defaults to <<<true>>>, meaning that parent directories will be created automatically,
+ as necessary. In this case, that means that the <<<"/">>> and <<<"/dir">>> parent directories will be created,
+ even though not explicitly specified.
+
+ * A single <<<UserAccount>>> with the specified username, password and home directory is configured and
+ attached to the <<<FakeFtpServer>>> instance in the <<<setUp()>>> method. That configured user ("user")
+ is the only one that will be able to sucessfully log in to the <<<FakeFtpServer>>>.
+
+
+* {Spring} Configuration
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+ You can easily configure a <<<FakeFtpServer>>> instance in the
+ {{{http://www.springframework.org/}Spring Framework}} or another, similar dependency-injection container.
+
+** Simple Spring Configuration Example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The following example shows a <Spring> configuration file for a simple <<<FakeFtpServer>>> instance.
+
++------------------------------------------------------------------------------
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
+
+ <bean id="fakeFtpServer" class="org.mockftpserver.fake.FakeFtpServer">
+ <property name="serverControlPort" value="9981"/>
+ <property name="systemName" value="UNIX"/>
+ <property name="userAccounts">
+ <list>
+ <bean class="org.mockftpserver.fake.UserAccount">
+ <property name="username" value="joe"/>
+ <property name="password" value="password"/>
+ <property name="homeDirectory" value="/"/>
+ </bean>
+ </list>
+ </property>
+
+ <property name="fileSystem">
+ <bean class="org.mockftpserver.fake.filesystem.UnixFakeFileSystem">
+ <property name="createParentDirectoriesAutomatically" value="false"/>
+ <property name="entries">
+ <list>
+ <bean class="org.mockftpserver.fake.filesystem.DirectoryEntry">
+ <property name="path" value="/"/>
+ </bean>
+ <bean class="org.mockftpserver.fake.filesystem.FileEntry">
+ <property name="path" value="/File.txt"/>
+ <property name="contents" value="abcdefghijklmnopqrstuvwxyz"/>
+ </bean>
+ </list>
+ </property>
+ </bean>
+ </property>
+
+ </bean>
+
+</beans>
++------------------------------------------------------------------------------
+
+ Things to note about the above example:
+
+ * The <<<FakeFtpServer>>> instance has a single user account for username "joe", password "password"
+ and home (default) directory of "/".
+
+ * A <<<UnixFakeFileSystem>>> instance is configured with a predefined directory of "/" and a
+ "/File.txt" file with the specified contents.
+
+ []
+
+ And here is the Java code to load the above <Spring> configuration file and start the
+ configured <<FakeFtpServer>>.
+
++------------------------------------------------------------------------------
+ApplicationContext context = new ClassPathXmlApplicationContext("fakeftpserver-beans.xml");
+FakeFtpServer = (FakeFtpServer) context.getBean("FakeFtpServer");
+FakeFtpServer.start();
++------------------------------------------------------------------------------
+
+
+** Spring Configuration Example With File and Directory Permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The following example shows a <Spring> configuration file for a <<<FakeFtpServer>>> instance that
+ also configures file and directory permissions. This will enable the <<<FakeFtpServer>>> to reply
+ with proper error codes when the logged in user does not have the required permissions to access
+ directories or files.
+
++------------------------------------------------------------------------------
+<?xml version="1.0" encoding="UTF-8"?>
+
+beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
+
+ <bean id="fakeFtpServer" class="org.mockftpserver.fake.FakeFtpServer">
+ <property name="serverControlPort" value="9981"/>
+ <property name="userAccounts">
+ <list>
+ <bean class="org.mockftpserver.fake.UserAccount">
+ <property name="username" value="joe"/>
+ <property name="password" value="password"/>
+ <property name="homeDirectory" value="c:\"/>
+ </bean>
+ </list>
+ </property>
+
+ <property name="fileSystem">
+ <bean class="org.mockftpserver.fake.filesystem.WindowsFakeFileSystem">
+ <property name="createParentDirectoriesAutomatically" value="false"/>
+ <property name="entries">
+ <list>
+ <bean class="org.mockftpserver.fake.filesystem.DirectoryEntry">
+ <property name="path" value="c:\"/>
+ <property name="permissionsFromString" value="rwxrwxrwx"/>
+ <property name="owner" value="joe"/>
+ <property name="group" value="users"/>
+ </bean>
+ <bean class="org.mockftpserver.fake.filesystem.FileEntry">
+ <property name="path" value="c:\File1.txt"/>
+ <property name="contents" value="1234567890"/>
+ <property name="permissionsFromString" value="rwxrwxrwx"/>
+ <property name="owner" value="peter"/>
+ <property name="group" value="users"/>
+ </bean>
+ <bean class="org.mockftpserver.fake.filesystem.FileEntry">
+ <property name="path" value="c:\File2.txt"/>
+ <property name="contents" value="abcdefghijklmnopqrstuvwxyz"/>
+ <property name="permissions">
+ <bean class="org.mockftpserver.fake.filesystem.Permissions">
+ <constructor-arg value="rwx------"/>
+ </bean>
+ </property>
+ <property name="owner" value="peter"/>
+ <property name="group" value="users"/>
+ </bean>
+ </list>
+ </property>
+ </bean>
+ </property>
+
+ </bean>
+</beans>
++------------------------------------------------------------------------------
+
+
+ Things to note about the above example:
+
+ * The <<<FakeFtpServer>>> instance is configured with a <<<WindowsFakeFileSystem>>> and a "c:\" root
+ directory containing two files. Permissions and owner/group are specified for that directory, as well
+ as the two predefined files contained within it.
+
+ * The permissions for "File1.txt" ("rwxrwxrwx") are specified using the "permissionsFromString" shortcut
+ method, while the permissions for "File2.txt" ("rwx------") are specified using the "permissions" setter,
+ which takes an instance of the <<<Permissions>>> class. Either method is fine.
+
+ []
+
+
+* Configuring Custom CommandHandlers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ <<FakeFtpServer>> is intentionally designed to keep the lower-level details of FTP server implementation
+ hidden from the user. In most cases, you can simply define the files and directories in the file
+ system, configure one or more login users, and then fire up the server, expecting it to behave like
+ a <real> FTP server.
+
+ There are some cases, however, where you might want to further customize the internal behavior of the
+ server. Such cases might include:
+
+ * You want to have a particular FTP server command return a predetermined error reply
+
+ * You want to add support for a command that is not provided out of the box by <<FakeFtpServer>>
+
+ Note that if you need the FTP server to reply with entirely predetermined (canned) responses, then
+ you may want to consider using <<StubFtpServer>> instead.
+
+
+** Using a StaticReplyCommandHandler
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ You can use one of the <CommandHandler> classes defined within the <<<org.mockftpserver.core.command>>>
+ package to configure a custom <CommandHandler>. The following example uses the <<<StaticReplyCommandHandler>>>
+ from that package to add support for the FEAT command. Note that in this case, we are setting the
+ <CommandHandler> for a new command (i.e., one that is not supported out of the box by <<FakeFtpServer>>).
+ We could just as easily set the <CommandHandler> for an existing command, overriding the default <CommandHandler>.
+
++------------------------------------------------------------------------------
+import org.mockftpserver.core.command.StaticReplyCommandHandler
+
+FakeFtpServer ftpServer = new FakeFtpServer()
+// ... set up files, directories and user accounts as usual
+
+StaticReplyCommandHandler featCommandHandler = new StaticReplyCommandHandler(211, "No Features");
+ftpServer.setCommandHandler("FEAT", featCommandHandler);
+
+// ...
+ftpServer.start()
++------------------------------------------------------------------------------
+
+
+** Using a Stub CommandHandler
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ You can also use a <<StubFtpServer>> <CommandHandler> -- i.e., one defined within the
+ <<<org.mockftpserver.stub.command>>> package. The following example uses the <stub> version of the
+ <<<CwdCommandHandler>>> from that package.
+
++------------------------------------------------------------------------------
+import org.mockftpserver.stub.command.CwdCommandHandler
+
+FakeFtpServer ftpServer = new FakeFtpServer()
+// ... set up files, directories and user accounts as usual
+
+final int REPLY_CODE = 502;
+CwdCommandHandler cwdCommandHandler = new CwdCommandHandler();
+cwdCommandHandler.setReplyCode(REPLY_CODE);
+ftpServer.setCommandHandler(CommandNames.CWD, cwdCommandHandler);
+
+// ...
+ftpServer.start()
++------------------------------------------------------------------------------
+
+
+** Creating Your Own Custom CommandHandler Class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ If one of the existing <CommandHandler> classes does not fulfill your needs, you can alternately create
+ your own custom <CommandHandler> class. The only requirement is that it implement the
+ <<<org.mockftpserver.core.command.CommandHandler>>> interface. You would, however, likely benefit from
+ inheriting from one of the existing abstract <CommandHandler> superclasses, such as
+ <<<org.mockftpserver.core.command.AbstractStaticReplyCommandHandler>>> or
+ <<<org.mockftpserver.core.command.AbstractCommandHandler>>>. See the javadoc of these classes for
+ more information.
+
+
+* FTP Command Reply Text ResourceBundle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The default text asociated with each FTP command reply code is contained within the
+ "ReplyText.properties" ResourceBundle file. You can customize these messages by providing a
+ locale-specific ResourceBundle file on the CLASSPATH, according to the normal lookup rules of
+ the ResourceBundle class (e.g., "ReplyText_de.properties"). Alternatively, you can
+ completely replace the ResourceBundle file by calling the calling the
+ <<<FakeFtpServer.setReplyTextBaseName(String)>>> method.
+
+* SLF4J Configuration Required to See Log Output
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Note that <<FakeFtpServer>> uses {{{http://www.slf4j.org/}SLF4J}} for logging. If you want to
+ see the logging output, then you must configure <<SLF4J>>. (If no binding is found on the class
+ path, then <<SLF4J>> will default to a no-operation implementation.)
+
+ See the {{{http://www.slf4j.org/manual.html}SLF4J User Manual}} for more information.