FakeFtpServerIntegrationTest.groovy revision 848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79
1/* 2 * Copyright 2008 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.mockftpserver.fake 17 18import org.apache.commons.net.ftp.FTP 19import org.apache.commons.net.ftp.FTPClient 20import org.apache.commons.net.ftp.FTPFile 21import org.mockftpserver.core.command.StaticReplyCommandHandler 22import org.mockftpserver.fake.FakeFtpServer 23import org.mockftpserver.fake.UserAccount 24import org.mockftpserver.fake.filesystem.* 25import org.mockftpserver.test.AbstractGroovyTest 26import org.mockftpserver.test.PortTestUtil 27 28/** 29 * Integration tests for FakeFtpServer. 30 * 31 * @version $Revision$ - $Date$ 32 * 33 * @author Chris Mair 34 */ 35class FakeFtpServerIntegrationTest extends AbstractGroovyTest { 36 37 static final SERVER = "localhost" 38 static final USERNAME = "user123" 39 static final PASSWORD = "password" 40 static final ACCOUNT = "account123" 41 static final ASCII_DATA = "abcdef\tghijklmnopqr" 42 static final BINARY_DATA = new byte[256] 43 static final ROOT_DIR = "c:/" 44 static final HOME_DIR = p(ROOT_DIR, "home") 45 static final SUBDIR_NAME = 'sub' 46 static final SUBDIR_NAME2 = "archive" 47 static final SUBDIR = p(HOME_DIR, SUBDIR_NAME) 48 static final FILENAME1 = "abc.txt" 49 static final FILENAME2 = "SomeOtherFile.xml" 50 static final FILE1 = p(HOME_DIR, FILENAME1) 51 static final SYSTEM_NAME = "WINDOWS" 52 53 private FakeFtpServer ftpServer 54 private FTPClient ftpClient 55 private FileSystem fileSystem 56 private UserAccount userAccount 57 58 //------------------------------------------------------------------------- 59 // Tests 60 //------------------------------------------------------------------------- 61 62 void testAbor() { 63 ftpClientConnectAndLogin() 64 assert ftpClient.abort() 65 verifyReplyCode("ABOR", 226) 66 } 67 68 void testAcct() { 69 ftpClientConnectAndLogin() 70 assert ftpClient.acct(ACCOUNT) == 230 71 } 72 73 void testAllo() { 74 ftpClientConnectAndLogin() 75 assert ftpClient.allocate(99) 76 verifyReplyCode("ALLO", 200) 77 } 78 79 void testAppe() { 80 def ORIGINAL_CONTENTS = '123 456 789' 81 fileSystem.add(new FileEntry(path: FILE1, contents: ORIGINAL_CONTENTS)) 82 83 ftpClientConnectAndLogin() 84 85 LOG.info("Put File for local path [$FILE1]") 86 def inputStream = new ByteArrayInputStream(ASCII_DATA.getBytes()) 87 assert ftpClient.appendFile(FILE1, inputStream) 88 def contents = fileSystem.getEntry(FILE1).createInputStream().text 89 LOG.info("File contents=[" + contents + "]") 90 assert contents == ORIGINAL_CONTENTS + ASCII_DATA 91 } 92 93 void testCdup() { 94 ftpClientConnectAndLogin() 95 assert ftpClient.changeToParentDirectory() 96 verifyReplyCode("changeToParentDirectory", 200) 97 } 98 99 void testCwd() { 100 ftpClientConnectAndLogin() 101 assert ftpClient.changeWorkingDirectory(SUBDIR_NAME) 102 verifyReplyCode("changeWorkingDirectory", 250) 103 } 104 105 void testCwd_UseStaticReplyCommandHandler() { 106 final int REPLY_CODE = 500; 107 StaticReplyCommandHandler cwdCommandHandler = new StaticReplyCommandHandler(REPLY_CODE); 108 cwdCommandHandler.replyTextBundle = ftpServer.replyTextBundle 109 ftpServer.setCommandHandler("CWD", cwdCommandHandler); 110 111 ftpClientConnectAndLogin() 112 assert !ftpClient.changeWorkingDirectory(SUBDIR_NAME) 113 verifyReplyCode("changeWorkingDirectory", 500) 114 } 115 116 void testDele() { 117 fileSystem.add(new FileEntry(FILE1)) 118 119 ftpClientConnectAndLogin() 120 assert ftpClient.deleteFile(FILENAME1) 121 verifyReplyCode("deleteFile", 250) 122 assert !fileSystem.exists(FILENAME1) 123 } 124 125 void testHelp() { 126 ftpServer.helpText = [a: 'aaa', '': 'default'] 127 ftpClientConnect() 128 129 String help = ftpClient.listHelp() 130 assert help.contains('default') 131 verifyReplyCode("listHelp", 214) 132 133 help = ftpClient.listHelp('a') 134 assert help.contains('aaa') 135 verifyReplyCode("listHelp", 214) 136 137 help = ftpClient.listHelp('bad') 138 assert help.contains('bad') 139 verifyReplyCode("listHelp", 214) 140 } 141 142 void testList() { 143 def LAST_MODIFIED = new Date() 144 fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME1), lastModified: LAST_MODIFIED, contents: ASCII_DATA)) 145 fileSystem.add(new DirectoryEntry(path: p(SUBDIR, SUBDIR_NAME2), lastModified: LAST_MODIFIED)) 146 147 ftpClientConnectAndLogin() 148 149 FTPFile[] files = ftpClient.listFiles(SUBDIR) 150 assert files.length == 2 151 verifyFTPFile(files[0], FTPFile.FILE_TYPE, FILENAME1, ASCII_DATA.size()) 152 verifyFTPFile(files[1], FTPFile.DIRECTORY_TYPE, SUBDIR_NAME2, 0) 153 verifyReplyCode("list", 226) 154 } 155 156 void testList_Unix() { 157 ftpServer.systemName = 'UNIX' 158 userAccount.homeDirectory = '/' 159 160 def unixFileSystem = new UnixFakeFileSystem() 161 unixFileSystem.createParentDirectoriesAutomatically = true 162 unixFileSystem.add(new DirectoryEntry('/')) 163 ftpServer.fileSystem = unixFileSystem 164 165 def LAST_MODIFIED = new Date() 166 unixFileSystem.add(new FileEntry(path: p('/', FILENAME1), lastModified: LAST_MODIFIED, contents: ASCII_DATA)) 167 unixFileSystem.add(new DirectoryEntry(path: p('/', SUBDIR_NAME2), lastModified: LAST_MODIFIED)) 168 169 ftpClientConnectAndLogin() 170 171 FTPFile[] files = ftpClient.listFiles('/') 172 assert files.length == 2 173 verifyFTPFile(files[0], FTPFile.DIRECTORY_TYPE, SUBDIR_NAME2, 0) 174 verifyFTPFile(files[1], FTPFile.FILE_TYPE, FILENAME1, ASCII_DATA.size()) 175 verifyReplyCode("list", 226) 176 } 177 178 void testLogin() { 179 ftpClientConnect() 180 LOG.info("Logging in as $USERNAME/$PASSWORD") 181 assert ftpClient.login(USERNAME, PASSWORD) 182 verifyReplyCode("login with $USERNAME/$PASSWORD", 230) 183 } 184 185 void testLogin_WithAccount() { 186 userAccount.accountRequiredForLogin = true 187 ftpClientConnect() 188 LOG.info("Logging in as $USERNAME/$PASSWORD with $ACCOUNT") 189 assert ftpClient.login(USERNAME, PASSWORD, ACCOUNT) 190 verifyReplyCode("login with $USERNAME/$PASSWORD with $ACCOUNT", 230) 191 } 192 193 void testMkd() { 194 ftpClientConnectAndLogin() 195 196 def DIR = p(HOME_DIR, 'NewDir') 197 assert ftpClient.makeDirectory(DIR) 198 verifyReplyCode("makeDirectory", 257) 199 assert fileSystem.isDirectory(DIR) 200 } 201 202 void testMode() { 203 ftpClientConnectAndLogin() 204 assert ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE); 205 verifyReplyCode("MODE", 200) 206 } 207 208 void testNlst() { 209 fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME1))) 210 fileSystem.add(new DirectoryEntry(path: p(SUBDIR, SUBDIR_NAME2))) 211 212 ftpClientConnectAndLogin() 213 214 String[] filenames = ftpClient.listNames(SUBDIR) 215 assert filenames == [FILENAME1, SUBDIR_NAME2] 216 verifyReplyCode("listNames", 226) 217 } 218 219 void testNoop() { 220 ftpClientConnectAndLogin() 221 assert ftpClient.sendNoOp() 222 verifyReplyCode("NOOP", 200) 223 } 224 225 void testPasv_Nlst() { 226 fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME1))) 227 fileSystem.add(new FileEntry(path: p(SUBDIR, FILENAME2))) 228 229 ftpClientConnectAndLogin() 230 ftpClient.enterLocalPassiveMode(); 231 232 String[] filenames = ftpClient.listNames(SUBDIR) 233 assert filenames == [FILENAME1, FILENAME2] 234 verifyReplyCode("listNames", 226) 235 } 236 237 void testPwd() { 238 ftpClientConnectAndLogin() 239 assert ftpClient.printWorkingDirectory() == HOME_DIR 240 verifyReplyCode("printWorkingDirectory", 257) 241 } 242 243 void testQuit() { 244 ftpClientConnect() 245 ftpClient.quit() 246 verifyReplyCode("quit", 221) 247 } 248 249 void testRein() { 250 ftpClientConnectAndLogin() 251 assert ftpClient.rein() == 220 252 assert ftpClient.cdup() == 530 // now logged out 253 } 254 255 void testRest() { 256 ftpClientConnectAndLogin() 257 assert ftpClient.rest("marker") == 350 258 } 259 260 void testRetr() { 261 fileSystem.add(new FileEntry(path: FILE1, contents: ASCII_DATA)) 262 263 ftpClientConnectAndLogin() 264 265 LOG.info("Get File for remotePath [$FILE1]") 266 def outputStream = new ByteArrayOutputStream() 267 assert ftpClient.retrieveFile(FILE1, outputStream) 268 LOG.info("File contents=[${outputStream.toString()}]") 269 assert outputStream.toString() == ASCII_DATA 270 } 271 272 void testRmd() { 273 ftpClientConnectAndLogin() 274 275 assert ftpClient.removeDirectory(SUBDIR) 276 verifyReplyCode("removeDirectory", 250) 277 assert !fileSystem.exists(SUBDIR) 278 } 279 280 void testRename() { // RNFR and RNTO 281 fileSystem.add(new FileEntry(FILE1)) 282 283 ftpClientConnectAndLogin() 284 285 assert ftpClient.rename(FILE1, FILE1 + "NEW") 286 verifyReplyCode("rename", 250) 287 assert !fileSystem.exists(FILE1) 288 assert fileSystem.exists(FILE1 + "NEW") 289 } 290 291 void testSite() { 292 ftpClientConnectAndLogin() 293 assert ftpClient.site("parameters,1,2,3") == 200 294 } 295 296 void testStor() { 297 ftpClientConnectAndLogin() 298 299 LOG.info("Put File for local path [$FILE1]") 300 def inputStream = new ByteArrayInputStream(ASCII_DATA.getBytes()) 301 assert ftpClient.storeFile(FILE1, inputStream) 302 def contents = fileSystem.getEntry(FILE1).createInputStream().text 303 LOG.info("File contents=[" + contents + "]") 304 assert contents == ASCII_DATA 305 } 306 307 void testStou() { 308 ftpClientConnectAndLogin() 309 310 def inputStream = new ByteArrayInputStream(ASCII_DATA.getBytes()) 311 assert ftpClient.storeUniqueFile(FILENAME1, inputStream) 312 313 def names = fileSystem.listNames(HOME_DIR) 314 def filename = names.find {name -> name.startsWith(FILENAME1) } 315 assert filename 316 317 def contents = fileSystem.getEntry(p(HOME_DIR, filename)).createInputStream().text 318 LOG.info("File contents=[" + contents + "]") 319 assert contents == ASCII_DATA 320 } 321 322 void testStru() { 323 ftpClientConnectAndLogin() 324 assert ftpClient.setFileStructure(FTP.FILE_STRUCTURE); 325 verifyReplyCode("STRU", 200) 326 } 327 328 void testSyst() { 329 ftpClientConnectAndLogin() 330 331 def systemName = ftpClient.getSystemName() 332 LOG.info("system name = [$systemName]") 333 assert systemName.contains('"' + SYSTEM_NAME + '"') 334 verifyReplyCode("getSystemName", 215) 335 } 336 337 void testType() { 338 ftpClientConnectAndLogin() 339 assert ftpClient.type(FTP.ASCII_FILE_TYPE) 340 verifyReplyCode("TYPE", 200) 341 } 342 343 // ------------------------------------------------------------------------- 344 // Test setup and tear-down 345 // ------------------------------------------------------------------------- 346 347 /** 348 * Perform initialization before each test 349 * @see org.mockftpserver.test.AbstractTest#setUp() 350 */ 351 void setUp() { 352 super.setUp() 353 354 for (int i = 0; i < BINARY_DATA.length; i++) { 355 BINARY_DATA[i] = (byte) i 356 } 357 358 ftpServer = new FakeFtpServer() 359 ftpServer.serverControlPort = PortTestUtil.getFtpServerControlPort() 360 ftpServer.systemName = SYSTEM_NAME 361 362 fileSystem = new WindowsFakeFileSystem() 363 fileSystem.createParentDirectoriesAutomatically = true 364 fileSystem.add(new DirectoryEntry(SUBDIR)) 365 ftpServer.fileSystem = fileSystem 366 367 userAccount = new UserAccount(USERNAME, PASSWORD, HOME_DIR) 368 ftpServer.userAccounts[USERNAME] = userAccount 369 370 ftpServer.start() 371 ftpClient = new FTPClient() 372 } 373 374 /** 375 * Perform cleanup after each test 376 * @see org.mockftpserver.test.AbstractTest#tearDown() 377 */ 378 void tearDown() { 379 super.tearDown() 380 ftpServer.stop() 381 } 382 383 // ------------------------------------------------------------------------- 384 // Internal Helper Methods 385 // ------------------------------------------------------------------------- 386 387 private ftpClientConnectAndLogin() { 388 ftpClientConnect() 389 assert ftpClient.login(USERNAME, PASSWORD) 390 } 391 392 /** 393 * Connect to the server from the FTPClient 394 */ 395 private void ftpClientConnect() { 396 def port = PortTestUtil.getFtpServerControlPort() 397 LOG.info("Conecting to $SERVER on port $port") 398 ftpClient.connect(SERVER, port) 399 verifyReplyCode("connect", 220) 400 } 401 402 /** 403 * Assert that the FtpClient reply code is equal to the expected value 404 * 405 * @param operation - the description of the operation performed used in the error message 406 * @param expectedReplyCode - the expected FtpClient reply code 407 */ 408 private void verifyReplyCode(String operation, int expectedReplyCode) { 409 int replyCode = ftpClient.getReplyCode() 410 LOG.info("Reply: operation=\"" + operation + "\" replyCode=" + replyCode) 411 assertEquals("Unexpected replyCode for " + operation, expectedReplyCode, replyCode) 412 } 413 414 private void verifyFTPFile(FTPFile ftpFile, int type, String name, long size) { 415 LOG.info(ftpFile) 416 assertEquals("type: " + ftpFile, type, ftpFile.getType()) 417 assertEquals("name: " + ftpFile, name, ftpFile.getName()) 418 assertEquals("size: " + ftpFile, size, ftpFile.getSize()) 419 } 420 421}