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

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

2# SPDX-License-Identifier: MIT 

3 

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) 

16 

17class TestApps: 

18 def setup(self): 

19 self.application_url = "/variables/" 

20 

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) 

42 

43 

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 

58 

59 

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 

88 

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 

163 

164 

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 

203 

204 

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 

211 

212 

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 

221 

222 

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 

229 

230 

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 

239 

240 

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 

276 

277 

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 

284 

285 

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 

292 

293 

294 

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 

301 

302 

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 

318 

319 

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 

335 

336 

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