2016-05-29 18:55:16 +00:00
|
|
|
"""Test Home Assistant location util methods."""
|
2019-05-08 18:15:04 +00:00
|
|
|
import aiohttp
|
|
|
|
import pytest
|
2016-05-29 18:55:16 +00:00
|
|
|
|
|
|
|
import homeassistant.util.location as location_util
|
|
|
|
|
2020-04-30 20:29:50 +00:00
|
|
|
from tests.async_mock import Mock, patch
|
2020-04-25 22:52:50 +00:00
|
|
|
from tests.common import load_fixture
|
2016-06-27 16:02:45 +00:00
|
|
|
|
2016-05-29 18:55:16 +00:00
|
|
|
# Paris
|
|
|
|
COORDINATES_PARIS = (48.864716, 2.349014)
|
|
|
|
# New York
|
|
|
|
COORDINATES_NEW_YORK = (40.730610, -73.935242)
|
|
|
|
|
|
|
|
# Results for the assertion (vincenty algorithm):
|
|
|
|
# Distance [km] Distance [miles]
|
|
|
|
# [0] 5846.39 3632.78
|
|
|
|
# [1] 5851 3635
|
|
|
|
#
|
|
|
|
# [0]: http://boulter.com/gps/distance/
|
|
|
|
# [1]: https://www.wolframalpha.com/input/?i=from+paris+to+new+york
|
|
|
|
DISTANCE_KM = 5846.39
|
|
|
|
DISTANCE_MILES = 3632.78
|
|
|
|
|
|
|
|
|
2019-05-08 18:15:04 +00:00
|
|
|
@pytest.fixture
|
|
|
|
async def session(hass):
|
|
|
|
"""Return aioclient session."""
|
|
|
|
return hass.helpers.aiohttp_client.async_get_clientsession()
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
async def raising_session(loop):
|
|
|
|
"""Return an aioclient session that only fails."""
|
|
|
|
return Mock(get=Mock(side_effect=aiohttp.ClientError))
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_distance_to_same_place():
|
|
|
|
"""Test getting the distance."""
|
|
|
|
meters = location_util.distance(
|
2019-07-31 19:25:30 +00:00
|
|
|
COORDINATES_PARIS[0],
|
|
|
|
COORDINATES_PARIS[1],
|
|
|
|
COORDINATES_PARIS[0],
|
|
|
|
COORDINATES_PARIS[1],
|
|
|
|
)
|
2019-05-08 18:15:04 +00:00
|
|
|
|
|
|
|
assert meters == 0
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_distance():
|
|
|
|
"""Test getting the distance."""
|
|
|
|
meters = location_util.distance(
|
2019-07-31 19:25:30 +00:00
|
|
|
COORDINATES_PARIS[0],
|
|
|
|
COORDINATES_PARIS[1],
|
|
|
|
COORDINATES_NEW_YORK[0],
|
|
|
|
COORDINATES_NEW_YORK[1],
|
|
|
|
)
|
2019-05-08 18:15:04 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
assert meters / 1000 - DISTANCE_KM < 0.01
|
2019-05-08 18:15:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_get_kilometers():
|
|
|
|
"""Test getting the distance between given coordinates in km."""
|
2019-07-31 19:25:30 +00:00
|
|
|
kilometers = location_util.vincenty(COORDINATES_PARIS, COORDINATES_NEW_YORK)
|
2019-05-08 18:15:04 +00:00
|
|
|
assert round(kilometers, 2) == DISTANCE_KM
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_miles():
|
|
|
|
"""Test getting the distance between given coordinates in miles."""
|
2019-07-31 19:25:30 +00:00
|
|
|
miles = location_util.vincenty(COORDINATES_PARIS, COORDINATES_NEW_YORK, miles=True)
|
2019-05-08 18:15:04 +00:00
|
|
|
assert round(miles, 2) == DISTANCE_MILES
|
|
|
|
|
|
|
|
|
|
|
|
async def test_detect_location_info_ipapi(aioclient_mock, session):
|
|
|
|
"""Test detect location info using ipapi.co."""
|
2019-07-31 19:25:30 +00:00
|
|
|
aioclient_mock.get(location_util.IPAPI, text=load_fixture("ipapi.co.json"))
|
2019-05-08 18:15:04 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
info = await location_util.async_detect_location_info(session, _test_real=True)
|
2019-05-08 18:15:04 +00:00
|
|
|
|
|
|
|
assert info is not None
|
2019-07-31 19:25:30 +00:00
|
|
|
assert info.ip == "1.2.3.4"
|
|
|
|
assert info.country_code == "CH"
|
|
|
|
assert info.country_name == "Switzerland"
|
|
|
|
assert info.region_code == "BE"
|
|
|
|
assert info.region_name == "Bern"
|
|
|
|
assert info.city == "Bern"
|
|
|
|
assert info.zip_code == "3000"
|
|
|
|
assert info.time_zone == "Europe/Zurich"
|
2019-05-08 18:15:04 +00:00
|
|
|
assert info.latitude == 46.9480278
|
|
|
|
assert info.longitude == 7.4490812
|
|
|
|
assert info.use_metric
|
|
|
|
|
|
|
|
|
2020-01-16 16:31:12 +00:00
|
|
|
async def test_detect_location_info_ipapi_exhaust(aioclient_mock, session):
|
|
|
|
"""Test detect location info using ipapi.co."""
|
|
|
|
aioclient_mock.get(location_util.IPAPI, json={"latitude": "Sign up to access"})
|
|
|
|
aioclient_mock.get(location_util.IP_API, text=load_fixture("ip-api.com.json"))
|
|
|
|
|
|
|
|
info = await location_util.async_detect_location_info(session, _test_real=True)
|
|
|
|
|
|
|
|
assert info is not None
|
|
|
|
# ip_api result because ipapi got skipped
|
|
|
|
assert info.country_code == "US"
|
|
|
|
assert len(aioclient_mock.mock_calls) == 2
|
|
|
|
|
|
|
|
|
2019-05-08 18:15:04 +00:00
|
|
|
async def test_detect_location_info_ip_api(aioclient_mock, session):
|
|
|
|
"""Test detect location info using ip-api.com."""
|
2019-07-31 19:25:30 +00:00
|
|
|
aioclient_mock.get(location_util.IP_API, text=load_fixture("ip-api.com.json"))
|
2019-05-08 18:15:04 +00:00
|
|
|
|
2020-04-25 22:52:50 +00:00
|
|
|
with patch("homeassistant.util.location._get_ipapi", return_value=None):
|
2019-07-31 19:25:30 +00:00
|
|
|
info = await location_util.async_detect_location_info(session, _test_real=True)
|
2019-05-08 18:15:04 +00:00
|
|
|
|
|
|
|
assert info is not None
|
2019-07-31 19:25:30 +00:00
|
|
|
assert info.ip == "1.2.3.4"
|
|
|
|
assert info.country_code == "US"
|
|
|
|
assert info.country_name == "United States"
|
|
|
|
assert info.region_code == "CA"
|
|
|
|
assert info.region_name == "California"
|
|
|
|
assert info.city == "San Diego"
|
|
|
|
assert info.zip_code == "92122"
|
|
|
|
assert info.time_zone == "America/Los_Angeles"
|
2019-05-08 18:15:04 +00:00
|
|
|
assert info.latitude == 32.8594
|
|
|
|
assert info.longitude == -117.2073
|
|
|
|
assert not info.use_metric
|
|
|
|
|
|
|
|
|
|
|
|
async def test_detect_location_info_both_queries_fail(session):
|
|
|
|
"""Ensure we return None if both queries fail."""
|
2020-04-25 22:52:50 +00:00
|
|
|
with patch("homeassistant.util.location._get_ipapi", return_value=None), patch(
|
|
|
|
"homeassistant.util.location._get_ip_api", return_value=None
|
|
|
|
):
|
2019-07-31 19:25:30 +00:00
|
|
|
info = await location_util.async_detect_location_info(session, _test_real=True)
|
2019-05-08 18:15:04 +00:00
|
|
|
assert info is None
|
|
|
|
|
|
|
|
|
|
|
|
async def test_freegeoip_query_raises(raising_session):
|
|
|
|
"""Test ipapi.co query when the request to API fails."""
|
|
|
|
info = await location_util._get_ipapi(raising_session)
|
|
|
|
assert info is None
|
|
|
|
|
|
|
|
|
|
|
|
async def test_ip_api_query_raises(raising_session):
|
|
|
|
"""Test ip api query when the request to API fails."""
|
|
|
|
info = await location_util._get_ip_api(raising_session)
|
|
|
|
assert info is None
|