test_geoip2.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import os
  2. import pathlib
  3. from unittest import mock, skipUnless
  4. from django.conf import settings
  5. from django.contrib.gis.geoip2 import HAS_GEOIP2
  6. from django.contrib.gis.geos import GEOSGeometry
  7. from django.test import SimpleTestCase
  8. from django.utils.deprecation import RemovedInDjango60Warning
  9. if HAS_GEOIP2:
  10. from django.contrib.gis.geoip2 import GeoIP2, GeoIP2Exception
  11. # Note: Requires both the GeoIP country and city datasets.
  12. # The GEOIP_DATA path should be the only setting set (the directory
  13. # should contain links or the actual database files 'GeoLite2-City.mmdb' and
  14. # 'GeoLite2-City.mmdb'.
  15. @skipUnless(
  16. HAS_GEOIP2 and getattr(settings, "GEOIP_PATH", None),
  17. "GeoIP is required along with the GEOIP_PATH setting.",
  18. )
  19. class GeoIPTest(SimpleTestCase):
  20. addr = "129.237.192.1"
  21. fqdn = "ku.edu"
  22. def test01_init(self):
  23. "GeoIP initialization."
  24. g1 = GeoIP2() # Everything inferred from GeoIP path
  25. path = settings.GEOIP_PATH
  26. g2 = GeoIP2(path, 0) # Passing in data path explicitly.
  27. g3 = GeoIP2.open(path, 0) # MaxMind Python API syntax.
  28. # path accepts str and pathlib.Path.
  29. if isinstance(path, str):
  30. g4 = GeoIP2(pathlib.Path(path))
  31. else:
  32. g4 = GeoIP2(str(path))
  33. for g in (g1, g2, g3, g4):
  34. self.assertTrue(g._country)
  35. self.assertTrue(g._city)
  36. # Only passing in the location of one database.
  37. city = os.path.join(path, "GeoLite2-City.mmdb")
  38. cntry = os.path.join(path, "GeoLite2-Country.mmdb")
  39. g4 = GeoIP2(city, country="")
  40. self.assertIsNone(g4._country)
  41. g5 = GeoIP2(cntry, city="")
  42. self.assertIsNone(g5._city)
  43. # Improper parameters.
  44. bad_params = (23, "foo", 15.23)
  45. for bad in bad_params:
  46. with self.assertRaises(GeoIP2Exception):
  47. GeoIP2(cache=bad)
  48. if isinstance(bad, str):
  49. e = GeoIP2Exception
  50. else:
  51. e = TypeError
  52. with self.assertRaises(e):
  53. GeoIP2(bad, 0)
  54. def test_no_database_file(self):
  55. invalid_path = os.path.join(os.path.dirname(__file__), "data")
  56. msg = "Could not load a database from %s." % invalid_path
  57. with self.assertRaisesMessage(GeoIP2Exception, msg):
  58. GeoIP2(invalid_path)
  59. def test02_bad_query(self):
  60. "GeoIP query parameter checking."
  61. cntry_g = GeoIP2(city="<foo>")
  62. # No city database available, these calls should fail.
  63. with self.assertRaises(GeoIP2Exception):
  64. cntry_g.city("tmc.edu")
  65. # Non-string query should raise TypeError
  66. with self.assertRaises(TypeError):
  67. cntry_g.country_code(17)
  68. with self.assertRaises(TypeError):
  69. cntry_g.country_name(GeoIP2)
  70. @mock.patch("socket.gethostbyname")
  71. def test03_country(self, gethostbyname):
  72. "GeoIP country querying methods."
  73. gethostbyname.return_value = "128.249.1.1"
  74. g = GeoIP2(city="<foo>")
  75. for query in (self.fqdn, self.addr):
  76. self.assertEqual(
  77. "US",
  78. g.country_code(query),
  79. "Failed for func country_code and query %s" % query,
  80. )
  81. self.assertEqual(
  82. "United States",
  83. g.country_name(query),
  84. "Failed for func country_name and query %s" % query,
  85. )
  86. self.assertEqual(
  87. {"country_code": "US", "country_name": "United States"},
  88. g.country(query),
  89. )
  90. @mock.patch("socket.gethostbyname")
  91. def test04_city(self, gethostbyname):
  92. "GeoIP city querying methods."
  93. gethostbyname.return_value = "129.237.192.1"
  94. g = GeoIP2(country="<foo>")
  95. for query in (self.fqdn, self.addr):
  96. # Country queries should still work.
  97. self.assertEqual(
  98. "US",
  99. g.country_code(query),
  100. "Failed for func country_code and query %s" % query,
  101. )
  102. self.assertEqual(
  103. "United States",
  104. g.country_name(query),
  105. "Failed for func country_name and query %s" % query,
  106. )
  107. self.assertEqual(
  108. {"country_code": "US", "country_name": "United States"},
  109. g.country(query),
  110. )
  111. # City information dictionary.
  112. d = g.city(query)
  113. self.assertEqual("NA", d["continent_code"])
  114. self.assertEqual("North America", d["continent_name"])
  115. self.assertEqual("US", d["country_code"])
  116. self.assertEqual("Lawrence", d["city"])
  117. self.assertEqual("KS", d["region"])
  118. self.assertEqual("America/Chicago", d["time_zone"])
  119. self.assertFalse(d["is_in_european_union"])
  120. geom = g.geos(query)
  121. self.assertIsInstance(geom, GEOSGeometry)
  122. for e1, e2 in (
  123. geom.tuple,
  124. g.lon_lat(query),
  125. g.lat_lon(query),
  126. ):
  127. self.assertIsInstance(e1, float)
  128. self.assertIsInstance(e2, float)
  129. def test06_ipv6_query(self):
  130. "GeoIP can lookup IPv6 addresses."
  131. g = GeoIP2()
  132. d = g.city("2002:81ed:c9a5::81ed:c9a5") # IPv6 address for www.nhm.ku.edu
  133. self.assertEqual("US", d["country_code"])
  134. self.assertEqual("Lawrence", d["city"])
  135. self.assertEqual("KS", d["region"])
  136. def test_repr(self):
  137. path = settings.GEOIP_PATH
  138. g = GeoIP2(path=path)
  139. meta = g._reader.metadata()
  140. version = "%s.%s" % (
  141. meta.binary_format_major_version,
  142. meta.binary_format_minor_version,
  143. )
  144. country_path = g._country_file
  145. city_path = g._city_file
  146. expected = (
  147. '<GeoIP2 [v%(version)s] _country_file="%(country)s", _city_file="%(city)s">'
  148. % {
  149. "version": version,
  150. "country": country_path,
  151. "city": city_path,
  152. }
  153. )
  154. self.assertEqual(repr(g), expected)
  155. @mock.patch("socket.gethostbyname", return_value="expected")
  156. def test_check_query(self, gethostbyname):
  157. g = GeoIP2()
  158. self.assertEqual(g._check_query("127.0.0.1"), "127.0.0.1")
  159. self.assertEqual(
  160. g._check_query("2002:81ed:c9a5::81ed:c9a5"), "2002:81ed:c9a5::81ed:c9a5"
  161. )
  162. self.assertEqual(g._check_query("invalid-ip-address"), "expected")
  163. def test_coords_deprecation_warning(self):
  164. g = GeoIP2()
  165. msg = "GeoIP2.coords() is deprecated. Use GeoIP2.lon_lat() instead."
  166. with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
  167. e1, e2 = g.coords(self.fqdn)
  168. self.assertIsInstance(e1, float)
  169. self.assertIsInstance(e2, float)