1/* 2 * Copyright 2007 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.core.session; 17 18import java.io.ByteArrayInputStream; 19import java.io.ByteArrayOutputStream; 20import java.io.IOException; 21import java.io.InputStream; 22import java.net.InetAddress; 23import java.net.SocketTimeoutException; 24import java.util.Collections; 25import java.util.HashMap; 26import java.util.Map; 27 28import org.apache.log4j.Logger; 29import org.mockftpserver.core.MockFtpServerException; 30import org.mockftpserver.core.command.Command; 31import org.mockftpserver.core.socket.StubServerSocket; 32import org.mockftpserver.core.socket.StubServerSocketFactory; 33import org.mockftpserver.core.socket.StubSocket; 34import org.mockftpserver.core.socket.StubSocketFactory; 35import org.mockftpserver.core.util.AssertFailedException; 36import org.mockftpserver.test.AbstractTest; 37 38/** 39 * Tests for the DefaultSession class 40 * 41 * @version $Revision$ - $Date$ 42 * 43 * @author Chris Mair 44 */ 45public final class DefaultSessionTest extends AbstractTest { 46 47 private static final Logger LOG = Logger.getLogger(DefaultSessionTest.class); 48 private static final String DATA = "sample data 123"; 49 private static final int PORT = 197; 50 private static final String NAME1 = "name1"; 51 private static final String NAME2 = "name2"; 52 private static final Object VALUE = "value"; 53 54 private DefaultSession session; 55 private ByteArrayOutputStream outputStream; 56 private Map commandHandlerMap; 57 private StubSocket stubSocket; 58 private InetAddress clientHost; 59 60 /** 61 * Perform initialization before each test 62 * 63 * @see org.mockftpserver.test.AbstractTest#setUp() 64 */ 65 protected void setUp() throws Exception { 66 super.setUp(); 67 68 commandHandlerMap = new HashMap(); 69 outputStream = new ByteArrayOutputStream(); 70 session = createDefaultSession(""); 71 clientHost = InetAddress.getLocalHost(); 72 } 73 74 /** 75 * @see org.mockftpserver.test.AbstractTest#tearDown() 76 */ 77 protected void tearDown() throws Exception { 78 super.tearDown(); 79 } 80 81 /** 82 * Test the Constructor when the control socket is null 83 */ 84 public void testConstructor_NullControlSocket() { 85 try { 86 new DefaultSession(null, commandHandlerMap); 87 fail("Expected AssertFailedException"); 88 } 89 catch (AssertFailedException expected) { 90 LOG.info("Expected: " + expected); 91 } 92 } 93 94 /** 95 * Test the Constructor when the command handler Map is null 96 */ 97 public void testConstructor_NullCommandHandlerMap() { 98 try { 99 new DefaultSession(stubSocket, null); 100 fail("Expected AssertFailedException"); 101 } 102 catch (AssertFailedException expected) { 103 LOG.info("Expected: " + expected); 104 } 105 } 106 107 /** 108 * Test the setClientDataPort() method 109 */ 110 public void testSetClientDataPort() { 111 StubSocket stubSocket = createTestSocket(""); 112 StubSocketFactory stubSocketFactory = new StubSocketFactory(stubSocket); 113 session.socketFactory = stubSocketFactory; 114 session.setClientDataPort(PORT); 115 session.setClientDataHost(clientHost); 116 session.openDataConnection(); 117 assertEquals("data port", PORT, stubSocketFactory.requestedDataPort); 118 } 119 120 /** 121 * Test the setClientDataPort() method after the session was in passive data mode 122 */ 123 public void testSetClientDataPort_AfterPassiveConnectionMode() throws IOException { 124 StubServerSocket stubServerSocket = new StubServerSocket(PORT); 125 StubServerSocketFactory stubServerSocketFactory = new StubServerSocketFactory(stubServerSocket); 126 session.serverSocketFactory = stubServerSocketFactory; 127 128 session.switchToPassiveMode(); 129 assertFalse("server socket closed", stubServerSocket.isClosed()); 130 assertNotNull("passiveModeDataSocket", session.passiveModeDataSocket); 131 session.setClientDataPort(PORT); 132 133 // Make sure that any passive mode connection info is cleared out 134 assertTrue("server socket closed", stubServerSocket.isClosed()); 135 assertNull("passiveModeDataSocket should be null", session.passiveModeDataSocket); 136 } 137 138 /** 139 * Test the setClientHost() method 140 */ 141 public void testSetClientHost() throws Exception { 142 StubSocket stubSocket = createTestSocket(""); 143 StubSocketFactory stubSocketFactory = new StubSocketFactory(stubSocket); 144 session.socketFactory = stubSocketFactory; 145 session.setClientDataHost(clientHost); 146 session.openDataConnection(); 147 assertEquals("client host", clientHost, stubSocketFactory.requestedHost); 148 } 149 150 /** 151 * Test the openDataConnection(), setClientDataPort() and setClientDataHost() methods 152 */ 153 public void testOpenDataConnection() { 154 StubSocket stubSocket = createTestSocket(""); 155 StubSocketFactory stubSocketFactory = new StubSocketFactory(stubSocket); 156 session.socketFactory = stubSocketFactory; 157 158 // Use default client data port 159 session.setClientDataHost(clientHost); 160 session.openDataConnection(); 161 assertEquals("data port", DefaultSession.DEFAULT_CLIENT_DATA_PORT, stubSocketFactory.requestedDataPort); 162 assertEquals("client host", clientHost, stubSocketFactory.requestedHost); 163 164 // Set client data port explicitly 165 session.setClientDataPort(PORT); 166 session.setClientDataHost(clientHost); 167 session.openDataConnection(); 168 assertEquals("data port", PORT, stubSocketFactory.requestedDataPort); 169 assertEquals("client host", clientHost, stubSocketFactory.requestedHost); 170 } 171 172 /** 173 * Test the OpenDataConnection method, when in passive mode and no incoming connection is 174 * initiated 175 */ 176 public void testOpenDataConnection_PassiveMode_NoConnection() throws IOException { 177 178 StubServerSocket stubServerSocket = new StubServerSocket(PORT); 179 StubServerSocketFactory stubServerSocketFactory = new StubServerSocketFactory(stubServerSocket); 180 session.serverSocketFactory = stubServerSocketFactory; 181 182 session.switchToPassiveMode(); 183 184 try { 185 session.openDataConnection(); 186 fail("Expected MockFtpServerException"); 187 } 188 catch (MockFtpServerException expected) { 189 LOG.info("Expected: " + expected); 190 assertSame("cause", SocketTimeoutException.class, expected.getCause().getClass()); 191 } 192 } 193 194 /** 195 * Test the OpenDataConnection method, when the clientHost has not been set 196 */ 197 public void testOpenDataConnection_NullClientHost() { 198 try { 199 session.openDataConnection(); 200 fail("Expected AssertFailedException"); 201 } 202 catch (AssertFailedException expected) { 203 LOG.info("Expected: " + expected); 204 } 205 } 206 207 /** 208 * Test the readData() method 209 */ 210 public void testReadData() { 211 StubSocket stubSocket = createTestSocket(DATA); 212 session.socketFactory = new StubSocketFactory(stubSocket); 213 session.setClientDataHost(clientHost); 214 215 session.openDataConnection(); 216 byte[] data = session.readData(); 217 LOG.info("data=[" + new String(data) + "]"); 218 assertEquals("data", DATA.getBytes(), data); 219 } 220 221 /** 222 * Test the readData() method after switching to passive mode 223 */ 224 public void testReadData_PassiveMode() throws IOException { 225 StubSocket stubSocket = createTestSocket(DATA); 226 StubServerSocket stubServerSocket = new StubServerSocket(PORT, stubSocket); 227 StubServerSocketFactory stubServerSocketFactory = new StubServerSocketFactory(stubServerSocket); 228 session.serverSocketFactory = stubServerSocketFactory; 229 230 session.switchToPassiveMode(); 231 session.openDataConnection(); 232 byte[] data = session.readData(); 233 LOG.info("data=[" + new String(data) + "]"); 234 assertEquals("data", DATA.getBytes(), data); 235 } 236 237 /** 238 * Test the closeDataConnection() method 239 */ 240 public void testCloseDataConnection() { 241 StubSocket stubSocket = createTestSocket(DATA); 242 session.socketFactory = new StubSocketFactory(stubSocket); 243 244 session.setClientDataHost(clientHost); 245 session.openDataConnection(); 246 session.closeDataConnection(); 247 assertTrue("client data socket should be closed", stubSocket.isClosed()); 248 } 249 250 /** 251 * Test the switchToPassiveMode() method 252 */ 253 public void testSwitchToPassiveMode() throws IOException { 254 StubServerSocket stubServerSocket = new StubServerSocket(PORT); 255 StubServerSocketFactory stubServerSocketFactory = new StubServerSocketFactory(stubServerSocket); 256 session.serverSocketFactory = stubServerSocketFactory; 257 258 assertNull("passiveModeDataSocket starts out null", session.passiveModeDataSocket); 259 int port = session.switchToPassiveMode(); 260 assertSame("passiveModeDataSocket", stubServerSocket, session.passiveModeDataSocket); 261 assertEquals("port", PORT, port); 262 } 263 264 /** 265 * Test the getServerHost() method 266 */ 267 public void testGetServerHost() { 268 assertEquals("host", DEFAULT_HOST, session.getServerHost()); 269 } 270 271 /** 272 * Test the getClientHost() method when the session is not yet started 273 */ 274 public void testGetClientHost_NotRunning() { 275 assertNull("null", session.getClientHost()); 276 } 277 278 /** 279 * Test the parseCommand() method 280 */ 281 public void testParseCommand() { 282 Command command = session.parseCommand("LIST"); 283 assertEquals("command name", "LIST", command.getName()); 284 assertEquals("command parameters", EMPTY, command.getParameters()); 285 286 command = session.parseCommand("USER user123"); 287 assertEquals("command name", "USER", command.getName()); 288 assertEquals("command parameters", array("user123"), command.getParameters()); 289 290 command = session.parseCommand("PORT 127,0,0,1,17,37"); 291 assertEquals("command name", "PORT", command.getName()); 292 assertEquals("command parameters", new String[] { "127", "0", "0", "1", "17", "37" }, command 293 .getParameters()); 294 } 295 296 /** 297 * Test the parseCommand() method, passing in an empty command String 298 */ 299 public void testParseCommand_EmptyCommandString() { 300 try { 301 session.parseCommand(""); 302 fail("Expected AssertFailedException"); 303 } 304 catch (AssertFailedException expected) { 305 LOG.info("Expected: " + expected); 306 } 307 } 308 309 /** 310 * Test the sendData() method, as well as the openDataConnection() and closeDataConnection() 311 */ 312 public void testSendData() { 313 StubSocket stubSocket = createTestSocket("1234567890 abcdef"); 314 session.socketFactory = new StubSocketFactory(stubSocket); 315 316 session.setClientDataHost(clientHost); 317 session.openDataConnection(); 318 session.sendData(DATA.getBytes(), DATA.length()); 319 LOG.info("output=[" + outputStream.toString() + "]"); 320 assertEquals("output", DATA, outputStream.toString()); 321 } 322 323 /** 324 * Test the SendData() method, passing in a null byte[] 325 */ 326 public void testSendData_Null() { 327 328 try { 329 session.sendData(null, 1); 330 fail("Expected AssertFailedException"); 331 } 332 catch (AssertFailedException expected) { 333 LOG.info("Expected: " + expected); 334 } 335 } 336 337 /** 338 * Test the SendReply(int,String) method, passing in an invalid reply code 339 */ 340 public void testSendReply_InvalidReplyCode() { 341 342 try { 343 session.sendReply(-66, "text"); 344 fail("Expected AssertFailedException"); 345 } 346 catch (AssertFailedException expected) { 347 LOG.info("Expected: " + expected); 348 } 349 } 350 351 /** 352 * Test the getAttribute() and setAttribute() methods 353 */ 354 public void testGetAndSetAttribute() { 355 assertNull("name does not exist yet", session.getAttribute(NAME1)); 356 session.setAttribute(NAME1, VALUE); 357 session.setAttribute(NAME2, null); 358 assertEquals("NAME1", VALUE, session.getAttribute(NAME1)); 359 assertNull("NAME2", session.getAttribute(NAME2)); 360 assertNull("no such name", session.getAttribute("noSuchName")); 361 } 362 363 /** 364 * Test the getAttribute() method, passing in a null name 365 */ 366 public void testGetAttribute_Null() { 367 try { 368 session.getAttribute(null); 369 fail("Expected AssertFailedException"); 370 } 371 catch (AssertFailedException expected) { 372 LOG.info("Expected: " + expected); 373 } 374 } 375 376 /** 377 * Test the setAttribute() method, passing in a null name 378 */ 379 public void testSetAttribute_NullName() { 380 try { 381 session.setAttribute(null, VALUE); 382 fail("Expected AssertFailedException"); 383 } 384 catch (AssertFailedException expected) { 385 LOG.info("Expected: " + expected); 386 } 387 } 388 389 /** 390 * Test the removeAttribute() 391 */ 392 public void testRemoveAttribute() { 393 session.removeAttribute("noSuchName"); // do nothing 394 session.setAttribute(NAME1, VALUE); 395 session.removeAttribute(NAME1); 396 assertNull("NAME1", session.getAttribute(NAME1)); 397 } 398 399 /** 400 * Test the removeAttribute() method, passing in a null name 401 */ 402 public void testRemoveAttribute_Null() { 403 try { 404 session.removeAttribute(null); 405 fail("Expected AssertFailedException"); 406 } 407 catch (AssertFailedException expected) { 408 LOG.info("Expected: " + expected); 409 } 410 } 411 412 /** 413 * Test the getAttributeNames() 414 */ 415 public void testGetAttributeNames() { 416 assertEquals("No names yet", Collections.EMPTY_SET, session.getAttributeNames()); 417 session.setAttribute(NAME1, VALUE); 418 assertEquals("1", Collections.singleton(NAME1), session.getAttributeNames()); 419 session.setAttribute(NAME2, VALUE); 420 assertEquals("2", set(NAME1, NAME2), session.getAttributeNames()); 421 } 422 423 // ------------------------------------------------------------------------- 424 // Internal Helper Methods 425 // ------------------------------------------------------------------------- 426 427 /** 428 * Create and return a DefaultSession object that reads from an InputStream with the specified 429 * contents and writes to the predefined outputStrean ByteArrayOutputStream. Also, save the 430 * StubSocket being used in the stubSocket attribute. 431 * 432 * @param inputStreamContents - the contents of the input stream 433 * @return the DefaultSession 434 */ 435 private DefaultSession createDefaultSession(String inputStreamContents) { 436 stubSocket = createTestSocket(inputStreamContents); 437 return new DefaultSession(stubSocket, commandHandlerMap); 438 } 439 440 /** 441 * Create and return a StubSocket that reads from an InputStream with the specified contents and 442 * writes to the predefined outputStrean ByteArrayOutputStream. 443 * 444 * @param inputStreamContents - the contents of the input stream 445 * @return the StubSocket 446 */ 447 private StubSocket createTestSocket(String inputStreamContents) { 448 InputStream inputStream = new ByteArrayInputStream(inputStreamContents.getBytes()); 449 StubSocket stubSocket = new StubSocket(inputStream, outputStream); 450 stubSocket._setLocalAddress(DEFAULT_HOST); 451 return stubSocket; 452 } 453 454} 455