diff --git a/eodag/api/collection.py b/eodag/api/collection.py index 48c020ad7b..e78e48b1f6 100644 --- a/eodag/api/collection.py +++ b/eodag/api/collection.py @@ -29,6 +29,7 @@ from stac_pydantic.collection import Extent, Provider, SpatialExtent, TimeInterval from stac_pydantic.links import Links +from eodag.api.product.metadata_mapping import NOT_AVAILABLE from eodag.types.queryables import CommonStacMetadata from eodag.types.stac_metadata import create_stac_metadata_model from eodag.utils import STAC_VERSION @@ -61,7 +62,7 @@ class Collection(BaseModel): id: str = Field() title: Optional[str] = Field(default=None) - description: Optional[str] = Field(default=None) + description: str = Field(default=NOT_AVAILABLE) extent: Extent = Field( default=Extent( spatial=SpatialExtent(bbox=[[-180.0, -90.0, 180.0, 90.0]]), # type: ignore @@ -75,7 +76,7 @@ class Collection(BaseModel): ), ) keywords: Optional[list[str]] = Field(default=None) - license: Optional[str] = Field(default=None) + license: str = Field(default="other") links: Optional[Links] = Field(default=None) providers: Optional[list[Provider]] = Field(default=None) diff --git a/tests/integration/test_core_search_results.py b/tests/integration/test_core_search_results.py index f0778b1efc..e1b25b95ec 100644 --- a/tests/integration/test_core_search_results.py +++ b/tests/integration/test_core_search_results.py @@ -37,6 +37,26 @@ mock, ) +STAC_SCHEMAS_DIR = os.path.join(TEST_RESOURCES_PATH, "stac", "schemas") + + +def _build_stac_schema_map(): + """Build a mapping of remote schema URLs to local file paths from $id fields.""" + schema_map = {} + for filename in os.listdir(STAC_SCHEMAS_DIR): + if not filename.endswith(".json"): + continue + filepath = os.path.join(STAC_SCHEMAS_DIR, filename) + with open(filepath) as f: + schema = json.load(f) + schema_id = schema.get("$id") + if schema_id: + schema_map[schema_id.rstrip("#")] = filepath + return schema_map + + +STAC_SCHEMA_MAP = _build_stac_schema_map() + class TestCoreSearchResults(EODagTestCase): def setUp(self): @@ -124,7 +144,10 @@ def test_core_serialize_search_results_with_filename(self): path = self.dag.serialize(self.search_result, filename=f.name) self.assertEqual(path, f.name) stac = stac_validator.StacValidate( - path, item_collection=True, links=True, assets=True + path, + item_collection=True, + core=True, + schema_map=STAC_SCHEMA_MAP, ) stac.validate_item_collection() for msg in stac.message: @@ -151,7 +174,11 @@ def test_core_serialize_search_results_with_filename(self): collection_path = tmpdir_path / f"{self.search_result[0].collection}.json" self.assertTrue(collection_path.exists()) # validate STAC collection - stac = stac_validator.StacValidate(str(collection_path)) + stac = stac_validator.StacValidate( + str(collection_path), + core=True, + schema_map=STAC_SCHEMA_MAP, + ) stac.run() for msg in stac.message: self.assertTrue(msg["valid_stac"], stac.message) @@ -180,7 +207,10 @@ def test_core_serialize_search_results_unknown_collection(self): path = self.dag.serialize(self.search_result, filename=f.name) self.assertEqual(path, f.name) stac = stac_validator.StacValidate( - path, item_collection=True, links=True, assets=True + path, + item_collection=True, + core=True, + schema_map=STAC_SCHEMA_MAP, ) stac.validate_item_collection() for msg in stac.message: @@ -192,11 +222,19 @@ def test_core_serialize_search_results_unknown_collection(self): self.assertTrue(collection1_path.exists()) self.assertTrue(collection2_path.exists()) # validate STAC collections - stac = stac_validator.StacValidate(str(collection1_path)) + stac = stac_validator.StacValidate( + str(collection1_path), + core=True, + schema_map=STAC_SCHEMA_MAP, + ) stac.run() for msg in stac.message: self.assertTrue(msg["valid_stac"], stac.message) - stac = stac_validator.StacValidate(str(collection2_path)) + stac = stac_validator.StacValidate( + str(collection2_path), + core=True, + schema_map=STAC_SCHEMA_MAP, + ) stac.run() for msg in stac.message: self.assertTrue(msg["valid_stac"], stac.message) diff --git a/tests/resources/stac/schemas/bands-v1.1.0.json b/tests/resources/stac/schemas/bands-v1.1.0.json new file mode 100644 index 0000000000..8060771e52 --- /dev/null +++ b/tests/resources/stac/schemas/bands-v1.1.0.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/bands.json", + "title": "Bands Field", + "type": "object", + "properties": { + "bands": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "allOf": [ + { + "$ref": "common.json" + } + ] + } + } + } +} diff --git a/tests/resources/stac/schemas/basics-v1.1.0.json b/tests/resources/stac/schemas/basics-v1.1.0.json new file mode 100644 index 0000000000..b92b7e292e --- /dev/null +++ b/tests/resources/stac/schemas/basics-v1.1.0.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/basics.json", + "title": "Basic Descriptive Fields", + "type": "object", + "properties": { + "title": { + "title": "Title", + "description": "A human-readable title describing the entity.", + "type": "string" + }, + "description": { + "title": "Description", + "description": "Detailed multi-line description to fully explain the entity.", + "type": "string", + "minLength": 1 + }, + "keywords": { + "title": "Keywords", + "description": "List of keywords describing the entity.", + "type": "array", + "items": { + "type": "string" + } + }, + "roles": { + "title": "Roles", + "type": "array", + "items": { + "type": "string" + } + } + } +} diff --git a/tests/resources/stac/schemas/collection-v1.1.0.json b/tests/resources/stac/schemas/collection-v1.1.0.json new file mode 100644 index 0000000000..02937041cf --- /dev/null +++ b/tests/resources/stac/schemas/collection-v1.1.0.json @@ -0,0 +1,230 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/collection-spec/json-schema/collection.json", + "title": "STAC Collection Specification", + "description": "This object represents Collections in a SpatioTemporal Asset Catalog.", + "allOf": [ + { + "$ref": "#/definitions/collection" + }, + { + "$ref": "../../item-spec/json-schema/common.json" + } + ], + "definitions": { + "collection": { + "title": "STAC Collection", + "description": "These are the fields specific to a STAC Collection.", + "type": "object", + "$comment": "title, description, keywords, providers and license is validated through the common metadata.", + "required": [ + "stac_version", + "type", + "id", + "description", + "license", + "extent", + "links" + ], + "properties": { + "stac_version": { + "title": "STAC version", + "type": "string", + "const": "1.1.0" + }, + "stac_extensions": { + "title": "STAC extensions", + "type": "array", + "uniqueItems": true, + "items": { + "title": "Reference to a JSON Schema", + "type": "string", + "format": "iri" + } + }, + "type": { + "title": "Type of STAC entity", + "const": "Collection" + }, + "id": { + "title": "Identifier", + "type": "string", + "minLength": 1 + }, + "extent": { + "title": "Extents", + "type": "object", + "required": [ + "spatial", + "temporal" + ], + "properties": { + "spatial": { + "title": "Spatial extent object", + "type": "object", + "required": [ + "bbox" + ], + "properties": { + "bbox": { + "title": "Spatial extents", + "type": "array", + "oneOf": [ + { + "minItems": 1, + "maxItems": 1 + }, + { + "minItems": 3 + } + ], + "items": { + "title": "Spatial extent", + "type": "array", + "oneOf": [ + { + "minItems": 4, + "maxItems": 4 + }, + { + "minItems": 6, + "maxItems": 6 + } + ], + "items": { + "type": "number" + } + } + } + } + }, + "temporal": { + "title": "Temporal extent object", + "type": "object", + "required": [ + "interval" + ], + "properties": { + "interval": { + "title": "Temporal extents", + "type": "array", + "minItems": 1, + "items": { + "title": "Temporal extent", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "pattern": "(\\+00:00|Z)$" + } + } + } + } + } + } + }, + "assets": { + "$ref": "../../item-spec/json-schema/item.json#/definitions/assets" + }, + "item_assets": { + "additionalProperties": { + "allOf": [ + { + "type": "object", + "minProperties": 2, + "properties": { + "href": { + "title": "Disallow href", + "not": {} + }, + "title": { + "title": "Asset title", + "type": "string" + }, + "description": { + "title": "Asset description", + "type": "string" + }, + "type": { + "title": "Asset type", + "type": "string" + }, + "roles": { + "title": "Asset roles", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "$ref": "../../item-spec/json-schema/common.json" + } + ] + } + }, + "links": { + "$ref": "../../item-spec/json-schema/item.json#/definitions/links" + }, + "summaries": { + "$ref": "#/definitions/summaries" + } + } + }, + "summaries": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "title": "JSON Schema", + "type": "object", + "minProperties": 1, + "allOf": [ + { + "$ref": "http://json-schema.org/draft-07/schema" + } + ] + }, + { + "title": "Range", + "type": "object", + "required": [ + "minimum", + "maximum" + ], + "properties": { + "minimum": { + "title": "Minimum value", + "type": [ + "number", + "string" + ] + }, + "maximum": { + "title": "Maximum value", + "type": [ + "number", + "string" + ] + } + } + }, + { + "title": "Set of values", + "type": "array", + "minItems": 1, + "items": { + "description": "For each field only the original data type of the property can occur (except for arrays), but we can't validate that in JSON Schema yet. See the sumamry description in the STAC specification for details." + } + } + ] + } + } + } +} diff --git a/tests/resources/stac/schemas/common-item-v1.1.0.json b/tests/resources/stac/schemas/common-item-v1.1.0.json new file mode 100644 index 0000000000..ae20499db2 --- /dev/null +++ b/tests/resources/stac/schemas/common-item-v1.1.0.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/common.json", + "title": "STAC Common Metadata", + "type": "object", + "description": "This schema includes all common metadata fields.", + "allOf": [ + { + "$ref": "basics.json" + }, + { + "$ref": "bands.json" + }, + { + "$ref": "datetime.json" + }, + { + "$ref": "data-values.json" + }, + { + "$ref": "instrument.json" + }, + { + "$ref": "licensing.json" + }, + { + "$ref": "provider.json" + } + ] +} diff --git a/tests/resources/stac/schemas/data-values-v1.1.0.json b/tests/resources/stac/schemas/data-values-v1.1.0.json new file mode 100644 index 0000000000..fd1efc8050 --- /dev/null +++ b/tests/resources/stac/schemas/data-values-v1.1.0.json @@ -0,0 +1,84 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/data-values.json#", + "title": "Fields related to data values", + "type": "object", + "properties": { + "data_type": { + "title": "Data type of the values", + "type": "string", + "enum": [ + "int8", + "int16", + "int32", + "int64", + "uint8", + "uint16", + "uint32", + "uint64", + "float16", + "float32", + "float64", + "cint16", + "cint32", + "cfloat32", + "cfloat64", + "other" + ] + }, + "nodata": { + "title": "No data value", + "oneOf": [ + { + "type": "number" + }, + { + "type": "string", + "enum": [ + "nan", + "inf", + "-inf" + ] + } + ] + }, + "statistics": { + "title": "Statistics", + "type": "object", + "minProperties": 1, + "properties": { + "minimum": { + "title": "Minimum value of all the data values", + "type": "number" + }, + "maximum": { + "title": "Maximum value of all the data values", + "type": "number" + }, + "mean": { + "title": "Mean value of all the data values", + "type": "number" + }, + "stddev": { + "title": "Standard deviation value of all the data values", + "type": "number" + }, + "count": { + "title": "Total number of all data values", + "type": "integer", + "minimum": 0 + }, + "valid_percent": { + "title": "Percentage of valid (not nodata) values", + "type": "number", + "minimum": 0, + "maximum": 100 + } + } + }, + "unit": { + "title": "Unit denomination of the data value", + "type": "string" + } + } +} diff --git a/tests/resources/stac/schemas/datetime-v1.1.0.json b/tests/resources/stac/schemas/datetime-v1.1.0.json new file mode 100644 index 0000000000..86bd996f9a --- /dev/null +++ b/tests/resources/stac/schemas/datetime-v1.1.0.json @@ -0,0 +1,53 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/datetime.json", + "title": "Date and Time Fields", + "type": "object", + "dependencies": { + "start_datetime": { + "required": [ + "end_datetime" + ] + }, + "end_datetime": { + "required": [ + "start_datetime" + ] + } + }, + "properties": { + "datetime": { + "title": "Date and Time", + "description": "The searchable date/time of the data, in UTC (Formatted in RFC 3339) ", + "type": ["string", "null"], + "format": "date-time", + "pattern": "(\\+00:00|Z)$" + }, + "start_datetime": { + "title": "Start Date and Time", + "description": "The searchable start date/time of the data, in UTC (Formatted in RFC 3339) ", + "type": "string", + "format": "date-time", + "pattern": "(\\+00:00|Z)$" + }, + "end_datetime": { + "title": "End Date and Time", + "description": "The searchable end date/time of the data, in UTC (Formatted in RFC 3339) ", + "type": "string", + "format": "date-time", + "pattern": "(\\+00:00|Z)$" + }, + "created": { + "title": "Creation Time", + "type": "string", + "format": "date-time", + "pattern": "(\\+00:00|Z)$" + }, + "updated": { + "title": "Last Update Time", + "type": "string", + "format": "date-time", + "pattern": "(\\+00:00|Z)$" + } + } +} diff --git a/tests/resources/stac/schemas/geojson-Feature.json b/tests/resources/stac/schemas/geojson-Feature.json new file mode 100644 index 0000000000..30151f53a9 --- /dev/null +++ b/tests/resources/stac/schemas/geojson-Feature.json @@ -0,0 +1,505 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://geojson.org/schema/Feature.json", + "title": "GeoJSON Feature", + "type": "object", + "required": [ + "type", + "properties", + "geometry" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Feature" + ] + }, + "id": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ] + }, + "properties": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object" + } + ] + }, + "geometry": { + "oneOf": [ + { + "type": "null" + }, + { + "title": "GeoJSON Point", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Point" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON LineString", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "LineString" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON Polygon", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Polygon" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 4, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiPoint", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiPoint" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiLineString", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiLineString" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiPolygon", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiPolygon" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "minItems": 4, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON GeometryCollection", + "type": "object", + "required": [ + "type", + "geometries" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "GeometryCollection" + ] + }, + "geometries": { + "type": "array", + "items": { + "oneOf": [ + { + "title": "GeoJSON Point", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Point" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON LineString", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "LineString" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON Polygon", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Polygon" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 4, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiPoint", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiPoint" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiLineString", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiLineString" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiPolygon", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiPolygon" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "minItems": 4, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + } + ] + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + } + ] + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } +} diff --git a/tests/resources/stac/schemas/geojson-Geometry.json b/tests/resources/stac/schemas/geojson-Geometry.json new file mode 100644 index 0000000000..de567162d2 --- /dev/null +++ b/tests/resources/stac/schemas/geojson-Geometry.json @@ -0,0 +1,218 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://geojson.org/schema/Geometry.json", + "title": "GeoJSON Geometry", + "oneOf": [ + { + "title": "GeoJSON Point", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Point" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON LineString", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "LineString" + ] + }, + "coordinates": { + "type": "array", + "minItems": 2, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON Polygon", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "Polygon" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 4, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiPoint", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiPoint" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiLineString", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiLineString" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + }, + { + "title": "GeoJSON MultiPolygon", + "type": "object", + "required": [ + "type", + "coordinates" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "MultiPolygon" + ] + }, + "coordinates": { + "type": "array", + "items": { + "type": "array", + "items": { + "type": "array", + "minItems": 4, + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "number" + } + } + } + } + }, + "bbox": { + "type": "array", + "minItems": 4, + "items": { + "type": "number" + } + } + } + } + ] +} diff --git a/tests/resources/stac/schemas/instrument-v1.1.0.json b/tests/resources/stac/schemas/instrument-v1.1.0.json new file mode 100644 index 0000000000..d03fc4cb50 --- /dev/null +++ b/tests/resources/stac/schemas/instrument-v1.1.0.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/instrument.json", + "title": "Instrument Fields", + "type": "object", + "properties": { + "platform": { + "title": "Platform", + "type": "string" + }, + "instruments": { + "title": "Instruments", + "type": "array", + "items": { + "type": "string" + } + }, + "constellation": { + "title": "Constellation", + "type": "string" + }, + "mission": { + "title": "Mission", + "type": "string" + }, + "gsd": { + "title": "Ground Sample Distance", + "type": "number", + "exclusiveMinimum": 0 + } + } +} diff --git a/tests/resources/stac/schemas/item-v1.1.0.json b/tests/resources/stac/schemas/item-v1.1.0.json new file mode 100644 index 0000000000..e7305db753 --- /dev/null +++ b/tests/resources/stac/schemas/item-v1.1.0.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/item.json", + "title": "STAC Item", + "type": "object", + "description": "This object represents the metadata for an item in a SpatioTemporal Asset Catalog.", + "allOf": [ + { + "$ref": "#/definitions/core" + } + ], + "definitions": { + "core": { + "allOf": [ + { + "$ref": "https://geojson.org/schema/Feature.json" + }, + { + "oneOf": [ + { + "type": "object", + "required": [ + "geometry", + "bbox" + ], + "properties": { + "geometry": { + "$ref": "https://geojson.org/schema/Geometry.json" + }, + "bbox": { + "type": "array", + "oneOf": [ + { + "minItems": 4, + "maxItems": 4 + }, + { + "minItems": 6, + "maxItems": 6 + } + ], + "items": { + "type": "number" + } + } + } + }, + { + "type": "object", + "required": [ + "geometry" + ], + "properties": { + "geometry": { + "type": "null" + }, + "bbox": { + "not": {} + } + } + } + ] + }, + { + "type": "object", + "required": [ + "stac_version", + "id", + "links", + "assets", + "properties" + ], + "properties": { + "stac_version": { + "title": "STAC version", + "type": "string", + "const": "1.1.0" + }, + "stac_extensions": { + "title": "STAC extensions", + "type": "array", + "uniqueItems": true, + "items": { + "title": "Reference to a JSON Schema", + "type": "string", + "format": "iri" + } + }, + "id": { + "title": "Provider ID", + "description": "Provider item ID", + "type": "string", + "minLength": 1 + }, + "links": { + "$ref": "#/definitions/links" + }, + "assets": { + "$ref": "#/definitions/assets" + }, + "properties": { + "allOf": [ + { + "$ref": "common.json" + }, + { + "anyOf": [ + { + "required": [ + "datetime" + ], + "properties": { + "datetime": { + "not": { + "type": "null" + } + } + } + }, + { + "required": [ + "datetime", + "start_datetime", + "end_datetime" + ] + } + ] + } + ] + } + }, + "$comment": "Rules enforcement for STAC Item", + "allOf": [ + { + "if": { + "properties": { + "links": { + "contains": { + "required": [ + "rel" + ], + "properties": { + "rel": { + "const": "collection" + } + } + } + } + } + }, + "then": { + "required": [ + "collection" + ], + "properties": { + "collection": { + "title": "Collection ID", + "description": "The ID of the STAC Collection this Item references to.", + "type": "string", + "minLength": 1 + } + } + }, + "else": { + "properties": { + "collection": { + "not": {} + } + } + } + }, + { + "$comment": "The if-then-else below checks whether the bands field is given in assets or not. If not, allows bands in properties (then), otherwise, disallows bands in properties (else).", + "if": { + "$comment": "If there is no asset with bands...", + "required": [ + "assets" + ], + "properties": { + "assets": { + "type": "object", + "additionalProperties": { + "properties": { + "bands": false + } + } + } + } + }, + "then": { + "$comment": "... then bands are not allowed in properties...", + "properties": { + "properties": { + "properties": { + "bands": false + } + } + } + }, + "else": { + "$comment": "... otherwise bands are allowed in properties.", + "properties": { + "properties": { + "$ref": "bands.json" + } + } + } + } + ] + } + ] + }, + "links": { + "title": "Item links", + "description": "Links to item relations", + "type": "array", + "items": { + "$ref": "#/definitions/link" + } + }, + "link": { + "allOf": [ + { + "type": "object", + "required": [ + "rel", + "href" + ], + "properties": { + "href": { + "title": "Link reference", + "type": "string", + "format": "iri-reference", + "minLength": 1 + }, + "rel": { + "title": "Link relation type", + "type": "string", + "minLength": 1 + }, + "type": { + "title": "Link type", + "type": "string" + }, + "title": { + "title": "Link title", + "type": "string" + }, + "method": { + "title": "Link method", + "type": "string", + "pattern": "^[A-Z]+$", + "default": "GET" + }, + "headers": { + "title": "Link headers", + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + }, + "body": { + "title": "Link body", + "$comment": "Any type is allowed." + } + }, + "$comment": "Link with relationship `self` must be absolute URI", + "if": { + "properties": { + "rel": { + "const": "self" + } + } + }, + "then": { + "properties": { + "href": { + "format": "iri" + } + } + } + }, + { + "$ref": "common.json" + } + ] + }, + "assets": { + "title": "Asset links", + "description": "Links to assets", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/asset" + } + }, + "asset": { + "allOf": [ + { + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "title": "Asset reference", + "type": "string", + "format": "iri-reference", + "minLength": 1 + }, + "title": { + "title": "Asset title", + "type": "string" + }, + "description": { + "title": "Asset description", + "type": "string" + }, + "type": { + "title": "Asset type", + "type": "string" + }, + "roles": { + "title": "Asset roles", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "$ref": "common.json" + } + ] + } + } +} diff --git a/tests/resources/stac/schemas/licensing-v1.1.0.json b/tests/resources/stac/schemas/licensing-v1.1.0.json new file mode 100644 index 0000000000..a1d2fa6b40 --- /dev/null +++ b/tests/resources/stac/schemas/licensing-v1.1.0.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/licensing.json", + "title": "Licensing Fields", + "type": "object", + "properties": { + "license": { + "type": "string", + "pattern": "^[\\w\\-\\.\\+]+$" + } + } +} diff --git a/tests/resources/stac/schemas/provider-v1.1.0.json b/tests/resources/stac/schemas/provider-v1.1.0.json new file mode 100644 index 0000000000..72c1caf090 --- /dev/null +++ b/tests/resources/stac/schemas/provider-v1.1.0.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schemas.stacspec.org/v1.1.0/item-spec/json-schema/provider.json", + "title": "Provider Fields", + "type": "object", + "properties": { + "providers": { + "title": "Providers", + "type": "array", + "items": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "title": "Organization name", + "type": "string", + "minLength": 1 + }, + "description": { + "title": "Organization description", + "type": "string" + }, + "roles": { + "title": "Organization roles", + "type": "array", + "items": { + "type": "string", + "enum": [ + "producer", + "licensor", + "processor", + "host" + ] + } + }, + "url": { + "title": "Organization homepage", + "type": "string", + "format": "iri" + } + } + } + } + } +}