Coverage for tests/test_variables.py: 100%
101 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-03 20:32 +0000
« 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
4import pytest
5import json
6from toardb.variables.models import Variable
7# Required imports 'create_test_database'
8from toardb.test_base import (
9 client,
10 get_test_db,
11 create_test_database,
12 url,
13 get_test_engine,
14 test_db_session as db,
15)
17class TestApps:
18 def setup(self):
19 self.application_url = "/variables/"
21 """Set up all the data before each test
22 If you want the setup only once (per test module),
23 the scope argument is not working in the expected way, as discussed here:
24 https://stackoverflow.com/questions/45817153/py-test-fixture-use-function-fixture-in-scope-fixture
25 """
26 @pytest.fixture(autouse=True)
27 def setup_db_data(self, db):
28 # id_seq will not be reset automatically between tests!
29 _db_conn = get_test_engine()
30 fake_conn = _db_conn.raw_connection()
31 fake_cur = fake_conn.cursor()
32 fake_cur.execute("ALTER SEQUENCE variables_id_seq RESTART WITH 1")
33 fake_conn.commit()
34 infilename = "tests/fixtures/variables/variables.json"
35 with open(infilename, encoding="utf-8") as f:
36 metajson=json.load(f)
37 for entry in metajson:
38 new_variable = Variable(**entry)
39 db.add(new_variable)
40 db.commit()
41 db.refresh(new_variable)
44 def test_get_variables(self, client, db):
45 response = client.get("/variables/?limit=3")
46 expected_status_code = 200
47 assert response.status_code == expected_status_code
48 expected_resp = [{'name': 'benzene', 'longname': 'benzene', 'displayname': 'Benzene',
49 'cf_standardname': 'mole_fraction_of_benzene_in_air',
50 'units': 'nmol mol-1', 'chemical_formula': 'C6H6', 'id': 1},
51 {'name': 'co', 'longname': 'carbon monoxide', 'displayname': 'CO',
52 'cf_standardname': 'mole_fraction_of_carbon_monoxide_in_air',
53 'units': 'nmol mol-1', 'chemical_formula': 'CO', 'id': 2},
54 {'name': 'no', 'longname': 'nitrogen monoxide', 'displayname': 'NO',
55 'cf_standardname': 'mole_fraction_of_nitrogen_monoxide_in_air',
56 'units': 'nmol mol-1', 'chemical_formula': 'NO', 'id': 3}]
57 assert response.json() == expected_resp
60 def test_get_all_variables_default_limit(self, client, db):
61 response = client.get("/variables/")
62 expected_status_code = 200
63 assert response.status_code == expected_status_code
64 expected_resp = [{'name': 'benzene', 'longname': 'benzene', 'displayname': 'Benzene',
65 'cf_standardname': 'mole_fraction_of_benzene_in_air',
66 'units': 'nmol mol-1', 'chemical_formula': 'C6H6', 'id': 1},
67 {'name': 'co', 'longname': 'carbon monoxide', 'displayname': 'CO',
68 'cf_standardname': 'mole_fraction_of_carbon_monoxide_in_air',
69 'units': 'nmol mol-1', 'chemical_formula': 'CO', 'id': 2},
70 {'name': 'no', 'longname': 'nitrogen monoxide', 'displayname': 'NO',
71 'cf_standardname': 'mole_fraction_of_nitrogen_monoxide_in_air',
72 'units': 'nmol mol-1', 'chemical_formula': 'NO', 'id': 3},
73 {'name': 'pm1', 'longname': 'particles up to 1 µm diameter', 'displayname': 'PM 1',
74 'cf_standardname': 'mass_concentration_of_pm1_ambient_aerosol_in_air', 'units': 'µg m-3', 'chemical_formula': '', 'id': 4},
75 {'name': 'o3', 'longname': 'ozone', 'displayname': 'Ozone',
76 'cf_standardname': 'mole_fraction_of_ozone_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'O3', 'id': 5},
77 {'name': 'no2', 'longname': 'nitrogen dioxide', 'displayname': 'NO2',
78 'cf_standardname': 'mole_fraction_of_nitrogen_dioxide_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'NO2', 'id': 6},
79 {'name': 'toluene', 'longname': 'toluene', 'displayname': 'Toluene',
80 'cf_standardname': 'mole_fraction_of_toluene_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'C7H8', 'id': 7},
81 {'name': 'so2', 'longname': 'Sulphur dioxide', 'displayname': 'SO2',
82 'cf_standardname': 'mole_fraction_of_sulfur_dioxide_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'SO2', 'id': 8},
83 {'name': 'ethane', 'longname': 'Ethane', 'displayname': 'Ethane',
84 'cf_standardname': 'mole_fraction_of_ethane_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'C2H6', 'id': 9},
85 {'name': 'propane', 'longname': 'Propane', 'displayname': 'Propane',
86 'cf_standardname': 'mole_fraction_of_propane_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'C3H8', 'id': 10}]
87 assert response.json() == expected_resp
89 def test_get_all_variables_unlimited(self, client, db):
90 response = client.get("/variables/?limit=None")
91 expected_status_code = 200
92 assert response.status_code == expected_status_code
93 expected_resp = [{'name': 'benzene', 'longname': 'benzene', 'displayname': 'Benzene',
94 'cf_standardname': 'mole_fraction_of_benzene_in_air',
95 'units': 'nmol mol-1', 'chemical_formula': 'C6H6', 'id': 1},
96 {'name': 'co', 'longname': 'carbon monoxide', 'displayname': 'CO',
97 'cf_standardname': 'mole_fraction_of_carbon_monoxide_in_air',
98 'units': 'nmol mol-1', 'chemical_formula': 'CO', 'id': 2},
99 {'name': 'no', 'longname': 'nitrogen monoxide', 'displayname': 'NO',
100 'cf_standardname': 'mole_fraction_of_nitrogen_monoxide_in_air',
101 'units': 'nmol mol-1', 'chemical_formula': 'NO', 'id': 3},
102 {'name': 'pm1', 'longname': 'particles up to 1 µm diameter', 'displayname': 'PM 1',
103 'cf_standardname': 'mass_concentration_of_pm1_ambient_aerosol_in_air', 'units': 'µg m-3', 'chemical_formula': '', 'id': 4},
104 {'name': 'o3', 'longname': 'ozone', 'displayname': 'Ozone',
105 'cf_standardname': 'mole_fraction_of_ozone_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'O3', 'id': 5},
106 {'name': 'no2', 'longname': 'nitrogen dioxide', 'displayname': 'NO2',
107 'cf_standardname': 'mole_fraction_of_nitrogen_dioxide_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'NO2', 'id': 6},
108 {'name': 'toluene', 'longname': 'toluene', 'displayname': 'Toluene',
109 'cf_standardname': 'mole_fraction_of_toluene_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'C7H8', 'id': 7},
110 {'name': 'so2', 'longname': 'Sulphur dioxide', 'displayname': 'SO2',
111 'cf_standardname': 'mole_fraction_of_sulfur_dioxide_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'SO2', 'id': 8},
112 {'name': 'ethane', 'longname': 'Ethane', 'displayname': 'Ethane',
113 'cf_standardname': 'mole_fraction_of_ethane_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'C2H6', 'id': 9},
114 {'name': 'propane', 'longname': 'Propane', 'displayname': 'Propane',
115 'cf_standardname': 'mole_fraction_of_propane_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'C3H8', 'id': 10},
116 {'name': 'ox', 'longname': 'Ox', 'displayname': 'Ox',
117 'cf_standardname': '', 'units': 'nmol mol-1', 'chemical_formula': '', 'id': 11},
118 {'name': 'aswdir', 'longname': 'direct downward sw radiation', 'displayname': 'downward sw radiation',
119 'cf_standardname': 'surface_downwelling_shortwave_flux_in_air', 'units': 'W/m**2', 'chemical_formula': '', 'id': 12},
120 {'name': 'pm10', 'longname': 'particles up to 10 µm diameter', 'displayname': 'PM 10',
121 'cf_standardname': 'mass_concentration_of_pm10_ambient_aerosol_in_air', 'units': 'µg m-3', 'chemical_formula': '', 'id': 13},
122 {'name': 'rn', 'longname': 'radon', 'displayname': 'Radon',
123 'cf_standardname': '', 'units': 'mBq m-3', 'chemical_formula': 'Rn', 'id': 14},
124 {'name': 'mpxylene', 'longname': 'm,p-xylene', 'displayname': 'm,p-Xylene',
125 'cf_standardname': '', 'units': 'nmol mol-1', 'chemical_formula': 'C8H10', 'id': 15},
126 {'name': 'oxylene', 'longname': 'o-xylene', 'displayname': 'o-Xylene',
127 'cf_standardname': '', 'units': 'nmol mol-1', 'chemical_formula': 'C8H10', 'id': 16},
128 {'name': 'ch4', 'longname': 'Methane', 'displayname': 'CH4',
129 'cf_standardname': 'mole_fraction_of_methane_in_air', 'units': 'nmol mol-1', 'chemical_formula': 'CH4', 'id': 17},
130 {'name': 'wdir', 'longname': 'wind direction', 'displayname': 'Wind direction',
131 'cf_standardname': 'wind_from_direction', 'units': 'degrees', 'chemical_formula': '', 'id': 18},
132 {'name': 'pm2p5', 'longname': 'particles up to 2.5 µm diameter', 'displayname': 'PM 2.5',
133 'cf_standardname': 'mass_concentration_of_pm2p5_ambient_aerosol_in_air', 'units': 'µg m-3', 'chemical_formula': '', 'id': 19},
134 {'name': 'nox', 'longname': 'reactive nitrogen oxides (NO+NO2)', 'displayname': 'NOx',
135 'cf_standardname': 'mole_fraction_of_nox_expressed_as_nitrogen_in_air', 'units': 'nmol mol-1', 'chemical_formula': '', 'id': 20},
136 {'name': 'temp', 'longname': 'atmospheric temperature', 'displayname': 'Temperature',
137 'cf_standardname': 'air_temperature', 'units': 'degC', 'chemical_formula': '', 'id': 21},
138 {'name': 'wspeed', 'longname': 'wind speed', 'displayname': 'Wind speed',
139 'cf_standardname': 'wind_speed', 'units': 'm s-1', 'chemical_formula': '', 'id': 22},
140 {'name': 'press', 'longname': 'atmospheric pressure', 'displayname': 'Pressure',
141 'cf_standardname': 'air_pressure', 'units': 'hPa', 'chemical_formula': '', 'id': 23},
142 {'name': 'cloudcover', 'longname': 'total cloud cover', 'displayname': 'total cloud cover',
143 'cf_standardname': 'cloud_area_fraction', 'units': '%', 'chemical_formula': '', 'id': 24},
144 {'name': 'pblheight', 'longname': 'height of PBL', 'displayname': 'PBL height',
145 'cf_standardname': 'atmosphere_boundary_layer_thickness', 'units': 'm', 'chemical_formula': '', 'id': 25},
146 {'name': 'relhum', 'longname': 'relative humidity', 'displayname': 'relative humidity',
147 'cf_standardname': 'relative_humidity', 'units': '%', 'chemical_formula': '', 'id': 26},
148 {'name': 'totprecip', 'longname': 'total precipitation', 'displayname': 'total precipitation',
149 'cf_standardname': 'precipitation_amount', 'units': 'kg m-2', 'chemical_formula': '', 'id': 27},
150 {'name': 'u', 'longname': 'u-component (zonal) of wind', 'displayname': 'U',
151 'cf_standardname': 'x_wind', 'units': 'm s-1', 'chemical_formula': '', 'id': 28},
152 {'name': 'v', 'longname': 'v-component (meridional) of wind', 'displayname': 'V',
153 'cf_standardname': 'y_wind', 'units': 'm s-1', 'chemical_formula': '', 'id': 29},
154 {'name': 'albedo', 'longname': 'albedo', 'displayname': 'albedo',
155 'cf_standardname': 'surface_albedo', 'units': '%', 'chemical_formula': '', 'id': 30},
156 {'name': 'aswdifu', 'longname': 'diffuse upward sw radiation', 'displayname': 'upward sw radiation',
157 'cf_standardname': '', 'units': 'W/m**2', 'chemical_formula': '', 'id': 31},
158 {'name': 'humidity', 'longname': 'atmospheric humidity', 'displayname': 'Humidity',
159 'cf_standardname': 'specific_humidity', 'units': 'g kg-1', 'chemical_formula': '', 'id': 32},
160 {'name': 'irradiance', 'longname': 'global surface irradiance', 'displayname': 'solar irradiance',
161 'cf_standardname': '', 'units': 'W m-2', 'chemical_formula': '', 'id': 33}]
162 assert response.json() == expected_resp
165 def test_get_all_variables_using_fields(self, client, db):
166 response = client.get("/variables/?limit=None&fields=name,units")
167 expected_status_code = 200
168 assert response.status_code == expected_status_code
169 expected_resp = [{'name': 'benzene', 'units': 'nmol mol-1'},
170 {'name': 'co', 'units': 'nmol mol-1'},
171 {'name': 'no', 'units': 'nmol mol-1'},
172 {'name': 'pm1', 'units': 'µg m-3'},
173 {'name': 'o3', 'units': 'nmol mol-1'},
174 {'name': 'no2', 'units': 'nmol mol-1'},
175 {'name': 'toluene', 'units': 'nmol mol-1'},
176 {'name': 'so2', 'units': 'nmol mol-1'},
177 {'name': 'ethane', 'units': 'nmol mol-1'},
178 {'name': 'propane', 'units': 'nmol mol-1'},
179 {'name': 'ox', 'units': 'nmol mol-1'},
180 {'name': 'aswdir', 'units': 'W/m**2'},
181 {'name': 'pm10', 'units': 'µg m-3'},
182 {'name': 'rn', 'units': 'mBq m-3'},
183 {'name': 'mpxylene', 'units': 'nmol mol-1'},
184 {'name': 'oxylene', 'units': 'nmol mol-1'},
185 {'name': 'ch4', 'units': 'nmol mol-1'},
186 {'name': 'wdir', 'units': 'degrees'},
187 {'name': 'pm2p5', 'units': 'µg m-3'},
188 {'name': 'nox', 'units': 'nmol mol-1'},
189 {'name': 'temp', 'units': 'degC'},
190 {'name': 'wspeed', 'units': 'm s-1'},
191 {'name': 'press', 'units': 'hPa'},
192 {'name': 'cloudcover', 'units': '%'},
193 {'name': 'pblheight', 'units': 'm'},
194 {'name': 'relhum', 'units': '%'},
195 {'name': 'totprecip', 'units': 'kg m-2'},
196 {'name': 'u', 'units': 'm s-1'},
197 {'name': 'v', 'units': 'm s-1'},
198 {'name': 'albedo', 'units': '%'},
199 {'name': 'aswdifu', 'units': 'W/m**2'},
200 {'name': 'humidity', 'units': 'g kg-1'},
201 {'name': 'irradiance', 'units': 'W m-2'}]
202 assert response.json() == expected_resp
205 def test_get_all_variables_wrong_fieldname(self, client, db):
206 response = client.get("/variables/?limit=None&fields=name,units,bla")
207 expected_status_code = 400
208 assert response.status_code == expected_status_code
209 expected_resp = "Wrong field given: bla"
210 assert response.json() == expected_resp
213 def test_get_special(self, client, db):
214 response = client.get("/variables/id/2")
215 expected_status_code = 200
216 assert response.status_code == expected_status_code
217 expected_resp = {'name': 'co', 'longname': 'carbon monoxide', 'displayname': 'CO',
218 'cf_standardname': 'mole_fraction_of_carbon_monoxide_in_air',
219 'units': 'nmol mol-1', 'chemical_formula': 'CO', 'id': 2}
220 assert response.json() == expected_resp
223 def test_get_special_out_of_index(self, client, db):
224 response = client.get("/variables/id/99")
225 expected_status_code = 404
226 assert response.status_code == expected_status_code
227 expected_resp = {"detail":"Variable not found."}
228 assert response.json() == expected_resp
231 def test_get_special_by_name(self, client, db):
232 response = client.get("/variables/CO")
233 expected_status_code = 200
234 assert response.status_code == expected_status_code
235 expected_resp = {'name': 'co', 'longname': 'carbon monoxide', 'displayname': 'CO',
236 'cf_standardname': 'mole_fraction_of_carbon_monoxide_in_air',
237 'units': 'nmol mol-1', 'chemical_formula': 'CO', 'id': 2}
238 assert response.json() == expected_resp
241 def test_get_special_by_units(self, client, db):
242 response = client.get("/variables/?units=nmol mol-1")
243 expected_status_code = 200
244 assert response.status_code == expected_status_code
245 expected_resp = [{'name': 'benzene', 'longname': 'benzene', 'displayname': 'Benzene',
246 'cf_standardname': 'mole_fraction_of_benzene_in_air', 'units': 'nmol mol-1',
247 'chemical_formula': 'C6H6', 'id': 1},
248 {'name': 'co', 'longname': 'carbon monoxide', 'displayname': 'CO',
249 'cf_standardname': 'mole_fraction_of_carbon_monoxide_in_air', 'units': 'nmol mol-1',
250 'chemical_formula': 'CO', 'id': 2},
251 {'name': 'no', 'longname': 'nitrogen monoxide', 'displayname': 'NO',
252 'cf_standardname': 'mole_fraction_of_nitrogen_monoxide_in_air',
253 'units': 'nmol mol-1', 'chemical_formula': 'NO', 'id': 3},
254 {'name': 'o3', 'longname': 'ozone', 'displayname': 'Ozone',
255 'cf_standardname': 'mole_fraction_of_ozone_in_air', 'units': 'nmol mol-1',
256 'chemical_formula': 'O3', 'id': 5},
257 {'name': 'no2', 'longname': 'nitrogen dioxide', 'displayname': 'NO2',
258 'cf_standardname': 'mole_fraction_of_nitrogen_dioxide_in_air', 'units': 'nmol mol-1',
259 'chemical_formula': 'NO2', 'id': 6},
260 {'name': 'toluene', 'longname': 'toluene', 'displayname': 'Toluene',
261 'cf_standardname': 'mole_fraction_of_toluene_in_air', 'units': 'nmol mol-1',
262 'chemical_formula': 'C7H8', 'id': 7},
263 {'name': 'so2', 'longname': 'Sulphur dioxide', 'displayname': 'SO2',
264 'cf_standardname': 'mole_fraction_of_sulfur_dioxide_in_air', 'units': 'nmol mol-1',
265 'chemical_formula': 'SO2', 'id': 8},
266 {'name': 'ethane', 'longname': 'Ethane', 'displayname': 'Ethane',
267 'cf_standardname': 'mole_fraction_of_ethane_in_air', 'units': 'nmol mol-1',
268 'chemical_formula': 'C2H6', 'id': 9},
269 {'name': 'propane', 'longname': 'Propane', 'displayname': 'Propane',
270 'cf_standardname': 'mole_fraction_of_propane_in_air', 'units': 'nmol mol-1',
271 'chemical_formula': 'C3H8', 'id': 10},
272 {'name': 'ox', 'longname': 'Ox', 'displayname': 'Ox',
273 'cf_standardname': '', 'units': 'nmol mol-1',
274 'chemical_formula': '', 'id': 11}]
275 assert response.json() == expected_resp
278 def test_get_special_by_name_not_existing(self, client, db):
279 response = client.get("/variables/sabinen")
280 expected_status_code = 404
281 assert response.status_code == expected_status_code
282 expected_resp = {"detail":"Variable not found."}
283 assert response.json() == expected_resp
286# def test_insert_new_without_credits(self):
287#? response = client.post("/variables/")
288# expected_status_code=401
289# assert response.status_code == expected_status_code
290#? expected_resp = ...
291# assert response.json() == expected_resp
295# def test_insert_new_wrong_credits(self):
296#? response = client.post("/variables/")
297# expected_status_code = 401
298# assert response.status_code == expected_status_code
299#? expected_resp = ...
300# assert response.json() == expected_resp
303 def test_insert_new(self, client, db):
304 response = client.post("/variables/",
305 json= {"name": "sabinene",
306 "longname": "sabinene",
307 "displayname": "Sabinene",
308 "cf_standardname": "mole_fraction_of_sabinene_in_air",
309 "units": "nmol mol-1",
310 "chemical_formula": "C10H16"}
311 )
312 expected_status_code = 200
313 assert response.status_code == expected_status_code
314 expected_resp = {'name': 'sabinene', 'longname': 'sabinene', 'displayname': 'Sabinene',
315 'cf_standardname': 'mole_fraction_of_sabinene_in_air',
316 'units': 'nmol mol-1', 'chemical_formula': 'C10H16', 'id': 34}
317 assert response.json() == expected_resp
320 def test_insert_new_again(self, client, db):
321 response = client.post("/variables/",
322 json= {"name": "sabinene",
323 "longname": "sabinene",
324 "displayname": "Sabinene",
325 "cf_standardname": "mole_fraction_of_sabinene_in_air",
326 "units": "nmol mol-1",
327 "chemical_formula": "C10H16"}
328 )
329 expected_status_code = 200
330 assert response.status_code == expected_status_code
331 expected_resp = {'name': 'sabinene', 'longname': 'sabinene', 'displayname': 'Sabinene',
332 'cf_standardname': 'mole_fraction_of_sabinene_in_air',
333 'units': 'nmol mol-1', 'chemical_formula': 'C10H16', 'id': 34}
334 assert response.json() == expected_resp
337 def test_insert_duplicate(self, client, db):
338 response = client.post("/variables/",
339 json= {"name": "benzene",
340 "longname": "benzene",
341 "displayname": "Benzene",
342 "cf_standardname": "mole_fraction_of_benzene_in_air",
343 "units": "nmol mol-1",
344 "chemical_formula": "C6H6"}
345 )
346 expected_status_code = 400
347 assert response.status_code == expected_status_code
348 expected_resp = {'detail': 'Variable already registered.'}
349 assert response.json() == expected_resp