diff --git a/pyproject.toml b/pyproject.toml index 1934212..c612708 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,6 +83,7 @@ dev = [ "responses", "bump-my-version", "jsonschema", + "pystac[validation]" ] [tool.pytest.ini_options] diff --git a/tests/schemas/datacube/v2.2.0.json b/tests/schemas/datacube/v2.2.0.json deleted file mode 100644 index c1bdc89..0000000 --- a/tests/schemas/datacube/v2.2.0.json +++ /dev/null @@ -1,622 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://stac-extensions.github.io/datacube/v2.2.0/schema.json", - "title": "Datacube Extension", - "description": "STAC Datacube Extension for STAC Items and STAC Collections.", - "oneOf": [ - { - "$comment": "This is the schema for STAC Items.", - "allOf": [ - { - "type": "object", - "required": [ - "type" - ], - "properties": { - "type": { - "const": "Feature" - } - } - }, - { - "$ref": "#/definitions/stac_extensions" - } - ], - "anyOf": [ - { - "type": "object", - "required": [ - "properties" - ], - "properties": { - "properties": { - "allOf": [ - { - "$ref": "#/definitions/require_field" - }, - { - "$ref": "#/definitions/fields" - } - ] - } - } - }, - { - "$comment": "This validates the fields in Item Assets.", - "required": [ - "assets" - ], - "properties": { - "assets": { - "type": "object", - "not": { - "additionalProperties": { - "not": { - "allOf": [ - { - "$ref": "#/definitions/require_field" - }, - { - "$ref": "#/definitions/fields" - } - ] - } - } - } - } - } - } - ] - }, - { - "$comment": "This is the schema for STAC Collections.", - "type": "object", - "allOf": [ - { - "required": [ - "type" - ], - "properties": { - "type": { - "const": "Collection" - } - } - }, - { - "$ref": "#/definitions/stac_extensions" - } - ], - "anyOf": [ - { - "$comment": "This is the schema for the top-level fields in a Collection.", - "allOf": [ - { - "$ref": "#/definitions/require_field" - }, - { - "$ref": "#/definitions/fields" - } - ] - }, - { - "$comment": "This validates the fields in Collection Assets.", - "required": [ - "assets" - ], - "properties": { - "assets": { - "type": "object", - "not": { - "additionalProperties": { - "not": { - "allOf": [ - { - "$ref": "#/definitions/require_field" - }, - { - "$ref": "#/definitions/fields" - } - ] - } - } - } - } - } - }, - { - "$comment": "This is the schema for the fields in Item Asset Definitions.", - "required": [ - "item_assets" - ], - "properties": { - "item_assets": { - "type": "object", - "not": { - "additionalProperties": { - "not": { - "allOf": [ - { - "$ref": "#/definitions/require_any_field" - }, - { - "$ref": "#/definitions/fields" - } - ] - } - } - } - } - } - }, - { - "$comment": "This is the schema for the fields in Summaries. By default, only checks the existance of the properties, but not the schema of the summaries.", - "required": [ - "summaries" - ], - "properties": { - "summaries": { - "$ref": "#/definitions/require_any_field" - } - } - } - ] - } - ], - "definitions": { - "stac_extensions": { - "type": "object", - "required": [ - "stac_extensions" - ], - "properties": { - "stac_extensions": { - "type": "array", - "contains": { - "const": "https://stac-extensions.github.io/datacube/v2.2.0/schema.json" - } - } - } - }, - "require_any_field": { - "$comment": "Please list all fields here so that we can force the existance of one of them in other parts of the schemas.", - "anyOf": [ - {"required": ["cube:dimensions"]}, - {"required": ["cube:variables"]} - ] - }, - "require_field": { - "required": [ - "cube:dimensions" - ] - }, - "fields": { - "$comment": "Add your new fields here. Don't require them here, do that above in the corresponding schema.", - "type": "object", - "properties": { - "cube:dimensions": { - "$ref": "#/definitions/cube:dimensions" - }, - "cube:variables": { - "$ref": "#/definitions/cube:variables" - } - }, - "patternProperties": { - "^(?!cube:)": {} - }, - "additionalProperties": false - }, - "cube:dimensions": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "$ref": "#/definitions/vector_dimension" - }, - { - "$ref": "#/definitions/horizontal_spatial_dimension" - }, - { - "$ref": "#/definitions/vertical_spatial_dimension" - }, - { - "$ref": "#/definitions/temporal_dimension" - }, - { - "$ref": "#/definitions/additional_dimension" - } - ] - } - }, - "cube:variables": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/variable" - } - }, - "additional_dimension": { - "title": "Additional Dimension Object", - "type": "object", - "anyOf": [ - { - "required": [ - "type", - "extent" - ] - }, - { - "required": [ - "type", - "values" - ] - } - ], - "not": { - "required": [ - "axis" - ] - }, - "properties": { - "type": { - "type": "string", - "not": { - "enum": [ - "spatial", - "geometry" - ] - } - }, - "description": { - "$ref": "#/definitions/description" - }, - "extent": { - "$ref": "#/definitions/extent_open" - }, - "values": { - "$ref": "#/definitions/values" - }, - "step": { - "$ref": "#/definitions/step" - }, - "unit": { - "$ref": "#/definitions/unit" - }, - "reference_system": { - "type": "string" - }, - "dimensions": { - "type": "array", - "items": { - "type": [ - "string" - ] - } - } - } - }, - "horizontal_spatial_dimension": { - "title": "Horizontal Spatial Raster Dimension Object", - "type": "object", - "required": [ - "type", - "axis", - "extent" - ], - "properties": { - "type": { - "$ref": "#/definitions/type_spatial" - }, - "axis": { - "$ref": "#/definitions/axis_xy" - }, - "description": { - "$ref": "#/definitions/description" - }, - "extent": { - "$ref": "#/definitions/extent_closed" - }, - "values": { - "$ref": "#/definitions/values_numeric" - }, - "step": { - "$ref": "#/definitions/step" - }, - "reference_system": { - "$ref": "#/definitions/reference_system_spatial" - } - } - }, - "vertical_spatial_dimension": { - "title": "Vertical Spatial Dimension Object", - "type": "object", - "anyOf": [ - { - "required": [ - "type", - "axis", - "extent" - ] - }, - { - "required": [ - "type", - "axis", - "values" - ] - } - ], - "properties": { - "type": { - "$ref": "#/definitions/type_spatial" - }, - "axis": { - "$ref": "#/definitions/axis_z" - }, - "description": { - "$ref": "#/definitions/description" - }, - "extent": { - "$ref": "#/definitions/extent_open" - }, - "values": { - "$ref": "#/definitions/values" - }, - "step": { - "$ref": "#/definitions/step" - }, - "unit": { - "$ref": "#/definitions/unit" - }, - "reference_system": { - "$ref": "#/definitions/reference_system_spatial" - } - } - }, - "vector_dimension": { - "title": "Spatial Vector Dimension Object", - "type": "object", - "required": [ - "type", - "bbox" - ], - "properties": { - "type": { - "type": "string", - "const": "geometry" - }, - "axes": { - "type": "array", - "uniqueItems": true, - "items": { - "type": "string", - "enum": [ - "x", - "y", - "z" - ] - } - }, - "description": { - "$ref": "#/definitions/description" - }, - "bbox": { - "title": "Spatial extent", - "type": "array", - "oneOf": [ - { - "minItems":4, - "maxItems":4 - }, - { - "minItems":6, - "maxItems":6 - } - ], - "items": { - "type": "number" - } - }, - "values": { - "type": "array", - "minItems": 1, - "items": { - "description": "WKT or Identifier", - "type": "string" - } - }, - "geometry_types": { - "type": "array", - "uniqueItems": true, - "items": { - "type": "string", - "enum": [ - "Point", - "MultiPoint", - "LineString", - "MultiLineString", - "Polygon", - "MultiPolygon", - "GeometryCollection" - ] - } - }, - "reference_system": { - "$ref": "#/definitions/reference_system_spatial" - } - } - }, - "temporal_dimension": { - "title": "Temporal Dimension Object", - "type": "object", - "required": [ - "type", - "extent" - ], - "not": { - "required": [ - "axis" - ] - }, - "properties": { - "type": { - "type": "string", - "const": "temporal" - }, - "description": { - "$ref": "#/definitions/description" - }, - "values": { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - }, - "extent": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "type": [ - "string", - "null" - ] - } - }, - "step": { - "type": [ - "string", - "null" - ] - } - } - }, - "variable": { - "title": "Variable Object", - "type": "object", - "required": [ - "dimensions" - ], - "properties": { - "variable_type": { - "type": "string", - "enum": [ - "data", - "auxiliary" - ] - }, - "description": { - "$ref": "#/definitions/description" - }, - "dimensions": { - "type": "array", - "items": { - "type": "string" - } - }, - "values": { - "type": "array", - "minItems": 1 - }, - "extent": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "type": [ - "string", - "number", - "null" - ] - } - }, - "unit": { - "$ref": "#/definitions/unit" - } - } - }, - "type_spatial": { - "type": "string", - "const": "spatial" - }, - "axis_xy": { - "type": "string", - "enum": [ - "x", - "y" - ] - }, - "axis_z": { - "type": "string", - "const": "z" - }, - "extent_closed": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "type": "number" - } - }, - "extent_open": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "type": [ - "number", - "null" - ] - } - }, - "values_numeric": { - "type": "array", - "minItems": 1, - "items": { - "type": "number" - } - }, - "values": { - "type": "array", - "minItems": 1, - "items": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ] - } - }, - "step": { - "type": [ - "number", - "null" - ] - }, - "unit": { - "type": "string" - }, - "reference_system_spatial": { - "oneOf": [ - { - "description": "WKT2", - "type": "string" - }, - { - "description": "EPSG code", - "type": "integer", - "minimum": 0 - }, - { - "$ref": "https://proj.org/schemas/v0.4/projjson.schema.json" - } - ], - "default": 4326 - }, - "description": { - "type": "string" - } - } -} diff --git a/tests/test_directory_loader.py b/tests/test_directory_loader.py index 361f123..88cf869 100644 --- a/tests/test_directory_loader.py +++ b/tests/test_directory_loader.py @@ -66,11 +66,18 @@ def test_directory_loader_populator_runner(prune_option: bool): assert request_mock.calls[1].request.path_url == "/stac/collections" assert request_mock.calls[1].request.body == file_contents["collection.json"] - assert request_mock.calls[2].request.path_url == f"/stac/collections/{base_col}/items" - assert request_mock.calls[2].request.body == file_contents["item-0.json"] + # NOTE: + # Because directory crawler users 'os.walk', loading order is OS-dependant. + # Since the order does not actually matter, consider item indices interchangeably. + req0_json = json.loads(request_mock.calls[2].request.body.decode()) + req0_item = req0_json["id"] + item0_idx, item1_idx = (2, 3) if "sample-0" in req0_item else (3, 2) - assert request_mock.calls[3].request.path_url == f"/stac/collections/{base_col}/items" - assert request_mock.calls[3].request.body == file_contents["item-1.json"] + assert request_mock.calls[item0_idx].request.path_url == f"/stac/collections/{base_col}/items" + assert request_mock.calls[item0_idx].request.body == file_contents["item-0.json"] + + assert request_mock.calls[item1_idx].request.path_url == f"/stac/collections/{base_col}/items" + assert request_mock.calls[item1_idx].request.body == file_contents["item-1.json"] if not prune_option: assert request_mock.calls[4].request.url == stac_host @@ -79,8 +86,15 @@ def test_directory_loader_populator_runner(prune_option: bool): assert request_mock.calls[5].request.path_url == "/stac/collections" assert request_mock.calls[5].request.body == file_contents["nested/collection.json"] - assert request_mock.calls[6].request.path_url == f"/stac/collections/{nested_col}/items" - assert request_mock.calls[6].request.body == file_contents["nested/item-0.json"] + # NOTE: + # Because directory crawler users 'os.walk', loading order is OS-dependant. + # Since the order does not actually matter, consider item indices interchangeably. + req0_json = json.loads(request_mock.calls[6].request.body.decode()) + req0_item = req0_json["id"] + item0_idx, item1_idx = (6, 7) if "sample-0" in req0_item else (7, 6) + + assert request_mock.calls[item0_idx].request.path_url == f"/stac/collections/{nested_col}/items" + assert request_mock.calls[item0_idx].request.body == file_contents["nested/item-0.json"] - assert request_mock.calls[7].request.path_url == f"/stac/collections/{nested_col}/items" - assert request_mock.calls[7].request.body == file_contents["nested/item-1.json"] + assert request_mock.calls[item1_idx].request.path_url == f"/stac/collections/{nested_col}/items" + assert request_mock.calls[item1_idx].request.body == file_contents["nested/item-1.json"]