-------------------------------------------------- StubFtpServer Getting Started -------------------------------------------------- StubFtpServer - Getting Started <> is a "stub" implementation of an FTP server. It supports the main FTP commands by implementing command handlers for each of the corresponding low-level FTP server commands (e.g. RETR, DELE, LIST). These s can be individually configured to return custom data or reply codes, allowing simulation of a complete range of both success and failure scenarios. The s can also be interrogated to verify command invocation data such as command parameters and timestamps. <> works out of the box with reasonable defaults, but can be fully configured programmatically or within a {{{http://www.springframework.org/}Spring Framework}} (or similar) container. Here is how to start the <> with the default configuration. This will return success reply codes, and return empty data (for retrieved files, directory listings, etc.). +------------------------------------------------------------------------------ StubFtpServer stubFtpServer = new StubFtpServer(); stubFtpServer.start(); +------------------------------------------------------------------------------ * CommandHandlers s are the heart of the <>. <> creates an appropriate default for each (supported) FTP server command. See the list of classes associated with FTP server commands in {{{stubftpserver-commandhandlers.html}FTP Commands and CommandHandlers}}. You can retrieve the existing defined for an FTP server command by calling the <<>> method, passing in the FTP server command name. For example: +------------------------------------------------------------------------------ PwdCommandHandler pwdCommandHandler = (PwdCommandHandler) stubFtpServer.getCommandHandler("PWD"); +------------------------------------------------------------------------------ You can replace the existing defined for an FTP server command by calling the <<>> method, passing in the FTP server command name, such as <<<"STOR">>> or <<<"USER">>>, and the <<>> instance. For example: +------------------------------------------------------------------------------ PwdCommandHandler pwdCommandHandler = new PwdCommandHandler(); pwdCommandHandler.setDirectory("some/dir"); stubFtpServer.setCommandHandler("PWD", pwdCommandHandler); +------------------------------------------------------------------------------ ** Generic CommandHandlers <> includes a couple generic classes that can be used to replace the default command handler for an FTP command. See the Javadoc for more information. * <> <<>> is a that always sends back the configured reply code and text. This can be a useful replacement for a default if you want a certain FTP command to always send back an error reply code. * <> <<>> is a composite that manages an internal ordered list of s to which it delegates. Starting with the first in the list, each invocation of this composite handler will invoke (delegate to) the current internal . Then it moves on the next in the internal list. * Programmatic Configuration You can customize the behavior of the FTP server through programmatic configuration. <> automatically creates a default for each supported command. If you want to customize the behavior of the server, you should create and configure a replacement for each command to be customized. The {{{#Example}Example Test Using Stub Ftp Server}} illustrates replacing the default with a customized handler. * Spring Configuration You can easily configure a <> instance in the {{{http://www.springframework.org/}Spring Framework}}. The following example shows a configuration file. +------------------------------------------------------------------------------ 11-09-01 12:30PM 406348 File2350.log 11-01-01 1:30PM <DIR> 0 archive +------------------------------------------------------------------------------ This example overrides the default handlers for the following FTP commands: * LIST - replies with a predefined directory listing * PWD - replies with a predefined directory pathname * DELE - replies with an error reply code (450) * RETR - replies with predefined contents for a retrieved file [] And here is the Java code to load the above configuration file and start the configured <>. +------------------------------------------------------------------------------ ApplicationContext context = new ClassPathXmlApplicationContext("stubftpserver-beans.xml"); stubFtpServer = (StubFtpServer) context.getBean("stubFtpServer"); stubFtpServer.start(); +------------------------------------------------------------------------------ * Retrieving Command Invocation Data Each manages a List of <<>> objects -- one for each time the is invoked. An <<>> contains the <<>> that triggered the invocation (containing the command name and parameters), as well as the invocation timestamp and client host address. The <<>> also contains a <<>>, with optional -specific data. See the Javadoc for more information. You can retrieve the <<>> from a by calling the <<>> method, passing in the (zero-based) index of the desired invocation. You can get the number of invocations for a by calling <<>>. The {{{#Example}Example Test Using Stub Ftp Server}} below illustrates retrieving and interrogating an <<>> from a . * {Example} Test Using StubFtpServer This section includes a simplified example of FTP client code to be tested, and a JUnit test for it that uses <>. ** FTP Client Code The following <<>> class includes a <<>> method that retrieves a remote ASCII file and returns its contents as a String. This class uses the <<>> from the {{{http://commons.apache.org/net/}Apache Commons Net}} framework. +------------------------------------------------------------------------------ public class RemoteFile { private String server; public String readFile(String filename) throws SocketException, IOException { FTPClient ftpClient = new FTPClient(); ftpClient.connect(server); 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; } // Other methods ... } +------------------------------------------------------------------------------ ** JUnit Test For FTP Client Code Using StubFtpServer The following <<>> class includes a couple of JUnit tests that use <>. +------------------------------------------------------------------------------ import java.io.IOException; import org.mockftpserver.core.command.InvocationRecord; import org.mockftpserver.stub.StubFtpServer; import org.mockftpserver.stub.command.RetrCommandHandler; import org.mockftpserver.test.AbstractTest; public class RemoteFileTest extends AbstractTest { private static final String FILENAME = "dir/sample.txt"; private RemoteFile remoteFile; private StubFtpServer stubFtpServer; /** * Test readFile() method */ public void testReadFile() throws Exception { final String CONTENTS = "abcdef 1234567890"; // Replace the default RETR CommandHandler; customize returned file contents RetrCommandHandler retrCommandHandler = new RetrCommandHandler(); retrCommandHandler.setFileContents(CONTENTS); stubFtpServer.setCommandHandler("RETR", retrCommandHandler); stubFtpServer.start(); String contents = remoteFile.readFile(FILENAME); // Verify returned file contents assertEquals("contents", CONTENTS, contents); // Verify the submitted filename InvocationRecord invocationRecord = retrCommandHandler.getInvocation(0); String filename = invocationRecord.getString(RetrCommandHandler.PATHNAME_KEY); assertEquals("filename", FILENAME, filename); } /** * Test the readFile() method when the FTP transfer fails (returns a non-success reply code) */ public void testReadFileThrowsException() { // Replace the default RETR CommandHandler; return failure reply code RetrCommandHandler retrCommandHandler = new RetrCommandHandler(); retrCommandHandler.setOverrideFinalReplyCode(550); stubFtpServer.setCommandHandler("RETR", retrCommandHandler); stubFtpServer.start(); try { remoteFile.readFile(FILENAME); fail("Expected IOException"); } catch (IOException expected) { // Expected this } } /** * @see org.mockftpserver.test.AbstractTest#setUp() */ protected void setUp() throws Exception { super.setUp(); remoteFile = new RemoteFile(); remoteFile.setServer("localhost"); stubFtpServer = new StubFtpServer(); } /** * @see org.mockftpserver.test.AbstractTest#tearDown() */ protected void tearDown() throws Exception { super.tearDown(); stubFtpServer.stop(); } } +------------------------------------------------------------------------------ Things to note about the above test: * The <<>> instance is created in the <<>> method, but is not started there because it must be configured differently for each test. The <<>> instance is stopped in the <<>> method, to ensure that it is stopped, even if the test fails. * 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 <<>> method.