Coverage for tests/test_toardb.py: 100%

57 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 

6# Required imports 'create_test_database' 

7from toardb.test_base import ( 

8 client, 

9 get_test_db, 

10 create_test_database, 

11 url, 

12 get_test_engine, 

13 test_db_session as db, 

14) 

15from toardb.stationmeta.models import StationmetaGlobalService 

16 

17class TestApps: 

18 def setup(self): 

19 self.application_url = "/controlled_vocabulary" 

20 

21 

22 @pytest.fixture(autouse=True) 

23 def setup_db_data(self, db): 

24 # id_seq will not be reset automatically between tests! 

25 _db_conn = get_test_engine() 

26 infilename = "tests/fixtures/stationmeta/stationmeta_global_services.json" 

27 with open(infilename) as f: 

28 metajson=json.load(f) 

29 for entry in metajson: 

30 new_stationmeta_global_service = StationmetaGlobalService(**entry) 

31 db.add(new_stationmeta_global_service) 

32 db.commit() 

33 db.refresh(new_stationmeta_global_service) 

34 

35 

36 

37 def test_get_controlled_vocabulary(self, client, db): 

38 response = client.get("/controlled_vocabulary") 

39 expected_status_code = 200 

40 assert response.status_code == expected_status_code 

41 expected_resp = {"Station Landcover Type": 

42 [[-1, 'Undefined', '-1 (undefined)'], 

43 [0, 'NoData', '0 (No Data)'], 

44 [10, 'CroplandRainfed', '10 (Cropland, rainfed)'], 

45 [11, 'CroplandRainfedHerbaceousCover', '11 (Cropland, rainfed, herbaceous cover)'], 

46 [12, 'CroplandRainfedTreeOrShrubCover', '12 (Cropland, rainfed, tree or shrub cover)'], 

47 [20, 'CroplandIrrigated', '20 (Cropland, irrigated or post-flooding)'], 

48 [30, 'MosaicCropland', '30 (Mosaic cropland (>50%) / natural vegetation (tree, shrub, herbaceous cover) (<50%))'], 

49 [40, 'MosaicNaturalVegetation', '40 (Mosaic natural vegetation (tree, shrub, herbaceous cover) (>50%) / cropland (<50%))'], 

50 [50, 'TreeBroadleavedEvergreenClosedToOpen', '50 (Tree cover, broadleaved, evergreen, closed to open (>15%))'], 

51 [60, 'TreeBroadleavedDeciduousClosedToOpen', '60 (Tree cover, broadleaved, deciduous, closed to open (>15%))'], 

52 [61, 'TreeBroadleavedDeciduousClosed', '61 (Tree cover, broadleaved, deciduous, closed (>40%))'], 

53 [62, 'TreeBroadleavedDeciduousOpen', '62 (Tree cover, broadleaved, deciduous, open (15-40%))'], 

54 [70, 'TreeNeedleleavedEvergreenClosedToOpen', '70 (Tree cover, needleleaved, evergreen, closed to open (>15%))'], 

55 [71, 'TreeNeedleleavedEvergreenClosed', '71 (Tree cover, needleleaved, evergreen, closed (>40%))'], 

56 [72, 'TreeNeedleleavedEvergreenOpen', '72 (Tree cover, needleleaved, evergreen, open (15-40%))'], 

57 [80, 'TreeNeedleleavedDeciduousClosedToOpen', '80 (Tree cover, needleleaved, deciduous, closed to open (>15%))'], 

58 [81, 'TreeNedleleavedDeciduousClosed', '81 (Tree cover, needleleaved, deciduous, closed (>40%))'], 

59 [82, 'TreeNeedleleavedDeciduousOpen', '82 (Tree cover, needleleaved, deciduous, open (15-40%))'], 

60 [90, 'TreeMixed', '90 (Tree cover, mixed leaf type (broadleaved and needleleaved))'], 

61 [100, 'MosaicTreeAndShrub', '100 (Mosaic tree and shrub (>50%) / herbaceous cover (<50%))'], 

62 [110, 'MosaicHerbaceous', '110 (Mosaic herbaceous cover (>50%) / tree and shrub (<50%))'], 

63 [120, 'Shrubland', '120 (Shrubland)'], 

64 [121, 'ShrublandEvergreen', '121 (Evergreen shrubland)'], 

65 [122, 'ShrublandDeciduous', '122 (Deciduous shrubland)'], 

66 [130, 'Grassland', '130 (Grassland)'], 

67 [140, 'LichensAndMosses', '140 (Lichens and mosses)'], 

68 [150, 'SparseVegetation', '150 (Sparse vegetation (tree, shrub, herbaceous cover) (<15%))'], 

69 [151, 'SparseTree', '151 (Sparse tree (<15%))'], 

70 [152, 'SparseShrub', '152 (Sparse shrub (<15%))'], 

71 [153, 'SparseHerbaceous', '153 (Sparse herbaceous cover (<15%))'], 

72 [160, 'TreeCoverFloodedFreshOrBrakishWater', '160 (Tree cover, flooded, fresh or brakish water)'], 

73 [170, 'TreeCoverFloodedSalineWater', '170 (Tree cover, flooded, saline water)'], 

74 [180, 'ShrubOrHerbaceousCoverFlooded', '180 (Shrub or herbaceous cover, flooded, fresh/saline/brakish water)'], 

75 [190, 'Urban', '190 (Urban areas)'], 

76 [200, 'BareAreas', '200 (Bare areas)'], 

77 [201, 'BareAreasConsolidated', '201 (Consolidated bare areas)'], 

78 [202, 'BareAreasUnconsolidated', '202 (Unconsolidated bare areas)'], 

79 [210, 'Water', '210 (Water bodies)'], 

80 [220, 'SnowAndIce', '220 (Permanent snow and ice)']], 

81 "Climatic Zone 2019": 

82 [[-1,"Undefined","-1 (undefined)"], 

83 [0,"Unclassified","0 (unclassified)"], 

84 [1, 'TropicalMontane', '1 (tropical montane)'], 

85 [2, 'TropicalWet', '2 (tropical wet)'], 

86 [3, 'TropicalMoist', '3 (tropical moist)'], 

87 [4, 'TropicalDry', '4 (tropical dry)'], 

88 [5, 'WarmTemperateMoist', '5 (warm temperate moist)'], 

89 [6, 'WarmTemperateDry', '6 (warm temperate dry)'], 

90 [7, 'CoolTemperateMoist', '7 (cool temperate moist)'], 

91 [8, 'CoolTemperateDry', '8 (cool temperate dry)'], 

92 [9, 'BorealMoist', '9 (boreal moist)'], 

93 [10, 'BorealDry', '10 (boreal dry)'], 

94 [11, 'PolarMoist', '11 (polar moist)'], 

95 [12, 'PolarDry', '12 (polar dry)']] } 

96 assert response.json()["Station Landcover Type"] == expected_resp["Station Landcover Type"] 

97 assert response.json()["Climatic Zone 2019"] == expected_resp["Climatic Zone 2019"] 

98 

99 

100 

101 def test_get_controlled_vocabulary_field(self, client, db): 

102 response = client.get("/controlled_vocabulary/Station Landcover Type") 

103 expected_status_code = 200 

104 assert response.status_code == expected_status_code 

105 expected_resp = [[-1, 'Undefined', '-1 (undefined)'], 

106 [0, 'NoData', '0 (No Data)'], 

107 [10, 'CroplandRainfed', '10 (Cropland, rainfed)'], 

108 [11, 'CroplandRainfedHerbaceousCover', '11 (Cropland, rainfed, herbaceous cover)'], 

109 [12, 'CroplandRainfedTreeOrShrubCover', '12 (Cropland, rainfed, tree or shrub cover)'], 

110 [20, 'CroplandIrrigated', '20 (Cropland, irrigated or post-flooding)'], 

111 [30, 'MosaicCropland', '30 (Mosaic cropland (>50%) / natural vegetation (tree, shrub, herbaceous cover) (<50%))'], 

112 [40, 'MosaicNaturalVegetation', '40 (Mosaic natural vegetation (tree, shrub, herbaceous cover) (>50%) / cropland (<50%))'], 

113 [50, 'TreeBroadleavedEvergreenClosedToOpen', '50 (Tree cover, broadleaved, evergreen, closed to open (>15%))'], 

114 [60, 'TreeBroadleavedDeciduousClosedToOpen', '60 (Tree cover, broadleaved, deciduous, closed to open (>15%))'], 

115 [61, 'TreeBroadleavedDeciduousClosed', '61 (Tree cover, broadleaved, deciduous, closed (>40%))'], 

116 [62, 'TreeBroadleavedDeciduousOpen', '62 (Tree cover, broadleaved, deciduous, open (15-40%))'], 

117 [70, 'TreeNeedleleavedEvergreenClosedToOpen', '70 (Tree cover, needleleaved, evergreen, closed to open (>15%))'], 

118 [71, 'TreeNeedleleavedEvergreenClosed', '71 (Tree cover, needleleaved, evergreen, closed (>40%))'], 

119 [72, 'TreeNeedleleavedEvergreenOpen', '72 (Tree cover, needleleaved, evergreen, open (15-40%))'], 

120 [80, 'TreeNeedleleavedDeciduousClosedToOpen', '80 (Tree cover, needleleaved, deciduous, closed to open (>15%))'], 

121 [81, 'TreeNedleleavedDeciduousClosed', '81 (Tree cover, needleleaved, deciduous, closed (>40%))'], 

122 [82, 'TreeNeedleleavedDeciduousOpen', '82 (Tree cover, needleleaved, deciduous, open (15-40%))'], 

123 [90, 'TreeMixed', '90 (Tree cover, mixed leaf type (broadleaved and needleleaved))'], 

124 [100, 'MosaicTreeAndShrub', '100 (Mosaic tree and shrub (>50%) / herbaceous cover (<50%))'], 

125 [110, 'MosaicHerbaceous', '110 (Mosaic herbaceous cover (>50%) / tree and shrub (<50%))'], 

126 [120, 'Shrubland', '120 (Shrubland)'], 

127 [121, 'ShrublandEvergreen', '121 (Evergreen shrubland)'], 

128 [122, 'ShrublandDeciduous', '122 (Deciduous shrubland)'], 

129 [130, 'Grassland', '130 (Grassland)'], 

130 [140, 'LichensAndMosses', '140 (Lichens and mosses)'], 

131 [150, 'SparseVegetation', '150 (Sparse vegetation (tree, shrub, herbaceous cover) (<15%))'], 

132 [151, 'SparseTree', '151 (Sparse tree (<15%))'], 

133 [152, 'SparseShrub', '152 (Sparse shrub (<15%))'], 

134 [153, 'SparseHerbaceous', '153 (Sparse herbaceous cover (<15%))'], 

135 [160, 'TreeCoverFloodedFreshOrBrakishWater', '160 (Tree cover, flooded, fresh or brakish water)'], 

136 [170, 'TreeCoverFloodedSalineWater', '170 (Tree cover, flooded, saline water)'], 

137 [180, 'ShrubOrHerbaceousCoverFlooded', '180 (Shrub or herbaceous cover, flooded, fresh/saline/brakish water)'], 

138 [190, 'Urban', '190 (Urban areas)'], 

139 [200, 'BareAreas', '200 (Bare areas)'], 

140 [201, 'BareAreasConsolidated', '201 (Consolidated bare areas)'], 

141 [202, 'BareAreasUnconsolidated', '202 (Unconsolidated bare areas)'], 

142 [210, 'Water', '210 (Water bodies)'], 

143 [220, 'SnowAndIce', '220 (Permanent snow and ice)']] 

144 assert response.json() == expected_resp 

145 

146 

147 def test_get_controlled_vocabulary_unknown_field(self, client, db): 

148 response = client.get("/controlled_vocabulary/Station Landuse Type") 

149 expected_status_code = 200 

150 assert response.status_code == expected_status_code 

151 expected_resp = "No controlled vocabulary found for 'Station Landuse Type'" 

152 assert response.json() == expected_resp 

153 

154 

155 def test_get_database_statistics(self, client, db): 

156 response = client.get("/database_statistics") 

157 expected_status_code = 200 

158 assert response.status_code == expected_status_code 

159 expected_resp = {'data records': 65637800808, 'stations': 23979, 'time-series': 432880, 'users': 0} 

160 assert response.json() == expected_resp 

161 

162 

163 def test_get_database_statistics_field(self, client, db): 

164 response = client.get("/database_statistics/stations") 

165 expected_status_code = 200 

166 assert response.status_code == expected_status_code 

167 expected_resp = 23979 

168 assert response.json() == expected_resp 

169 

170 

171 def test_get_geopeas_urls(self, client, db): 

172 response = client.get("/geopeas_urls") 

173 expected_status_code = 200 

174 assert response.status_code == expected_status_code 

175 expected_resp = [ 

176 { 

177 "service_url":"{base_url}/climatic_zone/?lat={lat}&lon={lon}", 

178 "variable_name":"climatic_zone_year2016" 

179 }, 

180 { 

181 "service_url":"{base_url}/major_road/?lat={lat}&lon={lon}", 

182 "variable_name":"distance_to_major_road_year2020" 

183 }, 

184 { 

185 "service_url":"{base_url}/population_density/?year=2015&lat={lat}&lon={lon}", 

186 "variable_name":"mean_population_density_250m_year2015" 

187 }, 

188 { 

189 "service_url":"{base_url}/population_density/?year=2015&lat={lat}&lon={lon}", 

190 "variable_name":"mean_population_density_5km_year2015" 

191 }, 

192 { 

193 "service_url":"{base_url}/population_density/?agg=max&radius=25000&year=2015&lat={lat}&lon={lon}", 

194 "variable_name":"max_population_density_25km_year2015" 

195 }, 

196 { 

197 "service_url":"{base_url}/population_density/?agg=mean&radius=250&year=1990&lat={lat}&lon={lon}", 

198 "variable_name":"mean_population_density_250m_year1990" 

199 }, 

200 { 

201 "service_url":"{base_url}/population_density/?agg=mean&radius=5000&year=1990&lat={lat}&lon={lon}", 

202 "variable_name":"mean_population_density_5km_year1990" 

203 }, 

204 { 

205 "service_url":"{base_url}/population_density/?agg=max&radius=25000&year=1990&lat={lat}&lon={lon}", 

206 "variable_name":"max_population_density_25km_year1990" 

207 }, 

208 { 

209 "service_url":"{base_url}/nox_emissions/?year=2015&lat={lat}&lon={lon}", 

210 "variable_name":"mean_nox_emissions_10km_year2015" 

211 }, 

212 { 

213 "service_url":"{base_url}/nox_emissions/?year=2000&lat={lat}&lon={lon}", 

214 "variable_name":"mean_nox_emissions_10km_year2000" 

215 }, 

216 { 

217 "service_url":"{base_url}/htap_region_tier1/?lat={lat}&country={country}", 

218 "variable_name":"htap_region_tier1_year2010" 

219 }, 

220 { 

221 "service_url":"{base_url}/ecoregion/?description=false&lat={lat}&lon={lon}", 

222 "variable_name":"dominant_ecoregion_year2017" 

223 }, 

224 { 

225 "service_url":"{base_url}/landcover/?year=2012&description=false&lat={lat}&lon={lon}", 

226 "variable_name":"dominant_landcover_year2012" 

227 }, 

228 { 

229 "service_url":"{base_url}/ecoregion/?description=true&radius=25000&lat={lat}&lon={lon}", 

230 "variable_name":"ecoregion_description_25km_year2017" 

231 }, 

232 { 

233 "service_url":"{base_url}/landcover/?year=2012&radius=25000&description=true&lat={lat}&lon={lon}", 

234 "variable_name":"landcover_description_25km_year2012" 

235 }, 

236 { 

237 "service_url":"{base_url}/topography_srtm/?relative=false&lat={lat}&lon={lon}", 

238 "variable_name":"mean_topography_srtm_alt_90m_year1994" 

239 }, 

240 { 

241 "service_url":"{base_url}/topography_srtm/?relative=false&agg=mean&radius=1000&lat={lat}&lon={lon}", 

242 "variable_name":"mean_topography_srtm_alt_1km_year1994" 

243 }, 

244 { 

245 "service_url":"{base_url}/topography_srtm/?relative=true&agg=max&radius=5000&lat={lat}&lon={lon}", 

246 "variable_name":"max_topography_srtm_relative_alt_5km_year1994" 

247 }, 

248 { 

249 "service_url":"{base_url}/topography_srtm/?relative=true&agg=min&radius=5000&lat={lat}&lon={lon}", 

250 "variable_name":"min_topography_srtm_relative_alt_5km_year1994" 

251 }, 

252 { 

253 "service_url":"{base_url}/topography_srtm/?relative=true&agg=stddev&radius=5000&lat={lat}&lon={lon}", 

254 "variable_name":"stddev_topography_srtm_relative_alt_5km_year1994" 

255 }, 

256 { 

257 "service_url":"{base_url}/stable_nightlights/?year=2013&lat={lat}&lon={lon}", 

258 "variable_name":"mean_stable_nightlights_1km_year2013" 

259 }, 

260 { 

261 "service_url":"{base_url}/stable_nightlights/?agg=mean&radius=5000&year=2013&lat={lat}&lon={lon}", 

262 "variable_name":"mean_stable_nightlights_5km_year2013" 

263 }, 

264 { 

265 "service_url":"{base_url}/stable_nightlights/?agg=max&radius=25000&year=2013&lat={lat}&lon={lon}", 

266 "variable_name":"max_stable_nightlights_25km_year2013" 

267 }, 

268 { 

269 "service_url":"{base_url}/stable_nightlights/?agg=max&radius=25000&year=1992&lat={lat}&lon={lon}", 

270 "variable_name":"max_stable_nightlights_25km_year1992" 

271 } 

272 ] 

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

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

275 assert set_response == set_expected_resp