blob: 7c5349fe64b79280e72ae6c14bba71e8b163925f [file] [log] [blame]
/*
* Copyright 2008 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.fake
import org.apache.commons.net.ftp.FTP
import org.apache.commons.net.ftp.FTPClient
import org.apache.commons.net.ftp.FTPFile
import org.mockftpserver.core.command.CommandNames
import org.mockftpserver.core.command.StaticReplyCommandHandler
import org.mockftpserver.fake.filesystem.DirectoryEntry
import org.mockftpserver.fake.filesystem.FileEntry
import org.mockftpserver.fake.filesystem.FileSystem
import org.mockftpserver.fake.filesystem.UnixFakeFileSystem
import org.mockftpserver.fake.filesystem.WindowsFakeFileSystem
import org.mockftpserver.stub.command.CwdCommandHandler
import org.mockftpserver.test.AbstractGroovyTestCase
import org.mockftpserver.test.PortTestUtil
/**
* Integration tests for FakeFtpServer.
*
* @version $Revision$ - $Date$
*
* @author Chris Mair
*/
class FakeFtpServerIntegrationTest extends AbstractGroovyTestCase {
static final SERVER = "localhost"
static final USERNAME = "user123"
static final PASSWORD = "password"
static final ACCOUNT = "account123"
static final ASCII_DATA = "abcdef\tghijklmnopqr"
static final BINARY_DATA = new byte[256]
static final ROOT_DIR = "c:/"
static final HOME_DIR = p(ROOT_DIR, "home")
static final SUBDIR_NAME = 'sub'
static final SUBDIR_NAME2 = "archive"
static final SUBDIR = p(HOME_DIR, SUBDIR_NAME)
static final FILENAME1 = "abc.txt"
static final FILENAME2 = "SomeOtherFile.xml"
static final FILE1 = p(HOME_DIR, FILENAME1)
static final SYSTEM_NAME = "WINDOWS"
private FakeFtpServer ftpServer
private FTPClient ftpClient
private FileSystem fileSystem
private UserAccount userAccount
//-------------------------------------------------------------------------
// Tests
//-------------------------------------------------------------------------
void testAbor() {
ftpClientConnectAndLogin()
assert ftpClient.abort()
verifyReplyCode("ABOR", 226)
}
void testAcct() {
ftpClientConnectAndLogin()
assert ftpClient.acct(ACCOUNT) == 230
}
void testAllo() {
ftpClientConnectAndLogin()
assert ftpClient.allocate(99)
verifyReplyCode("ALLO", 200)
}
void testAppe() {
def ORIGINAL_CONTENTS = '123 456 789'
fileSystem.add(new FileEntry(path: FILE1, contents: ORIGINAL_CONTENTS))
ftpClientConnectAndLogin()
LOG.info("Put File for local path [$FILE1]")
def inputStream = new ByteArrayInputStream(ASCII_DATA.getBytes())
assert ftpClient.appendFile(FILE1, inputStream)
def contents = fileSystem.getEntry(FILE1).createInputStream().text
LOG.info("File contents=[" + contents + "]")
assert contents == ORIGINAL_CONTENTS + ASCII_DATA
}
void testCdup() {
ftpClientConnectAndLogin()
assert ftpClient.changeToParentDirectory()
verifyReplyCode("changeToParentDirectory", 200)
}
void testCwd() {
ftpClientConnectAndLogin()
assert ftpClient.changeWorkingDirectory(SUBDIR_NAME)
verifyReplyCode("changeWorkingDirectory", 250)
}
/**
* Test that a CWD to ".." properly resolves the current dir (without the "..") so that PWD returns the parent
*/
void testCwd_DotDot_Pwd() {
ftpClientConnectAndLogin()
assert ftpClient.changeWorkingDirectory("..")
verifyReplyCode("changeWorkingDirectory", 250)
assert p(ftpClient.printWorkingDirectory()) == p(ROOT_DIR)
assert ftpClient.changeWorkingDirectory("home")
assert p(ftpClient.printWorkingDirectory()) == p(HOME_DIR)
}
/**
* Test that a CWD to "." properly resolves the current dir (without the ".") so that PWD returns the parent
*/
void testCwd_Dot_Pwd() {
ftpClientConnectAndLogin()
assert ftpClient.changeWorkingDirectory(".")
verifyReplyCode("changeWorkingDirectory", 250)
assert p(ftpClient.printWorkingDirectory()) == p(HOME_DIR)
}
void testCwd_UseStaticReplyCommandHandler() {
final int REPLY_CODE = 500;
StaticReplyCommandHandler cwdCommandHandler = new StaticReplyCommandHandler(REPLY_CODE);
ftpServer.setCommandHandler(CommandNames.CWD, cwdCommandHandler);
ftpClientConnectAndLogin()
assert !ftpClient.changeWorkingDirectory(SUBDIR_NAME)
verifyReplyCode("changeWorkingDirectory", REPLY_CODE)
}
void testCwd_UseStubCommandHandler() {
final int REPLY_CODE = 502;
CwdCommandHandler cwdCommandHandler = new CwdCommandHandler(); // Stub command handler
cwdCommandHandler.setReplyCode(REPLY_CODE);
ftpServer.setCommandHandler(CommandNames.CWD, cwdCommandHandler);
ftpClientConnectAndLogin()
assert !ftpClient.changeWorkingDirectory(SUBDIR_NAME)
verifyReplyCode("changeWorkingDirectory", REPLY_CODE)
assert cwdCommandHandler.getInvocation(0)
}
void testDele() {
fileSystem.add(new FileEntry(FILE1))
ftpClientConnectAndLogin()
assert ftpClient.deleteFile(FILENAME1)
verifyReplyCode("deleteFile", 250)
assert !fileSystem.exists(FILENAME1)
}
void testEprt() {
log("Skipping...")
// ftpClientConnectAndLogin()
// assert ftpClient.sendCommand("EPRT", "|2|1080::8:800:200C:417A|5282|") == 200
}
void testEpsv() {
ftpClientConnectAndLogin()
assert ftpClient.sendCommand("EPSV") == 229
}
void testFeat_UseStaticReplyCommandHandler() {
// The FEAT command is not supported out of the box
StaticReplyCommandHandler featCommandHandler = new StaticReplyCommandHandler(211, "No Features");
ftpServer.setCommandHandler("FEAT", featCommandHandler);
ftpClientConnectAndLogin()
assert ftpClient.sendCommand("FEAT") == 211
}
void testHelp() {
ftpServer.helpText = [a: 'aaa', '': 'default']
ftpClientConnect()
String help = ftpClient.listHelp()
assert help.contains('default')
verifyReplyCode("listHelp", 214)
help = ftpClient.listHelp('a')
assert help.contains('aaa')
verifyReplyCode("listHelp", 214)
help = ftpClient.listHelp('bad')
assert help.contains('bad')
verifyReplyCode("listHelp", 214)
}
void testList() {
def LAST_MODIFIED = new Date()
fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME1), lastModified: LAST_MODIFIED, contents: ASCII_DATA))
fileSystem.add(new DirectoryEntry(path: p(SUBDIR, SUBDIR_NAME2), lastModified: LAST_MODIFIED))
ftpClientConnectAndLogin()
FTPFile[] files = ftpClient.listFiles(SUBDIR)
assert files.length == 2
// Can't be sure of order
FTPFile fileEntry = (files[0].getType() == FTPFile.FILE_TYPE) ? files[0] : files[1]
FTPFile dirEntry = (files[0].getType() == FTPFile.FILE_TYPE) ? files[1] : files[0]
verifyFTPFile(fileEntry, FTPFile.FILE_TYPE, FILENAME1, ASCII_DATA.size())
verifyFTPFile(dirEntry, FTPFile.DIRECTORY_TYPE, SUBDIR_NAME2, 0)
verifyReplyCode("list", 226)
}
void testList_Unix() {
ftpServer.systemName = 'UNIX'
userAccount.homeDirectory = '/'
def unixFileSystem = new UnixFakeFileSystem()
unixFileSystem.createParentDirectoriesAutomatically = true
unixFileSystem.add(new DirectoryEntry('/'))
ftpServer.fileSystem = unixFileSystem
def LAST_MODIFIED = new Date()
unixFileSystem.add(new FileEntry(path: p('/', FILENAME1), lastModified: LAST_MODIFIED, contents: ASCII_DATA))
unixFileSystem.add(new DirectoryEntry(path: p('/', SUBDIR_NAME2), lastModified: LAST_MODIFIED))
ftpClientConnectAndLogin()
FTPFile[] files = ftpClient.listFiles('/')
assert files.length == 2
// Can't be sure of order
FTPFile fileEntry = (files[0].getType() == FTPFile.FILE_TYPE) ? files[0] : files[1]
FTPFile dirEntry = (files[0].getType() == FTPFile.FILE_TYPE) ? files[1] : files[0]
verifyFTPFile(dirEntry, FTPFile.DIRECTORY_TYPE, SUBDIR_NAME2, 0)
verifyFTPFile(fileEntry, FTPFile.FILE_TYPE, FILENAME1, ASCII_DATA.size())
verifyReplyCode("list", 226)
}
void testLogin() {
ftpClientConnect()
LOG.info("Logging in as $USERNAME/$PASSWORD")
assert ftpClient.login(USERNAME, PASSWORD)
verifyReplyCode("login with $USERNAME/$PASSWORD", 230)
assertTrue("isStarted", ftpServer.isStarted());
assertFalse("isShutdown", ftpServer.isShutdown());
}
void testLogin_WithAccount() {
userAccount.accountRequiredForLogin = true
ftpClientConnect()
LOG.info("Logging in as $USERNAME/$PASSWORD with $ACCOUNT")
assert ftpClient.login(USERNAME, PASSWORD, ACCOUNT)
verifyReplyCode("login with $USERNAME/$PASSWORD with $ACCOUNT", 230)
}
void testMkd() {
ftpClientConnectAndLogin()
def DIR = p(HOME_DIR, 'NewDir')
assert ftpClient.makeDirectory(DIR)
verifyReplyCode("makeDirectory", 257)
assert fileSystem.isDirectory(DIR)
}
void testMode() {
ftpClientConnectAndLogin()
assert ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
verifyReplyCode("MODE", 200)
}
void testNlst() {
fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME1)))
fileSystem.add(new DirectoryEntry(path: p(SUBDIR, SUBDIR_NAME2)))
ftpClientConnectAndLogin()
String[] filenames = ftpClient.listNames(SUBDIR)
assert filenames as Set == [FILENAME1, SUBDIR_NAME2] as Set
verifyReplyCode("listNames", 226)
}
void testNoop() {
ftpClientConnectAndLogin()
assert ftpClient.sendNoOp()
verifyReplyCode("NOOP", 200)
}
void testPasv_Nlst() {
fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME1)))
fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME2)))
ftpClientConnectAndLogin()
ftpClient.enterLocalPassiveMode();
String[] filenames = ftpClient.listNames(SUBDIR)
assert filenames == [FILENAME1, FILENAME2]
verifyReplyCode("listNames", 226)
}
void testPwd() {
ftpClientConnectAndLogin()
assert ftpClient.printWorkingDirectory() == HOME_DIR
verifyReplyCode("printWorkingDirectory", 257)
}
void testQuit() {
ftpClientConnect()
ftpClient.quit()
verifyReplyCode("quit", 221)
}
void testRein() {
ftpClientConnectAndLogin()
assert ftpClient.rein() == 220
assert ftpClient.cdup() == 530 // now logged out
}
void testRest() {
ftpClientConnectAndLogin()
assert ftpClient.rest("marker") == 350
}
void testRetr() {
fileSystem.add(new FileEntry(path: FILE1, contents: ASCII_DATA))
ftpClientConnectAndLogin()
LOG.info("Get File for remotePath [$FILE1]")
def outputStream = new ByteArrayOutputStream()
assert ftpClient.retrieveFile(FILE1, outputStream)
LOG.info("File contents=[${outputStream.toString()}]")
assert outputStream.toString() == ASCII_DATA
}
void testRmd() {
ftpClientConnectAndLogin()
assert ftpClient.removeDirectory(SUBDIR)
verifyReplyCode("removeDirectory", 250)
assert !fileSystem.exists(SUBDIR)
}
void testRename() { // RNFR and RNTO
fileSystem.add(new FileEntry(FILE1))
ftpClientConnectAndLogin()
assert ftpClient.rename(FILE1, FILE1 + "NEW")
verifyReplyCode("rename", 250)
assert !fileSystem.exists(FILE1)
assert fileSystem.exists(FILE1 + "NEW")
}
void testSite() {
ftpClientConnectAndLogin()
assert ftpClient.site("parameters,1,2,3") == 200
}
void testSmnt() {
ftpClientConnectAndLogin()
assert ftpClient.smnt("dir") == 250
}
void testStat() {
ftpClientConnectAndLogin()
def status = ftpClient.getStatus()
assert status.contains('Connected')
verifyReplyCode("stat", 211)
}
void testStor() {
ftpClientConnectAndLogin()
LOG.info("Put File for local path [$FILE1]")
def inputStream = new ByteArrayInputStream(ASCII_DATA.getBytes())
assert ftpClient.storeFile(FILENAME1, inputStream) // relative to homeDirectory
def contents = fileSystem.getEntry(FILE1).createInputStream().text
LOG.info("File contents=[" + contents + "]")
assert contents == ASCII_DATA
}
void testStou() {
ftpClientConnectAndLogin()
def inputStream = new ByteArrayInputStream(ASCII_DATA.getBytes())
assert ftpClient.storeUniqueFile(FILENAME1, inputStream)
def names = fileSystem.listNames(HOME_DIR)
def filename = names.find {name -> name.startsWith(FILENAME1) }
assert filename
def contents = fileSystem.getEntry(p(HOME_DIR, filename)).createInputStream().text
LOG.info("File contents=[" + contents + "]")
assert contents == ASCII_DATA
}
void testStru() {
ftpClientConnectAndLogin()
assert ftpClient.setFileStructure(FTP.FILE_STRUCTURE);
verifyReplyCode("STRU", 200)
}
void testSyst() {
ftpClientConnectAndLogin()
def systemName = ftpClient.getSystemName()
LOG.info("system name = [$systemName]")
assert systemName.contains('"' + SYSTEM_NAME + '"')
verifyReplyCode("getSystemName", 215)
}
void testType() {
ftpClientConnectAndLogin()
assert ftpClient.type(FTP.ASCII_FILE_TYPE)
verifyReplyCode("TYPE", 200)
}
void testUnrecognizedCommand() {
ftpClientConnectAndLogin()
assert ftpClient.sendCommand("XXX") == 502
verifyReplyCode("XXX", 502)
}
// -------------------------------------------------------------------------
// Test setup and tear-down
// -------------------------------------------------------------------------
/**
* Perform initialization before each test
* @see org.mockftpserver.test.AbstractTestCase#setUp()
*/
void setUp() {
super.setUp()
for (int i = 0; i < BINARY_DATA.length; i++) {
BINARY_DATA[i] = (byte) i
}
ftpServer = new FakeFtpServer()
ftpServer.serverControlPort = PortTestUtil.getFtpServerControlPort()
ftpServer.systemName = SYSTEM_NAME
fileSystem = new WindowsFakeFileSystem()
fileSystem.createParentDirectoriesAutomatically = true
fileSystem.add(new DirectoryEntry(SUBDIR))
ftpServer.fileSystem = fileSystem
userAccount = new UserAccount(USERNAME, PASSWORD, HOME_DIR)
ftpServer.addUserAccount(userAccount)
ftpServer.start()
ftpClient = new FTPClient()
}
/**
* Perform cleanup after each test
* @see org.mockftpserver.test.AbstractTestCase#tearDown()
*/
void tearDown() {
super.tearDown()
ftpServer.stop()
}
// -------------------------------------------------------------------------
// Internal Helper Methods
// -------------------------------------------------------------------------
private ftpClientConnectAndLogin() {
ftpClientConnect()
assert ftpClient.login(USERNAME, PASSWORD)
}
/**
* Connect to the server from the FTPClient
*/
private void ftpClientConnect() {
def port = PortTestUtil.getFtpServerControlPort()
LOG.info("Conecting to $SERVER on port $port")
ftpClient.connect(SERVER, port)
verifyReplyCode("connect", 220)
}
/**
* 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)
}
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())
}
}