Skip to content

Commit

Permalink
Split out requrementA5_2 and add test.
Browse files Browse the repository at this point in the history
  • Loading branch information
ways committed Nov 29, 2024
1 parent 201688d commit 0820ce4
Show file tree
Hide file tree
Showing 8 changed files with 355 additions and 34 deletions.
2 changes: 1 addition & 1 deletion sedr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def main() -> None:
util.test_functions["conformance"] += rodeoprofile.tests_conformance
util.test_functions["collection"] += rodeoprofile.tests_collection

# TODO: include profile tests based on conformance_url
# TODO: include profile tests based on conformance_url, https://github.com/metno/sedr/issues/32
# if rodeoprofile.conformance_url in conformance_json["conformsTo"]:
# util.args.rodeo_profile = True

Expand Down
26 changes: 25 additions & 1 deletion sedr/edreq12.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,30 @@ def requirementA11_1(jsondata: dict) -> tuple[bool, str]:
)


def requrementA5_2(jsondata: dict) -> tuple[bool, str]:
"""
OGC API - Environmental Data Retrieval Standard
Version: 1.2
Requirement A5.2
Check extent spatial bbox
"""

spec_url = f"{edr_root_url}#req_core_rc-bbox-definition"
collection_url = util.parse_collection_url(jsondata)

extent = None
extent = util.parse_spatial_bbox(jsondata)
if extent is None or len(extent) > 1 or not isinstance(extent, list):
return (
False,
f"Extent→spatial→bbox should be a list of bboxes with exactly "
f"one bbox in, found {len(extent)} in collection "
f"<{jsondata['id']}>. See {spec_url} for more info."
)
return True, f"Extent→spatial→bbox for collection is {extent}"


tests_landing: list[Callable[[dict], tuple[bool, str]]] = []
tests_conformance = [requirementA2_2_A5, requirementA11_1]
tests_collection: list[Callable[[dict], tuple[bool, str]]] = []
tests_collection = [requrementA5_2]
10 changes: 5 additions & 5 deletions sedr/preflight.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ def fetch_landing(url: str, timeout: int) -> tuple[bool, dict]:
landing_json = response.json()
except requests.exceptions.ConnectionError as err:
util.logger.error(
f"{__name__} fetch_landing Unable to get landing page <%s>.\n%s", url, err
f"Unable to get landing page <%s>.\n%s", url, err
)
return False, landing_json
except json.decoder.JSONDecodeError:
except json.decoder.JSONDecodeError as err:
util.logger.error(
f"{__name__} fetch_landing Landing page <%s> is not valid JSON.", url
f"fetch_landing Landing page <%s> is not valid JSON.\n%s", url, err
)
return False, landing_json
return True, landing_json
Expand All @@ -37,12 +37,12 @@ def fetch_conformance(url: str, timeout: int) -> tuple[bool, dict]:
conformance_json = response.json()
except requests.exceptions.ConnectionError as err:
util.logger.error(
f"{__name__} fetch_landing Unable to get landing page <%s>.\n%s", url, err
f"Unable to get conformance <%s>.\n%s", url, err
)
return False, conformance_json
except json.decoder.JSONDecodeError as err:
util.logger.error(
"Conformance page <%s> is not valid JSON:\n%s", conformance_url, err
"Conformance <%s> is not valid JSON:\n%s", conformance_url, err
)
return False, conformance_json
return True, conformance_json
Expand Down
31 changes: 4 additions & 27 deletions sedr/schemat.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,39 +108,16 @@ def test_edr_collections(case):

for collection_json in json.loads(response.text)["collections"]:
# Use url as key for extents. Remove trailing slash from url.
collection_url = collection_json["links"][0]["href"].rstrip("/")
collection_url = util.parse_collection_url(collection_json)

collection_ids[collection_url] = collection_json["id"]
util.logger.debug(
"test_collections found collection id %s", collection_json["id"]
)

extent = None
try:
extent = collection_json["extent"]["spatial"]["bbox"][
0
] # TODO: assuming only one extent

# Make sure bbox contains a list of extents, not just an extent
assert isinstance(
extent, list
), f"Extent→spatial→bbox should be a list of bboxes with one bbox in, not a single bbox. \
Example [[1, 2, 3, 4]]. Was <{collection_json['extent']['spatial']['bbox']}>. See {spec_ref} for more info."
extents[collection_url] = tuple(extent)

util.logger.debug(
"test_collections found extent for %s: %s", collection_url, extent
)
except AttributeError:
pass
except KeyError as err:
if err.args[0] == "extent":
raise AssertionError(
f"Unable to find extent for collection ID "
f"{collection_json['id']}. Found "
f"[{', '.join(collection_json.keys())}]. "
f"See {spec_ref} for more info."
) from err
# Validation done in requrementA5_2
extent = util.parse_spatial_bbox(collection_json)
extents[collection_url] = tuple(extent[0])

# Run edr, ogc, profile tests
for f in util.test_functions["collection"]:
Expand Down
33 changes: 33 additions & 0 deletions sedr/test_edreq12.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Unit tests for test_edreq12.py."""

import unittest
import json
import util
import edreq12 as edreq


class TestEDR(unittest.TestCase):
__version__ = "testversion"
util.args = util.parse_args(["--url", "https://example.com/"], __version__)
util.logger = util.set_up_logging(
args=util.args, logfile=util.args.log_file, version=__version__
)

def test_requrementA5_2(self):
# Good tests
jsondata = {}
with open("testdata/edrisobaric_collection.json", "r", encoding="utf-8") as f:
jsondata = json.load(f)
ok, _ = edreq.requrementA5_2(jsondata)
self.assertTrue(ok)

# Bad tests
jsondata = {}
with open("testdata/edrisobaric_collection_bad_bbox.json", "r", encoding="utf-8") as f:
jsondata = json.load(f)
ok, _ = edreq.requrementA5_2(jsondata)
self.assertFalse(ok)


if __name__ == "__main__":
unittest.main()
11 changes: 11 additions & 0 deletions sedr/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,14 @@ def locate_openapi_url(url: str, timeout: int) -> str:
def build_conformance_url(url: str) -> str:
"""Build the conformance URL based on main URL."""
return urljoin(url, "/conformance")


def parse_collection_url(jsondata: dict) -> str:
return jsondata["links"][0]["href"].rstrip("/")


def parse_spatial_bbox(jsondata: dict) -> list:
try:
return jsondata["extent"]["spatial"]["bbox"]
except (AttributeError, KeyError) as err:
return None
139 changes: 139 additions & 0 deletions testdata/edrisobaric_collection.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
{
"id": "weather_forecast",
"title": "IsobaricGRIB - GRIB files",
"description": "These files are used by Avinor ATM systems but possibly also of interest to others. They contain temperature and wind forecasts for a set of isobaric layers (i.e. altitudes having the same pressure). The files are (normally) produced every 6 hours. You can check the time when generated using the Last-Modified header or the `updated` key in `available`. These files are in GRIB2 format (filetype BIN) for the following regions: southern_norway Area 64.25N -1.45W 55.35S 14.51E, resolution .1 degrees? (km?) FIXME It includes every odd-numbered isobaric layer from 1 to 137 (in hundreds of feet?)",
"keywords": [
"position",
"data",
"api",
"temperature",
"wind",
"forecast",
"isobaric",
"weather_forecast"
],
"links": [
{
"href": "https://edrisobaric.k8s.met.no/collections/weather_forecast/",
"rel": "data"
},
{
"href": "https://data.norge.no/nlod/en/2.0/",
"rel": "license",
"type": "text/html"
},
{
"href": "https://creativecommons.org/licenses/by/4.0/",
"rel": "license",
"type": "text/html"
}
],
"extent": {
"spatial": {
"bbox": [
[
-1.4499999999999886,
55.35,
14.45,
64.25
]
],
"crs": "GEOGCS[\"Unknown\", DATUM[\"Unknown\", SPHEROID[\"WGS_1984\", 6378137.0, 298.257223563]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\", 0.017453], AXIS[\"Lon\", EAST], AXIS[\"Lat\", NORTH]]"
},
"temporal": {
"interval": [
[
"2024-11-28T18:00:00Z",
"2024-11-29T06:00:00Z"
]
],
"values": [
"2024-11-28T18:00:00+00:00"
],
"trs": "TIMECRS[\"DateTime\",TDATUM[\"Gregorian Calendar\"],CS[TemporalDateTime,1],AXIS[\"Time (T)\",future]"
},
"vertical": {
"interval": [
[
"850.0"
],
[
"100.0"
]
],
"values": [
"850.0",
"750.0",
"700.0",
"600.0",
"500.0",
"450.0",
"400.0",
"350.0",
"300.0",
"275.0",
"250.0",
"225.0",
"200.0",
"150.0",
"100.0"
],
"vrs": "Vertical Reference System: PressureLevel"
}
},
"data_queries": {
"position": {
"link": {
"href": "https://edrisobaric.k8s.met.no/collections/weather_forecast/position",
"rel": "data",
"variables": {
"query_type": "position",
"output_formats": [
"CoverageJSON"
],
"default_output_format": "CoverageJSON"
}
}
}
},
"crs": [
"CRS:84"
],
"parameter_names": {
"wind_from_direction": {
"type": "Parameter",
"id": "wind_from_direction",
"unit": {
"symbol": {
"value": "˚",
"type": "https://codes.wmo.int/common/unit/_degree_(angle)"
}
},
"observedProperty": {
"id": "http://vocab.met.no/CFSTDN/en/page/wind_from_direction",
"label": "Wind from direction"
}
},
"wind_speed": {
"type": "Parameter",
"observedProperty": {
"id": "http://vocab.met.no/CFSTDN/en/page/wind_speed",
"label": "Wind speed"
}
},
"Air temperature": {
"type": "Parameter",
"id": "Temperature",
"unit": {
"symbol": {
"value": "˚C",
"type": "https://codes.wmo.int/common/unit/_Cel"
}
},
"observedProperty": {
"id": "http://vocab.met.no/CFSTDN/en/page/air_temperature",
"label": "Air temperature"
}
}
}
}
Loading

0 comments on commit 0820ce4

Please sign in to comment.