Coverage for tests/test_search_aggregations.py: 100%

197 statements  

« prev     ^ index     » next       coverage.py v7.11.0, created at 2025-11-03 20:32 +0000

1# SPDX-FileCopyrightText: 2021 Forschungszentrum Jülich GmbH 

2# SPDX-License-Identifier: MIT 

3 

4import pytest 

5import json 

6from sqlalchemy import insert 

7from toardb.timeseries.models import Timeseries, timeseries_timeseries_roles_table 

8from toardb.timeseries.models_programme import TimeseriesProgramme 

9from toardb.timeseries.models_role import TimeseriesRole 

10from toardb.stationmeta.models import StationmetaCore, StationmetaGlobal, StationmetaChangelog 

11from toardb.stationmeta.schemas import get_geom_from_coordinates, Coordinates 

12from toardb.variables.models import Variable 

13from toardb.contacts.models import Person, Organisation, Contact 

14from toardb.auth_user.models import AuthUser 

15 

16# Required imports 'create_test_database' 

17from toardb.test_base import ( 

18 client, 

19 get_test_db, 

20 create_test_database, 

21 url, 

22 get_test_engine, 

23 test_db_session as db, 

24) 

25 

26 

27class TestApps: 

28 def setup(self): 

29 self.application_url = "/timeseries/" 

30 

31 """Set up all the data before each test 

32 If you want the setup only once (per test module), 

33 the scope argument is not working in the expected way, as discussed here: 

34 https://stackoverflow.com/questions/45817153/py-test-fixture-use-function-fixture-in-scope-fixture 

35 """ 

36 

37 @pytest.fixture(autouse=True) 

38 def setup_db_data(self, db): 

39 _db_conn = get_test_engine() 

40 # id_seq will not be reset automatically between tests! 

41 fake_conn = _db_conn.raw_connection() 

42 fake_cur = fake_conn.cursor() 

43 fake_cur.execute("ALTER SEQUENCE auth_user_id_seq RESTART WITH 1") 

44 fake_conn.commit() 

45 fake_cur.execute("ALTER SEQUENCE variables_id_seq RESTART WITH 1") 

46 fake_conn.commit() 

47 fake_cur.execute("ALTER SEQUENCE stationmeta_core_id_seq RESTART WITH 1") 

48 fake_conn.commit() 

49 fake_cur.execute("ALTER SEQUENCE stationmeta_global_id_seq RESTART WITH 1") 

50 fake_conn.commit() 

51 fake_cur.execute("ALTER SEQUENCE stationmeta_roles_id_seq RESTART WITH 1") 

52 fake_conn.commit() 

53 fake_cur.execute("ALTER SEQUENCE stationmeta_annotations_id_seq RESTART WITH 1") 

54 fake_conn.commit() 

55 fake_cur.execute("ALTER SEQUENCE stationmeta_aux_doc_id_seq RESTART WITH 1") 

56 fake_conn.commit() 

57 fake_cur.execute("ALTER SEQUENCE stationmeta_aux_image_id_seq RESTART WITH 1") 

58 fake_conn.commit() 

59 fake_cur.execute("ALTER SEQUENCE stationmeta_aux_url_id_seq RESTART WITH 1") 

60 fake_conn.commit() 

61 fake_cur.execute("ALTER SEQUENCE persons_id_seq RESTART WITH 1") 

62 fake_conn.commit() 

63 fake_cur.execute("ALTER SEQUENCE organisations_id_seq RESTART WITH 1") 

64 fake_conn.commit() 

65 fake_cur.execute("ALTER SEQUENCE contacts_id_seq RESTART WITH 1") 

66 fake_conn.commit() 

67 fake_cur.execute("ALTER SEQUENCE timeseries_annotations_id_seq RESTART WITH 1") 

68 fake_conn.commit() 

69 fake_cur.execute("ALTER SEQUENCE timeseries_roles_id_seq RESTART WITH 3") 

70 fake_conn.commit() 

71 fake_cur.execute("ALTER SEQUENCE timeseries_programmes_id_seq RESTART WITH 1") 

72 fake_conn.commit() 

73 fake_cur.execute("ALTER SEQUENCE timeseries_id_seq RESTART WITH 1") 

74 fake_conn.commit() 

75 infilename = "tests/fixtures/auth_user/auth.json" 

76 with open(infilename) as f: 

77 metajson = json.load(f) 

78 for entry in metajson: 

79 new_auth_user = AuthUser(**entry) 

80 db.add(new_auth_user) 

81 db.commit() 

82 db.refresh(new_auth_user) 

83 infilename = "tests/fixtures/contacts/persons.json" 

84 with open(infilename) as f: 

85 metajson = json.load(f) 

86 for entry in metajson: 

87 new_person = Person(**entry) 

88 db.add(new_person) 

89 db.commit() 

90 db.refresh(new_person) 

91 infilename = "tests/fixtures/contacts/organisations.json" 

92 with open(infilename) as f: 

93 metajson = json.load(f) 

94 for entry in metajson: 

95 new_organisation = Organisation(**entry) 

96 db.add(new_organisation) 

97 db.commit() 

98 db.refresh(new_organisation) 

99 infilename = "tests/fixtures/contacts/contacts.json" 

100 with open(infilename) as f: 

101 metajson = json.load(f) 

102 for entry in metajson: 

103 new_contact = Contact(**entry) 

104 db.add(new_contact) 

105 db.commit() 

106 db.refresh(new_contact) 

107 infilename = "tests/fixtures/variables/variables.json" 

108 with open(infilename) as f: 

109 metajson = json.load(f) 

110 for entry in metajson: 

111 new_variable = Variable(**entry) 

112 db.add(new_variable) 

113 db.commit() 

114 db.refresh(new_variable) 

115 infilename = "tests/fixtures/stationmeta/stationmeta_core.json" 

116 with open(infilename) as f: 

117 metajson = json.load(f) 

118 for entry in metajson: 

119 new_stationmeta_core = StationmetaCore(**entry) 

120 # there's a mismatch with coordinates --> how to automatically switch back and forth?! 

121 tmp_coordinates = new_stationmeta_core.coordinates 

122 new_stationmeta_core.coordinates = get_geom_from_coordinates( 

123 Coordinates(**new_stationmeta_core.coordinates) 

124 ) 

125 db.add(new_stationmeta_core) 

126 db.commit() 

127 db.refresh(new_stationmeta_core) 

128 infilename = "tests/fixtures/stationmeta/stationmeta_changelog.json" 

129 with open(infilename) as f: 

130 metajson = json.load(f) 

131 for entry in metajson: 

132 new_stationmeta_changelog = StationmetaChangelog(**entry) 

133 db.add(new_stationmeta_changelog) 

134 db.commit() 

135 db.refresh(new_stationmeta_changelog) 

136 infilename = "tests/fixtures/stationmeta/stationmeta_global.json" 

137 with open(infilename) as f: 

138 metajson = json.load(f) 

139 for entry in metajson: 

140 new_stationmeta_global = StationmetaGlobal(**entry) 

141 db.add(new_stationmeta_global) 

142 db.commit() 

143 db.refresh(new_stationmeta_global) 

144 infilename = "tests/fixtures/timeseries/timeseries_programmes.json" 

145 with open(infilename) as f: 

146 metajson = json.load(f) 

147 for entry in metajson: 

148 new_timeseries_programme = TimeseriesProgramme(**entry) 

149 db.add(new_timeseries_programme) 

150 db.commit() 

151 db.refresh(new_timeseries_programme) 

152 infilename = "tests/fixtures/timeseries/timeseries.json" 

153 with open(infilename) as f: 

154 metajson = json.load(f) 

155 for entry in metajson: 

156 new_timeseries = Timeseries(**entry) 

157 db.add(new_timeseries) 

158 db.commit() 

159 db.refresh(new_timeseries) 

160 infilename = "tests/fixtures/timeseries/timeseries_roles.json" 

161 with open(infilename) as f: 

162 metajson = json.load(f) 

163 for entry in metajson: 

164 new_timeseries_role = TimeseriesRole(**entry) 

165 db.add(new_timeseries_role) 

166 db.commit() 

167 db.refresh(new_timeseries_role) 

168 infilename = "tests/fixtures/timeseries/timeseries_timeseries_roles.json" 

169 with open(infilename) as f: 

170 metajson = json.load(f) 

171 for entry in metajson: 

172 db.execute( 

173 insert(timeseries_timeseries_roles_table).values( 

174 timeseries_id=entry["timeseries_id"], role_id=entry["role_id"] 

175 ) 

176 ) 

177 db.execute("COMMIT") 

178 

179 def test_search_base(self, client, db): 

180 response = client.get("/search/a?") 

181 expected_status_code = 200 

182 assert response.status_code == expected_status_code 

183 expected_resp = [{'id': 1, 

184 'label': 'CMA', 

185 'order': 1, 

186 'sampling_frequency': 'hourly', 

187 'aggregation': 'mean', 

188 'data_start_date': '2003-09-07T15:30:00+00:00', 

189 'data_end_date': '2016-12-31T14:30:00+00:00', 

190 'data_origin': 'instrument', 

191 'data_origin_type': 'measurement', 

192 'provider_version': 'N/A', 

193 'sampling_height': 7.0, 

194 'additional_metadata': {"original_units": "ppb"}, 

195 'doi': '', 

196 'coverage': -1.0, 

197 'station': {'id': 2, 

198 'codes': ['SDZ54421'], 

199 'name': 'Shangdianzi', 

200 'coordinates': {'lat': 40.65, 'lng': 117.106, 'alt': 293.9}, 

201 'coordinate_validation_status': 'not checked', 

202 'country': 'China', 

203 'state': 'Beijing Shi', 

204 'type': 'unknown', 

205 'type_of_area': 'unknown', 

206 'timezone': 'Asia/Shanghai', 

207 'additional_metadata': {'add_type': 'nature reservation'}, 

208 'aux_images': [], 

209 'aux_docs': [], 

210 'aux_urls': [], 

211 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0, 

212 'mean_topography_srtm_alt_1km_year1994': -999.0, 

213 'max_topography_srtm_relative_alt_5km_year1994': -999.0, 

214 'min_topography_srtm_relative_alt_5km_year1994': -999.0, 

215 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, 

216 'climatic_zone_year2016': '6 (warm temperate dry)', 

217 'htap_region_tier1_year2010': '11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)', 

218 'dominant_landcover_year2012': '11 (Cropland, rainfed, herbaceous cover)', 

219 'landcover_description_25km_year2012': '', 

220 'dominant_ecoregion_year2017': '-1 (undefined)', 

221 'ecoregion_description_25km_year2017': '', 

222 'distance_to_major_road_year2020': -999.0, 

223 'mean_stable_nightlights_1km_year2013': -999.0, 

224 'mean_stable_nightlights_5km_year2013': -999.0, 

225 'max_stable_nightlights_25km_year2013': -999.0, 

226 'max_stable_nightlights_25km_year1992': -999.0, 

227 'mean_population_density_250m_year2015': -1.0, 

228 'mean_population_density_5km_year2015': -1.0, 

229 'max_population_density_25km_year2015': -1.0, 

230 'mean_population_density_250m_year1990': -1.0, 

231 'mean_population_density_5km_year1990': -1.0, 

232 'max_population_density_25km_year1990': -1.0, 

233 'mean_nox_emissions_10km_year2015': -999.0, 

234 'mean_nox_emissions_10km_year2000': -999.0, 

235 'toar1_category': 'unclassified', 

236 'toar2_category': 'suburban'}, 

237 'changelog': [{'datetime': '2023-07-15T19:27:09.463245+00:00', 

238 'description': 'station created', 

239 'old_value': '', 

240 'new_value': '', 

241 'station_id': 2, 

242 'author_id': 1, 

243 'type_of_change': 'created'}]}, 

244 'variable': {'name': 'toluene', 

245 'longname': 'toluene', 

246 'displayname': 'Toluene', 

247 'cf_standardname': 'mole_fraction_of_toluene_in_air', 

248 'units': 'nmol mol-1', 

249 'chemical_formula': 'C7H8', 

250 'id': 7}, 

251 'programme': {'id': 0, 

252 'name': '', 

253 'longname': '', 

254 'homepage': '', 

255 'description': ''}, 

256 'roles': [{'id': 2, 

257 'role': 'resource provider', 

258 'status': 'active', 

259 'contact': {'id': 4, 

260 'organisation': {'id': 1, 

261 'name': 'UBA', 

262 'longname': 'Umweltbundesamt', 

263 'kind': 'government', 

264 'city': 'Dessau-Roßlau', 

265 'postcode': '06844', 

266 'street_address': 'Wörlitzer Platz 1', 

267 'country': 'Germany', 

268 'homepage': 'https://www.umweltbundesamt.de', 

269 'contact_url': 'mailto:immission@uba.de'}}}, 

270 {'id': 3, 

271 'role': 'principal investigator', 

272 'status': 'active', 

273 'contact': {'id': 3, 

274 'person': {'email': 's.schroeder@fz-juelich.de', 

275 'id': 3, 

276 'isprivate': False, 

277 'name': 'Sabine Schröder', 

278 'orcid': '0000-0002-0309-8010', 

279 'phone': '+49-2461-61-6397'}}}]}, 

280 {'id': 2, 

281 'label': 'CMA', 

282 'order': 1, 

283 'sampling_frequency': 'hourly', 

284 'aggregation': 'mean', 

285 'data_start_date': '2003-09-07T15:30:00+00:00', 

286 'data_end_date': '2016-12-31T14:30:00+00:00', 

287 'data_origin': 'instrument', 

288 'data_origin_type': 'measurement', 

289 'provider_version': 'N/A', 

290 'sampling_height': 7.0, 

291 'additional_metadata': {'original_units': {'since_19740101000000': 'nmol/mol'}, 

292 'measurement_method': 'uv_abs', 

293 'absorption_cross_section': 'Hearn 1961', 

294 'ebas_metadata_19740101000000_29y': 

295 {'Submitter': 'Unknown, Lady, lady.unknown@unknown.com, some long division name, SHORT, , 111 Streetname, , zipcode, Boulder, CO, USA', 

296 'Data level': '2', 

297 'Frameworks': 'GAW-WDCRG NOAA-ESRL', 

298 'Station code': 'XXX', 

299 'Station name': 'Secret'}}, 

300 'doi': '', 

301 'coverage': -1.0, 

302 'station': {'id': 3, 

303 'codes': ['China_test8'], 

304 'name': 'Test_China', 

305 'coordinates': {'lat': 36.256, 'lng': 117.106, 'alt': 1534.0}, 

306 'coordinate_validation_status': 'not checked', 

307 'country': 'China', 

308 'state': 'Shandong Sheng', 

309 'type': 'unknown', 

310 'type_of_area': 'unknown', 

311 'timezone': 'Asia/Shanghai', 

312 'additional_metadata': {}, 

313 'aux_images': [], 

314 'aux_docs': [], 

315 'aux_urls': [], 

316 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0, 

317 'mean_topography_srtm_alt_1km_year1994': -999.0, 

318 'max_topography_srtm_relative_alt_5km_year1994': -999.0, 

319 'min_topography_srtm_relative_alt_5km_year1994': -999.0, 

320 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, 

321 'climatic_zone_year2016': '6 (warm temperate dry)', 

322 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', 

323 'dominant_landcover_year2012': '10 (Cropland, rainfed)', 

324 'landcover_description_25km_year2012': '', 

325 'dominant_ecoregion_year2017': '-1 (undefined)', 

326 'ecoregion_description_25km_year2017': '', 

327 'distance_to_major_road_year2020': -999.0, 

328 'mean_stable_nightlights_1km_year2013': -999.0, 

329 'mean_stable_nightlights_5km_year2013': -999.0, 

330 'max_stable_nightlights_25km_year2013': -999.0, 

331 'max_stable_nightlights_25km_year1992': -999.0, 

332 'mean_population_density_250m_year2015': -1.0, 

333 'mean_population_density_5km_year2015': -1.0, 

334 'max_population_density_25km_year2015': -1.0, 

335 'mean_population_density_250m_year1990': -1.0, 

336 'mean_population_density_5km_year1990': -1.0, 

337 'max_population_density_25km_year1990': -1.0, 

338 'mean_nox_emissions_10km_year2015': -999.0, 

339 'mean_nox_emissions_10km_year2000': -999.0, 

340 'toar1_category': 'unclassified', 

341 'toar2_category': 'suburban'}, 

342 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00', 

343 'description': 'station created', 

344 'old_value': '', 

345 'new_value': '', 

346 'station_id': 3, 

347 'author_id': 1, 

348 'type_of_change': 'created'}]}, 

349 'variable': {'name': 'o3', 

350 'longname': 'ozone', 

351 'displayname': 'Ozone', 

352 'cf_standardname': 'mole_fraction_of_ozone_in_air', 

353 'units': 'nmol mol-1', 

354 'chemical_formula': 'O3', 

355 'id': 5}, 

356 'programme': {'id': 0, 

357 'name': '', 

358 'longname': '', 

359 'homepage': '', 

360 'description': ''}, 

361 'roles': [{'id': 1, 

362 'role': 'resource provider', 

363 'status': 'active', 

364 'contact': {'id': 5, 

365 'organisation': 

366 {'id': 2, 

367 'name': 'FZJ', 

368 'longname': 'Forschungszentrum Jülich', 

369 'kind': 'research', 

370 'city': 'Jülich', 

371 'postcode': '52425', 

372 'street_address': 'Wilhelm-Johnen-Straße', 

373 'country': 'Germany', 

374 'homepage': 'https://www.fz-juelich.de', 

375 'contact_url': 'mailto:toar-data@fz-juelich.de'}}}]}, 

376 {'id': 18763, 

377 'additional_metadata': {'original_units': 'ppb'}, 

378 'aggregation': 'mean', 

379 'coverage': -1.0, 

380 'data_start_date': '1991-01-01T00:00:00+00:00', 

381 'data_end_date': '2025-02-25T14:00:00+00:00', 

382 'data_origin': 'instrument', 

383 'data_origin_type': 'measurement', 

384 'doi': '', 

385 'label': '', 

386 'order': 1, 

387 'programme': {'description': '', 

388 'homepage': '', 

389 'id': 0, 

390 'longname': '', 

391 'name': ''}, 

392 'provider_version': 'N/A', 

393 'roles': [{'contact': {'id': 5, 

394 'organisation': {'city': 'Jülich', 

395 'contact_url': 'mailto:toar-data@fz-juelich.de', 

396 'country': 'Germany', 

397 'homepage': 'https://www.fz-juelich.de', 

398 'id': 2, 

399 'kind': 'research', 

400 'longname': 'Forschungszentrum ' 

401 'Jülich', 

402 'name': 'FZJ', 

403 'postcode': '52425', 

404 'street_address': 'Wilhelm-Johnen-Straße'}}, 

405 'id': 1, 

406 'role': 'resource provider', 

407 'status': 'active'}], 

408 'sampling_frequency': 'hourly', 

409 'sampling_height': 7.0, 

410 'station': {'additional_metadata': {'add_type': 'nature reservation'}, 

411 'aux_docs': [], 

412 'aux_images': [], 

413 'aux_urls': [], 

414 'changelog': [{'author_id': 1, 

415 'datetime': '2023-07-15T19:27:09.463245+00:00', 

416 'description': 'station created', 

417 'new_value': '', 

418 'old_value': '', 

419 'station_id': 2, 

420 'type_of_change': 'created'}], 

421 'codes': ['SDZ54421'], 

422 'coordinate_validation_status': 'not checked', 

423 'coordinates': {'alt': 293.9, 

424 'lat': 40.65, 

425 'lng': 117.106}, 

426 'country': 'China', 

427 'globalmeta': {'climatic_zone_year2016': '6 (warm temperate dry)', 

428 'distance_to_major_road_year2020': -999.0, 

429 'dominant_ecoregion_year2017': '-1 (undefined)', 

430 'dominant_landcover_year2012': '11 (Cropland, ' 

431 'rainfed, ' 

432 'herbaceous cover)', 

433 'ecoregion_description_25km_year2017': '', 

434 'htap_region_tier1_year2010': '11 (MDE Middle ' 

435 'East: S. Arabia, ' 

436 'Oman, etc, Iran, ' 

437 'Iraq)', 

438 'landcover_description_25km_year2012': '', 

439 'max_population_density_25km_year1990': -1.0, 

440 'max_population_density_25km_year2015': -1.0, 

441 'max_stable_nightlights_25km_year1992': -999.0, 

442 'max_stable_nightlights_25km_year2013': -999.0, 

443 'max_topography_srtm_relative_alt_5km_year1994': -999.0, 

444 'mean_nox_emissions_10km_year2000': -999.0, 

445 'mean_nox_emissions_10km_year2015': -999.0, 

446 'mean_population_density_250m_year1990': -1.0, 

447 'mean_population_density_250m_year2015': -1.0, 

448 'mean_population_density_5km_year1990': -1.0, 

449 'mean_population_density_5km_year2015': -1.0, 

450 'mean_stable_nightlights_1km_year2013': -999.0, 

451 'mean_stable_nightlights_5km_year2013': -999.0, 

452 'mean_topography_srtm_alt_1km_year1994': -999.0, 

453 'mean_topography_srtm_alt_90m_year1994': -999.0, 

454 'min_topography_srtm_relative_alt_5km_year1994': -999.0, 

455 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, 

456 'toar1_category': 'unclassified', 

457 'toar2_category': 'suburban'}, 

458 'id': 2, 

459 'name': 'Shangdianzi', 

460 'state': 'Beijing Shi', 

461 'timezone': 'Asia/Shanghai', 

462 'type': 'unknown', 

463 'type_of_area': 'unknown'}, 

464 'variable': {'cf_standardname': 'mole_fraction_of_ozone_in_air', 

465 'chemical_formula': 'O3', 

466 'displayname': 'Ozone', 

467 'id': 5, 

468 'longname': 'ozone', 

469 'name': 'o3', 

470 'units': 'nmol mol-1'}}, 

471 {'additional_metadata': {'original_units': 'ppb'}, 

472 'aggregation': 'mean', 

473 'coverage': -1.0, 

474 'data_end_date': '2025-02-25T14:00:00+00:00', 

475 'data_origin': 'instrument', 

476 'data_origin_type': 'measurement', 

477 'data_start_date': '1991-01-01T00:00:00+00:00', 

478 'doi': '', 

479 'id': 30890, 

480 'label': '', 

481 'order': 2, 

482 'programme': {'description': '', 

483 'homepage': '', 

484 'id': 0, 

485 'longname': '', 

486 'name': ''}, 

487 'provider_version': 'N/A', 

488 'roles': [{'contact': {'id': 5, 

489 'organisation': {'city': 'Jülich', 

490 'contact_url': 'mailto:toar-data@fz-juelich.de', 

491 'country': 'Germany', 

492 'homepage': 'https://www.fz-juelich.de', 

493 'id': 2, 

494 'kind': 'research', 

495 'longname': 'Forschungszentrum ' 

496 'Jülich', 

497 'name': 'FZJ', 

498 'postcode': '52425', 

499 'street_address': 'Wilhelm-Johnen-Straße'}}, 

500 'id': 1, 

501 'role': 'resource provider', 

502 'status': 'active'}], 

503 'sampling_frequency': 'hourly', 

504 'sampling_height': 7.0, 

505 'station': {'additional_metadata': {'add_type': 'nature reservation'}, 

506 'aux_docs': [], 

507 'aux_images': [], 

508 'aux_urls': [], 

509 'changelog': [{'author_id': 1, 

510 'datetime': '2023-07-15T19:27:09.463245+00:00', 

511 'description': 'station created', 

512 'new_value': '', 

513 'old_value': '', 

514 'station_id': 2, 

515 'type_of_change': 'created'}], 

516 'codes': ['SDZ54421'], 

517 'coordinate_validation_status': 'not checked', 

518 'coordinates': {'alt': 293.9, 

519 'lat': 40.65, 

520 'lng': 117.106}, 

521 'country': 'China', 

522 'globalmeta': {'climatic_zone_year2016': '6 (warm temperate dry)', 

523 'distance_to_major_road_year2020': -999.0, 

524 'dominant_ecoregion_year2017': '-1 (undefined)', 

525 'dominant_landcover_year2012': '11 (Cropland, ' 

526 'rainfed, ' 

527 'herbaceous cover)', 

528 'ecoregion_description_25km_year2017': '', 

529 'htap_region_tier1_year2010': '11 (MDE Middle ' 

530 'East: S. Arabia, ' 

531 'Oman, etc, Iran, ' 

532 'Iraq)', 

533 'landcover_description_25km_year2012': '', 

534 'max_population_density_25km_year1990': -1.0, 

535 'max_population_density_25km_year2015': -1.0, 

536 'max_stable_nightlights_25km_year1992': -999.0, 

537 'max_stable_nightlights_25km_year2013': -999.0, 

538 'max_topography_srtm_relative_alt_5km_year1994': -999.0, 

539 'mean_nox_emissions_10km_year2000': -999.0, 

540 'mean_nox_emissions_10km_year2015': -999.0, 

541 'mean_population_density_250m_year1990': -1.0, 

542 'mean_population_density_250m_year2015': -1.0, 

543 'mean_population_density_5km_year1990': -1.0, 

544 'mean_population_density_5km_year2015': -1.0, 

545 'mean_stable_nightlights_1km_year2013': -999.0, 

546 'mean_stable_nightlights_5km_year2013': -999.0, 

547 'mean_topography_srtm_alt_1km_year1994': -999.0, 

548 'mean_topography_srtm_alt_90m_year1994': -999.0, 

549 'min_topography_srtm_relative_alt_5km_year1994': -999.0, 

550 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, 

551 'toar1_category': 'unclassified', 

552 'toar2_category': 'suburban'}, 

553 'id': 2, 

554 'name': 'Shangdianzi', 

555 'state': 'Beijing Shi', 

556 'timezone': 'Asia/Shanghai', 

557 'type': 'unknown', 

558 'type_of_area': 'unknown'}, 

559 'variable': {'cf_standardname': 'mole_fraction_of_ozone_in_air', 

560 'chemical_formula': 'O3', 

561 'displayname': 'Ozone', 

562 'id': 5, 

563 'longname': 'ozone', 

564 'name': 'o3', 

565 'units': 'nmol mol-1'}}, 

566 {'additional_metadata': {'original_units': 'ppb'}, 

567 'aggregation': 'mean', 

568 'coverage': -1.0, 

569 'data_end_date': '2025-02-25T14:00:00+00:00', 

570 'data_origin': 'instrument', 

571 'data_origin_type': 'measurement', 

572 'data_start_date': '1991-01-01T00:00:00+00:00', 

573 'doi': '', 

574 'id': 434870, 

575 'label': '', 

576 'order': 2, 

577 'programme': { 

578 'description': '', 

579 'homepage': '', 

580 'id': 0, 

581 'longname': '', 

582 'name': '', 

583 }, 

584 'provider_version': 'N/A', 

585 'roles': [ 

586 { 

587 'contact': { 

588 'id': 4, 

589 'organisation': { 

590 'city': 'Dessau-Roßlau', 

591 'contact_url': 'mailto:immission@uba.de', 

592 'country': 'Germany', 

593 'homepage': 'https://www.umweltbundesamt.de', 

594 'id': 1, 

595 'kind': 'government', 

596 'longname': 'Umweltbundesamt', 

597 'name': 'UBA', 

598 'postcode': '06844', 

599 'street_address': 'Wörlitzer Platz 1', 

600 }, 

601 }, 

602 'id': 2, 

603 'role': 'resource provider', 

604 'status': 'active', 

605 }, 

606 ], 

607 'sampling_frequency': 'hourly', 

608 'sampling_height': 7.0, 

609 'station': { 

610 'additional_metadata': {'add_type': 'nature reservation'}, 

611 'aux_docs': [], 

612 'aux_images': [], 

613 'aux_urls': [], 

614 'changelog': [ 

615 { 

616 'author_id': 1, 

617 'datetime': '2023-07-15T19:27:09.463245+00:00', 

618 'description': 'station created', 

619 'new_value': '', 

620 'old_value': '', 

621 'station_id': 2, 

622 'type_of_change': 'created', 

623 }, 

624 ], 

625 'codes': [ 

626 'SDZ54421', 

627 ], 

628 'coordinate_validation_status': 'not checked', 

629 'coordinates': { 

630 'alt': 293.9, 

631 'lat': 40.65, 

632 'lng': 117.106 

633 }, 

634 'country': 'China', 

635 'globalmeta': { 

636 'climatic_zone_year2016': '6 (warm temperate dry)', 

637 'distance_to_major_road_year2020': -999.0, 

638 'dominant_ecoregion_year2017': '-1 (undefined)', 

639 'dominant_landcover_year2012': '11 (Cropland, rainfed, herbaceous cover)', 

640 'ecoregion_description_25km_year2017': '', 

641 'htap_region_tier1_year2010': '11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)', 

642 'landcover_description_25km_year2012': '', 

643 'max_population_density_25km_year1990': -1.0, 

644 'max_population_density_25km_year2015': -1.0, 

645 'max_stable_nightlights_25km_year1992': -999.0, 

646 'max_stable_nightlights_25km_year2013': -999.0, 

647 'max_topography_srtm_relative_alt_5km_year1994': -999.0, 

648 'mean_nox_emissions_10km_year2000': -999.0, 

649 'mean_nox_emissions_10km_year2015': -999.0, 

650 'mean_population_density_250m_year1990': -1.0, 

651 'mean_population_density_250m_year2015': -1.0, 

652 'mean_population_density_5km_year1990': -1.0, 

653 'mean_population_density_5km_year2015': -1.0, 

654 'mean_stable_nightlights_1km_year2013': -999.0, 

655 'mean_stable_nightlights_5km_year2013': -999.0, 

656 'mean_topography_srtm_alt_1km_year1994': -999.0, 

657 'mean_topography_srtm_alt_90m_year1994': -999.0, 

658 'min_topography_srtm_relative_alt_5km_year1994': -999.0, 

659 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, 

660 'toar1_category': 'unclassified', 

661 'toar2_category': 'suburban', 

662 }, 

663 'id': 2, 

664 'name': 'Shangdianzi', 

665 'state': 'Beijing Shi', 

666 'timezone': 'Asia/Shanghai', 

667 'type': 'unknown', 

668 'type_of_area': 'unknown', 

669 }, 

670 'variable': { 

671 'cf_standardname': 'mole_fraction_of_ozone_in_air', 

672 'chemical_formula': 'O3', 

673 'displayname': 'Ozone', 

674 'id': 5, 

675 'longname': 'ozone', 

676 'name': 'o3', 

677 'units': 'nmol mol-1' }}] 

678 assert response.json() == expected_resp 

679 

680 

681 def test_search_single(self, client, db): 

682 response = client.get("/search/a?id=2") 

683 expected_status_code = 200 

684 assert response.status_code == expected_status_code 

685 expected_resp = [ 

686 {'id': 2, 

687 'label': 'CMA', 

688 'order': 1, 

689 'sampling_frequency': 'hourly', 

690 'aggregation': 'mean', 

691 'data_start_date': '2003-09-07T15:30:00+00:00', 

692 'data_end_date': '2016-12-31T14:30:00+00:00', 

693 'data_origin': 'instrument', 

694 'data_origin_type': 'measurement', 

695 'provider_version': 'N/A', 

696 'sampling_height': 7.0, 

697 'additional_metadata': {'original_units': {'since_19740101000000': 'nmol/mol'}, 

698 'measurement_method': 'uv_abs', 

699 'absorption_cross_section': 'Hearn 1961', 

700 'ebas_metadata_19740101000000_29y': 

701 {'Submitter': 'Unknown, Lady, lady.unknown@unknown.com, some long division name, SHORT, , 111 Streetname, , zipcode, Boulder, CO, USA', 

702 'Data level': '2', 

703 'Frameworks': 'GAW-WDCRG NOAA-ESRL', 

704 'Station code': 'XXX', 

705 'Station name': 'Secret'}}, 

706 'doi': '', 

707 'coverage': -1.0, 

708 'station': {'id': 3, 

709 'codes': ['China_test8'], 

710 'name': 'Test_China', 

711 'coordinates': {'lat': 36.256, 'lng': 117.106, 'alt': 1534.0}, 

712 'coordinate_validation_status': 'not checked', 

713 'country': 'China', 

714 'state': 'Shandong Sheng', 

715 'type': 'unknown', 

716 'type_of_area': 'unknown', 

717 'timezone': 'Asia/Shanghai', 

718 'additional_metadata': {}, 

719 'aux_images': [], 

720 'aux_docs': [], 

721 'aux_urls': [], 

722 'globalmeta': {'mean_topography_srtm_alt_90m_year1994': -999.0, 

723 'mean_topography_srtm_alt_1km_year1994': -999.0, 

724 'max_topography_srtm_relative_alt_5km_year1994': -999.0, 

725 'min_topography_srtm_relative_alt_5km_year1994': -999.0, 

726 'stddev_topography_srtm_relative_alt_5km_year1994': -999.0, 

727 'climatic_zone_year2016': '6 (warm temperate dry)', 

728 'htap_region_tier1_year2010': '10 (SAF Sub Saharan/sub Sahel Africa)', 

729 'dominant_landcover_year2012': '10 (Cropland, rainfed)', 

730 'landcover_description_25km_year2012': '', 

731 'dominant_ecoregion_year2017': '-1 (undefined)', 

732 'ecoregion_description_25km_year2017': '', 

733 'distance_to_major_road_year2020': -999.0, 

734 'mean_stable_nightlights_1km_year2013': -999.0, 

735 'mean_stable_nightlights_5km_year2013': -999.0, 

736 'max_stable_nightlights_25km_year2013': -999.0, 

737 'max_stable_nightlights_25km_year1992': -999.0, 

738 'mean_population_density_250m_year2015': -1.0, 

739 'mean_population_density_5km_year2015': -1.0, 

740 'max_population_density_25km_year2015': -1.0, 

741 'mean_population_density_250m_year1990': -1.0, 

742 'mean_population_density_5km_year1990': -1.0, 

743 'max_population_density_25km_year1990': -1.0, 

744 'mean_nox_emissions_10km_year2015': -999.0, 

745 'mean_nox_emissions_10km_year2000': -999.0, 

746 'toar1_category': 'unclassified', 

747 'toar2_category': 'suburban'}, 

748 'changelog': [{'datetime': '2023-08-15T21:16:20.596545+00:00', 

749 'description': 'station created', 

750 'old_value': '', 

751 'new_value': '', 

752 'station_id': 3, 

753 'author_id': 1, 

754 'type_of_change': 'created'}]}, 

755 'variable': {'name': 'o3', 

756 'longname': 'ozone', 

757 'displayname': 'Ozone', 

758 'cf_standardname': 'mole_fraction_of_ozone_in_air', 

759 'units': 'nmol mol-1', 

760 'chemical_formula': 'O3', 

761 'id': 5}, 

762 'programme': {'id': 0, 

763 'name': '', 

764 'longname': '', 

765 'homepage': '', 

766 'description': ''}, 

767 'roles': [{'id': 1, 

768 'role': 'resource provider', 

769 'status': 'active', 

770 'contact': {'id': 5, 

771 'organisation': 

772 {'id': 2, 

773 'name': 'FZJ', 

774 'longname': 'Forschungszentrum Jülich', 

775 'kind': 'research', 

776 'city': 'Jülich', 

777 'postcode': '52425', 

778 'street_address': 'Wilhelm-Johnen-Straße', 

779 'country': 'Germany', 

780 'homepage': 'https://www.fz-juelich.de', 

781 'contact_url': 'mailto:toar-data@fz-juelich.de'}}}]}] 

782 assert response.json() == expected_resp 

783 

784 def test_search_plus(self, client, db): 

785 response = client.get("/search/a?id=1+id=2") 

786 expected_status_code = 200 

787 assert response.status_code == expected_status_code 

788 expected_resp = [ 

789 { 

790 "id": 1, 

791 "label": "CMA", 

792 "order": 1, 

793 "sampling_frequency": "hourly", 

794 "aggregation": "mean", 

795 "data_start_date": "2003-09-07T15:30:00+00:00", 

796 "data_end_date": "2016-12-31T14:30:00+00:00", 

797 "data_origin": "instrument", 

798 "data_origin_type": "measurement", 

799 "provider_version": "N/A", 

800 "sampling_height": 7.0, 

801 "additional_metadata": { 

802 "original_units": "ppb", 

803 }, 

804 "doi": "", 

805 "coverage": -1.0, 

806 "station": { 

807 "id": 2, 

808 "codes": ["SDZ54421"], 

809 "name": "Shangdianzi", 

810 "coordinates": {"lat": 40.65, "lng": 117.106, "alt": 293.9}, 

811 "coordinate_validation_status": "not checked", 

812 "country": "China", 

813 "state": "Beijing Shi", 

814 "type": "unknown", 

815 "type_of_area": "unknown", 

816 "timezone": "Asia/Shanghai", 

817 "additional_metadata": {"add_type": "nature reservation"}, 

818 "aux_images": [], 

819 "aux_docs": [], 

820 "aux_urls": [], 

821 "globalmeta": { 

822 "mean_topography_srtm_alt_90m_year1994": -999.0, 

823 "mean_topography_srtm_alt_1km_year1994": -999.0, 

824 "max_topography_srtm_relative_alt_5km_year1994": -999.0, 

825 "min_topography_srtm_relative_alt_5km_year1994": -999.0, 

826 "stddev_topography_srtm_relative_alt_5km_year1994": -999.0, 

827 "climatic_zone_year2016": "6 (warm temperate dry)", 

828 "htap_region_tier1_year2010": "11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)", 

829 "dominant_landcover_year2012": "11 (Cropland, rainfed, herbaceous cover)", 

830 "landcover_description_25km_year2012": "", 

831 "dominant_ecoregion_year2017": "-1 (undefined)", 

832 "ecoregion_description_25km_year2017": "", 

833 "distance_to_major_road_year2020": -999.0, 

834 "mean_stable_nightlights_1km_year2013": -999.0, 

835 "mean_stable_nightlights_5km_year2013": -999.0, 

836 "max_stable_nightlights_25km_year2013": -999.0, 

837 "max_stable_nightlights_25km_year1992": -999.0, 

838 "mean_population_density_250m_year2015": -1.0, 

839 "mean_population_density_5km_year2015": -1.0, 

840 "max_population_density_25km_year2015": -1.0, 

841 "mean_population_density_250m_year1990": -1.0, 

842 "mean_population_density_5km_year1990": -1.0, 

843 "max_population_density_25km_year1990": -1.0, 

844 "mean_nox_emissions_10km_year2015": -999.0, 

845 "mean_nox_emissions_10km_year2000": -999.0, 

846 "toar1_category": "unclassified", 

847 "toar2_category": "suburban" 

848 }, 

849 "changelog": [ 

850 { 

851 "datetime": "2023-07-15T19:27:09.463245+00:00", 

852 "description": "station created", 

853 "old_value": "", 

854 "new_value": "", 

855 "station_id": 2, 

856 "author_id": 1, 

857 "type_of_change": "created", 

858 } 

859 ], 

860 }, 

861 "variable": { 

862 "name": "toluene", 

863 "longname": "toluene", 

864 "displayname": "Toluene", 

865 "cf_standardname": "mole_fraction_of_toluene_in_air", 

866 "units": "nmol mol-1", 

867 "chemical_formula": "C7H8", 

868 "id": 7, 

869 }, 

870 "programme": {"id": 0, "name": "", "longname": "", "homepage": "", "description": ""}, 

871 "roles": [ 

872 { 

873 "id": 2, 

874 "role": "resource provider", 

875 "status": "active", 

876 "contact": { 

877 "id": 4, 

878 "organisation": { 

879 "id": 1, 

880 "name": "UBA", 

881 "longname": "Umweltbundesamt", 

882 "kind": "government", 

883 "city": "Dessau-Roßlau", 

884 "postcode": "06844", 

885 "street_address": "Wörlitzer Platz 1", 

886 "country": "Germany", 

887 "homepage": "https://www.umweltbundesamt.de", 

888 "contact_url": "mailto:immission@uba.de", 

889 }, 

890 }, 

891 }, 

892 { 

893 "id": 3, 

894 "role": "principal investigator", 

895 "status": "active", 

896 "contact": { 

897 "id": 3, 

898 "person": { 

899 "email": "s.schroeder@fz-juelich.de", 

900 "id": 3, 

901 "isprivate": False, 

902 "name": "Sabine Schröder", 

903 "orcid": "0000-0002-0309-8010", 

904 "phone": "+49-2461-61-6397", 

905 }, 

906 }, 

907 } 

908 ], 

909 }, 

910 { 

911 "id": 2, 

912 "label": "CMA", 

913 "order": 1, 

914 "sampling_frequency": "hourly", 

915 "aggregation": "mean", 

916 "data_start_date": "2003-09-07T15:30:00+00:00", 

917 "data_end_date": "2016-12-31T14:30:00+00:00", 

918 "data_origin": "instrument", 

919 "data_origin_type": "measurement", 

920 "provider_version": "N/A", 

921 "sampling_height": 7.0, 

922 "additional_metadata": { 

923 "original_units": {"since_19740101000000": "nmol/mol"}, 

924 "measurement_method": "uv_abs", 

925 "absorption_cross_section": "Hearn 1961", 

926 "ebas_metadata_19740101000000_29y": { 

927 "Submitter": "Unknown, Lady, lady.unknown@unknown.com, some long division name, SHORT, , 111 Streetname, , zipcode, Boulder, CO, USA", 

928 "Data level": "2", 

929 "Frameworks": "GAW-WDCRG NOAA-ESRL", 

930 "Station code": "XXX", 

931 "Station name": "Secret", 

932 }, 

933 }, 

934 "doi": "", 

935 "coverage": -1.0, 

936 "station": { 

937 "id": 3, 

938 "codes": ["China_test8"], 

939 "name": "Test_China", 

940 "coordinates": {"lat": 36.256, "lng": 117.106, "alt": 1534.0}, 

941 "coordinate_validation_status": "not checked", 

942 "country": "China", 

943 "state": "Shandong Sheng", 

944 "type": "unknown", 

945 "type_of_area": "unknown", 

946 "timezone": "Asia/Shanghai", 

947 "additional_metadata": {}, 

948 "aux_images": [], 

949 "aux_docs": [], 

950 "aux_urls": [], 

951 "globalmeta": { 

952 "mean_topography_srtm_alt_90m_year1994": -999.0, 

953 "mean_topography_srtm_alt_1km_year1994": -999.0, 

954 "max_topography_srtm_relative_alt_5km_year1994": -999.0, 

955 "min_topography_srtm_relative_alt_5km_year1994": -999.0, 

956 "stddev_topography_srtm_relative_alt_5km_year1994": -999.0, 

957 "climatic_zone_year2016": "6 (warm temperate dry)", 

958 "htap_region_tier1_year2010": "10 (SAF Sub Saharan/sub Sahel Africa)", 

959 "dominant_landcover_year2012": "10 (Cropland, rainfed)", 

960 "landcover_description_25km_year2012": "", 

961 "dominant_ecoregion_year2017": "-1 (undefined)", 

962 "ecoregion_description_25km_year2017": "", 

963 "distance_to_major_road_year2020": -999.0, 

964 "mean_stable_nightlights_1km_year2013": -999.0, 

965 "mean_stable_nightlights_5km_year2013": -999.0, 

966 "max_stable_nightlights_25km_year2013": -999.0, 

967 "max_stable_nightlights_25km_year1992": -999.0, 

968 "mean_population_density_250m_year2015": -1.0, 

969 "mean_population_density_5km_year2015": -1.0, 

970 "max_population_density_25km_year2015": -1.0, 

971 "mean_population_density_250m_year1990": -1.0, 

972 "mean_population_density_5km_year1990": -1.0, 

973 "max_population_density_25km_year1990": -1.0, 

974 "mean_nox_emissions_10km_year2015": -999.0, 

975 "mean_nox_emissions_10km_year2000": -999.0, 

976 "toar1_category": "unclassified", 

977 "toar2_category": "suburban" 

978 }, 

979 "changelog": [ 

980 { 

981 "datetime": "2023-08-15T21:16:20.596545+00:00", 

982 "description": "station created", 

983 "old_value": "", 

984 "new_value": "", 

985 "station_id": 3, 

986 "author_id": 1, 

987 "type_of_change": "created", 

988 } 

989 ], 

990 }, 

991 "variable": { 

992 "name": "o3", 

993 "longname": "ozone", 

994 "displayname": "Ozone", 

995 "cf_standardname": "mole_fraction_of_ozone_in_air", 

996 "units": "nmol mol-1", 

997 "chemical_formula": "O3", 

998 "id": 5, 

999 }, 

1000 "programme": {"id": 0, "name": "", "longname": "", "homepage": "", "description": ""}, 

1001 "roles": [ 

1002 { 

1003 "id": 1, 

1004 "role": "resource provider", 

1005 "status": "active", 

1006 "contact": { 

1007 "id": 5, 

1008 "organisation": { 

1009 "id": 2, 

1010 "name": "FZJ", 

1011 "longname": "Forschungszentrum Jülich", 

1012 "kind": "research", 

1013 "city": "Jülich", 

1014 "postcode": "52425", 

1015 "street_address": "Wilhelm-Johnen-Straße", 

1016 "country": "Germany", 

1017 "homepage": "https://www.fz-juelich.de", 

1018 "contact_url": "mailto:toar-data@fz-juelich.de", 

1019 }, 

1020 }, 

1021 } 

1022 ], 

1023 }, 

1024 ] 

1025 assert response.json() == expected_resp 

1026 

1027 def test_search_minus(self, client, db): 

1028 response = client.get("/search/a?id=2-id=2") 

1029 expected_status_code = 200 

1030 assert response.status_code == expected_status_code 

1031 expected_resp = [] 

1032 assert response.json() == expected_resp 

1033 

1034 def test_search_distinct(self, client, db): 

1035 response = client.get("/search/a?id=1+id=1+id=1+id=1") 

1036 expected_status_code = 200 

1037 assert response.status_code == expected_status_code 

1038 expected_resp = [ 

1039 { 

1040 "id": 1, 

1041 "label": "CMA", 

1042 "order": 1, 

1043 "sampling_frequency": "hourly", 

1044 "aggregation": "mean", 

1045 "data_start_date": "2003-09-07T15:30:00+00:00", 

1046 "data_end_date": "2016-12-31T14:30:00+00:00", 

1047 "data_origin": "instrument", 

1048 "data_origin_type": "measurement", 

1049 "provider_version": "N/A", 

1050 "sampling_height": 7.0, 

1051 "additional_metadata": {"original_units": "ppb"}, 

1052 "doi": "", 

1053 "coverage": -1.0, 

1054 "station": { 

1055 "id": 2, 

1056 "codes": ["SDZ54421"], 

1057 "name": "Shangdianzi", 

1058 "coordinates": {"lat": 40.65, "lng": 117.106, "alt": 293.9}, 

1059 "coordinate_validation_status": "not checked", 

1060 "country": "China", 

1061 "state": "Beijing Shi", 

1062 "type": "unknown", 

1063 "type_of_area": "unknown", 

1064 "timezone": "Asia/Shanghai", 

1065 "additional_metadata": {"add_type": "nature reservation"}, 

1066 "aux_images": [], 

1067 "aux_docs": [], 

1068 "aux_urls": [], 

1069 "globalmeta": { 

1070 "mean_topography_srtm_alt_90m_year1994": -999.0, 

1071 "mean_topography_srtm_alt_1km_year1994": -999.0, 

1072 "max_topography_srtm_relative_alt_5km_year1994": -999.0, 

1073 "min_topography_srtm_relative_alt_5km_year1994": -999.0, 

1074 "stddev_topography_srtm_relative_alt_5km_year1994": -999.0, 

1075 "climatic_zone_year2016": "6 (warm temperate dry)", 

1076 "htap_region_tier1_year2010": "11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)", 

1077 "dominant_landcover_year2012": "11 (Cropland, rainfed, herbaceous cover)", 

1078 "landcover_description_25km_year2012": "", 

1079 "dominant_ecoregion_year2017": "-1 (undefined)", 

1080 "ecoregion_description_25km_year2017": "", 

1081 "distance_to_major_road_year2020": -999.0, 

1082 "mean_stable_nightlights_1km_year2013": -999.0, 

1083 "mean_stable_nightlights_5km_year2013": -999.0, 

1084 "max_stable_nightlights_25km_year2013": -999.0, 

1085 "max_stable_nightlights_25km_year1992": -999.0, 

1086 "mean_population_density_250m_year2015": -1.0, 

1087 "mean_population_density_5km_year2015": -1.0, 

1088 "max_population_density_25km_year2015": -1.0, 

1089 "mean_population_density_250m_year1990": -1.0, 

1090 "mean_population_density_5km_year1990": -1.0, 

1091 "max_population_density_25km_year1990": -1.0, 

1092 "mean_nox_emissions_10km_year2015": -999.0, 

1093 "mean_nox_emissions_10km_year2000": -999.0, 

1094 "toar1_category": "unclassified", 

1095 "toar2_category": "suburban" 

1096 }, 

1097 "changelog": [ 

1098 { 

1099 "datetime": "2023-07-15T19:27:09.463245+00:00", 

1100 "description": "station created", 

1101 "old_value": "", 

1102 "new_value": "", 

1103 "station_id": 2, 

1104 "author_id": 1, 

1105 "type_of_change": "created", 

1106 } 

1107 ], 

1108 }, 

1109 "variable": { 

1110 "name": "toluene", 

1111 "longname": "toluene", 

1112 "displayname": "Toluene", 

1113 "cf_standardname": "mole_fraction_of_toluene_in_air", 

1114 "units": "nmol mol-1", 

1115 "chemical_formula": "C7H8", 

1116 "id": 7, 

1117 }, 

1118 "programme": {"id": 0, "name": "", "longname": "", "homepage": "", "description": ""}, 

1119 "roles": [ 

1120 { 

1121 "id": 2, 

1122 "role": "resource provider", 

1123 "status": "active", 

1124 "contact": { 

1125 "id": 4, 

1126 "organisation": { 

1127 "id": 1, 

1128 "name": "UBA", 

1129 "longname": "Umweltbundesamt", 

1130 "kind": "government", 

1131 "city": "Dessau-Roßlau", 

1132 "postcode": "06844", 

1133 "street_address": "Wörlitzer Platz 1", 

1134 "country": "Germany", 

1135 "homepage": "https://www.umweltbundesamt.de", 

1136 "contact_url": "mailto:immission@uba.de", 

1137 }, 

1138 }, 

1139 }, 

1140 { 

1141 "id": 3, 

1142 "role": "principal investigator", 

1143 "status": "active", 

1144 "contact": { 

1145 "id": 3, 

1146 "person": { 

1147 "email": "s.schroeder@fz-juelich.de", 

1148 "id": 3, 

1149 "isprivate": False, 

1150 "name": "Sabine Schröder", 

1151 "orcid": "0000-0002-0309-8010", 

1152 "phone": "+49-2461-61-6397", 

1153 }, 

1154 }, 

1155 } 

1156 ], 

1157 }] 

1158 assert response.json() == expected_resp 

1159 

1160 def test_search_complex(self, client, db): 

1161 response = client.get("/search/a?id=1+id=2-id=2") 

1162 expected_status_code = 200 

1163 assert response.status_code == expected_status_code 

1164 expected_resp = [ 

1165 { 

1166 "id": 1, 

1167 "label": "CMA", 

1168 "order": 1, 

1169 "sampling_frequency": "hourly", 

1170 "aggregation": "mean", 

1171 "data_start_date": "2003-09-07T15:30:00+00:00", 

1172 "data_end_date": "2016-12-31T14:30:00+00:00", 

1173 "data_origin": "instrument", 

1174 "data_origin_type": "measurement", 

1175 "provider_version": "N/A", 

1176 "sampling_height": 7.0, 

1177 "additional_metadata": {"original_units": "ppb"}, 

1178 "doi": "", 

1179 "coverage": -1.0, 

1180 "station": { 

1181 "id": 2, 

1182 "codes": ["SDZ54421"], 

1183 "name": "Shangdianzi", 

1184 "coordinates": {"lat": 40.65, "lng": 117.106, "alt": 293.9}, 

1185 "coordinate_validation_status": "not checked", 

1186 "country": "China", 

1187 "state": "Beijing Shi", 

1188 "type": "unknown", 

1189 "type_of_area": "unknown", 

1190 "timezone": "Asia/Shanghai", 

1191 "additional_metadata": {"add_type": "nature reservation"}, 

1192 "aux_images": [], 

1193 "aux_docs": [], 

1194 "aux_urls": [], 

1195 "globalmeta": { 

1196 "mean_topography_srtm_alt_90m_year1994": -999.0, 

1197 "mean_topography_srtm_alt_1km_year1994": -999.0, 

1198 "max_topography_srtm_relative_alt_5km_year1994": -999.0, 

1199 "min_topography_srtm_relative_alt_5km_year1994": -999.0, 

1200 "stddev_topography_srtm_relative_alt_5km_year1994": -999.0, 

1201 "climatic_zone_year2016": "6 (warm temperate dry)", 

1202 "htap_region_tier1_year2010": "11 (MDE Middle East: S. Arabia, Oman, etc, Iran, Iraq)", 

1203 "dominant_landcover_year2012": "11 (Cropland, rainfed, herbaceous cover)", 

1204 "landcover_description_25km_year2012": "", 

1205 "dominant_ecoregion_year2017": "-1 (undefined)", 

1206 "ecoregion_description_25km_year2017": "", 

1207 "distance_to_major_road_year2020": -999.0, 

1208 "mean_stable_nightlights_1km_year2013": -999.0, 

1209 "mean_stable_nightlights_5km_year2013": -999.0, 

1210 "max_stable_nightlights_25km_year2013": -999.0, 

1211 "max_stable_nightlights_25km_year1992": -999.0, 

1212 "mean_population_density_250m_year2015": -1.0, 

1213 "mean_population_density_5km_year2015": -1.0, 

1214 "max_population_density_25km_year2015": -1.0, 

1215 "mean_population_density_250m_year1990": -1.0, 

1216 "mean_population_density_5km_year1990": -1.0, 

1217 "max_population_density_25km_year1990": -1.0, 

1218 "mean_nox_emissions_10km_year2015": -999.0, 

1219 "mean_nox_emissions_10km_year2000": -999.0, 

1220 "toar1_category": "unclassified", 

1221 "toar2_category": "suburban" 

1222 }, 

1223 "changelog": [ 

1224 { 

1225 "datetime": "2023-07-15T19:27:09.463245+00:00", 

1226 "description": "station created", 

1227 "old_value": "", 

1228 "new_value": "", 

1229 "station_id": 2, 

1230 "author_id": 1, 

1231 "type_of_change": "created", 

1232 } 

1233 ], 

1234 }, 

1235 "variable": { 

1236 "name": "toluene", 

1237 "longname": "toluene", 

1238 "displayname": "Toluene", 

1239 "cf_standardname": "mole_fraction_of_toluene_in_air", 

1240 "units": "nmol mol-1", 

1241 "chemical_formula": "C7H8", 

1242 "id": 7, 

1243 }, 

1244 "programme": {"id": 0, "name": "", "longname": "", "homepage": "", "description": ""}, 

1245 "roles": [ 

1246 { 

1247 "id": 2, 

1248 "role": "resource provider", 

1249 "status": "active", 

1250 "contact": { 

1251 "id": 4, 

1252 "organisation": { 

1253 "id": 1, 

1254 "name": "UBA", 

1255 "longname": "Umweltbundesamt", 

1256 "kind": "government", 

1257 "city": "Dessau-Roßlau", 

1258 "postcode": "06844", 

1259 "street_address": "Wörlitzer Platz 1", 

1260 "country": "Germany", 

1261 "homepage": "https://www.umweltbundesamt.de", 

1262 "contact_url": "mailto:immission@uba.de", 

1263 }, 

1264 }, 

1265 }, 

1266 { 

1267 "id": 3, 

1268 "role": "principal investigator", 

1269 "status": "active", 

1270 "contact": { 

1271 "id": 3, 

1272 "person": { 

1273 "email": "s.schroeder@fz-juelich.de", 

1274 "id": 3, 

1275 "isprivate": False, 

1276 "name": "Sabine Schröder", 

1277 "orcid": "0000-0002-0309-8010", 

1278 "phone": "+49-2461-61-6397", 

1279 }, 

1280 }, 

1281 } 

1282 ], 

1283 }] 

1284 assert response.json() == expected_resp 

1285 

1286 def test_inconsistent_fields(self, client, db): 

1287 response = client.get("/search/a?fields=id+fields=role") 

1288 expected_status_code = 400 

1289 assert response.status_code == expected_status_code 

1290 

1291 def test_consistent_fields(self, client, db): 

1292 response = client.get("/search/a?fields=id+fields=id") 

1293 expected_status_code = 200 

1294 assert response.status_code == expected_status_code 

1295 expected_resp = [{'id': 2}, {'id': 30890}, {'id': 18763}, {'id': 1}, {'id': 434870}] 

1296 set_expected_resp = {json.dumps(item, sort_keys=True) for item in expected_resp} 

1297 set_response = {json.dumps(item, sort_keys=True) for item in response.json()} 

1298 assert set_response == set_expected_resp