test_address.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. from __future__ import division, absolute_import
  4. import re
  5. import os
  6. import socket
  7. from twisted.trial import unittest
  8. from twisted.internet.address import IPv4Address, UNIXAddress, IPv6Address
  9. from twisted.internet.address import HostnameAddress
  10. from twisted.python.compat import nativeString
  11. from twisted.python.runtime import platform
  12. if not platform._supportsSymlinks():
  13. symlinkSkip = "Platform does not support symlinks"
  14. else:
  15. symlinkSkip = None
  16. try:
  17. socket.AF_UNIX
  18. except AttributeError:
  19. unixSkip = "Platform doesn't support UNIX sockets."
  20. else:
  21. unixSkip = None
  22. class AddressTestCaseMixin(object):
  23. def test_addressComparison(self):
  24. """
  25. Two different address instances, sharing the same properties are
  26. considered equal by C{==} and not considered not equal by C{!=}.
  27. Note: When applied via UNIXAddress class, this uses the same
  28. filename for both objects being compared.
  29. """
  30. self.assertTrue(self.buildAddress() == self.buildAddress())
  31. self.assertFalse(self.buildAddress() != self.buildAddress())
  32. def _stringRepresentation(self, stringFunction):
  33. """
  34. Verify that the string representation of an address object conforms to a
  35. simple pattern (the usual one for Python object reprs) and contains
  36. values which accurately reflect the attributes of the address.
  37. """
  38. addr = self.buildAddress()
  39. pattern = "".join([
  40. "^",
  41. "([^\(]+Address)", # class name,
  42. "\(", # opening bracket,
  43. "([^)]+)", # arguments,
  44. "\)", # closing bracket,
  45. "$"
  46. ])
  47. stringValue = stringFunction(addr)
  48. m = re.match(pattern, stringValue)
  49. self.assertNotEqual(
  50. None, m,
  51. "%s does not match the standard __str__ pattern "
  52. "ClassName(arg1, arg2, etc)" % (stringValue,))
  53. self.assertEqual(addr.__class__.__name__, m.group(1))
  54. args = [x.strip() for x in m.group(2).split(",")]
  55. self.assertEqual(
  56. args,
  57. [argSpec[1] % (getattr(addr, argSpec[0]),)
  58. for argSpec in self.addressArgSpec])
  59. def test_str(self):
  60. """
  61. C{str} can be used to get a string representation of an address instance
  62. containing information about that address.
  63. """
  64. self._stringRepresentation(str)
  65. def test_repr(self):
  66. """
  67. C{repr} can be used to get a string representation of an address
  68. instance containing information about that address.
  69. """
  70. self._stringRepresentation(repr)
  71. def test_hash(self):
  72. """
  73. C{__hash__} can be used to get a hash of an address, allowing
  74. addresses to be used as keys in dictionaries, for instance.
  75. """
  76. addr = self.buildAddress()
  77. d = {addr: True}
  78. self.assertTrue(d[self.buildAddress()])
  79. def test_differentNamesComparison(self):
  80. """
  81. Check that comparison operators work correctly on address objects
  82. when a different name is passed in
  83. """
  84. self.assertFalse(self.buildAddress() == self.buildDifferentAddress())
  85. self.assertFalse(self.buildDifferentAddress() == self.buildAddress())
  86. self.assertTrue(self.buildAddress() != self.buildDifferentAddress())
  87. self.assertTrue(self.buildDifferentAddress() != self.buildAddress())
  88. def assertDeprecations(self, testMethod, message):
  89. """
  90. Assert that the a DeprecationWarning with the given message was
  91. emitted against the given method.
  92. """
  93. warnings = self.flushWarnings([testMethod])
  94. self.assertEqual(warnings[0]['category'], DeprecationWarning)
  95. self.assertEqual(warnings[0]['message'], message)
  96. self.assertEqual(len(warnings), 1)
  97. class IPv4AddressTestCaseMixin(AddressTestCaseMixin):
  98. addressArgSpec = (("type", "%s"), ("host", "%r"), ("port", "%d"))
  99. class HostnameAddressTests(unittest.TestCase, AddressTestCaseMixin):
  100. """
  101. Test case for L{HostnameAddress}.
  102. """
  103. addressArgSpec = (("hostname", "%s"), ("port", "%d"))
  104. def buildAddress(self):
  105. """
  106. Create an arbitrary new L{HostnameAddress} instance.
  107. @return: A L{HostnameAddress} instance.
  108. """
  109. return HostnameAddress(b"example.com", 0)
  110. def buildDifferentAddress(self):
  111. """
  112. Like L{buildAddress}, but with a different hostname.
  113. @return: A L{HostnameAddress} instance.
  114. """
  115. return HostnameAddress(b"example.net", 0)
  116. class IPv4AddressTCPTests(unittest.SynchronousTestCase,
  117. IPv4AddressTestCaseMixin):
  118. def buildAddress(self):
  119. """
  120. Create an arbitrary new L{IPv4Address} instance with a C{"TCP"}
  121. type. A new instance is created for each call, but always for the
  122. same address.
  123. """
  124. return IPv4Address("TCP", "127.0.0.1", 0)
  125. def buildDifferentAddress(self):
  126. """
  127. Like L{buildAddress}, but with a different fixed address.
  128. """
  129. return IPv4Address("TCP", "127.0.0.2", 0)
  130. def test_bwHackDeprecation(self):
  131. """
  132. If a value is passed for the C{_bwHack} parameter to L{IPv4Address},
  133. a deprecation warning is emitted.
  134. """
  135. # Construct this for warning side-effects, disregard the actual object.
  136. IPv4Address("TCP", "127.0.0.3", 0, _bwHack="TCP")
  137. message = (
  138. "twisted.internet.address.IPv4Address._bwHack is deprecated "
  139. "since Twisted 11.0")
  140. return self.assertDeprecations(self.test_bwHackDeprecation, message)
  141. class IPv4AddressUDPTests(unittest.SynchronousTestCase,
  142. IPv4AddressTestCaseMixin):
  143. def buildAddress(self):
  144. """
  145. Create an arbitrary new L{IPv4Address} instance with a C{"UDP"}
  146. type. A new instance is created for each call, but always for the
  147. same address.
  148. """
  149. return IPv4Address("UDP", "127.0.0.1", 0)
  150. def buildDifferentAddress(self):
  151. """
  152. Like L{buildAddress}, but with a different fixed address.
  153. """
  154. return IPv4Address("UDP", "127.0.0.2", 0)
  155. def test_bwHackDeprecation(self):
  156. """
  157. If a value is passed for the C{_bwHack} parameter to L{IPv4Address},
  158. a deprecation warning is emitted.
  159. """
  160. # Construct this for warning side-effects, disregard the actual object.
  161. IPv4Address("UDP", "127.0.0.3", 0, _bwHack="UDP")
  162. message = (
  163. "twisted.internet.address.IPv4Address._bwHack is deprecated "
  164. "since Twisted 11.0")
  165. return self.assertDeprecations(self.test_bwHackDeprecation, message)
  166. class IPv6AddressTests(unittest.SynchronousTestCase, AddressTestCaseMixin):
  167. addressArgSpec = (("type", "%s"), ("host", "%r"), ("port", "%d"))
  168. def buildAddress(self):
  169. """
  170. Create an arbitrary new L{IPv6Address} instance with a C{"TCP"}
  171. type. A new instance is created for each call, but always for the
  172. same address.
  173. """
  174. return IPv6Address("TCP", "::1", 0)
  175. def buildDifferentAddress(self):
  176. """
  177. Like L{buildAddress}, but with a different fixed address.
  178. """
  179. return IPv6Address("TCP", "::2", 0)
  180. class UNIXAddressTests(unittest.SynchronousTestCase):
  181. skip = unixSkip
  182. addressArgSpec = (("name", "%r"),)
  183. def setUp(self):
  184. self._socketAddress = self.mktemp()
  185. self._otherAddress = self.mktemp()
  186. def buildAddress(self):
  187. """
  188. Create an arbitrary new L{UNIXAddress} instance. A new instance is
  189. created for each call, but always for the same address.
  190. """
  191. return UNIXAddress(self._socketAddress)
  192. def buildDifferentAddress(self):
  193. """
  194. Like L{buildAddress}, but with a different fixed address.
  195. """
  196. return UNIXAddress(self._otherAddress)
  197. def test_repr(self):
  198. """
  199. The repr of L{UNIXAddress} returns with the filename that the
  200. L{UNIXAddress} is for.
  201. """
  202. self.assertEqual(repr(self.buildAddress()), "UNIXAddress('%s')" % (
  203. nativeString(self._socketAddress)))
  204. def test_comparisonOfLinkedFiles(self):
  205. """
  206. UNIXAddress objects compare as equal if they link to the same file.
  207. """
  208. linkName = self.mktemp()
  209. with open(self._socketAddress, 'w') as self.fd:
  210. os.symlink(os.path.abspath(self._socketAddress), linkName)
  211. self.assertEqual(UNIXAddress(self._socketAddress),
  212. UNIXAddress(linkName))
  213. self.assertEqual(UNIXAddress(linkName),
  214. UNIXAddress(self._socketAddress))
  215. if not unixSkip:
  216. test_comparisonOfLinkedFiles.skip = symlinkSkip
  217. def test_hashOfLinkedFiles(self):
  218. """
  219. UNIXAddress Objects that compare as equal have the same hash value.
  220. """
  221. linkName = self.mktemp()
  222. with open(self._socketAddress, 'w') as self.fd:
  223. os.symlink(os.path.abspath(self._socketAddress), linkName)
  224. self.assertEqual(hash(UNIXAddress(self._socketAddress)),
  225. hash(UNIXAddress(linkName)))
  226. if not unixSkip:
  227. test_hashOfLinkedFiles.skip = symlinkSkip
  228. class EmptyUNIXAddressTests(unittest.SynchronousTestCase,
  229. AddressTestCaseMixin):
  230. """
  231. Tests for L{UNIXAddress} operations involving a L{None} address.
  232. """
  233. skip = unixSkip
  234. addressArgSpec = (("name", "%r"),)
  235. def setUp(self):
  236. self._socketAddress = self.mktemp()
  237. def buildAddress(self):
  238. """
  239. Create an arbitrary new L{UNIXAddress} instance. A new instance is
  240. created for each call, but always for the same address. This builds it
  241. with a fixed address of L{None}.
  242. """
  243. return UNIXAddress(None)
  244. def buildDifferentAddress(self):
  245. """
  246. Like L{buildAddress}, but with a random temporary directory.
  247. """
  248. return UNIXAddress(self._socketAddress)
  249. def test_comparisonOfLinkedFiles(self):
  250. """
  251. A UNIXAddress referring to a L{None} address does not compare equal to a
  252. UNIXAddress referring to a symlink.
  253. """
  254. linkName = self.mktemp()
  255. with open(self._socketAddress, 'w') as self.fd:
  256. os.symlink(os.path.abspath(self._socketAddress), linkName)
  257. self.assertNotEqual(UNIXAddress(self._socketAddress),
  258. UNIXAddress(None))
  259. self.assertNotEqual(UNIXAddress(None),
  260. UNIXAddress(self._socketAddress))
  261. if not unixSkip:
  262. test_comparisonOfLinkedFiles.skip = symlinkSkip
  263. def test_emptyHash(self):
  264. """
  265. C{__hash__} can be used to get a hash of an address, even one referring
  266. to L{None} rather than a real path.
  267. """
  268. addr = self.buildAddress()
  269. d = {addr: True}
  270. self.assertTrue(d[self.buildAddress()])
  271. def test_bwHackDeprecation(self):
  272. """
  273. If a value is passed for the C{_bwHack} parameter to L{UNIXAddress},
  274. a deprecation warning is emitted.
  275. """
  276. # Construct this for warning side-effects, disregard the actual object.
  277. UNIXAddress(None, _bwHack='UNIX')
  278. message = (
  279. "twisted.internet.address.UNIXAddress._bwHack is deprecated "
  280. "since Twisted 11.0")
  281. return self.assertDeprecations(self.test_bwHackDeprecation, message)