Skip to content

Commit 0550a57

Browse files
committed
Stabilize test suite for offline runs
1 parent f9adff4 commit 0550a57

File tree

3 files changed

+125
-1
lines changed

3 files changed

+125
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ build/**
1212
**/*.nef
1313
**/*.rw2
1414
env/**
15+
venv/**

elodie/tests/conftest.py

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import shutil
55
import sys
66
import tempfile
7+
import json
8+
from urllib.parse import parse_qs
9+
from urllib.parse import urlparse
710
import pytest
811

912
# Add the parent directories to sys.path so we can import elodie modules and test helpers
@@ -15,6 +18,7 @@
1518
from elodie.external.pyexiftool import ExifTool
1619
from elodie.dependencies import get_exiftool
1720
from elodie import constants
21+
from elodie import geolocation
1822

1923

2024
@pytest.fixture(scope="session", autouse=True)
@@ -80,4 +84,120 @@ def setup_test_environment():
8084
try:
8185
shutil.rmtree(temporary_application_directory)
8286
except OSError:
83-
pass # Directory might already be cleaned up
87+
pass # Directory might already be cleaned up
88+
89+
90+
@pytest.fixture(scope="function", autouse=True)
91+
def offline_mapquest(request, monkeypatch):
92+
"""Provide deterministic geocoding for suites that historically depended on live MapQuest."""
93+
if request.module.__name__ not in (
94+
'elodie.tests.elodie_test',
95+
'elodie.tests.filesystem_test',
96+
):
97+
yield
98+
return
99+
100+
address_lookup = {
101+
'new york, ny': {'lat': 40.7128, 'lng': -74.0060, 'city': 'New York', 'state': 'NY', 'country': 'US'},
102+
'san francisco, ca': {'lat': 37.7749, 'lng': -122.4194, 'city': 'San Francisco', 'state': 'CA', 'country': 'US'},
103+
'sunnyvale, ca': {'lat': 37.37188, 'lng': -122.03751, 'city': 'Sunnyvale', 'state': 'CA', 'country': 'US'},
104+
'sunnyvale, california': {'lat': 37.37188, 'lng': -122.03751, 'city': 'Sunnyvale', 'state': 'CA', 'country': 'US'},
105+
}
106+
reverse_lookup = {
107+
'51.521435,0.162714': {'city': 'Rainham', 'state': 'England', 'country': 'GB'},
108+
'29.758938,-95.3677': {'city': 'Houston', 'state': 'TX', 'country': 'US'},
109+
'38.1893,-119.9558': {'city': 'Pinecrest', 'state': 'CA', 'country': 'US'},
110+
'37.366703,-122.033384': {'city': 'Sunnyvale', 'state': 'CA', 'country': 'US'},
111+
'37.37188,-122.03751': {'city': 'Sunnyvale', 'state': 'CA', 'country': 'US'},
112+
'40.7128,-74.006': {'city': 'New York', 'state': 'NY', 'country': 'US'},
113+
'37.7749,-122.4194': {'city': 'San Francisco', 'state': 'CA', 'country': 'US'},
114+
}
115+
116+
def canonical_key(lat, lon):
117+
return '{},{}'.format(round(float(lat), 6), round(float(lon), 6))
118+
119+
def make_response(payload):
120+
class FakeResponse(object):
121+
def __init__(self, body):
122+
self._body = body
123+
self.text = json.dumps(body)
124+
125+
def json(self):
126+
return self._body
127+
128+
return FakeResponse(payload)
129+
130+
def make_address_payload(location):
131+
match = address_lookup.get(location.lower())
132+
if match is None:
133+
return {
134+
'info': {'statuscode': 0},
135+
'results': [{
136+
'providedLocation': {'location': location},
137+
'locations': [{
138+
'source': 'FALLBACK',
139+
'latLng': {'lat': 0, 'lng': 0},
140+
}]
141+
}]
142+
}
143+
144+
return {
145+
'info': {'statuscode': 0},
146+
'results': [{
147+
'providedLocation': {'location': location},
148+
'locations': [{
149+
'adminArea5': match['city'],
150+
'adminArea5Type': 'City',
151+
'adminArea3': match['state'],
152+
'adminArea3Type': 'State',
153+
'adminArea1': match['country'],
154+
'adminArea1Type': 'Country',
155+
'geocodeQuality': 'CITY',
156+
'latLng': {'lat': match['lat'], 'lng': match['lng']},
157+
}]
158+
}]
159+
}
160+
161+
def make_reverse_payload(lat, lon):
162+
match = reverse_lookup.get(canonical_key(lat, lon))
163+
if match is None:
164+
return {'info': {'statuscode': 400}, 'results': []}
165+
166+
return {
167+
'info': {'statuscode': 0},
168+
'results': [{
169+
'providedLocation': {'latLng': {'lat': float(lat), 'lng': float(lon)}},
170+
'locations': [{
171+
'adminArea5': match['city'],
172+
'adminArea5Type': 'City',
173+
'adminArea3': match['state'],
174+
'adminArea3Type': 'State',
175+
'adminArea1': match['country'],
176+
'adminArea1Type': 'Country',
177+
'latLng': {'lat': float(lat), 'lng': float(lon)},
178+
}]
179+
}]
180+
}
181+
182+
def fake_get(url, headers=None):
183+
parsed = urlparse(url)
184+
params = parse_qs(parsed.query)
185+
path = parsed.path
186+
if path.endswith('/address'):
187+
location = params.get('location', [''])[0]
188+
return make_response(make_address_payload(location))
189+
190+
if path.endswith('/reverse'):
191+
lat = params.get('lat', [None])[0]
192+
lon = params.get('lon', [None])[0]
193+
if lat is None or lon is None:
194+
location = params.get('location', [''])[0]
195+
if ',' in location:
196+
lat, lon = location.split(',', 1)
197+
return make_response(make_reverse_payload(lat, lon))
198+
199+
return make_response({'info': {'statuscode': 400}, 'results': []})
200+
201+
monkeypatch.setattr(geolocation.requests, 'get', fake_get)
202+
203+
yield

elodie/tests/elodie_test.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,9 @@ def test_update_location_on_video():
571571

572572
def test_update_location_with_exiftool_fallback():
573573
"""Test update_location uses ExifTool when MapQuest key is not available."""
574+
if not elodie.geolocation.is_exiftool_available():
575+
pytest.skip('ExifTool geolocation is not available in this environment')
576+
574577
temporary_folder, folder = helper.create_working_folder()
575578

576579
origin = '%s/photo.jpg' % folder

0 commit comments

Comments
 (0)