note requires both the geoip country and city datasets the geoipdata path should be the only setting set the directory should contain links or the actual database files geolite2city mmdb and geolite2city mmdb path accepts str and pathlib path only passing in the location of one database improper parameters no city database available these calls should fail nonstring query should raise typeerror country queries should still work city information dictionary note requires both the geoip country and city datasets the geoip_data path should be the only setting set the directory should contain links or the actual database files geolite2 city mmdb and geolite2 city mmdb everything inferred from geoip path passing in data path explicitly maxmind python api syntax path accepts str and pathlib path only passing in the location of one database improper parameters no city database available these calls should fail non string query should raise typeerror country queries should still work city information dictionary ipv6 address for www nhm ku edu
import os
import pathlib
from unittest import mock, skipUnless

from django.conf import settings
from django.contrib.gis.geoip2 import HAS_GEOIP2
from django.contrib.gis.geos import GEOSGeometry
from django.test import SimpleTestCase
from django.utils.deprecation import RemovedInDjango60Warning

if HAS_GEOIP2:
    from django.contrib.gis.geoip2 import GeoIP2, GeoIP2Exception






@skipUnless(
    HAS_GEOIP2 and getattr(settings, "GEOIP_PATH", None),
    "GeoIP is required along with the GEOIP_PATH setting.",
)
class GeoIPTest(SimpleTestCase):
    addr = "129.237.192.1"
    fqdn = "ku.edu"

    def test01_init(self):
        "GeoIP initialization."
        g1 = GeoIP2()  
        path = settings.GEOIP_PATH
        g2 = GeoIP2(path, 0)  
        g3 = GeoIP2.open(path, 0)  
        
        if isinstance(path, str):
            g4 = GeoIP2(pathlib.Path(path))
        else:
            g4 = GeoIP2(str(path))

        for g in (g1, g2, g3, g4):
            self.assertTrue(g._country)
            self.assertTrue(g._city)

        
        city = os.path.join(path, "GeoLite2-City.mmdb")
        cntry = os.path.join(path, "GeoLite2-Country.mmdb")
        g4 = GeoIP2(city, country="")
        self.assertIsNone(g4._country)
        g5 = GeoIP2(cntry, city="")
        self.assertIsNone(g5._city)

        
        bad_params = (23, "foo", 15.23)
        for bad in bad_params:
            with self.assertRaises(GeoIP2Exception):
                GeoIP2(cache=bad)
            if isinstance(bad, str):
                e = GeoIP2Exception
            else:
                e = TypeError
            with self.assertRaises(e):
                GeoIP2(bad, 0)

    def test_no_database_file(self):
        invalid_path = os.path.join(os.path.dirname(__file__), "data")
        msg = "Could not load a database from %s." % invalid_path
        with self.assertRaisesMessage(GeoIP2Exception, msg):
            GeoIP2(invalid_path)

    def test02_bad_query(self):
        "GeoIP query parameter checking."
        cntry_g = GeoIP2(city="<foo>")
        
        with self.assertRaises(GeoIP2Exception):
            cntry_g.city("tmc.edu")

        
        with self.assertRaises(TypeError):
            cntry_g.country_code(17)
        with self.assertRaises(TypeError):
            cntry_g.country_name(GeoIP2)

    @mock.patch("socket.gethostbyname")
    def test03_country(self, gethostbyname):
        "GeoIP country querying methods."
        gethostbyname.return_value = "128.249.1.1"
        g = GeoIP2(city="<foo>")

        for query in (self.fqdn, self.addr):
            self.assertEqual(
                "US",
                g.country_code(query),
                "Failed for func country_code and query %s" % query,
            )
            self.assertEqual(
                "United States",
                g.country_name(query),
                "Failed for func country_name and query %s" % query,
            )
            self.assertEqual(
                {"country_code": "US", "country_name": "United States"},
                g.country(query),
            )

    @mock.patch("socket.gethostbyname")
    def test04_city(self, gethostbyname):
        "GeoIP city querying methods."
        gethostbyname.return_value = "129.237.192.1"
        g = GeoIP2(country="<foo>")

        for query in (self.fqdn, self.addr):
            
            self.assertEqual(
                "US",
                g.country_code(query),
                "Failed for func country_code and query %s" % query,
            )
            self.assertEqual(
                "United States",
                g.country_name(query),
                "Failed for func country_name and query %s" % query,
            )
            self.assertEqual(
                {"country_code": "US", "country_name": "United States"},
                g.country(query),
            )

            
            d = g.city(query)
            self.assertEqual("NA", d["continent_code"])
            self.assertEqual("North America", d["continent_name"])
            self.assertEqual("US", d["country_code"])
            self.assertEqual("Lawrence", d["city"])
            self.assertEqual("KS", d["region"])
            self.assertEqual("America/Chicago", d["time_zone"])
            self.assertFalse(d["is_in_european_union"])
            geom = g.geos(query)
            self.assertIsInstance(geom, GEOSGeometry)

            for e1, e2 in (
                geom.tuple,
                g.lon_lat(query),
                g.lat_lon(query),
            ):
                self.assertIsInstance(e1, float)
                self.assertIsInstance(e2, float)

    def test06_ipv6_query(self):
        "GeoIP can lookup IPv6 addresses."
        g = GeoIP2()
        d = g.city("2002:81ed:c9a5::81ed:c9a5")  
        self.assertEqual("US", d["country_code"])
        self.assertEqual("Lawrence", d["city"])
        self.assertEqual("KS", d["region"])

    def test_del(self):
        g = GeoIP2()
        city = g._city
        country = g._country
        self.assertIs(city._db_reader.closed, False)
        self.assertIs(country._db_reader.closed, False)
        del g
        self.assertIs(city._db_reader.closed, True)
        self.assertIs(country._db_reader.closed, True)

    def test_repr(self):
        path = settings.GEOIP_PATH
        g = GeoIP2(path=path)
        meta = g._reader.metadata()
        version = "%s.%s" % (
            meta.binary_format_major_version,
            meta.binary_format_minor_version,
        )
        country_path = g._country_file
        city_path = g._city_file
        expected = (
            '<GeoIP2 [v%(version)s] _country_file="%(country)s", _city_file="%(city)s">'
            % {
                "version": version,
                "country": country_path,
                "city": city_path,
            }
        )
        self.assertEqual(repr(g), expected)

    @mock.patch("socket.gethostbyname", return_value="expected")
    def test_check_query(self, gethostbyname):
        g = GeoIP2()
        self.assertEqual(g._check_query("127.0.0.1"), "127.0.0.1")
        self.assertEqual(
            g._check_query("2002:81ed:c9a5::81ed:c9a5"), "2002:81ed:c9a5::81ed:c9a5"
        )
        self.assertEqual(g._check_query("invalid-ip-address"), "expected")

    def test_coords_deprecation_warning(self):
        g = GeoIP2()
        msg = "GeoIP2.coords() is deprecated. Use GeoIP2.lon_lat() instead."
        with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
            e1, e2 = g.coords(self.fqdn)
        self.assertIsInstance(e1, float)
        self.assertIsInstance(e2, float)