Coverage for tests / test_stationmeta.py: 100%
329 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 12:51 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-12 12:51 +0000
1# SPDX-FileCopyrightText: 2021 Forschungszentrum Jülich GmbH
2# SPDX-License-Identifier: MIT
4import pytest
5import json
6from fastapi import Request
7from sqlalchemy import insert
8from toardb.stationmeta.models import (
9 StationmetaCore,
10 StationmetaGlobal,
11 StationmetaGlobalService,
12 StationmetaRole,
13 StationmetaChangelog,
14 stationmeta_core_stationmeta_roles_table
15)
16from toardb.toardb import app
17from toardb.stationmeta import crud
18from toardb.stationmeta.schemas import (
19 get_geom_from_coordinates,
20 Coordinates,
21 StationmetaCreate
22)
23from toardb.auth_user.models import AuthUser
24from toardb.contacts.models import Person, Organisation, Contact
25from toardb.test_base import (
26 client,
27 get_test_db,
28 override_dependency,
29 create_test_database,
30 url,
31 get_test_engine,
32 test_db_session as db,
33)
34from unittest.mock import patch
37class TestApps:
38 def setup(self):
39 self.application_url = "/stationmeta/"
41 """Set up all the data before each test
42 If you want the setup only once (per test module),
43 the scope argument is not working in the expected way, as discussed here:
44 https://stackoverflow.com/questions/45817153/py-test-fixture-use-function-fixture-in-scope-fixture
45 """
46 @pytest.fixture(autouse=True)
47 def setup_db_data(self, db):
48 # id_seq will not be reset automatically between tests!
49 _db_conn = get_test_engine()
50 fake_conn = _db_conn.raw_connection()
51 fake_cur = fake_conn.cursor()
52 fake_cur.execute("ALTER SEQUENCE auth_user_id_seq RESTART WITH 1")
53 fake_conn.commit()
54 fake_cur.execute("ALTER SEQUENCE stationmeta_core_id_seq RESTART WITH 1")
55 fake_conn.commit()
56 fake_cur.execute("ALTER SEQUENCE stationmeta_global_id_seq RESTART WITH 1")
57 fake_conn.commit()
58 fake_cur.execute("ALTER SEQUENCE stationmeta_annotations_id_seq RESTART WITH 1")
59 fake_conn.commit()
60 fake_cur.execute("ALTER SEQUENCE stationmeta_roles_id_seq RESTART WITH 3")
61 fake_conn.commit()
62 fake_cur.execute("ALTER SEQUENCE stationmeta_aux_doc_id_seq RESTART WITH 1")
63 fake_conn.commit()
64 fake_cur.execute("ALTER SEQUENCE stationmeta_aux_image_id_seq RESTART WITH 1")
65 fake_conn.commit()
66 fake_cur.execute("ALTER SEQUENCE stationmeta_aux_url_id_seq RESTART WITH 1")
67 fake_conn.commit()
68 fake_cur.execute("ALTER SEQUENCE persons_id_seq RESTART WITH 1")
69 fake_conn.commit()
70 fake_cur.execute("ALTER SEQUENCE organisations_id_seq RESTART WITH 1")
71 fake_conn.commit()
72 fake_cur.execute("ALTER SEQUENCE contacts_id_seq RESTART WITH 1")
73 fake_conn.commit()
74 infilename = "tests/fixtures/auth_user/auth.json"
75 with open(infilename) as f:
76 metajson=json.load(f)
77 for entry in metajson:
78 new_auth_user= AuthUser(**entry)
79 db.add(new_auth_user)
80 db.commit()
81 db.refresh(new_auth_user)
82 infilename = "tests/fixtures/contacts/persons.json"
83 with open(infilename) as f:
84 metajson=json.load(f)
85 for entry in metajson:
86 new_person = Person(**entry)
87 db.add(new_person)
88 db.commit()
89 db.refresh(new_person)
90 infilename = "tests/fixtures/contacts/organisations.json"
91 with open(infilename) as f:
92 metajson=json.load(f)
93 for entry in metajson:
94 new_organisation = Organisation(**entry)
95 db.add(new_organisation)
96 db.commit()
97 db.refresh(new_organisation)
98 infilename = "tests/fixtures/contacts/contacts.json"
99 with open(infilename) as f:
100 metajson=json.load(f)
101 for entry in metajson:
102 new_contact = Contact(**entry)
103 db.add(new_contact)
104 db.commit()
105 db.refresh(new_contact)
106 # I also need to upload tests with nested data!!!
107 infilename = "tests/fixtures/stationmeta/stationmeta_core.json"
108 with open(infilename) as f:
109 metajson=json.load(f)
110 for entry in metajson:
111 new_stationmeta_core = StationmetaCore(**entry)
112 # there's a mismatch with coordinates --> how to automatically switch back and forth?!
113 tmp_coordinates = new_stationmeta_core.coordinates
114 new_stationmeta_core.coordinates = get_geom_from_coordinates(Coordinates(**new_stationmeta_core.coordinates))
115 # there's also a mismatch with additional_metadata --> BUT: this should not be switched back!
116 # in upload command, we have now: "additional_metadata": "{}"
117 # but return from this method gives: "additional_metadata": {}
118 # ==> there is a mismatch between model(JSONB) and schema(JSON)
119 new_stationmeta_core.additional_metadata = str(new_stationmeta_core.additional_metadata)
120 db.add(new_stationmeta_core)
121 db.commit()
122 db.refresh(new_stationmeta_core)
123 infilename = "tests/fixtures/stationmeta/stationmeta_changelog.json"
124 with open(infilename) as f:
125 metajson=json.load(f)
126 for entry in metajson:
127 new_stationmeta_changelog = StationmetaChangelog(**entry)
128 db.add(new_stationmeta_changelog)
129 db.commit()
130 db.refresh(new_stationmeta_changelog)
131 infilename = "tests/fixtures/stationmeta/stationmeta_global.json"
132 with open(infilename) as f:
133 metajson=json.load(f)
134 for entry in metajson:
135 new_stationmeta_global = StationmetaGlobal(**entry)
136 db.add(new_stationmeta_global)
137 db.commit()
138 db.refresh(new_stationmeta_global)
139 infilename = "tests/fixtures/stationmeta/stationmeta_global_services.json"
140 with open(infilename) as f:
141 metajson=json.load(f)
142 for entry in metajson:
143 new_stationmeta_global_service = StationmetaGlobalService(**entry)
144 db.add(new_stationmeta_global_service)
145 db.commit()
146 db.refresh(new_stationmeta_global_service)
147 infilename = "tests/fixtures/stationmeta/stationmeta_roles.json"
148 with open(infilename) as f:
149 metajson=json.load(f)
150 for entry in metajson:
151 new_stationmeta_role = StationmetaRole(**entry)
152 db.add(new_stationmeta_role)
153 db.commit()
154 db.refresh(new_stationmeta_role)
155 infilename = "tests/fixtures/stationmeta/stationmeta_core_stationmeta_roles.json"
156 with open(infilename) as f:
157 metajson=json.load(f)
158 for entry in metajson:
159 db.execute(insert(stationmeta_core_stationmeta_roles_table).values(station_id=entry["station_id"], role_id=entry["role_id"]))
160 db.execute("COMMIT")
163 # 1. tests retrieving station metadata
165 def test_get_all(self, client, db):
166 response = client.get("/stationmeta/")
167 expected_status_code = 200
168 assert response.status_code == expected_status_code
169 expected_resp = [{'id': 1,
170 'codes': ['China11'],
171 'name': 'Mount Tai',
172 'coordinates': {'lat': 36.256, 'lng': 117.106, 'alt': 1534.0},
173 'coordinate_validation_status': 'not checked',
174 'country': 'Germany',
175 'state': 'Shandong Sheng',
176 'type': 'unknown',
177 'type_of_area': 'unknown',
178 'timezone': 'Asia/Shanghai',
179 'additional_metadata': {'dummy_info': 'Here is some more information about the station'},
180 'roles': [{'id': 2,
181 'role': 'resource provider',
182 'status': 'active',
183 'contact': {'id': 1,
184 'name': 'UBA',
185 'longname': 'Umweltbundesamt',
186 'kind': 'government',
187 'city': 'Dessau-Roßlau',
188 'postcode': '06844',
189 'street_address': 'Wörlitzer Platz 1',
190 'country': 'Germany',
191 'homepage': 'https://www.umweltbundesamt.de',
192 'contact_url': 'mailto:immission@uba.de'}}],
193 'aux_images': [],
194 'aux_docs': [],
195 'aux_urls': [],
196 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0,
197 'mean_topography_srtm_alt_1km_year1994': -999.0,
198 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
199 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
200 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
201 'climatic_zone_year2016': '6 (warm temperate dry)',
202 'htap_region_tier1_year2010': '11 (MDE Middle East: S. '
203 'Arabia, Oman, etc, Iran, Iraq)',
204 'dominant_landcover_year2012': '10 (Cropland, rainfed)',
205 'landcover_description_25km_year2012': '11 (Cropland, '
206 'rainfed, herbaceous '
207 'cover): 30.7 %, 12 '
208 '(Cropland, rainfed, '
209 'tree or shrub cover): '
210 '25.0 %, 210 (Water '
211 'bodies): 16.9 %, 130 '
212 '(Grassland): 8.6 %, '
213 '190 (Urban areas): '
214 '5.8 %, 100 (Mosaic '
215 'tree and shrub (>50%) '
216 '/ herbaceous cover '
217 '(<50%)): 3.5 %, 40 '
218 '(Mosaic natural '
219 'vegetation (tree, '
220 'shrub, herbaceous '
221 'cover) (>50%) / '
222 'cropland (<50%)): 2.6 '
223 '%, 10 (Cropland, '
224 'rainfed): 2.0 %, 30 '
225 '(Mosaic cropland '
226 '(>50%) / natural '
227 'vegetation (tree, '
228 'shrub, herbaceous '
229 'cover) (<50%)): 1.9 %',
230 'dominant_ecoregion_year2017': '-1 (undefined)',
231 'ecoregion_description_25km_year2017': '',
232 'distance_to_major_road_year2020': -999.0,
233 'mean_stable_nightlights_1km_year2013': -999.0,
234 'mean_stable_nightlights_5km_year2013': -999.0,
235 'max_stable_nightlights_25km_year2013': -999.0,
236 'max_stable_nightlights_25km_year1992': -999.0,
237 'mean_population_density_250m_year2015': -1.0,
238 'mean_population_density_5km_year2015': -1.0,
239 'max_population_density_25km_year2015': -1.0,
240 'mean_population_density_250m_year1990': -1.0,
241 'mean_population_density_5km_year1990': -1.0,
242 'max_population_density_25km_year1990': -1.0,
243 'mean_nox_emissions_10km_year2015': -999.0,
244 'mean_nox_emissions_10km_year2000': -999.0,
245 'toar1_category': 'unclassified',
246 'toar2_category': 'urban'},
247 'changelog': [{'datetime': '2023-07-05T08:23:04.551645+00:00',
248 'description': 'station created',
249 'old_value': '',
250 'new_value': '',
251 'station_id': 1,
252 'author_id': 1,
253 'type_of_change': 'created'}]},
254 {'id': 2,
255 'codes': ['SDZ54421'],
256 'name': 'Shangdianzi',
257 'coordinates': {'lat': 40.65, 'lng': 117.106, 'alt': 293.9},
258 'coordinate_validation_status': 'not checked',
259 'country': 'China',
260 'state': 'Beijing Shi',
261 'type': 'unknown',
262 'type_of_area': 'unknown',
263 'timezone': 'Asia/Shanghai',
264 'additional_metadata': {'add_type': 'nature reservation'},
265 'roles': [{'id': 1,
266 'role': 'resource provider',
267 'status': 'active',
268 'contact': {'id': 2,
269 'name': 'FZJ',
270 'longname': 'Forschungszentrum Jülich',
271 'kind': 'research',
272 'city': 'Jülich',
273 'postcode': '52425',
274 'street_address': 'Wilhelm-Johnen-Straße',
275 'country': 'Germany',
276 'homepage': 'https://www.fz-juelich.de',
277 'contact_url': 'mailto:toar-data@fz-juelich.de'}}],
278 'aux_images': [],
279 'aux_docs': [],
280 'aux_urls': [],
281 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0,
282 'mean_topography_srtm_alt_1km_year1994': -999.0,
283 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
284 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
285 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
286 'climatic_zone_year2016': '6 (warm temperate dry)',
287 'htap_region_tier1_year2010': '11 (MDE Middle East: S. '
288 'Arabia, Oman, etc, Iran, Iraq)',
289 'dominant_landcover_year2012': '11 (Cropland, rainfed, herbaceous cover)',
290 'landcover_description_25km_year2012': '',
291 'dominant_ecoregion_year2017': '-1 (undefined)',
292 'ecoregion_description_25km_year2017': '',
293 'distance_to_major_road_year2020': -999.0,
294 'mean_stable_nightlights_1km_year2013': -999.0,
295 'mean_stable_nightlights_5km_year2013': -999.0,
296 'max_stable_nightlights_25km_year2013': -999.0,
297 'max_stable_nightlights_25km_year1992': -999.0,
298 'mean_population_density_250m_year2015': -1.0,
299 'mean_population_density_5km_year2015': -1.0,
300 'max_population_density_25km_year2015': -1.0,
301 'mean_population_density_250m_year1990': -1.0,
302 'mean_population_density_5km_year1990': -1.0,
303 'max_population_density_25km_year1990': -1.0,
304 'mean_nox_emissions_10km_year2015': -999.0,
305 'mean_nox_emissions_10km_year2000': -999.0,
306 'toar1_category': 'unclassified',
307 'toar2_category': 'suburban'},
308 'changelog': [{'datetime': '2023-07-15T19:27:09.463245+00:00',
309 'description': 'station created',
310 'old_value': '',
311 'new_value': '',
312 'station_id': 2,
313 'author_id': 1,
314 'type_of_change': 'created'}]},
315 {'id': 3,
316 'codes': ['China_test8'],
317 'name': 'Test_China',
318 'coordinates': {'lat': 36.256, 'lng': 117.106, 'alt': 1534.0},
319 'coordinate_validation_status': 'not checked',
320 'country': 'China',
321 'state': 'Shandong Sheng',
322 'type': 'unknown',
323 'type_of_area': 'unknown',
324 'timezone': 'Asia/Shanghai',
325 'additional_metadata': {},
326 'aux_images': [],
327 'aux_docs': [],
328 'aux_urls': [],
329 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0,
330 'mean_topography_srtm_alt_1km_year1994': -999.0,
331 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
332 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
333 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
334 'climatic_zone_year2016': '6 (warm temperate dry)',
335 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel '
336 'Africa)',
337 'dominant_landcover_year2012': '10 (Cropland, rainfed)',
338 'landcover_description_25km_year2012': '',
339 'dominant_ecoregion_year2017': '-1 (undefined)',
340 'ecoregion_description_25km_year2017': '',
341 'distance_to_major_road_year2020': -999.0,
342 'mean_stable_nightlights_1km_year2013': -999.0,
343 'mean_stable_nightlights_5km_year2013': -999.0,
344 'max_stable_nightlights_25km_year2013': -999.0,
345 'max_stable_nightlights_25km_year1992': -999.0,
346 'mean_population_density_250m_year2015': -1.0,
347 'mean_population_density_5km_year2015': -1.0,
348 'max_population_density_25km_year2015': -1.0,
349 'mean_population_density_250m_year1990': -1.0,
350 'mean_population_density_5km_year1990': -1.0,
351 'max_population_density_25km_year1990': -1.0,
352 'mean_nox_emissions_10km_year2015': -999.0,
353 'mean_nox_emissions_10km_year2000': -999.0,
354 'toar1_category': 'unclassified',
355 'toar2_category': 'suburban'},
356 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00',
357 'description': 'station created',
358 'old_value': '',
359 'new_value': '',
360 'station_id': 3,
361 'author_id': 1,
362 'type_of_change': 'created'}]}]
363 assert response.json() == expected_resp
366 def test_get_special_nested(self, client, db):
367 response = client.get("/stationmeta/China_test8")
368 expected_status_code = 200
369 assert response.status_code == expected_status_code
370 expected_resp = {'id': 3, 'codes': ['China_test8'], 'name': 'Test_China',
371 'coordinates': {'lat': 36.256, 'lng': 117.106, 'alt': 1534.0},
372 'coordinate_validation_status': 'not checked',
373 'country': 'China', 'state': 'Shandong Sheng',
374 'type': 'unknown',
375 'type_of_area': 'unknown', 'timezone': 'Asia/Shanghai',
376 'additional_metadata': {},
377 'aux_images': [], 'aux_docs': [],
378 'aux_urls': [],
379 'globalmeta': {'climatic_zone_year2016': '6 (warm temperate dry)',
380 'distance_to_major_road_year2020': -999.0,
381 'dominant_ecoregion_year2017': '-1 (undefined)',
382 'dominant_landcover_year2012': '10 (Cropland, rainfed)',
383 'ecoregion_description_25km_year2017': '',
384 'landcover_description_25km_year2012': '',
385 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)',
386 'max_stable_nightlights_25km_year1992': -999.0,
387 'max_stable_nightlights_25km_year2013': -999.0,
388 'max_population_density_25km_year1990': -1.0,
389 'max_population_density_25km_year2015': -1.0,
390 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
391 'mean_stable_nightlights_1km_year2013': -999.0,
392 'mean_stable_nightlights_5km_year2013': -999.0,
393 'mean_nox_emissions_10km_year2000': -999.0,
394 'mean_nox_emissions_10km_year2015': -999.0,
395 'mean_population_density_250m_year1990': -1.0,
396 'mean_population_density_250m_year2015': -1.0,
397 'mean_population_density_5km_year1990': -1.0,
398 'mean_population_density_5km_year2015': -1.0,
399 'mean_topography_srtm_alt_1km_year1994': -999.0,
400 'mean_topography_srtm_alt_90m_year1994': -999.0,
401 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
402 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
403 'toar1_category': 'unclassified',
404 'toar2_category': 'suburban'},
405 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00',
406 'description': 'station created',
407 'old_value': '',
408 'new_value': '',
409 'station_id': 3,
410 'author_id': 1,
411 'type_of_change': 'created'
412 }]}
413 assert response.json() == expected_resp
416 def test_get_special_with_fields(self, client, db):
417 response = client.get("/stationmeta/China11?fields=codes,globalmeta")
418 expected_status_code = 200
419 assert response.status_code == expected_status_code
420 expected_resp = {'codes': ['China11'],
421 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0,
422 'mean_topography_srtm_alt_1km_year1994': -999.0,
423 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
424 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
425 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
426 'climatic_zone_year2016': '6 (warm temperate dry)',
427 'htap_region_tier1_year2010': '11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)',
428 'dominant_landcover_year2012': '10 (Cropland, rainfed)',
429 'landcover_description_25km_year2012': '11 (Cropland, rainfed, herbaceous cover): 30.7 %, 12 (Cropland, rainfed, tree or shrub cover): 25.0 %, 210 (Water bodies): 16.9 %, 130 (Grassland): 8.6 %, 190 (Urban areas): 5.8 %, 100 (Mosaic tree and shrub (>50%) / herbaceous cover (<50%)): 3.5 %, 40 (Mosaic natural vegetation (tree, shrub, herbaceous cover) (>50%) / cropland (<50%)): 2.6 %, 10 (Cropland, rainfed): 2.0 %, 30 (Mosaic cropland (>50%) / natural vegetation (tree, shrub, herbaceous cover) (<50%)): 1.9 %',
430 'dominant_ecoregion_year2017': '-1 (undefined)',
431 'ecoregion_description_25km_year2017': '',
432 'distance_to_major_road_year2020': -999.0,
433 'mean_stable_nightlights_1km_year2013': -999.0,
434 'mean_stable_nightlights_5km_year2013': -999.0,
435 'max_stable_nightlights_25km_year2013': -999.0,
436 'max_stable_nightlights_25km_year1992': -999.0,
437 'mean_population_density_250m_year2015': -1.0,
438 'mean_population_density_5km_year2015': -1.0,
439 'max_population_density_25km_year2015': -1.0,
440 'mean_population_density_250m_year1990': -1.0,
441 'mean_population_density_5km_year1990': -1.0,
442 'max_population_density_25km_year1990': -1.0,
443 'mean_nox_emissions_10km_year2015': -999.0,
444 'mean_nox_emissions_10km_year2000': -999.0,
445 'toar1_category': 'unclassified',
446 'toar2_category': 'urban'
447 }
448 }
449 assert response.json() == expected_resp
451 def test_get_special_with_id_and_fields(self, client, db):
452 response = client.get("/stationmeta/?fields=id,toar2_category&id=1")
453 expected_status_code = 200
454 assert response.status_code == expected_status_code
455 expected_resp = [{'globalmeta': {'toar2_category': '1'}, 'id': 1}]
456 assert response.json() == expected_resp
459 def test_get_special_with_ambiguous_field(self, client, db):
460 response = client.get("/stationmeta/China11?fields=id")
461 expected_status_code = 200
462 assert response.status_code == expected_status_code
463 expected_resp = {'id': 1}
464 assert response.json() == expected_resp
467 def test_get_special_with_fields_station_not_found(self, client, db):
468 response = client.get("/stationmeta/DENW078?fields=codes,globalmeta")
469 expected_status_code = 404
470 assert response.status_code == expected_status_code
471 expected_resp = {"detail":"Metadata for station 'DENW078' not found."}
472 assert response.json() == expected_resp
474 def test_get_all_with_fields(self, client, db):
475 response = client.get("/stationmeta/?fields=codes,globalmeta")
476 expected_status_code = 200
477 assert response.status_code == expected_status_code
478 expected_resp = [{'codes': ['China11'],
479 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0,
480 'mean_topography_srtm_alt_1km_year1994': -999.0,
481 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
482 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
483 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
484 'climatic_zone_year2016': '6 (warm temperate dry)',
485 'htap_region_tier1_year2010': '11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)',
486 'dominant_landcover_year2012': '10 (Cropland, rainfed)',
487 'landcover_description_25km_year2012': '11 (Cropland, rainfed, herbaceous cover): 30.7 %, 12 (Cropland, rainfed, tree or shrub cover): 25.0 %, 210 (Water bodies): 16.9 %, 130 (Grassland): 8.6 %, 190 (Urban areas): 5.8 %, 100 (Mosaic tree and shrub (>50%) / herbaceous cover (<50%)): 3.5 %, 40 (Mosaic natural vegetation (tree, shrub, herbaceous cover) (>50%) / cropland (<50%)): 2.6 %, 10 (Cropland, rainfed): 2.0 %, 30 (Mosaic cropland (>50%) / natural vegetation (tree, shrub, herbaceous cover) (<50%)): 1.9 %',
488 'dominant_ecoregion_year2017': '-1 (undefined)',
489 'ecoregion_description_25km_year2017': '',
490 'distance_to_major_road_year2020': -999.0,
491 'mean_stable_nightlights_1km_year2013': -999.0,
492 'mean_stable_nightlights_5km_year2013': -999.0,
493 'max_stable_nightlights_25km_year2013': -999.0,
494 'max_stable_nightlights_25km_year1992': -999.0,
495 'mean_population_density_250m_year2015': -1.0,
496 'mean_population_density_5km_year2015': -1.0,
497 'max_population_density_25km_year2015': -1.0,
498 'mean_population_density_250m_year1990': -1.0,
499 'mean_population_density_5km_year1990': -1.0,
500 'max_population_density_25km_year1990': -1.0,
501 'mean_nox_emissions_10km_year2015': -999.0,
502 'mean_nox_emissions_10km_year2000': -999.0,
503 'toar1_category': 'unclassified',
504 'toar2_category': 'urban'
505 }
506 },
507 {'codes': ['SDZ54421'],
508 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0,
509 'mean_topography_srtm_alt_1km_year1994': -999.0,
510 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
511 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
512 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
513 'climatic_zone_year2016': '6 (warm temperate dry)',
514 'htap_region_tier1_year2010': '11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)',
515 'dominant_landcover_year2012': '11 (Cropland, rainfed, herbaceous cover)',
516 'landcover_description_25km_year2012': '',
517 'dominant_ecoregion_year2017': '-1 (undefined)',
518 'ecoregion_description_25km_year2017': '',
519 'distance_to_major_road_year2020': -999.0,
520 'mean_stable_nightlights_1km_year2013': -999.0,
521 'mean_stable_nightlights_5km_year2013': -999.0,
522 'max_stable_nightlights_25km_year2013': -999.0,
523 'max_stable_nightlights_25km_year1992': -999.0,
524 'mean_population_density_250m_year2015': -1.0,
525 'mean_population_density_5km_year2015': -1.0,
526 'max_population_density_25km_year2015': -1.0,
527 'mean_population_density_250m_year1990': -1.0,
528 'mean_population_density_5km_year1990': -1.0,
529 'max_population_density_25km_year1990': -1.0,
530 'mean_nox_emissions_10km_year2015': -999.0,
531 'mean_nox_emissions_10km_year2000': -999.0,
532 'toar1_category': 'unclassified',
533 'toar2_category': 'suburban'
534 }
535 },
536 {'codes': ['China_test8'],
537 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0,
538 'mean_topography_srtm_alt_1km_year1994': -999.0,
539 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
540 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
541 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
542 'climatic_zone_year2016': '6 (warm temperate dry)',
543 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)',
544 'dominant_landcover_year2012': '10 (Cropland, rainfed)',
545 'landcover_description_25km_year2012': '',
546 'dominant_ecoregion_year2017': '-1 (undefined)',
547 'ecoregion_description_25km_year2017': '',
548 'distance_to_major_road_year2020': -999.0,
549 'mean_stable_nightlights_1km_year2013': -999.0,
550 'mean_stable_nightlights_5km_year2013': -999.0,
551 'max_stable_nightlights_25km_year2013': -999.0,
552 'max_stable_nightlights_25km_year1992': -999.0,
553 'mean_population_density_250m_year2015': -1.0,
554 'mean_population_density_5km_year2015': -1.0,
555 'max_population_density_25km_year2015': -1.0,
556 'mean_population_density_250m_year1990': -1.0,
557 'mean_population_density_5km_year1990': -1.0,
558 'max_population_density_25km_year1990': -1.0,
559 'mean_nox_emissions_10km_year2015': -999.0,
560 'mean_nox_emissions_10km_year2000': -999.0,
561 'toar1_category': 'unclassified',
562 'toar2_category': 'suburban'
563 }
564 }]
565 assert response.json() == expected_resp
568 def test_get_all_wrong_params(self, client, db):
569 response = client.get("/stationmeta/?altitude=2000&limit=None")
570 expected_status_code = 400
571 assert response.status_code == expected_status_code
572 expected_resp = "'An unknown argument was received: altitude.'"
573 assert response.json() == expected_resp
576 def test_get_stationmeta_not_found(self, client, db):
577 response = client.get("/stationmeta/-1")
578 expected_status_code = 404
579 assert response.status_code == expected_status_code
580 expected_resp = {"detail": "Metadata for station '-1' not found."}
581 assert response.json() == expected_resp
584 def test_get_stationmeta_by_id_not_found(self, client, db):
585 response = client.get("/stationmeta/id/-1")
586 expected_status_code = 404
587 assert response.status_code == expected_status_code
588 expected_resp = {"detail": "Metadata for station with ID '-1' not found."}
589 assert response.json() == expected_resp
592 def test_get_stationmeta_by_id(self, client, db):
593 response = client.get("/stationmeta/id/1")
594 expected_status_code = 200
595 assert response.status_code == expected_status_code
596 expected_resp = {'id': 1, 'codes': ['China11'], 'name': 'Mount Tai',
597 'coordinates': {'lat': 36.256, 'lng': 117.106, 'alt': 1534.0},
598 'coordinate_validation_status': 'not checked',
599 'country': 'Germany', 'state': 'Shandong Sheng',
600 'type': 'unknown', 'type_of_area': 'unknown',
601 'timezone': 'Asia/Shanghai', 'additional_metadata': {},
602 'roles': [{ 'contact': {
603 'city': 'Dessau-Roßlau',
604 'contact_url': 'mailto:immission@uba.de',
605 'country': 'Germany',
606 'homepage': 'https://www.umweltbundesamt.de',
607 'id': 1,
608 'kind': 'government',
609 'longname': 'Umweltbundesamt',
610 'name': 'UBA',
611 'postcode': '06844',
612 'street_address': 'Wörlitzer Platz 1',
613 },
614 'id': 2,
615 'role': 'resource provider',
616 'status': 'active' }],
617 'additional_metadata': {'dummy_info': 'Here is some more information about the station'},
618 'aux_images': [], 'aux_docs': [], 'aux_urls': [],
619 'globalmeta': {'climatic_zone_year2016': '6 (warm temperate dry)',
620 'distance_to_major_road_year2020': -999.0,
621 'dominant_ecoregion_year2017': '-1 (undefined)',
622 'dominant_landcover_year2012': '10 (Cropland, rainfed)',
623 'ecoregion_description_25km_year2017': '',
624 'landcover_description_25km_year2012': '11 (Cropland, rainfed, '
625 +'herbaceous cover): '
626 +'30.7 %, 12 (Cropland, '
627 +'rainfed, tree or shrub '
628 +'cover): 25.0 %, 210 '
629 +'(Water bodies): 16.9 '
630 +'%, 130 (Grassland): '
631 +'8.6 %, 190 (Urban '
632 +'areas): 5.8 %, 100 '
633 +'(Mosaic tree and shrub '
634 +'(>50%) / herbaceous '
635 +'cover (<50%)): 3.5 %, '
636 +'40 (Mosaic natural '
637 +'vegetation (tree, '
638 +'shrub, herbaceous '
639 +'cover) (>50%) / '
640 +'cropland (<50%)): 2.6 '
641 +'%, 10 (Cropland, '
642 +'rainfed): 2.0 %, 30 '
643 +'(Mosaic cropland '
644 +'(>50%) / natural '
645 +'vegetation (tree, '
646 +'shrub, herbaceous '
647 +'cover) (<50%)): 1.9 %',
648 'htap_region_tier1_year2010': '11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)',
649 'max_stable_nightlights_25km_year1992': -999.0,
650 'max_stable_nightlights_25km_year2013': -999.0,
651 'max_population_density_25km_year1990': -1.0,
652 'max_population_density_25km_year2015': -1.0,
653 'max_topography_srtm_relative_alt_5km_year1994': -999.0,
654 'mean_stable_nightlights_1km_year2013': -999.0,
655 'mean_stable_nightlights_5km_year2013': -999.0,
656 'mean_nox_emissions_10km_year2000': -999.0,
657 'mean_nox_emissions_10km_year2015': -999.0,
658 'mean_population_density_250m_year1990': -1.0,
659 'mean_population_density_250m_year2015': -1.0,
660 'mean_population_density_5km_year1990': -1.0,
661 'mean_population_density_5km_year2015': -1.0,
662 'mean_topography_srtm_alt_1km_year1994': -999.0,
663 'mean_topography_srtm_alt_90m_year1994': -999.0,
664 'min_topography_srtm_relative_alt_5km_year1994': -999.0,
665 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0,
666 'toar1_category': 'unclassified',
667 'toar2_category': 'urban'},
668 'changelog': [{'datetime': '2023-07-05T08:23:04.551645+00:00',
669 'description': 'station created',
670 'old_value': '',
671 'new_value': '',
672 'station_id': 1,
673 'author_id': 1,
674 'type_of_change': 'created'
675 }]}
676 assert response.json() == expected_resp
679 def test_get_stationmeta_changelog(self, client, db):
680 response = client.get("/stationmeta_changelog/1")
681 expected_status_code = 200
682 assert response.status_code == expected_status_code
683 expected_resp = [{ 'datetime': '2023-07-05T08:23:04.551645+00:00',
684 'description': 'station created',
685 'old_value': '',
686 'new_value': '',
687 'station_id': 1,
688 'author_id': 1,
689 'type_of_change': 'created'
690 }]
691 assert response.json() == expected_resp
693 # 2. tests creating station metadata
696 def test_insert_new_wrong_credentials(self, client, db):
697 response = client.post("/stationmeta/",
698 json={"stationmeta":
699 {"codes":["ttt3","ttt4"],
700 "name":"Test_China","coordinates":{"lat":37.256,"lng":117.106,"alt":1534.0},
701 "coordinate_validation_status": "NotChecked",
702 "country":"CN","state":"Shandong Sheng",
703 "type":"Unknown","type_of_area":"Unknown","timezone":"Asia/Shanghai",
704 "additional_metadata": "{}" }
705 },
706 headers={"email": "j.doe@fz-juelich.de"}
707 )
708 expected_status_code=401
709 assert response.status_code == expected_status_code
710 expected_resp = {'detail': 'Unauthorized.'}
711 assert response.json() == expected_resp
714 def test_insert_new_without_credentials(self, client, db):
715 response = client.post("/stationmeta/",
716 json={"stationmeta":
717 {"codes":["ttt3","ttt4"],
718 "name":"Test_China","coordinates":{"lat":37.256,"lng":117.106,"alt":1534.0},
719 "coordinate_validation_status": "NotChecked",
720 "country":"CN","state":"Shandong Sheng",
721 "type":"Unknown","type_of_area":"Unknown","timezone":"Asia/Shanghai",
722 "additional_metadata": "{}" }
723 })
724 expected_status_code=401
725 assert response.status_code == expected_status_code
726 expected_resp = {'detail': 'Unauthorized.'}
727 assert response.json() == expected_resp
730 def test_insert_new(self, client, db):
731 with patch("toardb.stationmeta.crud.determine_stationmeta_global", return_value={}):
732 response = client.post("/stationmeta/",
733 json={"stationmeta":
734 {"codes":["ttt3","ttt4"],
735 "name":"Test_China","coordinates":{"lat":37.256,"lng":117.106,"alt":1534.0},
736 "coordinate_validation_status": "NotChecked",
737 "country":"CN","state":"Shandong Sheng",
738 "type":"Unknown","type_of_area":"Unknown","timezone":"Asia/Shanghai",
739 "additional_metadata": "{}" }
740 },
741 headers={"email": "s.schroeder@fz-juelich.de"}
742 )
743 expected_status_code = 200
744 assert response.status_code == expected_status_code
745 expected_resp = {'detail': {'message': "new station: ['ttt3', 'ttt4'],Test_China,{'lat': 37.256, 'lng': 117.106, 'alt': 1534.0}",
746 'station_id': 4}}
747 assert response.json() == expected_resp
750 def test_insert_new_with_roles(self, client, db):
751 with patch("toardb.stationmeta.crud.determine_stationmeta_global", return_value={}):
752 response = client.post("/stationmeta/",
753 json={"stationmeta":
754 {"codes":["ttt3","ttt4"],
755 "name":"Test_China","coordinates":{"lat":37.256,"lng":117.106,"alt":1534.0},
756 "coordinate_validation_status": "NotChecked",
757 "country":"CN","state":"Shandong Sheng",
758 "type":"Unknown","type_of_area":"Unknown","timezone":"Asia/Shanghai",
759 "roles": [{"role": "PointOfContact", "contact_id": 3, "status": "Active"},
760 {"role": "Originator", "contact_id": 1, "status": "Active"}],
761 "additional_metadata": "{}" }
762 },
763 headers={"email": "s.schroeder@fz-juelich.de"}
764 )
765 expected_status_code = 200
766 assert response.status_code == expected_status_code
767 expected_resp = {'detail': {'message': "new station: ['ttt3', 'ttt4'],Test_China,{'lat': 37.256, 'lng': 117.106, 'alt': 1534.0}",
768 'station_id': 4}}
769 assert response.json() == expected_resp
772 def test_insert_new_with_annotations(self, client, db):
773 with patch("toardb.stationmeta.crud.determine_stationmeta_global", return_value={}):
774 response = client.post("/stationmeta/",
775 json={"stationmeta":
776 {"codes":["ttt3","ttt4"],
777 "name":"Test_China","coordinates":{"lat":37.256,"lng":117.106,"alt":1534.0},
778 "coordinate_validation_status": "NotChecked",
779 "country":"CN","state":"Shandong Sheng",
780 "type":"Unknown","type_of_area":"Unknown","timezone":"Asia/Shanghai",
781 "annotations": [{"kind": "User",
782 "text": "some foo",
783 "date_added":"2021-07-27 00:00",
784 "approved": True,
785 "contributor_id":1}],
786 "additional_metadata": "{}" }
787 },
788 headers={"email": "s.schroeder@fz-juelich.de"}
789 )
790 expected_status_code = 200
791 assert response.status_code == expected_status_code
792 expected_resp = {'detail': {'message': "new station: ['ttt3', 'ttt4'],Test_China,{'lat': 37.256, 'lng': 117.106, 'alt': 1534.0}",
793 'station_id': 4}}
794 assert response.json() == expected_resp
797 def test_insert_new_same_coordinates(self, client, db):
798 response = client.post("/stationmeta/",
799 json={"stationmeta":
800 {"codes":["ttt3","ttt4"],
801 "name":"Test_China","coordinates":{"lat":36.256,"lng":117.106,"alt":1534.0},
802 "coordinate_validation_status": "NotChecked",
803 "country":"CN","state":"Shandong Sheng",
804 "type":"Unknown","type_of_area":"Unknown","timezone":"Asia/Shanghai",
805 "additional_metadata":"{}"},
806 },
807 headers={"email": "s.schroeder@fz-juelich.de"}
808 )
809 expected_status_code = 444
810 assert response.status_code == expected_status_code
811 expected_resp = {'detail': {'message': 'more than one station falls within the given radius!\nchoose which station record to patch (add station code)',
812 'station_ids': [1, 3],
813 'station_records': [[['China11'], 'lat=36.256 lng=117.106 alt=1534.0', 'Shandong Sheng', 84],
814 [['China_test8'], 'lat=36.256 lng=117.106 alt=1534.0', 'Shandong Sheng', 48]]}}
815 assert response.json() == expected_resp
818 def test_insert_duplicate(self, client, db):
819 response = client.post("/stationmeta/",
820 json={"stationmeta":
821 {"codes":["China11"],
822 "name":"Test_China","coordinates":{"lat":36.256,"lng":117.106,"alt":1534.0},
823 "coordinate_validation_status": "NotChecked",
824 "country":"CN","state":"Shandong Sheng",
825 "type":"Unknown","type_of_area":"Unknown","timezone":"Asia/Shanghai",
826 "additional_metadata":"{}"}
827 },
828 headers={"email": "s.schroeder@fz-juelich.de"}
829 )
830 expected_status_code = 443
831 assert response.status_code == expected_status_code
832 expected_resp = {'detail' : {'message': 'Station already registered!',
833 'station_id': 1}}
834 assert response.json() == expected_resp
837 # 3. tests updating station metadata
839 def test_patch_stationmeta_no_description(self, client, db):
840 response = client.patch("/stationmeta/-1",
841 json={"stationmeta":
842 {"name":"TTTT95TTTT"}
843 },
844 headers={"email": "s.schroeder@fz-juelich.de"}
845 )
846 expected_status_code = 404
847 assert response.status_code == expected_status_code
848 expected_resp = {"detail": "description text ist missing."}
849 assert response.json() == expected_resp
852 def test_patch_stationmeta_not_found1(self, client, db):
853 response = client.patch("/stationmeta/-1?description=changing station name",
854 json={"stationmeta":
855 {"name":"TTTT95TTTT"}
856 },
857 headers={"email": "s.schroeder@fz-juelich.de"}
858 )
859 expected_status_code = 404
860 assert response.status_code == expected_status_code
861 expected_resp = {"detail": "Station for patching not found."}
862 assert response.json() == expected_resp
865 def test_patch_stationmeta_name(self, client, db):
866 response = client.patch("/stationmeta/SDZ54421?description=changing station name",
867 json={"stationmeta":
868 {"name":"TTTT95TTTT"}
869 },
870 headers={"email": "s.schroeder@fz-juelich.de"}
871 )
872 expected_status_code = 200
873 assert response.status_code == expected_status_code
874 expected_resp = {'message': 'patched stationmeta record for station_id 2', 'station_id': 2}
875 response_json = response.json()
876 assert response_json == expected_resp
877 response = client.get(f"/stationmeta/id/{response_json['station_id']}")
878 response_json = response.json()
879 # just check special changes
880 assert response_json['name'] == 'TTTT95TTTT'
881 assert response_json['changelog'][1]['old_value'] == "{'name': 'Shangdianzi'}"
882 assert response_json['changelog'][1]['new_value'] == "{'name': 'TTTT95TTTT'}"
883 assert response_json['changelog'][1]['author_id'] == 1
884 assert response_json['changelog'][1]['type_of_change'] == 'single value correction in metadata'
887 def test_patch_single_stationmeta_global(self, client, db):
888 response = client.patch("/stationmeta/SDZ54421?description=changing global metadata",
889 json={"stationmeta":
890 {"globalmeta": {"climatic_zone_year2016": "WarmTemperateMoist"}}
891 },
892 headers={"email": "s.schroeder@fz-juelich.de"}
893 )
894 expected_status_code = 200
895 assert response.status_code == expected_status_code
896 expected_resp = {'message': 'patched stationmeta record for station_id 2', 'station_id': 2}
897 response_json = response.json()
898 assert response_json == expected_resp
899 response = client.get(f"/stationmeta/id/{response_json['station_id']}")
900 response_json = response.json()
901 # just check special changes
902 assert response_json['name'] == 'Shangdianzi'
903 assert response_json['changelog'][1]['old_value'] == "{'climatic_zone_year2016': 'WarmTemperateDry'}"
904 assert response_json['changelog'][1]['new_value'] == "{'climatic_zone_year2016': 'WarmTemperateMoist'}"
905 assert response_json['changelog'][1]['author_id'] == 1
906 assert response_json['changelog'][1]['type_of_change'] == 'single value correction in metadata'
909 def test_patch_multiple_stationmeta_global(self, client, db):
910 response = client.patch("/stationmeta/SDZ54421?description=changing global metadata",
911 json={"stationmeta":
912 {"globalmeta": {"climatic_zone_year2016": "WarmTemperateMoist",
913 "toar1_category": "RuralLowElevation",
914 "toar2_category": "Urban",
915 "htap_region_tier1_year2010": "HTAPTier1PAN",
916 "dominant_landcover_year2012": "TreeNeedleleavedEvergreenClosedToOpen",
917 "landcover_description_25km_year2012": "TreeNeedleleavedEvergreenClosedToOpen: 100 %",
918 "dominant_ecoregion_year2017": "Guianansavanna",
919 "ecoregion_description_25km_year2017": "Guianansavanna: 90 %, Miskitopineforests: 10 %"}}
920 },
921 headers={"email": "s.schroeder@fz-juelich.de"}
922 )
923 expected_status_code = 200
924 assert response.status_code == expected_status_code
925 expected_resp = {'message': 'patched stationmeta record for station_id 2', 'station_id': 2}
926 response_json = response.json()
927 assert response_json == expected_resp
928 response = client.get(f"/stationmeta/id/{response_json['station_id']}")
929 response_json = response.json()
930 # just check special changes
931 assert response_json['name'] == 'Shangdianzi'
932 assert response_json['changelog'][1]['old_value'] == (
933 "{'climatic_zone_year2016': 'WarmTemperateDry', "
934 "'htap_region_tier1_year2010': 'HTAPTier1MDE', "
935 "'dominant_landcover_year2012': 'CroplandRainfedHerbaceousCover', "
936 "'landcover_description_25km_year2012': '', "
937 "'dominant_ecoregion_year2017': 'Undefined', "
938 "'ecoregion_description_25km_year2017': '', "
939 "'toar1_category': 'Unclassified', "
940 "'toar2_category': 'Suburban'}" )
941 assert response_json['changelog'][1]['new_value'] == (
942 "{'climatic_zone_year2016': 'WarmTemperateMoist', "
943 "'htap_region_tier1_year2010': 'HTAPTier1PAN', "
944 "'dominant_landcover_year2012': 'TreeNeedleleavedEvergreenClosedToOpen', "
945 "'landcover_description_25km_year2012': 'TreeNeedleleavedEvergreenClosedToOpen: 100 %', "
946 "'dominant_ecoregion_year2017': 'Guianansavanna', "
947 "'ecoregion_description_25km_year2017': 'Guianansavanna: 90 %, Miskitopineforests: 10 %'"
948 ", 'toar1_category': 'RuralLowElevation'"
949 ", 'toar2_category': 'Urban'}" )
950 assert response_json['changelog'][1]['author_id'] == 1
951 assert response_json['changelog'][1]['type_of_change'] == 'single value correction in metadata'
954 def test_patch_stationmeta_roles_and_annotations(self, client, db):
955 response = client.patch("/stationmeta/SDZ54421?description=adding annotation text",
956 json={"stationmeta":
957 {"roles": [{"role": "PointOfContact", "contact_id": 3, "status": "Active"},
958 {"role": "Originator", "contact_id": 1, "status": "Active"}],
959 "annotations": [{"kind": "User",
960 "text": "some annotation text",
961 "date_added": "2025-02-10 17:00",
962 "approved": True,
963 "contributor_id":1}]
964 }
965 },
966 headers={"email": "s.schroeder@fz-juelich.de"}
967 )
968 expected_status_code = 200
969 assert response.status_code == expected_status_code
970 expected_resp = {'message': 'patched stationmeta record for station_id 2', 'station_id': 2}
971 response_json = response.json()
972 assert response_json == expected_resp
973 response = client.get(f"/stationmeta/id/{response_json['station_id']}")
974 response_json = response.json()
975 assert response_json['annotations'] == [{'id': 1, 'kind': 'user comment', 'text': 'some annotation text', 'date_added': '2025-02-10T17:00:00+00:00', 'approved': True, 'contributor_id': 1}]
976 assert response_json['changelog'][1]['old_value'] == "{'roles': {{'role': 'ResourceProvider', 'status': 'Active', 'contact_id': 5},}"
977 assert response_json['changelog'][1]['new_value'] == (
978 "{'roles': [{'role': 'PointOfContact', 'contact_id': 3, 'status': 'Active'}, "
979 "{'role': 'Originator', 'contact_id': 1, 'status': 'Active'}], "
980 "'annotations': [{'kind': 'User', 'text': 'some annotation text', 'date_added': '2025-02-10 17:00', 'approved': True, 'contributor_id': 1}]}" )
981 assert response_json['changelog'][1]['author_id'] == 1
982 assert response_json['changelog'][1]['type_of_change'] == 'comprehensive metadata revision'
985 def test_delete_roles_from_stationmeta(self, client, db):
986 response = client.patch("/stationmeta/delete_field/China11?field=roles",
987 headers={"email": "s.schroeder@fz-juelich.de"})
988 expected_status_code = 200
989 assert response.status_code == expected_status_code
990 # Database defaults cannot be patched within pytest
991 patched_response = response.json()
992 patched_response["changelog"][-1]["datetime"] = ""
993 expected_resp = {'id': 1,
994 'codes': ['China11'],
995 'name': 'Mount Tai',
996 'coordinates': {'lat': 36.256, 'lng': 117.106, 'alt': 1534.0},
997 'coordinate_validation_status': 'not checked',
998 'country': 'Germany',
999 'state': 'Shandong Sheng',
1000 'type': 'unknown',
1001 'type_of_area': 'unknown',
1002 'timezone': 'Asia/Shanghai',
1003 'additional_metadata': {'dummy_info': 'Here is some more information about the station'},
1004 'aux_images': [],
1005 'aux_docs': [],
1006 'aux_urls': [],
1007 'changelog': [
1008 {
1009 'author_id': 1,
1010 'datetime': '2023-07-05T08:23:04.551645+00:00',
1011 'description': 'station created',
1012 'new_value': '',
1013 'old_value': '',
1014 'station_id': 1,
1015 'type_of_change': 'created',
1016 },
1017 {
1018 'author_id': 1,
1019 'datetime': '',
1020 'description': 'delete field roles',
1021 'new_value': "'roles': []",
1022 'old_value': "'roles': '[]'",
1023 'station_id': 1,
1024 'type_of_change': 'single value correction in metadata',
1025 },
1026 ],
1027 }
1028 assert patched_response == expected_resp
1031 def test_delete_field_station_not_found(self, client, db):
1032 response = client.patch("/stationmeta/delete_field/China22?field=timezone",
1033 headers={"email": "s.schroeder@fz-juelich.de"})
1034 expected_status_code = 404
1035 assert response.status_code == expected_status_code
1036 expected_resp = {'detail': 'Station for deleting field not found.'}
1037 assert response.json() == expected_resp
1040 def test_test(self, client, db):
1041 response = client.patch("/stationmeta/SDY54421?description=changing global metadata",
1042 json={"stationmeta":
1043 {"globalmeta": { "toar2_category": "Rural"}}
1044 },
1045 headers={"email": "s.schroeder@fz-juelich.de"}
1046 )
1047 expected_status_code = 404
1048 assert response.status_code == expected_status_code
1049 expected_resp = {'detail': 'Station for patching not found.'}
1050 assert response.json() == expected_resp