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