| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: twisted.mail.test.test_pop3client -*- | |
| 2 # Copyright (c) 2001-2004 Divmod Inc. | |
| 3 # See LICENSE for details. | |
| 4 | |
| 5 from zope.interface import directlyProvides | |
| 6 | |
| 7 from twisted.mail.pop3 import AdvancedPOP3Client as POP3Client | |
| 8 from twisted.mail.pop3 import InsecureAuthenticationDisallowed | |
| 9 from twisted.mail.pop3 import ServerErrorResponse | |
| 10 from twisted.protocols import loopback | |
| 11 from twisted.internet import reactor, defer, error, protocol, interfaces | |
| 12 from twisted.python import log | |
| 13 | |
| 14 from twisted.trial import unittest | |
| 15 from twisted.test.proto_helpers import StringTransport | |
| 16 from twisted.protocols import basic | |
| 17 | |
| 18 from twisted.mail.test import pop3testserver | |
| 19 | |
| 20 try: | |
| 21 from twisted.test.ssl_helpers import ClientTLSContext, ServerTLSContext | |
| 22 except ImportError: | |
| 23 ClientTLSContext = ServerTLSContext = None | |
| 24 | |
| 25 | |
| 26 class StringTransportWithConnectionLosing(StringTransport): | |
| 27 def loseConnection(self): | |
| 28 self.protocol.connectionLost(error.ConnectionDone()) | |
| 29 | |
| 30 | |
| 31 capCache = {"TOP": None, "LOGIN-DELAY": "180", "UIDL": None, \ | |
| 32 "STLS": None, "USER": None, "SASL": "LOGIN"} | |
| 33 def setUp(greet=True): | |
| 34 p = POP3Client() | |
| 35 | |
| 36 # Skip the CAPA login will issue if it doesn't already have a | |
| 37 # capability cache | |
| 38 p._capCache = capCache | |
| 39 | |
| 40 t = StringTransportWithConnectionLosing() | |
| 41 t.protocol = p | |
| 42 p.makeConnection(t) | |
| 43 | |
| 44 if greet: | |
| 45 p.dataReceived('+OK Hello!\r\n') | |
| 46 | |
| 47 return p, t | |
| 48 | |
| 49 def strip(f): | |
| 50 return lambda result, f=f: f() | |
| 51 | |
| 52 class POP3ClientLoginTestCase(unittest.TestCase): | |
| 53 def testNegativeGreeting(self): | |
| 54 p, t = setUp(greet=False) | |
| 55 p.allowInsecureLogin = True | |
| 56 d = p.login("username", "password") | |
| 57 p.dataReceived('-ERR Offline for maintenance\r\n') | |
| 58 return self.assertFailure( | |
| 59 d, ServerErrorResponse).addCallback( | |
| 60 lambda exc: self.assertEquals(exc.args[0], "Offline for maintenance"
)) | |
| 61 | |
| 62 | |
| 63 def testOkUser(self): | |
| 64 p, t = setUp() | |
| 65 d = p.user("username") | |
| 66 self.assertEquals(t.value(), "USER username\r\n") | |
| 67 p.dataReceived("+OK send password\r\n") | |
| 68 return d.addCallback(self.assertEqual, "send password") | |
| 69 | |
| 70 def testBadUser(self): | |
| 71 p, t = setUp() | |
| 72 d = p.user("username") | |
| 73 self.assertEquals(t.value(), "USER username\r\n") | |
| 74 p.dataReceived("-ERR account suspended\r\n") | |
| 75 return self.assertFailure( | |
| 76 d, ServerErrorResponse).addCallback( | |
| 77 lambda exc: self.assertEquals(exc.args[0], "account suspended")) | |
| 78 | |
| 79 def testOkPass(self): | |
| 80 p, t = setUp() | |
| 81 d = p.password("password") | |
| 82 self.assertEquals(t.value(), "PASS password\r\n") | |
| 83 p.dataReceived("+OK you're in!\r\n") | |
| 84 return d.addCallback(self.assertEqual, "you're in!") | |
| 85 | |
| 86 def testBadPass(self): | |
| 87 p, t = setUp() | |
| 88 d = p.password("password") | |
| 89 self.assertEquals(t.value(), "PASS password\r\n") | |
| 90 p.dataReceived("-ERR go away\r\n") | |
| 91 return self.assertFailure( | |
| 92 d, ServerErrorResponse).addCallback( | |
| 93 lambda exc: self.assertEquals(exc.args[0], "go away")) | |
| 94 | |
| 95 def testOkLogin(self): | |
| 96 p, t = setUp() | |
| 97 p.allowInsecureLogin = True | |
| 98 d = p.login("username", "password") | |
| 99 self.assertEquals(t.value(), "USER username\r\n") | |
| 100 p.dataReceived("+OK go ahead\r\n") | |
| 101 self.assertEquals(t.value(), "USER username\r\nPASS password\r\n") | |
| 102 p.dataReceived("+OK password accepted\r\n") | |
| 103 return d.addCallback(self.assertEqual, "password accepted") | |
| 104 | |
| 105 def testBadPasswordLogin(self): | |
| 106 p, t = setUp() | |
| 107 p.allowInsecureLogin = True | |
| 108 d = p.login("username", "password") | |
| 109 self.assertEquals(t.value(), "USER username\r\n") | |
| 110 p.dataReceived("+OK waiting on you\r\n") | |
| 111 self.assertEquals(t.value(), "USER username\r\nPASS password\r\n") | |
| 112 p.dataReceived("-ERR bogus login\r\n") | |
| 113 return self.assertFailure( | |
| 114 d, ServerErrorResponse).addCallback( | |
| 115 lambda exc: self.assertEquals(exc.args[0], "bogus login")) | |
| 116 | |
| 117 def testBadUsernameLogin(self): | |
| 118 p, t = setUp() | |
| 119 p.allowInsecureLogin = True | |
| 120 d = p.login("username", "password") | |
| 121 self.assertEquals(t.value(), "USER username\r\n") | |
| 122 p.dataReceived("-ERR bogus login\r\n") | |
| 123 return self.assertFailure( | |
| 124 d, ServerErrorResponse).addCallback( | |
| 125 lambda exc: self.assertEquals(exc.args[0], "bogus login")) | |
| 126 | |
| 127 def testServerGreeting(self): | |
| 128 p, t = setUp(greet=False) | |
| 129 p.dataReceived("+OK lalala this has no challenge\r\n") | |
| 130 self.assertEquals(p.serverChallenge, None) | |
| 131 | |
| 132 def testServerGreetingWithChallenge(self): | |
| 133 p, t = setUp(greet=False) | |
| 134 p.dataReceived("+OK <here is the challenge>\r\n") | |
| 135 self.assertEquals(p.serverChallenge, "<here is the challenge>") | |
| 136 | |
| 137 def testAPOP(self): | |
| 138 p, t = setUp(greet=False) | |
| 139 p.dataReceived("+OK <challenge string goes here>\r\n") | |
| 140 d = p.login("username", "password") | |
| 141 self.assertEquals(t.value(), "APOP username f34f1e464d0d7927607753129cab
e39a\r\n") | |
| 142 p.dataReceived("+OK Welcome!\r\n") | |
| 143 return d.addCallback(self.assertEqual, "Welcome!") | |
| 144 | |
| 145 def testInsecureLoginRaisesException(self): | |
| 146 p, t = setUp(greet=False) | |
| 147 p.dataReceived("+OK Howdy\r\n") | |
| 148 d = p.login("username", "password") | |
| 149 self.failIf(t.value()) | |
| 150 return self.assertFailure( | |
| 151 d, InsecureAuthenticationDisallowed) | |
| 152 | |
| 153 | |
| 154 def testSSLTransportConsideredSecure(self): | |
| 155 """ | |
| 156 If a server doesn't offer APOP but the transport is secured using | |
| 157 SSL or TLS, a plaintext login should be allowed, not rejected with | |
| 158 an InsecureAuthenticationDisallowed exception. | |
| 159 """ | |
| 160 p, t = setUp(greet=False) | |
| 161 directlyProvides(t, interfaces.ISSLTransport) | |
| 162 p.dataReceived("+OK Howdy\r\n") | |
| 163 d = p.login("username", "password") | |
| 164 self.assertEquals(t.value(), "USER username\r\n") | |
| 165 t.clear() | |
| 166 p.dataReceived("+OK\r\n") | |
| 167 self.assertEquals(t.value(), "PASS password\r\n") | |
| 168 p.dataReceived("+OK\r\n") | |
| 169 return d | |
| 170 | |
| 171 | |
| 172 | |
| 173 class ListConsumer: | |
| 174 def __init__(self): | |
| 175 self.data = {} | |
| 176 | |
| 177 def consume(self, (item, value)): | |
| 178 self.data.setdefault(item, []).append(value) | |
| 179 | |
| 180 class MessageConsumer: | |
| 181 def __init__(self): | |
| 182 self.data = [] | |
| 183 | |
| 184 def consume(self, line): | |
| 185 self.data.append(line) | |
| 186 | |
| 187 class POP3ClientListTestCase(unittest.TestCase): | |
| 188 def testListSize(self): | |
| 189 p, t = setUp() | |
| 190 d = p.listSize() | |
| 191 self.assertEquals(t.value(), "LIST\r\n") | |
| 192 p.dataReceived("+OK Here it comes\r\n") | |
| 193 p.dataReceived("1 3\r\n2 2\r\n3 1\r\n.\r\n") | |
| 194 return d.addCallback(self.assertEqual, [3, 2, 1]) | |
| 195 | |
| 196 def testListSizeWithConsumer(self): | |
| 197 p, t = setUp() | |
| 198 c = ListConsumer() | |
| 199 f = c.consume | |
| 200 d = p.listSize(f) | |
| 201 self.assertEquals(t.value(), "LIST\r\n") | |
| 202 p.dataReceived("+OK Here it comes\r\n") | |
| 203 p.dataReceived("1 3\r\n2 2\r\n3 1\r\n") | |
| 204 self.assertEquals(c.data, {0: [3], 1: [2], 2: [1]}) | |
| 205 p.dataReceived("5 3\r\n6 2\r\n7 1\r\n") | |
| 206 self.assertEquals(c.data, {0: [3], 1: [2], 2: [1], 4: [3], 5: [2], 6: [1
]}) | |
| 207 p.dataReceived(".\r\n") | |
| 208 return d.addCallback(self.assertIdentical, f) | |
| 209 | |
| 210 def testFailedListSize(self): | |
| 211 p, t = setUp() | |
| 212 d = p.listSize() | |
| 213 self.assertEquals(t.value(), "LIST\r\n") | |
| 214 p.dataReceived("-ERR Fatal doom server exploded\r\n") | |
| 215 return self.assertFailure( | |
| 216 d, ServerErrorResponse).addCallback( | |
| 217 lambda exc: self.assertEquals(exc.args[0], "Fatal doom server explod
ed")) | |
| 218 | |
| 219 def testListUID(self): | |
| 220 p, t = setUp() | |
| 221 d = p.listUID() | |
| 222 self.assertEquals(t.value(), "UIDL\r\n") | |
| 223 p.dataReceived("+OK Here it comes\r\n") | |
| 224 p.dataReceived("1 abc\r\n2 def\r\n3 ghi\r\n.\r\n") | |
| 225 return d.addCallback(self.assertEqual, ["abc", "def", "ghi"]) | |
| 226 | |
| 227 def testListUIDWithConsumer(self): | |
| 228 p, t = setUp() | |
| 229 c = ListConsumer() | |
| 230 f = c.consume | |
| 231 d = p.listUID(f) | |
| 232 self.assertEquals(t.value(), "UIDL\r\n") | |
| 233 p.dataReceived("+OK Here it comes\r\n") | |
| 234 p.dataReceived("1 xyz\r\n2 abc\r\n5 mno\r\n") | |
| 235 self.assertEquals(c.data, {0: ["xyz"], 1: ["abc"], 4: ["mno"]}) | |
| 236 p.dataReceived(".\r\n") | |
| 237 return d.addCallback(self.assertIdentical, f) | |
| 238 | |
| 239 def testFailedListUID(self): | |
| 240 p, t = setUp() | |
| 241 d = p.listUID() | |
| 242 self.assertEquals(t.value(), "UIDL\r\n") | |
| 243 p.dataReceived("-ERR Fatal doom server exploded\r\n") | |
| 244 return self.assertFailure( | |
| 245 d, ServerErrorResponse).addCallback( | |
| 246 lambda exc: self.assertEquals(exc.args[0], "Fatal doom server explod
ed")) | |
| 247 | |
| 248 class POP3ClientMessageTestCase(unittest.TestCase): | |
| 249 def testRetrieve(self): | |
| 250 p, t = setUp() | |
| 251 d = p.retrieve(7) | |
| 252 self.assertEquals(t.value(), "RETR 8\r\n") | |
| 253 p.dataReceived("+OK Message incoming\r\n") | |
| 254 p.dataReceived("La la la here is message text\r\n") | |
| 255 p.dataReceived("..Further message text tra la la\r\n") | |
| 256 p.dataReceived(".\r\n") | |
| 257 return d.addCallback( | |
| 258 self.assertEqual, | |
| 259 ["La la la here is message text", | |
| 260 ".Further message text tra la la"]) | |
| 261 | |
| 262 def testRetrieveWithConsumer(self): | |
| 263 p, t = setUp() | |
| 264 c = MessageConsumer() | |
| 265 f = c.consume | |
| 266 d = p.retrieve(7, f) | |
| 267 self.assertEquals(t.value(), "RETR 8\r\n") | |
| 268 p.dataReceived("+OK Message incoming\r\n") | |
| 269 p.dataReceived("La la la here is message text\r\n") | |
| 270 p.dataReceived("..Further message text\r\n.\r\n") | |
| 271 return d.addCallback(self._cbTestRetrieveWithConsumer, f, c) | |
| 272 | |
| 273 def _cbTestRetrieveWithConsumer(self, result, f, c): | |
| 274 self.assertIdentical(result, f) | |
| 275 self.assertEquals(c.data, ["La la la here is message text", | |
| 276 ".Further message text"]) | |
| 277 | |
| 278 def testPartialRetrieve(self): | |
| 279 p, t = setUp() | |
| 280 d = p.retrieve(7, lines=2) | |
| 281 self.assertEquals(t.value(), "TOP 8 2\r\n") | |
| 282 p.dataReceived("+OK 2 lines on the way\r\n") | |
| 283 p.dataReceived("Line the first! Woop\r\n") | |
| 284 p.dataReceived("Line the last! Bye\r\n") | |
| 285 p.dataReceived(".\r\n") | |
| 286 return d.addCallback( | |
| 287 self.assertEqual, | |
| 288 ["Line the first! Woop", | |
| 289 "Line the last! Bye"]) | |
| 290 | |
| 291 def testPartialRetrieveWithConsumer(self): | |
| 292 p, t = setUp() | |
| 293 c = MessageConsumer() | |
| 294 f = c.consume | |
| 295 d = p.retrieve(7, f, lines=2) | |
| 296 self.assertEquals(t.value(), "TOP 8 2\r\n") | |
| 297 p.dataReceived("+OK 2 lines on the way\r\n") | |
| 298 p.dataReceived("Line the first! Woop\r\n") | |
| 299 p.dataReceived("Line the last! Bye\r\n") | |
| 300 p.dataReceived(".\r\n") | |
| 301 return d.addCallback(self._cbTestPartialRetrieveWithConsumer, f, c) | |
| 302 | |
| 303 def _cbTestPartialRetrieveWithConsumer(self, result, f, c): | |
| 304 self.assertIdentical(result, f) | |
| 305 self.assertEquals(c.data, ["Line the first! Woop", | |
| 306 "Line the last! Bye"]) | |
| 307 | |
| 308 def testFailedRetrieve(self): | |
| 309 p, t = setUp() | |
| 310 d = p.retrieve(0) | |
| 311 self.assertEquals(t.value(), "RETR 1\r\n") | |
| 312 p.dataReceived("-ERR Fatal doom server exploded\r\n") | |
| 313 return self.assertFailure( | |
| 314 d, ServerErrorResponse).addCallback( | |
| 315 lambda exc: self.assertEquals(exc.args[0], "Fatal doom server explod
ed")) | |
| 316 | |
| 317 | |
| 318 def test_concurrentRetrieves(self): | |
| 319 """ | |
| 320 Issue three retrieve calls immediately without waiting for any to | |
| 321 succeed and make sure they all do succeed eventually. | |
| 322 """ | |
| 323 p, t = setUp() | |
| 324 messages = [ | |
| 325 p.retrieve(i).addCallback( | |
| 326 self.assertEquals, | |
| 327 ["First line of %d." % (i + 1,), | |
| 328 "Second line of %d." % (i + 1,)]) | |
| 329 for i | |
| 330 in range(3)] | |
| 331 | |
| 332 for i in range(1, 4): | |
| 333 self.assertEquals(t.value(), "RETR %d\r\n" % (i,)) | |
| 334 t.clear() | |
| 335 p.dataReceived("+OK 2 lines on the way\r\n") | |
| 336 p.dataReceived("First line of %d.\r\n" % (i,)) | |
| 337 p.dataReceived("Second line of %d.\r\n" % (i,)) | |
| 338 self.assertEquals(t.value(), "") | |
| 339 p.dataReceived(".\r\n") | |
| 340 | |
| 341 return defer.DeferredList(messages, fireOnOneErrback=True) | |
| 342 | |
| 343 | |
| 344 | |
| 345 class POP3ClientMiscTestCase(unittest.TestCase): | |
| 346 def testCapability(self): | |
| 347 p, t = setUp() | |
| 348 d = p.capabilities(useCache=0) | |
| 349 self.assertEquals(t.value(), "CAPA\r\n") | |
| 350 p.dataReceived("+OK Capabilities on the way\r\n") | |
| 351 p.dataReceived("X\r\nY\r\nZ\r\nA 1 2 3\r\nB 1 2\r\nC 1\r\n.\r\n") | |
| 352 return d.addCallback( | |
| 353 self.assertEqual, | |
| 354 {"X": None, "Y": None, "Z": None, | |
| 355 "A": ["1", "2", "3"], | |
| 356 "B": ["1", "2"], | |
| 357 "C": ["1"]}) | |
| 358 | |
| 359 def testCapabilityError(self): | |
| 360 p, t = setUp() | |
| 361 d = p.capabilities(useCache=0) | |
| 362 self.assertEquals(t.value(), "CAPA\r\n") | |
| 363 p.dataReceived("-ERR This server is lame!\r\n") | |
| 364 return d.addCallback(self.assertEquals, {}) | |
| 365 | |
| 366 def testStat(self): | |
| 367 p, t = setUp() | |
| 368 d = p.stat() | |
| 369 self.assertEquals(t.value(), "STAT\r\n") | |
| 370 p.dataReceived("+OK 1 1212\r\n") | |
| 371 return d.addCallback(self.assertEqual, (1, 1212)) | |
| 372 | |
| 373 def testStatError(self): | |
| 374 p, t = setUp() | |
| 375 d = p.stat() | |
| 376 self.assertEquals(t.value(), "STAT\r\n") | |
| 377 p.dataReceived("-ERR This server is lame!\r\n") | |
| 378 return self.assertFailure( | |
| 379 d, ServerErrorResponse).addCallback( | |
| 380 lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) | |
| 381 | |
| 382 def testNoop(self): | |
| 383 p, t = setUp() | |
| 384 d = p.noop() | |
| 385 self.assertEquals(t.value(), "NOOP\r\n") | |
| 386 p.dataReceived("+OK No-op to you too!\r\n") | |
| 387 return d.addCallback(self.assertEqual, "No-op to you too!") | |
| 388 | |
| 389 def testNoopError(self): | |
| 390 p, t = setUp() | |
| 391 d = p.noop() | |
| 392 self.assertEquals(t.value(), "NOOP\r\n") | |
| 393 p.dataReceived("-ERR This server is lame!\r\n") | |
| 394 return self.assertFailure( | |
| 395 d, ServerErrorResponse).addCallback( | |
| 396 lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) | |
| 397 | |
| 398 def testRset(self): | |
| 399 p, t = setUp() | |
| 400 d = p.reset() | |
| 401 self.assertEquals(t.value(), "RSET\r\n") | |
| 402 p.dataReceived("+OK Reset state\r\n") | |
| 403 return d.addCallback(self.assertEqual, "Reset state") | |
| 404 | |
| 405 def testRsetError(self): | |
| 406 p, t = setUp() | |
| 407 d = p.reset() | |
| 408 self.assertEquals(t.value(), "RSET\r\n") | |
| 409 p.dataReceived("-ERR This server is lame!\r\n") | |
| 410 return self.assertFailure( | |
| 411 d, ServerErrorResponse).addCallback( | |
| 412 lambda exc: self.assertEquals(exc.args[0], "This server is lame!")) | |
| 413 | |
| 414 def testDelete(self): | |
| 415 p, t = setUp() | |
| 416 d = p.delete(3) | |
| 417 self.assertEquals(t.value(), "DELE 4\r\n") | |
| 418 p.dataReceived("+OK Hasta la vista\r\n") | |
| 419 return d.addCallback(self.assertEqual, "Hasta la vista") | |
| 420 | |
| 421 def testDeleteError(self): | |
| 422 p, t = setUp() | |
| 423 d = p.delete(3) | |
| 424 self.assertEquals(t.value(), "DELE 4\r\n") | |
| 425 p.dataReceived("-ERR Winner is not you.\r\n") | |
| 426 return self.assertFailure( | |
| 427 d, ServerErrorResponse).addCallback( | |
| 428 lambda exc: self.assertEquals(exc.args[0], "Winner is not you.")) | |
| 429 | |
| 430 | |
| 431 class SimpleClient(POP3Client): | |
| 432 def __init__(self, deferred, contextFactory = None): | |
| 433 self.deferred = deferred | |
| 434 self.allowInsecureLogin = True | |
| 435 | |
| 436 def serverGreeting(self, challenge): | |
| 437 self.deferred.callback(None) | |
| 438 | |
| 439 class POP3HelperMixin: | |
| 440 serverCTX = None | |
| 441 clientCTX = None | |
| 442 | |
| 443 def setUp(self): | |
| 444 d = defer.Deferred() | |
| 445 self.server = pop3testserver.POP3TestServer(contextFactory=self.serverCT
X) | |
| 446 self.client = SimpleClient(d, contextFactory=self.clientCTX) | |
| 447 self.client.timeout = 30 | |
| 448 self.connected = d | |
| 449 | |
| 450 def tearDown(self): | |
| 451 del self.server | |
| 452 del self.client | |
| 453 del self.connected | |
| 454 | |
| 455 def _cbStopClient(self, ignore): | |
| 456 self.client.transport.loseConnection() | |
| 457 | |
| 458 def _ebGeneral(self, failure): | |
| 459 self.client.transport.loseConnection() | |
| 460 self.server.transport.loseConnection() | |
| 461 return failure | |
| 462 | |
| 463 def loopback(self): | |
| 464 return loopback.loopbackTCP(self.server, self.client, noisy=False) | |
| 465 | |
| 466 | |
| 467 class TLSServerFactory(protocol.ServerFactory): | |
| 468 class protocol(basic.LineReceiver): | |
| 469 context = None | |
| 470 output = [] | |
| 471 def connectionMade(self): | |
| 472 self.factory.input = [] | |
| 473 self.output = self.output[:] | |
| 474 map(self.sendLine, self.output.pop(0)) | |
| 475 def lineReceived(self, line): | |
| 476 self.factory.input.append(line) | |
| 477 map(self.sendLine, self.output.pop(0)) | |
| 478 if line == 'STLS': | |
| 479 self.transport.startTLS(self.context) | |
| 480 | |
| 481 | |
| 482 class POP3TLSTestCase(unittest.TestCase): | |
| 483 def testStartTLS(self): | |
| 484 sf = TLSServerFactory() | |
| 485 sf.protocol.output = [ | |
| 486 ['+OK'], # Server greeting | |
| 487 ['+OK', 'STLS', '.'], # CAPA response | |
| 488 ['+OK'], # STLS response | |
| 489 ['+OK', '.'], # Second CAPA response | |
| 490 ['+OK'] # QUIT response | |
| 491 ] | |
| 492 sf.protocol.context = ServerTLSContext() | |
| 493 port = reactor.listenTCP(0, sf, interface='127.0.0.1') | |
| 494 H = port.getHost().host | |
| 495 P = port.getHost().port | |
| 496 | |
| 497 cp = SimpleClient(defer.Deferred(), ClientTLSContext()) | |
| 498 cf = protocol.ClientFactory() | |
| 499 cf.protocol = lambda: cp | |
| 500 | |
| 501 conn = reactor.connectTCP(H, P, cf) | |
| 502 | |
| 503 def cbConnected(ignored): | |
| 504 log.msg("Connected to server; starting TLS") | |
| 505 return cp.startTLS() | |
| 506 | |
| 507 def cbStartedTLS(ignored): | |
| 508 log.msg("Started TLS; disconnecting") | |
| 509 return cp.quit() | |
| 510 | |
| 511 def cbDisconnected(ign): | |
| 512 log.msg("Disconnected; asserting correct input received") | |
| 513 self.assertEquals( | |
| 514 sf.input, | |
| 515 ['CAPA', 'STLS', 'CAPA', 'QUIT']) | |
| 516 | |
| 517 def cleanup(result): | |
| 518 log.msg("Asserted correct input; disconnecting client and shutting d
own server") | |
| 519 conn.disconnect() | |
| 520 | |
| 521 def cbShutdown(ignored): | |
| 522 log.msg("Shut down server") | |
| 523 return result | |
| 524 | |
| 525 return defer.maybeDeferred(port.stopListening).addCallback(cbShutdow
n) | |
| 526 | |
| 527 cp.deferred.addCallback(cbConnected) | |
| 528 cp.deferred.addCallback(cbStartedTLS) | |
| 529 cp.deferred.addCallback(cbDisconnected) | |
| 530 cp.deferred.addBoth(cleanup) | |
| 531 | |
| 532 return cp.deferred | |
| 533 | |
| 534 | |
| 535 class POP3TimeoutTestCase(POP3HelperMixin, unittest.TestCase): | |
| 536 def testTimeout(self): | |
| 537 def login(): | |
| 538 d = self.client.login('test', 'twisted') | |
| 539 d.addCallback(loggedIn) | |
| 540 d.addErrback(timedOut) | |
| 541 return d | |
| 542 | |
| 543 def loggedIn(result): | |
| 544 self.fail("Successfully logged in!? Impossible!") | |
| 545 | |
| 546 | |
| 547 def timedOut(failure): | |
| 548 failure.trap(error.TimeoutError) | |
| 549 self._cbStopClient(None) | |
| 550 | |
| 551 def quit(): | |
| 552 return self.client.quit() | |
| 553 | |
| 554 self.client.timeout = 0.01 | |
| 555 | |
| 556 # Tell the server to not return a response to client. This | |
| 557 # will trigger a timeout. | |
| 558 pop3testserver.TIMEOUT_RESPONSE = True | |
| 559 | |
| 560 methods = [login, quit] | |
| 561 map(self.connected.addCallback, map(strip, methods)) | |
| 562 self.connected.addCallback(self._cbStopClient) | |
| 563 self.connected.addErrback(self._ebGeneral) | |
| 564 return self.loopback() | |
| 565 | |
| 566 | |
| 567 if ClientTLSContext is None: | |
| 568 for case in (POP3TLSTestCase,): | |
| 569 case.skip = "OpenSSL not present" | |
| 570 elif interfaces.IReactorSSL(reactor, None) is None: | |
| 571 for case in (POP3TLSTestCase,): | |
| 572 case.skip = "Reactor doesn't support SSL" | |
| 573 | |
| OLD | NEW |