55import unittest
66from unittest .mock import patch
77
8+ from sqlalchemy .orm import Session
9+
10+ from shared .database .database import with_db_session
11+ from shared .helpers .src .shared .database_gen .sqlacodegen_models import Gtfsfeed
812from tasks .geojson .update_geojson_files_precision import (
913 process_geojson ,
1014 update_geojson_files_precision_handler ,
1115 GEOLOCATION_FILENAME ,
1216)
17+ from test_shared .test_utils .database_utils import default_db_url
1318
1419
1520class _FakeBlobContext :
16- def __init__ (self , bucket , name ):
21+ def __init__ (self , bucket , name , blob_exists = True ):
1722 self .bucket = bucket
1823 self .name = name
24+ self .blob_exists = blob_exists
1925
2026 def __enter__ (self ):
2127 return self
2228
23- def __exit__ (self , exc_type , exc , tb ):
24- return False
29+ # def __exit__(self, exc_type, exc, tb):
30+ # return self.exists
2531
2632 def exists (self ):
27- return self .name in self . bucket . initial_blobs
33+ return self .blob_exists
2834
2935 def download_as_text (self ):
3036 return self .bucket .initial_blobs [self .name ]
@@ -60,15 +66,16 @@ def bucket(self, name):
6066
6167
6268class FakeStorageModule :
63- def __init__ (self , bucket ):
69+ def __init__ (self , bucket , blob_exists = True ):
6470 self ._bucket = bucket
71+ self ._blob_exists = blob_exists
6572
6673 def Client (self ):
6774 return FakeClient (self ._bucket )
6875
6976 # storage.Blob(...) used as a context manager in the handler
7077 def Blob (self , * , bucket , name ):
71- return _FakeBlobContext (bucket , name )
78+ return _FakeBlobContext (bucket , name , self . _blob_exists )
7279
7380
7481class TestUpdateGeojsonFilesPrecision (unittest .TestCase ):
@@ -129,8 +136,8 @@ def test_process_geojson_single_feature_and_list_variants(self):
129136 [round (1.23456789 , 3 ), round (2.3456789 , 3 )],
130137 )
131138
132- @patch ( "tasks.geojson.update_geojson_files_precision.query_unprocessed_feeds" )
133- def test_handler_uploads_and_updates_feed_info (self , mock_query ):
139+ @with_db_session ( db_url = default_db_url )
140+ def test_handler_uploads_and_updates_feed_info (self , db_session : Session ):
134141 geo = {
135142 "type" : "FeatureCollection" ,
136143 "features" : [
@@ -144,11 +151,12 @@ def test_handler_uploads_and_updates_feed_info(self, mock_query):
144151 }
145152 ],
146153 }
147- feed_stable_id = "feed_123"
154+ testing_feed = db_session .query (Gtfsfeed ).limit (1 ).first ()
155+ feed_stable_id = testing_feed .stable_id
148156 blob_name = f"{ feed_stable_id } /{ GEOLOCATION_FILENAME } "
149157
150158 fake_bucket = FakeBucket (initial_blobs = {blob_name : json .dumps (geo )})
151- fake_storage = FakeStorageModule (fake_bucket )
159+ fake_storage = FakeStorageModule (fake_bucket , blob_exists = True )
152160
153161 # create module objects for google and google.cloud and inject via sys.modules
154162 cloud_mod = types .ModuleType ("google.cloud" )
@@ -157,32 +165,6 @@ def test_handler_uploads_and_updates_feed_info(self, mock_query):
157165 google_mod = types .ModuleType ("google" )
158166 google_mod .cloud = cloud_mod
159167
160- fake_feed = types .SimpleNamespace (
161- stable_id = feed_stable_id ,
162- geolocation_file_created_date = None ,
163- gtfsdatasets = [
164- types .SimpleNamespace (
165- bounding_box = types .SimpleNamespace (id = "bbid" ), downloaded_date = None
166- )
167- ],
168- )
169-
170- mock_query .return_value = [fake_feed ]
171-
172- # fake db session
173- class FakeExecResult :
174- def scalar (self ):
175- return "NOW_TS"
176-
177- class FakeDBSession :
178- def execute (self , q ):
179- return FakeExecResult ()
180-
181- def commit (self ):
182- return None
183-
184- fake_db = FakeDBSession ()
185-
186168 payload = {
187169 "bucket_name" : "any-bucket" ,
188170 "dry_run" : False ,
@@ -193,7 +175,9 @@ def commit(self):
193175 # Inject modules into sys.modules for the duration of the handler call
194176 with patch .dict (sys .modules , {"google.cloud" : cloud_mod , "google" : google_mod }):
195177 # call wrapped handler to provide fake db_session
196- update_geojson_files_precision_handler (payload , db_session = fake_db )
178+ result = update_geojson_files_precision_handler (
179+ payload , db_session = db_session
180+ )
197181
198182 # verify upload happened
199183 self .assertIn ("geolocation.geojson" , fake_bucket .uploaded )
@@ -202,8 +186,111 @@ def commit(self):
202186 coords = uploaded_geo .get ("features" )[0 ]["geometry" ]["coordinates" ]
203187 self .assertEqual (coords , [round (100.1234567 , 5 ), round (0.9876543 , 5 )])
204188
189+ self .assertEqual (
190+ {
191+ "total_processed_files" : 1 ,
192+ "errors" : [],
193+ "not_found_file" : 0 ,
194+ "params" : {
195+ "dry_run" : False ,
196+ "precision" : 5 ,
197+ "limit" : 1 ,
198+ },
199+ },
200+ result ,
201+ )
205202 # feed updated
206- self .assertEqual (fake_feed .geolocation_file_created_date , "NOW_TS" )
203+ reloaded_testing_feed = (
204+ db_session .query (Gtfsfeed )
205+ .filter (Gtfsfeed .id .__eq__ (testing_feed .id ))
206+ .limit (1 )
207+ .first ()
208+ )
209+ self .assertIsNotNone (reloaded_testing_feed .geolocation_file_dataset_id )
210+ self .assertIsNotNone (reloaded_testing_feed .geolocation_file_created_date )
211+
212+ @with_db_session (db_url = default_db_url )
213+ def test_handler_file_dont_exists (self , db_session : Session ):
214+ fake_bucket = FakeBucket (initial_blobs = {})
215+ fake_storage = FakeStorageModule (fake_bucket , blob_exists = False )
216+
217+ # create module objects for google and google.cloud and inject via sys.modules
218+ cloud_mod = types .ModuleType ("google.cloud" )
219+ # 'from google.cloud import storage' in handler will bind 'storage' to this attribute
220+ cloud_mod .storage = fake_storage
221+ google_mod = types .ModuleType ("google" )
222+ google_mod .cloud = cloud_mod
223+
224+ payload = {
225+ "bucket_name" : "any-bucket" ,
226+ "dry_run" : False ,
227+ "precision" : 5 ,
228+ "limit" : 1 ,
229+ }
230+
231+ # Inject modules into sys.modules for the duration of the handler call
232+ with patch .dict (sys .modules , {"google.cloud" : cloud_mod , "google" : google_mod }):
233+ # call wrapped handler to provide fake db_session
234+ result = update_geojson_files_precision_handler (
235+ payload , db_session = db_session
236+ )
237+ self .assertEqual (
238+ {
239+ "total_processed_files" : 0 ,
240+ "errors" : [],
241+ "not_found_file" : 1 ,
242+ "params" : {
243+ "dry_run" : False ,
244+ "precision" : 5 ,
245+ "limit" : 1 ,
246+ },
247+ },
248+ result ,
249+ )
250+
251+ @with_db_session (db_url = default_db_url )
252+ def test_handler_file_not_valid_file (self , db_session : Session ):
253+ geo = "{}"
254+ testing_feed = db_session .query (Gtfsfeed ).limit (1 ).first ()
255+ feed_stable_id = testing_feed .stable_id
256+ blob_name = f"{ feed_stable_id } /{ GEOLOCATION_FILENAME } "
257+
258+ fake_bucket = FakeBucket (initial_blobs = {blob_name : geo })
259+ fake_storage = FakeStorageModule (fake_bucket , blob_exists = True )
260+
261+ # create module objects for google and google.cloud and inject via sys.modules
262+ cloud_mod = types .ModuleType ("google.cloud" )
263+ # 'from google.cloud import storage' in handler will bind 'storage' to this attribute
264+ cloud_mod .storage = fake_storage
265+ google_mod = types .ModuleType ("google" )
266+ google_mod .cloud = cloud_mod
267+
268+ payload = {
269+ "bucket_name" : "any-bucket" ,
270+ "dry_run" : False ,
271+ "precision" : 5 ,
272+ "limit" : 1 ,
273+ }
274+ testing_feed = db_session .query (Gtfsfeed ).limit (1 ).first ()
275+ # Inject modules into sys.modules for the duration of the handler call
276+ with patch .dict (sys .modules , {"google.cloud" : cloud_mod , "google" : google_mod }):
277+ # call wrapped handler to provide fake db_session
278+ result = update_geojson_files_precision_handler (
279+ payload , db_session = db_session
280+ )
281+ self .assertEqual (
282+ {
283+ "total_processed_files" : 0 ,
284+ "errors" : [testing_feed .stable_id ],
285+ "not_found_file" : 0 ,
286+ "params" : {
287+ "dry_run" : False ,
288+ "precision" : 5 ,
289+ "limit" : 1 ,
290+ },
291+ },
292+ result ,
293+ )
207294
208295
209296if __name__ == "__main__" :
0 commit comments