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
« 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
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
17class TestApps:
18 def setup(self):
19 self.application_url = "/controlled_vocabulary"
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)
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"]
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
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
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
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
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