add support for OpenAPI validation (#717) (#718)

* add support for OpenAPI validation (#717)

* update copyright years

* fix ES ref

* update CLI
This commit is contained in:
Tom Kralidis
2021-06-29 08:48:22 -04:00
committed by GitHub
parent 4ccb0e574d
commit 7ecac02693
24 changed files with 1921 additions and 178 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
include README.md LICENSE.md requirements.txt
recursive-include pygeoapi *.html
recursive-include pygeoapi *.html *.json
recursive-include pygeoapi/static *
+1
View File
@@ -18,6 +18,7 @@ Depends: ${python3:Depends},
python3-click,
python3-dateutil,
python3-flask,
python3-jsonschema,
python3-tz,
python3-unicodecsv,
python3-yaml,
+1 -1
View File
@@ -60,7 +60,7 @@ function error() {
cd ${PYGEOAPI_HOME}
echo "Trying to generate openapi.yml"
pygeoapi generate-openapi-document -c ${PYGEOAPI_CONFIG} > ${PYGEOAPI_OPENAPI}
pygeoapi openapi generate -c ${PYGEOAPI_CONFIG} > ${PYGEOAPI_OPENAPI}
[[ $? -ne 0 ]] && error "openapi.yml could not be generated ERROR"
+16 -4
View File
@@ -7,31 +7,32 @@ Now that you have pygeoapi installed and a basic configuration setup, it's time
the administrative steps required before starting up the server. The remaining steps are:
- create OpenAPI document
- validate OpenAPI document
- set system environment variables
Creating the OpenAPI document
-----------------------------
The OpenAPI document ia a YAML configuration which is generated from the pygeoapi configuration,
The OpenAPI document is a YAML configuration which is generated from the pygeoapi configuration,
and describes the server information, endpoints, and parameters.
To generate the OpenAPI document, run the following:
.. code-block:: bash
pygeoapi generate-openapi-document -c /path/to/my-pygeoapi-config.yml
pygeoapi openapi generate -c /path/to/my-pygeoapi-config.yml
This will dump the OpenAPI document as YAML to your system's ``stdout``. To save to a file on disk, run:
.. code-block:: bash
pygeoapi generate-openapi-document -c /path/to/my-pygeoapi-config.yml > /path/to/my-pygeoapi-openapi.yml
pygeoapi openapi generate -c /path/to/my-pygeoapi-config.yml > /path/to/my-pygeoapi-openapi.yml
To generate the OpenAPI document as JSON, run:
.. code-block:: bash
pygeoapi generate-openapi-document -c /path/to/my-pygeoapi-config.yml -f json > /path/to/my-pygeoapi-openapi.json
pygeoapi openapi generate -c /path/to/my-pygeoapi-config.yml -f json > /path/to/my-pygeoapi-openapi.json
.. note::
Generate as YAML or JSON? If your OpenAPI YAML definition is slow to render as JSON,
@@ -47,6 +48,17 @@ To generate the OpenAPI document as JSON, run:
:ref:`openapi` for more information on pygeoapi's OpenAPI support
Validating the OpenAPI document
-------------------------------
To ensure your OpenAPI document is valid, pygeoapi provides a validation
utility that can be run as follows:
.. code-block:: bash
pygeoapi validate-openapi-document -o /path/to/my-pygeoapi-openapi.yml
Verifying configuration files
-----------------------------
+1 -1
View File
@@ -31,7 +31,7 @@ For developers and the truly impatient
vi example-config.yml
export PYGEOAPI_CONFIG=example-config.yml
export PYGEOAPI_OPENAPI=example-openapi.yml
pygeoapi generate-openapi-document -c $PYGEOAPI_CONFIG > $PYGEOAPI_OPENAPI
pygeoapi openapi generate -c $PYGEOAPI_CONFIG > $PYGEOAPI_OPENAPI
pygeoapi serve
curl http://localhost:5000
+3 -3
View File
@@ -2,7 +2,7 @@
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2018 Tom Kralidis
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -30,7 +30,7 @@
__version__ = '0.11.dev0'
import click
from pygeoapi.openapi import generate_openapi_document
from pygeoapi.openapi import openapi
@click.group()
@@ -58,4 +58,4 @@ def serve(ctx, server):
raise click.ClickException('--flask/--starlette is required')
cli.add_command(generate_openapi_document)
cli.add_command(openapi)
+58 -10
View File
@@ -28,10 +28,12 @@
# =================================================================
from copy import deepcopy
import json
import logging
import os
import click
from jsonschema import validate as jsonschema_validate
import yaml
from pygeoapi import __version__
@@ -54,6 +56,8 @@ OPENAPI_YAML = {
'oat': 'https://raw.githubusercontent.com/opengeospatial/ogcapi-tiles/master/openapi/swaggerHubUnresolved/ogc-api-tiles.yaml', # noqa
}
THISDIR = os.path.dirname(os.path.realpath(__file__))
def get_ogc_schemas_location(server_config):
@@ -417,7 +421,7 @@ def get_oas_30(cfg):
'get': {
'summary': 'Get {} metadata'.format(title),
'description': desc,
'tags': name,
'tags': [name],
'operationId': 'describe{}Collection'.format(name.capitalize()), # noqa
'parameters': [
{'$ref': '#/components/parameters/f'},
@@ -508,7 +512,7 @@ def get_oas_30(cfg):
paths[items_path]['get']['parameters'].append(
{'$ref': '{}#/components/parameters/datetime'.format(OPENAPI_YAML['oapif'])}) # noqa
for field, type in p.fields.items():
for field, type_ in p.fields.items():
if p.properties and field not in p.properties:
LOGGER.debug('Provider specified not to advertise property') # noqa
@@ -518,25 +522,23 @@ def get_oas_30(cfg):
LOGGER.debug('q parameter already declared, skipping')
continue
if type == 'date':
if type_ == 'date':
schema = {
'type': 'string',
'format': 'date'
}
elif type == 'float':
elif type_ == 'float':
schema = {
'type': 'number',
'format': 'float'
}
elif type == 'long':
elif type_ == 'long':
schema = {
'type': 'integer',
'format': 'int64'
}
else:
schema = {
'type': type
}
schema = type_
path_ = '{}/items'.format(collection_name_path)
paths['{}'.format(path_)]['get']['parameters'].append({
@@ -756,6 +758,7 @@ def get_oas_30(cfg):
}
mimetype = tile_extension['format']['mimetype']
paths[tiles_data_path]['get']['responses']['200'] = {
'description': 'successful operation',
'content': {
mimetype: {
'schema': {
@@ -1027,12 +1030,37 @@ def get_oas(cfg, version='3.0'):
raise RuntimeError('OpenAPI version not supported')
@click.command('generate-openapi-document')
def validate_openapi_document(instance_dict):
"""
Validate an OpenAPI document against the OpenAPI schema
:param instance_dict: dict of OpenAPI instance
:returns: `bool` of validation
"""
schema_file = os.path.join(THISDIR, 'schemas', 'openapi',
'openapi-3.0.x.json')
with open(schema_file) as fh2:
schema_dict = json.load(fh2)
jsonschema_validate(instance_dict, schema_dict)
return True
@click.group()
def openapi():
"""OpenAPI management"""
pass
@click.command()
@click.pass_context
@click.option('--config', '-c', 'config_file', help='configuration file')
@click.option('--format', '-f', 'format_', type=click.Choice(['json', 'yaml']),
default='yaml', help='output format (json|yaml)')
def generate_openapi_document(ctx, config_file, format_='yaml'):
def generate(ctx, config_file, format_='yaml'):
"""Generate OpenAPI Document"""
if config_file is None:
@@ -1044,3 +1072,23 @@ def generate_openapi_document(ctx, config_file, format_='yaml'):
click.echo(yaml.safe_dump(get_oas(s), default_flow_style=False))
else:
click.echo(to_json(get_oas(s), pretty=pretty_print))
@click.command()
@click.pass_context
@click.option('--openapi', '-o', 'openapi_file', help='OpenAPI document')
def validate(ctx, openapi_file):
"""Validate OpenAPI Document"""
if openapi_file is None:
raise click.ClickException('--openapi/-o required')
with open(openapi_file) as ff:
click.echo('Validating {}'.format(openapi_file))
instance = yaml_load(ff)
validate_openapi_document(instance)
click.echo('Valid OpenAPI document')
openapi.add_command(generate)
openapi.add_command(validate)
+4 -4
View File
@@ -134,11 +134,11 @@ class ElasticsearchProvider(BaseProvider):
for k, v in p['properties'].items():
if 'type' in v:
if v['type'] == 'text':
type_ = 'string'
fields_[k] = {'type': 'string'}
elif v['type'] == 'date':
fields_[k] = {'type': 'string', 'format': 'date'}
else:
type_ = v['type']
fields_[k] = {'type': type_}
fields_[k] = {'type': v['type']}
return fields_
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,6 +1,7 @@
Babel
click<8
Flask
jsonschema
pyproj
python-dateutil
pytz
+28
View File
@@ -0,0 +1,28 @@
# =================================================================
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
+1 -1
View File
@@ -14,6 +14,6 @@ pip install gunicorn
cd tests/cite/ogcapi-features
. cite.env
python ../../load_es_data.py ./canada-hydat-daily-mean-02hc003.geojson IDENTIFIER
pygeoapi generate-openapi-document -c $PYGEOAPI_CONFIG > $PYGEOAPI_OPENAPI
pygeoapi openapi generate -c $PYGEOAPI_CONFIG > $PYGEOAPI_OPENAPI
gunicorn pygeoapi.flask_app:APP -b 0.0.0.0:5001 --access-logfile '-'
```
+27 -27
View File
@@ -102,11 +102,11 @@ paths:
parameters:
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/LandingPage
400:
'400':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
500:
'500':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
summary: Landing page
tags:
@@ -117,9 +117,9 @@ paths:
parameters:
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: '#/components/responses/200'
400:
'400':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
default:
$ref: '#/components/responses/default'
@@ -132,11 +132,11 @@ paths:
parameters:
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collections
400:
'400':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
500:
'500':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
summary: Feature Collections
tags:
@@ -147,13 +147,13 @@ paths:
parameters:
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Collection
400:
'400':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
404:
'404':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
500:
'500':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
summary: Get feature collection metadata
tags:
@@ -182,13 +182,13 @@ paths:
- $ref: '#/components/parameters/sortby'
- $ref: '#/components/parameters/startindex'
responses:
200:
'200':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Features
400:
'400':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
404:
'404':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
500:
'500':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
summary: Get Observations features
tags:
@@ -200,13 +200,13 @@ paths:
- $ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/parameters/featureId
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/Feature
400:
'400':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
404:
'404':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/NotFound
500:
'500':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
summary: Get Observations feature by id
tags:
@@ -217,11 +217,11 @@ paths:
parameters:
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ConformanceDeclaration
400:
'400':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/InvalidParameter
500:
'500':
$ref: http://schemas.opengis.net/ogcapi/features/part1/1.0/openapi/ogcapi-features-1.yaml#/components/responses/ServerError
summary: API conformance definition
tags:
@@ -232,7 +232,7 @@ paths:
parameters:
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: '#/components/responses/200'
default:
$ref: '#/components/responses/default'
@@ -245,7 +245,7 @@ paths:
parameters:
- $ref: '#/components/parameters/f'
responses:
200:
'200':
$ref: '#/components/responses/200'
default:
$ref: '#/components/responses/default'
@@ -256,7 +256,7 @@ paths:
get:
description: Hello World process
responses:
200:
'200':
$ref: '#/components/responses/200'
default:
$ref: '#/components/responses/default'
@@ -279,7 +279,7 @@ paths:
description: Mandatory execute request JSON
required: true
responses:
200:
'200':
$ref: '#/components/responses/200'
default:
$ref: '#/components/responses/default'
+2 -38
View File
@@ -28,58 +28,22 @@
# =================================================================
import json
import os
import logging
import time
from pyld import jsonld
import pytest
from werkzeug.test import create_environ
from werkzeug.wrappers import Request
from werkzeug.datastructures import ImmutableMultiDict
from pygeoapi.api import (
API, APIRequest, FORMAT_TYPES, validate_bbox, validate_datetime,
F_HTML, F_JSON, F_JSONLD
)
from pygeoapi.util import yaml_load
from .util import get_test_file_path, mock_request
LOGGER = logging.getLogger(__name__)
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
def mock_request(params: dict = None, data=None, **headers) -> Request:
"""
Mocks a Request object so the @pre_process decorator can inject it
as an APIRequest.
:param params: Optional query parameter dict for the request.
Will be set to {} if omitted.
:param data: Optional data/body to send with the request.
Can be text/bytes or a JSON dictionary.
:param headers: Optional request HTTP headers to set.
:returns: A Werkzeug Request instance.
"""
params = params or {}
# TODO: We are not setting a path in the create_environ() call.
# This is fine as long as an API test does not need the URL path.
if isinstance(data, dict):
environ = create_environ(base_url='http://localhost:5000/', json=data)
else:
environ = create_environ(base_url='http://localhost:5000/', data=data)
environ.update(headers)
request = Request(environ)
request.args = ImmutableMultiDict(params.items())
return request
@pytest.fixture()
def config():
with open(get_test_file_path('pygeoapi-test-config.yml')) as fh:
+2 -9
View File
@@ -2,7 +2,7 @@
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2019 Tom Kralidis
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -33,14 +33,7 @@ import pytest
from pygeoapi.util import yaml_load
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
from .util import get_test_file_path
def test_config_envvars():
+2 -12
View File
@@ -2,7 +2,7 @@
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2018 Tom Kralidis
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -27,22 +27,12 @@
#
# =================================================================
import os
import pytest
from pygeoapi.provider.base import ProviderItemNotFoundError
from pygeoapi.provider.csv_ import CSVProvider
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
from .util import get_test_file_path
path = get_test_file_path('data/obs.csv')
+3 -11
View File
@@ -26,13 +26,14 @@
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
import os
from babel import Locale
import pytest
from pygeoapi import l10n
from pygeoapi.util import yaml_load
import pytest
from .util import get_test_file_path
def test_str2locale():
@@ -223,15 +224,6 @@ def test_setresponselanguage():
assert headers['Content-Language'] == 'en'
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
@pytest.fixture()
def config():
with open(get_test_file_path('pygeoapi-test-config.yml')) as fh:
+36 -2
View File
@@ -2,7 +2,7 @@
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2020 Tom Kralidis
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -27,7 +27,25 @@
#
# =================================================================
from pygeoapi.openapi import get_ogc_schemas_location
import pytest
from pygeoapi.openapi import (get_oas, get_ogc_schemas_location,
validate_openapi_document)
from pygeoapi.util import yaml_load
from .util import get_test_file_path
@pytest.fixture()
def config():
with open(get_test_file_path('pygeoapi-test-config.yml')) as fh:
return yaml_load(fh)
@pytest.fixture()
def openapi():
with open(get_test_file_path('pygeoapi-test-openapi.yml')) as fh:
return yaml_load(fh)
def test_str2bool():
@@ -45,3 +63,19 @@ def test_str2bool():
default['ogc_schemas_location'] = '/opt/schemas.opengis.net'
osl = get_ogc_schemas_location(default)
def test_get_oas(config, openapi):
openapi_doc = get_oas(config)
assert isinstance(openapi_doc, dict)
is_valid = validate_openapi_document(openapi_doc)
assert is_valid is True
def test_validate_openapi_document(openapi):
is_valid = validate_openapi_document(openapi)
assert is_valid is True
+2 -11
View File
@@ -2,7 +2,7 @@
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2020 Tom Kralidis
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -27,20 +27,11 @@
#
# =================================================================
import os
import pytest
from pygeoapi.provider.rasterio_ import RasterioProvider
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
from .util import get_test_file_path
path = get_test_file_path(
'tests/data/CMC_glb_TMP_TGL_2_latlon.15x.15_2020081000_P000.grib2')
+1 -11
View File
@@ -27,22 +27,12 @@
#
# =================================================================
import os
import pytest
from pygeoapi.provider.base import ProviderItemNotFoundError
from pygeoapi.provider.tinydb_ import TinyDBCatalogueProvider
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
from .util import get_test_file_path
path = get_test_file_path('tests/data/open.canada.ca/sample-records.tinydb')
+2 -10
View File
@@ -2,7 +2,7 @@
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2020 Tom Kralidis
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -29,21 +29,13 @@
from datetime import datetime, date, time
from decimal import Decimal
import os
import pytest
from pygeoapi import util
from pygeoapi.provider.base import ProviderTypeError
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
from .util import get_test_file_path
def test_get_typed_value():
+2 -11
View File
@@ -2,7 +2,7 @@
#
# Authors: Gregory Petrochenkov <gpetrochenkov@usgs.gov>
#
# Copyright (c) 2020 Gregory Petrochenkov
# Copyright (c) 2021 Gregory Petrochenkov
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -27,21 +27,12 @@
#
# =================================================================
import os
import pytest
from pygeoapi.provider.base import ProviderQueryError
from pygeoapi.provider.xarray_ import XarrayProvider
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
from .util import get_test_file_path
path = get_test_file_path('tests/data/coads_sst.nc')
+2 -11
View File
@@ -2,7 +2,7 @@
#
# Authors: Gregory Petrochenkov <gpetrochenkov@usgs.gov>
#
# Copyright (c) 2020 Gregory Petrochenkov
# Copyright (c) 2021 Gregory Petrochenkov
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -27,20 +27,11 @@
#
# =================================================================
import os
import pytest
from pygeoapi.provider.xarray_ import XarrayProvider
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
from .util import get_test_file_path
path = get_test_file_path(
'data/analysed_sst.zarr')
+71
View File
@@ -0,0 +1,71 @@
# =================================================================
#
# Authors: Tom Kralidis <tomkralidis@gmail.com>
#
# Copyright (c) 2021 Tom Kralidis
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================
import os
import logging
from werkzeug.test import create_environ
from werkzeug.wrappers import Request
from werkzeug.datastructures import ImmutableMultiDict
LOGGER = logging.getLogger(__name__)
def get_test_file_path(filename):
"""helper function to open test file safely"""
if os.path.isfile(filename):
return filename
else:
return 'tests/{}'.format(filename)
def mock_request(params: dict = None, data=None, **headers) -> Request:
"""
Mocks a Request object so the @pre_process decorator can inject it
as an APIRequest.
:param params: Optional query parameter dict for the request.
Will be set to {} if omitted.
:param data: Optional data/body to send with the request.
Can be text/bytes or a JSON dictionary.
:param headers: Optional request HTTP headers to set.
:returns: A Werkzeug Request instance.
"""
params = params or {}
# TODO: We are not setting a path in the create_environ() call.
# This is fine as long as an API test does not need the URL path.
if isinstance(data, dict):
environ = create_environ(base_url='http://localhost:5000/', json=data)
else:
environ = create_environ(base_url='http://localhost:5000/', data=data)
environ.update(headers)
request = Request(environ)
request.args = ImmutableMultiDict(params.items())
return request