test_factories.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Test code for basic Factory classes.
  5. """
  6. from __future__ import division, absolute_import
  7. import pickle
  8. from twisted.trial.unittest import TestCase
  9. from twisted.internet.task import Clock
  10. from twisted.internet.protocol import ReconnectingClientFactory, Protocol
  11. class FakeConnector(object):
  12. """
  13. A fake connector class, to be used to mock connections failed or lost.
  14. """
  15. def stopConnecting(self):
  16. pass
  17. def connect(self):
  18. pass
  19. class ReconnectingFactoryTests(TestCase):
  20. """
  21. Tests for L{ReconnectingClientFactory}.
  22. """
  23. def test_stopTryingWhenConnected(self):
  24. """
  25. If a L{ReconnectingClientFactory} has C{stopTrying} called while it is
  26. connected, it does not subsequently attempt to reconnect if the
  27. connection is later lost.
  28. """
  29. class NoConnectConnector(object):
  30. def stopConnecting(self):
  31. raise RuntimeError("Shouldn't be called, we're connected.")
  32. def connect(self):
  33. raise RuntimeError("Shouldn't be reconnecting.")
  34. c = ReconnectingClientFactory()
  35. c.protocol = Protocol
  36. # Let's pretend we've connected:
  37. c.buildProtocol(None)
  38. # Now we stop trying, then disconnect:
  39. c.stopTrying()
  40. c.clientConnectionLost(NoConnectConnector(), None)
  41. self.assertFalse(c.continueTrying)
  42. def test_stopTryingDoesNotReconnect(self):
  43. """
  44. Calling stopTrying on a L{ReconnectingClientFactory} doesn't attempt a
  45. retry on any active connector.
  46. """
  47. class FactoryAwareFakeConnector(FakeConnector):
  48. attemptedRetry = False
  49. def stopConnecting(self):
  50. """
  51. Behave as though an ongoing connection attempt has now
  52. failed, and notify the factory of this.
  53. """
  54. f.clientConnectionFailed(self, None)
  55. def connect(self):
  56. """
  57. Record an attempt to reconnect, since this is what we
  58. are trying to avoid.
  59. """
  60. self.attemptedRetry = True
  61. f = ReconnectingClientFactory()
  62. f.clock = Clock()
  63. # simulate an active connection - stopConnecting on this connector should
  64. # be triggered when we call stopTrying
  65. f.connector = FactoryAwareFakeConnector()
  66. f.stopTrying()
  67. # make sure we never attempted to retry
  68. self.assertFalse(f.connector.attemptedRetry)
  69. self.assertFalse(f.clock.getDelayedCalls())
  70. def test_serializeUnused(self):
  71. """
  72. A L{ReconnectingClientFactory} which hasn't been used for anything
  73. can be pickled and unpickled and end up with the same state.
  74. """
  75. original = ReconnectingClientFactory()
  76. reconstituted = pickle.loads(pickle.dumps(original))
  77. self.assertEqual(original.__dict__, reconstituted.__dict__)
  78. def test_serializeWithClock(self):
  79. """
  80. The clock attribute of L{ReconnectingClientFactory} is not serialized,
  81. and the restored value sets it to the default value, the reactor.
  82. """
  83. clock = Clock()
  84. original = ReconnectingClientFactory()
  85. original.clock = clock
  86. reconstituted = pickle.loads(pickle.dumps(original))
  87. self.assertIsNone(reconstituted.clock)
  88. def test_deserializationResetsParameters(self):
  89. """
  90. A L{ReconnectingClientFactory} which is unpickled does not have an
  91. L{IConnector} and has its reconnecting timing parameters reset to their
  92. initial values.
  93. """
  94. factory = ReconnectingClientFactory()
  95. factory.clientConnectionFailed(FakeConnector(), None)
  96. self.addCleanup(factory.stopTrying)
  97. serialized = pickle.dumps(factory)
  98. unserialized = pickle.loads(serialized)
  99. self.assertIsNone(unserialized.connector)
  100. self.assertIsNone(unserialized._callID)
  101. self.assertEqual(unserialized.retries, 0)
  102. self.assertEqual(unserialized.delay, factory.initialDelay)
  103. self.assertTrue(unserialized.continueTrying)
  104. def test_parametrizedClock(self):
  105. """
  106. The clock used by L{ReconnectingClientFactory} can be parametrized, so
  107. that one can cleanly test reconnections.
  108. """
  109. clock = Clock()
  110. factory = ReconnectingClientFactory()
  111. factory.clock = clock
  112. factory.clientConnectionLost(FakeConnector(), None)
  113. self.assertEqual(len(clock.calls), 1)