/* | |
* Copyright 2007 the original author or authors. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.mockftpserver.stub; | |
import org.apache.commons.net.ftp.FTP; | |
import org.apache.commons.net.ftp.FTPClient; | |
import org.apache.commons.net.ftp.FTPFile; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.mockftpserver.core.command.CommandHandler; | |
import org.mockftpserver.core.command.CommandNames; | |
import org.mockftpserver.core.command.InvocationRecord; | |
import org.mockftpserver.core.command.SimpleCompositeCommandHandler; | |
import org.mockftpserver.core.command.StaticReplyCommandHandler; | |
import org.mockftpserver.stub.command.*; | |
import org.mockftpserver.test.*; | |
import org.mockftpserver.test.AbstractTestCase; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
/** | |
* Tests for StubFtpServer using the Apache Jakarta Commons Net FTP client. | |
* | |
* @author Chris Mair | |
* @version $Revision$ - $Date$ | |
*/ | |
public final class StubFtpServerIntegrationTest extends AbstractTestCase implements IntegrationTest { | |
private static final Logger LOG = LoggerFactory.getLogger(StubFtpServerIntegrationTest.class); | |
private static final String SERVER = "localhost"; | |
private static final String USERNAME = "user123"; | |
private static final String PASSWORD = "password"; | |
private static final String FILENAME = "abc.txt"; | |
private static final String ASCII_CONTENTS = "abcdef\tghijklmnopqr"; | |
private static final byte[] BINARY_CONTENTS = new byte[256]; | |
private StubFtpServer stubFtpServer; | |
private FTPClient ftpClient; | |
private RetrCommandHandler retrCommandHandler; | |
private StorCommandHandler storCommandHandler; | |
//------------------------------------------------------------------------- | |
// Tests | |
//------------------------------------------------------------------------- | |
public void testLogin() throws Exception { | |
// Connect | |
LOG.info("Conecting to " + SERVER); | |
ftpClientConnect(); | |
verifyReplyCode("connect", 220); | |
// Login | |
String userAndPassword = USERNAME + "/" + PASSWORD; | |
LOG.info("Logging in as " + userAndPassword); | |
boolean success = ftpClient.login(USERNAME, PASSWORD); | |
assertTrue("Unable to login with " + userAndPassword, success); | |
verifyReplyCode("login with " + userAndPassword, 230); | |
assertTrue("isStarted", stubFtpServer.isStarted()); | |
assertFalse("isShutdown", stubFtpServer.isShutdown()); | |
// Quit | |
LOG.info("Quit"); | |
ftpClient.quit(); | |
verifyReplyCode("quit", 221); | |
} | |
public void testAcct() throws Exception { | |
ftpClientConnect(); | |
// ACCT | |
int replyCode = ftpClient.acct("123456"); | |
assertEquals("acct", 230, replyCode); | |
} | |
/** | |
* Test the stop() method when no session has ever been started | |
*/ | |
public void testStop_NoSessionEverStarted() throws Exception { | |
LOG.info("Testing a stop() when no session has ever been started"); | |
} | |
public void testHelp() throws Exception { | |
// Modify HELP CommandHandler to return a predefined help message | |
final String HELP = "help message"; | |
HelpCommandHandler helpCommandHandler = (HelpCommandHandler) stubFtpServer.getCommandHandler(CommandNames.HELP); | |
helpCommandHandler.setHelpMessage(HELP); | |
ftpClientConnect(); | |
// HELP | |
String help = ftpClient.listHelp(); | |
assertTrue("Wrong response", help.indexOf(HELP) != -1); | |
verifyReplyCode("listHelp", 214); | |
} | |
/** | |
* Test the LIST and SYST commands. | |
*/ | |
public void testList() throws Exception { | |
ftpClientConnect(); | |
// Set directory listing | |
ListCommandHandler listCommandHandler = (ListCommandHandler) stubFtpServer.getCommandHandler(CommandNames.LIST); | |
listCommandHandler.setDirectoryListing("11-09-01 12:30PM 406348 File2350.log\n" | |
+ "11-01-01 1:30PM <DIR> archive"); | |
// LIST | |
FTPFile[] files = ftpClient.listFiles(); | |
assertEquals("number of files", 2, files.length); | |
verifyFTPFile(files[0], FTPFile.FILE_TYPE, "File2350.log", 406348L); | |
verifyFTPFile(files[1], FTPFile.DIRECTORY_TYPE, "archive", 0L); | |
verifyReplyCode("list", 226); | |
} | |
/** | |
* Test the LIST, PASV and SYST commands, transferring a directory listing in passive mode | |
*/ | |
public void testList_PassiveMode() throws Exception { | |
ftpClientConnect(); | |
ftpClient.enterLocalPassiveMode(); | |
// Set directory listing | |
ListCommandHandler listCommandHandler = (ListCommandHandler) stubFtpServer.getCommandHandler(CommandNames.LIST); | |
listCommandHandler.setDirectoryListing("11-09-01 12:30PM 406348 File2350.log"); | |
// LIST | |
FTPFile[] files = ftpClient.listFiles(); | |
assertEquals("number of files", 1, files.length); | |
verifyReplyCode("list", 226); | |
} | |
public void testNlst() throws Exception { | |
ftpClientConnect(); | |
// Set directory listing | |
NlstCommandHandler nlstCommandHandler = (NlstCommandHandler) stubFtpServer.getCommandHandler(CommandNames.NLST); | |
nlstCommandHandler.setDirectoryListing("File1.txt\nfile2.data"); | |
// NLST | |
String[] filenames = ftpClient.listNames(); | |
assertEquals("number of files", 2, filenames.length); | |
assertEquals(filenames[0], "File1.txt"); | |
assertEquals(filenames[1], "file2.data"); | |
verifyReplyCode("listNames", 226); | |
} | |
/** | |
* Test printing the current working directory (PWD) | |
*/ | |
public void testPwd() throws Exception { | |
// Modify PWD CommandHandler to return a predefined directory | |
final String DIR = "some/dir"; | |
PwdCommandHandler pwdCommandHandler = (PwdCommandHandler) stubFtpServer.getCommandHandler(CommandNames.PWD); | |
pwdCommandHandler.setDirectory(DIR); | |
ftpClientConnect(); | |
// PWD | |
String dir = ftpClient.printWorkingDirectory(); | |
assertEquals("Unable to PWD", DIR, dir); | |
verifyReplyCode("printWorkingDirectory", 257); | |
} | |
public void testStat() throws Exception { | |
// Modify Stat CommandHandler to return predefined text | |
final String STATUS = "some information 123"; | |
StatCommandHandler statCommandHandler = (StatCommandHandler) stubFtpServer.getCommandHandler(CommandNames.STAT); | |
statCommandHandler.setStatus(STATUS); | |
ftpClientConnect(); | |
// STAT | |
String status = ftpClient.getStatus(); | |
assertEquals("STAT reply", "211 " + STATUS + ".", status.trim()); | |
verifyReplyCode("getStatus", 211); | |
} | |
/** | |
* Test getting the status (STAT), when the reply text contains multiple lines | |
*/ | |
public void testStat_MultilineReplyText() throws Exception { | |
// Modify Stat CommandHandler to return predefined text | |
final String STATUS = "System name: abc.def\nVersion 3.5.7\nNumber of failed logins: 2"; | |
final String FORMATTED_REPLY_STATUS = "211-System name: abc.def\r\nVersion 3.5.7\r\n211 Number of failed logins: 2."; | |
StatCommandHandler statCommandHandler = (StatCommandHandler) stubFtpServer.getCommandHandler(CommandNames.STAT); | |
statCommandHandler.setStatus(STATUS); | |
ftpClientConnect(); | |
// STAT | |
String status = ftpClient.getStatus(); | |
assertEquals("STAT reply", FORMATTED_REPLY_STATUS, status.trim()); | |
verifyReplyCode("getStatus", 211); | |
} | |
public void testSyst() throws Exception { | |
ftpClientConnect(); | |
// SYST | |
assertEquals("getSystemName()", "\"WINDOWS\" system type.", ftpClient.getSystemName()); | |
verifyReplyCode("syst", 215); | |
} | |
public void testCwd() throws Exception { | |
// Connect | |
LOG.info("Conecting to " + SERVER); | |
ftpClientConnect(); | |
verifyReplyCode("connect", 220); | |
// CWD | |
boolean success = ftpClient.changeWorkingDirectory("dir1/dir2"); | |
assertTrue("Unable to CWD", success); | |
verifyReplyCode("changeWorkingDirectory", 250); | |
} | |
/** | |
* Test changing the current working directory (CWD), when it causes a remote error | |
*/ | |
public void testCwd_Error() throws Exception { | |
// Override CWD CommandHandler to return error reply code | |
final int REPLY_CODE = 500; | |
StaticReplyCommandHandler cwdCommandHandler = new StaticReplyCommandHandler(REPLY_CODE); | |
stubFtpServer.setCommandHandler("CWD", cwdCommandHandler); | |
ftpClientConnect(); | |
// CWD | |
boolean success = ftpClient.changeWorkingDirectory("dir1/dir2"); | |
assertFalse("Expected failure", success); | |
verifyReplyCode("changeWorkingDirectory", REPLY_CODE); | |
} | |
public void testCdup() throws Exception { | |
ftpClientConnect(); | |
// CDUP | |
boolean success = ftpClient.changeToParentDirectory(); | |
assertTrue("Unable to CDUP", success); | |
verifyReplyCode("changeToParentDirectory", 200); | |
} | |
public void testDele() throws Exception { | |
ftpClientConnect(); | |
// DELE | |
boolean success = ftpClient.deleteFile(FILENAME); | |
assertTrue("Unable to DELE", success); | |
verifyReplyCode("deleteFile", 250); | |
} | |
public void testEprt() throws Exception { | |
LOG.info("Skipping..."); | |
// ftpClientConnect(); | |
// ftpClient.sendCommand("EPRT", "|2|1080::8:800:200C:417A|5282|"); | |
// verifyReplyCode("EPRT", 200); | |
} | |
public void testEpsv() throws Exception { | |
ftpClientConnect(); | |
ftpClient.sendCommand("EPSV"); | |
verifyReplyCode("EPSV", 229); | |
} | |
public void testFeat_UseStaticReplyCommandHandler() throws IOException { | |
// The FEAT command is not supported out of the box | |
final String FEAT_TEXT = "Extensions supported:\n" + | |
"MLST size*;create;modify*;perm;media-type\n" + | |
"SIZE\n" + | |
"COMPRESSION\n" + | |
"END"; | |
StaticReplyCommandHandler featCommandHandler = new StaticReplyCommandHandler(211, FEAT_TEXT); | |
stubFtpServer.setCommandHandler("FEAT", featCommandHandler); | |
ftpClientConnect(); | |
assertEquals(ftpClient.sendCommand("FEAT"), 211); | |
LOG.info(ftpClient.getReplyString()); | |
} | |
public void testMkd() throws Exception { | |
ftpClientConnect(); | |
// MKD | |
boolean success = ftpClient.makeDirectory("dir1/dir2"); | |
assertTrue("Unable to CWD", success); | |
verifyReplyCode("makeDirectory", 257); | |
} | |
public void testNoop() throws Exception { | |
ftpClientConnect(); | |
// NOOP | |
boolean success = ftpClient.sendNoOp(); | |
assertTrue("Unable to NOOP", success); | |
verifyReplyCode("NOOP", 200); | |
} | |
public void testRest() throws Exception { | |
ftpClientConnect(); | |
// REST | |
int replyCode = ftpClient.rest("marker"); | |
assertEquals("Unable to REST", 350, replyCode); | |
} | |
public void testRmd() throws Exception { | |
ftpClientConnect(); | |
// RMD | |
boolean success = ftpClient.removeDirectory("dir1/dir2"); | |
assertTrue("Unable to RMD", success); | |
verifyReplyCode("removeDirectory", 250); | |
} | |
public void testRename() throws Exception { | |
ftpClientConnect(); | |
// Rename (RNFR, RNTO) | |
boolean success = ftpClient.rename(FILENAME, "new_" + FILENAME); | |
assertTrue("Unable to RENAME", success); | |
verifyReplyCode("rename", 250); | |
} | |
public void testAllo() throws Exception { | |
ftpClientConnect(); | |
// ALLO | |
assertTrue("ALLO", ftpClient.allocate(1024)); | |
assertTrue("ALLO with recordSize", ftpClient.allocate(1024, 64)); | |
} | |
/** | |
* Test GET and PUT of ASCII files | |
*/ | |
public void testTransferAsciiFile() throws Exception { | |
retrCommandHandler.setFileContents(ASCII_CONTENTS); | |
ftpClientConnect(); | |
// Get File | |
LOG.info("Get File for remotePath [" + FILENAME + "]"); | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
assertTrue(ftpClient.retrieveFile(FILENAME, outputStream)); | |
LOG.info("File contents=[" + outputStream.toString()); | |
assertEquals("File contents", ASCII_CONTENTS, outputStream.toString()); | |
// Put File | |
LOG.info("Put File for local path [" + FILENAME + "]"); | |
ByteArrayInputStream inputStream = new ByteArrayInputStream(ASCII_CONTENTS.getBytes()); | |
assertTrue(ftpClient.storeFile(FILENAME, inputStream)); | |
InvocationRecord invocationRecord = storCommandHandler.getInvocation(0); | |
byte[] contents = (byte[]) invocationRecord.getObject(StorCommandHandler.FILE_CONTENTS_KEY); | |
LOG.info("File contents=[" + contents + "]"); | |
assertEquals("File contents", ASCII_CONTENTS.getBytes(), contents); | |
} | |
/** | |
* Test GET and PUT of binary files | |
*/ | |
public void testTransferBinaryFiles() throws Exception { | |
retrCommandHandler.setFileContents(BINARY_CONTENTS); | |
ftpClientConnect(); | |
ftpClient.setFileType(FTP.BINARY_FILE_TYPE); | |
// Get File | |
LOG.info("Get File for remotePath [" + FILENAME + "]"); | |
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |
assertTrue("GET", ftpClient.retrieveFile(FILENAME, outputStream)); | |
LOG.info("GET File length=" + outputStream.size()); | |
assertEquals("File contents", BINARY_CONTENTS, outputStream.toByteArray()); | |
// Put File | |
LOG.info("Put File for local path [" + FILENAME + "]"); | |
ByteArrayInputStream inputStream = new ByteArrayInputStream(BINARY_CONTENTS); | |
assertTrue("PUT", ftpClient.storeFile(FILENAME, inputStream)); | |
InvocationRecord invocationRecord = storCommandHandler.getInvocation(0); | |
byte[] contents = (byte[]) invocationRecord.getObject(StorCommandHandler.FILE_CONTENTS_KEY); | |
LOG.info("PUT File length=" + contents.length); | |
assertEquals("File contents", BINARY_CONTENTS, contents); | |
} | |
public void testStou() throws Exception { | |
StouCommandHandler stouCommandHandler = (StouCommandHandler) stubFtpServer.getCommandHandler(CommandNames.STOU); | |
stouCommandHandler.setFilename(FILENAME); | |
ftpClientConnect(); | |
// Stor a File (STOU) | |
ByteArrayInputStream inputStream = new ByteArrayInputStream(ASCII_CONTENTS.getBytes()); | |
assertTrue(ftpClient.storeUniqueFile(FILENAME, inputStream)); | |
InvocationRecord invocationRecord = stouCommandHandler.getInvocation(0); | |
byte[] contents = (byte[]) invocationRecord.getObject(StorCommandHandler.FILE_CONTENTS_KEY); | |
LOG.info("File contents=[" + contents + "]"); | |
assertEquals("File contents", ASCII_CONTENTS.getBytes(), contents); | |
} | |
public void testAppe() throws Exception { | |
AppeCommandHandler appeCommandHandler = (AppeCommandHandler) stubFtpServer.getCommandHandler(CommandNames.APPE); | |
ftpClientConnect(); | |
// Append a File (APPE) | |
ByteArrayInputStream inputStream = new ByteArrayInputStream(ASCII_CONTENTS.getBytes()); | |
assertTrue(ftpClient.appendFile(FILENAME, inputStream)); | |
InvocationRecord invocationRecord = appeCommandHandler.getInvocation(0); | |
byte[] contents = (byte[]) invocationRecord.getObject(AppeCommandHandler.FILE_CONTENTS_KEY); | |
LOG.info("File contents=[" + contents + "]"); | |
assertEquals("File contents", ASCII_CONTENTS.getBytes(), contents); | |
} | |
public void testAbor() throws Exception { | |
ftpClientConnect(); | |
// ABOR | |
assertTrue("ABOR", ftpClient.abort()); | |
} | |
public void testPasv() throws Exception { | |
ftpClientConnect(); | |
// PASV | |
ftpClient.enterLocalPassiveMode(); | |
// no reply code; the PASV command is sent only when the data connection is opened | |
} | |
public void testMode() throws Exception { | |
ftpClientConnect(); | |
// MODE | |
boolean success = ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE); | |
assertTrue("Unable to MODE", success); | |
verifyReplyCode("setFileTransferMode", 200); | |
} | |
public void testStru() throws Exception { | |
ftpClientConnect(); | |
// STRU | |
boolean success = ftpClient.setFileStructure(FTP.FILE_STRUCTURE); | |
assertTrue("Unable to STRU", success); | |
verifyReplyCode("setFileStructure", 200); | |
} | |
public void testSimpleCompositeCommandHandler() throws Exception { | |
// Replace CWD CommandHandler with a SimpleCompositeCommandHandler | |
CommandHandler commandHandler1 = new StaticReplyCommandHandler(500); | |
CommandHandler commandHandler2 = new CwdCommandHandler(); | |
SimpleCompositeCommandHandler simpleCompositeCommandHandler = new SimpleCompositeCommandHandler(); | |
simpleCompositeCommandHandler.addCommandHandler(commandHandler1); | |
simpleCompositeCommandHandler.addCommandHandler(commandHandler2); | |
stubFtpServer.setCommandHandler("CWD", simpleCompositeCommandHandler); | |
// Connect | |
ftpClientConnect(); | |
// CWD | |
assertFalse("first", ftpClient.changeWorkingDirectory("dir1/dir2")); | |
assertTrue("first", ftpClient.changeWorkingDirectory("dir1/dir2")); | |
} | |
public void testSite() throws Exception { | |
ftpClientConnect(); | |
// SITE | |
int replyCode = ftpClient.site("parameters,1,2,3"); | |
assertEquals("SITE", 200, replyCode); | |
} | |
public void testSmnt() throws Exception { | |
ftpClientConnect(); | |
// SMNT | |
assertTrue("SMNT", ftpClient.structureMount("dir1/dir2")); | |
verifyReplyCode("structureMount", 250); | |
} | |
public void testRein() throws Exception { | |
ftpClientConnect(); | |
// REIN | |
assertEquals("REIN", 220, ftpClient.rein()); | |
} | |
/** | |
* Test that command names in lowercase or mixed upper/lower case are accepted | |
*/ | |
public void testCommandNamesInLowerOrMixedCase() throws Exception { | |
ftpClientConnect(); | |
assertEquals("rein", 220, ftpClient.sendCommand("rein")); | |
assertEquals("rEIn", 220, ftpClient.sendCommand("rEIn")); | |
assertEquals("reiN", 220, ftpClient.sendCommand("reiN")); | |
assertEquals("Rein", 220, ftpClient.sendCommand("Rein")); | |
} | |
public void testUnrecognizedCommand() throws Exception { | |
ftpClientConnect(); | |
assertEquals("Unrecognized:XXXX", 502, ftpClient.sendCommand("XXXX")); | |
} | |
// ------------------------------------------------------------------------- | |
// Test setup and tear-down | |
// ------------------------------------------------------------------------- | |
/** | |
* Perform initialization before each test | |
* | |
* @see org.mockftpserver.test.AbstractTestCase#setUp() | |
*/ | |
protected void setUp() throws Exception { | |
super.setUp(); | |
for (int i = 0; i < BINARY_CONTENTS.length; i++) { | |
BINARY_CONTENTS[i] = (byte) i; | |
} | |
stubFtpServer = new StubFtpServer(); | |
stubFtpServer.setServerControlPort(PortTestUtil.getFtpServerControlPort()); | |
stubFtpServer.start(); | |
ftpClient = new FTPClient(); | |
retrCommandHandler = (RetrCommandHandler) stubFtpServer.getCommandHandler(CommandNames.RETR); | |
storCommandHandler = (StorCommandHandler) stubFtpServer.getCommandHandler(CommandNames.STOR); | |
} | |
/** | |
* Perform cleanup after each test | |
* | |
* @see org.mockftpserver.test.AbstractTestCase#tearDown() | |
*/ | |
protected void tearDown() throws Exception { | |
super.tearDown(); | |
stubFtpServer.stop(); | |
} | |
// ------------------------------------------------------------------------- | |
// Internal Helper Methods | |
// ------------------------------------------------------------------------- | |
/** | |
* Connect to the server from the FTPClient | |
*/ | |
private void ftpClientConnect() throws IOException { | |
ftpClient.connect(SERVER, PortTestUtil.getFtpServerControlPort()); | |
} | |
/** | |
* Assert that the FtpClient reply code is equal to the expected value | |
* | |
* @param operation - the description of the operation performed; used in the error message | |
* @param expectedReplyCode - the expected FtpClient reply code | |
*/ | |
private void verifyReplyCode(String operation, int expectedReplyCode) { | |
int replyCode = ftpClient.getReplyCode(); | |
LOG.info("Reply: operation=\"" + operation + "\" replyCode=" + replyCode); | |
assertEquals("Unexpected replyCode for " + operation, expectedReplyCode, replyCode); | |
} | |
/** | |
* Verify that the FTPFile has the specified properties | |
* | |
* @param ftpFile - the FTPFile to verify | |
* @param type - the expected file type | |
* @param name - the expected file name | |
* @param size - the expected file size (will be zero for a directory) | |
*/ | |
private void verifyFTPFile(FTPFile ftpFile, int type, String name, long size) { | |
LOG.info(ftpFile.toString()); | |
assertEquals("type: " + ftpFile, type, ftpFile.getType()); | |
assertEquals("name: " + ftpFile, name, ftpFile.getName()); | |
assertEquals("size: " + ftpFile, size, ftpFile.getSize()); | |
} | |
} |