Commit 60e7cef4 authored by Mark Hewitt's avatar Mark Hewitt
Browse files

schema add --overwrite-existing option

parent 357b16d8
Pipeline #70912 passed with stages
in 1 minute and 41 seconds
......@@ -28,6 +28,11 @@ For more information, specify the `-h` flag:
Change Log
==========
0.0.19
------
- schema add --overwrite-existing option
0.0.18
------
......
......@@ -58,7 +58,7 @@ setup(
package_dir={"": "src"},
py_modules=[splitext(basename(path))[0] for path in glob("src/*.py")],
include_package_data=True,
install_requires=["click", "jmespath", "osdu-sdk==0.0.6", "requests", "tabulate", "msal"],
install_requires=["click", "jmespath", "osdu-sdk==0.0.7", "requests", "tabulate", "msal"],
project_urls={
"Issue Tracker": "https://community.opengroup.org/osdu/platform/data-flow/data-loading/osdu-cli/-/issues",
},
......
......@@ -15,7 +15,7 @@ import os
import sys
from configparser import NoOptionError, NoSectionError
from functools import wraps
from typing import Tuple, Union
from typing import Union
from urllib.parse import urljoin
import requests
......@@ -44,10 +44,11 @@ MSG_JSON_DECODE_ERROR = (
" more information"
)
MSG_HTTP_ERROR = (
"Unable to access the api. Try running again with the --debug command line argument for"
"An error occurred when accessing the api. Try running again with the --debug command line argument for"
" more information"
)
logger = get_logger(__name__)
......@@ -277,36 +278,41 @@ class CliOsduClient(OsduClient):
def cli_put(
self,
url: str,
# config_url_key: str,
# url_extra_path: str,
filepath: str,
) -> Tuple[requests.Response, dict]:
"""PUT the file at the given path to the given url.
Includes common CLI specific error handling
config_url_key: str,
url_extra_path: str,
data: Union[str, dict],
ok_status_codes: list = None,
) -> requests.Response:
"""[summary]
Args:
config_url_key (str): key in configuration for the base path
url_extra_path (str): extra path to add to the base path
filepath (str): path to a file to PUT
Returns:
Tuple[requests.Response, dict]: Turle with response object and returned json
ok_status_codes (list, optional): Status codes for successful call. Defaults to [200].
"""
try:
# url = CliOsduClient._url_from_config(config_url_key, url_extra_path)
response = self.put(url, filepath)
if response.status_code in [200]:
return response, response.json()
url = self._url_from_config(config_url_key, url_extra_path)
response = self.put(url, data)
if ok_status_codes is not None and response.status_code not in ok_status_codes:
raise HTTPError(response=response)
return response
logger.error(MSG_HTTP_ERROR)
logger.error("Error (%s) - %s", response.status_code, response.reason)
except ValueError as ex:
logger.error(MSG_JSON_DECODE_ERROR)
logger.debug(ex)
except (NoOptionError, NoSectionError) as ex:
logger.warning(
"Configuration missing from config ('%s'). Run 'osdu config update'", ex.args[0]
)
def cli_put_returning_json(
self,
config_url_key: str,
url_extra_path: str,
data: Union[str, dict],
ok_status_codes: list = None,
) -> dict:
"""PUT the data to the given url.
sys.exit(1)
Args:
config_url_key (str): key in configuration for the base path
url_extra_path (str): extra path to add to the base path
data (Union[str, dict]): data to send
ok_status_codes (list, optional): accepted ok response codes. Defaults to None.
Returns:
dict: returned json
"""
url = self._url_from_config(config_url_key, url_extra_path)
return self.put_returning_json(url, data, ok_status_codes)
......@@ -47,20 +47,31 @@ logger = get_logger(__name__)
default="DEVELOPMENT",
show_default=True,
)
@click.option(
"--overwrite-existing",
help="Overwrite any existing schema with the same version.",
is_flag=True,
show_default=True,
)
@click.option(
"--self-contained",
help="Make the schema self contained by including all references.",
is_flag=True,
show_default=True,
)
@handle_cli_exceptions
@command_with_output(None)
def _click_command(state: State, path: str, kind: str, status: str, self_contained: bool):
def _click_command(
state: State, path: str, kind: str, status: str, overwrite_existing: bool, self_contained: bool
):
"""Add a schema"""
return add_schema(state, path, kind, status, self_contained)
return add_schema(state, path, kind, status, overwrite_existing, self_contained)
# pylint: disable=too-many-locals
def add_schema(state: State, path: str, kind: str, status: str, self_contained: bool) -> dict:
def add_schema(
state: State, path: str, kind: str, status: str, overwrite_existing: bool, self_contained: bool
) -> dict:
"""Add schemas to OSDU
Args:
......@@ -106,9 +117,15 @@ def add_schema(state: State, path: str, kind: str, status: str, self_contained:
schema_info = _get_schema_info(kind, status)
payload = {"schemaInfo": schema_info, "schema": schema_object}
response_json = connection.cli_post_returning_json(
CONFIG_SCHEMA_URL, url, payload, [200, 201]
)
response_json = None
if overwrite_existing:
response_json = connection.cli_put_returning_json(
CONFIG_SCHEMA_URL, url, payload, [200, 201]
)
else:
response_json = connection.cli_post_returning_json(
CONFIG_SCHEMA_URL, url, payload, [200, 201]
)
responses.append(response_json)
return responses
......
......@@ -15,7 +15,9 @@
import logging
from knack.testsdk import ScenarioTest
from mock import MagicMock, PropertyMock, patch
from mock import MagicMock, Mock, PropertyMock, patch
from nose2.tools import params
from osdu.client import OsduClient
from osdu.identity import OsduTokenCredential
from requests.models import HTTPError
from testfixtures import LogCapture
......@@ -23,6 +25,10 @@ from testfixtures import LogCapture
from osducli.cliclient import MSG_HTTP_ERROR, CliOsduClient
from osducli.config import CONFIG_AUTHENTICATION_MODE, CONFIG_SERVER
SAMPLE_JSON = {
"name": "value",
}
def mock_config_values(section, name, fallback=None): # pylint: disable=W0613
"""Validate and mock config returns"""
......@@ -35,9 +41,20 @@ def mock_config_values(section, name, fallback=None): # pylint: disable=W0613
return f"{section}_{name}"
def mock_config_values_invalid_auth(section, name, fallback=None): # pylint: disable=W0613
"""Validate and mock config returns"""
if name == CONFIG_AUTHENTICATION_MODE:
return "invalid"
return mock_config_values(section, name, fallback)
MOCK_CONFIG = MagicMock()
MOCK_CONFIG.get.side_effect = mock_config_values
MOCK_CONFIG_INVALID_AUTH = MagicMock()
MOCK_CONFIG_INVALID_AUTH.get.side_effect = mock_config_values_invalid_auth
class CliOsduClientTests(ScenarioTest):
"""Test cases for unit commands
......@@ -60,6 +77,18 @@ class CliOsduClientTests(ScenarioTest):
self.vcr.register_matcher("always", CliOsduClientTests._vcrpy_match_always)
self.vcr.match_on = ["always"]
def test_init(self):
"""Test the init method"""
client = CliOsduClient(MOCK_CONFIG)
self.assertEqual(client.server_url, mock_config_values("core", "server"))
self.assertEqual(client.data_partition, mock_config_values("core", "data_partition_id"))
def test_init_invalid_auth(self):
"""Test the init method"""
with self.assertRaises(SystemExit):
CliOsduClient(MOCK_CONFIG_INVALID_AUTH)
# """Playground test for unit commands - some notes / examples"""
# @patch('osducli.commands.unit.custom.get_as_json', side_effect=ValueError('ValueError'))
# @patch('osducli.commands.unit.custom.get_url_as_json', autospec=True, return_value=(not_found_response_mock,None))
......@@ -125,6 +154,113 @@ class CliOsduClientTests(ScenarioTest):
"""Return true always (only 1 query)."""
return True
# region test cli_put
@params(
("config", "/path", "string1"),
("config", "/path1", "string1"),
("config", "/path2", "string1"),
("config", "/path2", "string2"),
("config2", "path2", "string2"),
("config2", "path2", "string2"),
("config2", "path2", SAMPLE_JSON),
)
def test_cli_put(self, config, path, data):
"""Test valid put with string returns expected values"""
response_mock = Mock()
with patch.object(OsduClient, "put", return_value=response_mock) as mock_put:
client = CliOsduClient(MOCK_CONFIG)
response = client.cli_put(config, path, data)
mock_put.assert_called_once()
mock_put.assert_called_with("https://dummy.com/core_" + config + path, data)
self.assertEqual(response_mock, response)
def test_cli_put_defaults(self):
"""Test valid put with string returns expected values"""
response_mock = Mock()
with patch.object(OsduClient, "put", return_value=response_mock) as mock_put:
client = CliOsduClient(MOCK_CONFIG)
response = client.cli_put("config", "/path", "data")
mock_put.assert_called_once()
mock_put.assert_called_with("https://dummy.com/core_config/path", "data")
self.assertEqual(response_mock, response)
@params(
(None, 200), # No status codes passed then all should be ok
(None, 404), # No status codes passed then all should be ok
([200], 200),
([200, 202], 202),
([202], 202),
)
def test_cli_put_status_codes(self, ok_status_codes, actual_status_code):
"""Test valid put returns expected values"""
response_mock = Mock()
type(response_mock).status_code = PropertyMock(return_value=actual_status_code)
with patch.object(OsduClient, "put", return_value=response_mock) as mock_put:
client = CliOsduClient(MOCK_CONFIG)
response = client.cli_put("config", "/path", SAMPLE_JSON, ok_status_codes)
mock_put.assert_called_once()
self.assertEqual(response_mock, response)
@params(
([], 200), # Empty list means everything should fail
([200], 404),
([200, 202], 500),
)
def test_put_http_error_throws_exception(self, ok_status_codes, actual_status_code):
"""Test put error returns expected values"""
response_mock = MagicMock()
type(response_mock).status_code = PropertyMock(return_value=actual_status_code)
with patch.object(OsduClient, "put", return_value=response_mock) as _:
with self.assertRaises(HTTPError):
client = CliOsduClient(MOCK_CONFIG)
client.cli_put("config", "/path", SAMPLE_JSON, ok_status_codes)
# endregion test cli_put
# region test cli_put_returning_json
@params(
("config", "/path", "string1", None),
("config", "/path1", "string1", None),
("config", "/path2", "string1", None),
("config", "/path2", "string2", None),
("config2", "path2", "string2", None),
("config2", "path2", "string2", [200]),
)
def test_cli_put_returning_json(self, config, path, string_data, status_codes):
"""Test valid put with string returns expected values"""
response_mock = Mock()
with patch.object(OsduClient, "put_returning_json", return_value=response_mock) as mock_put:
client = CliOsduClient(MOCK_CONFIG)
response = client.cli_put_returning_json(config, path, string_data, status_codes)
mock_put.assert_called_once()
mock_put.assert_called_with(
"https://dummy.com/core_" + config + path, string_data, status_codes
)
self.assertEqual(response_mock, response)
def test_cli_put_returning_json_defaults(self):
"""Test valid put with string returns expected values"""
response_mock = Mock()
with patch.object(OsduClient, "put_returning_json", return_value=response_mock) as mock_put:
client = CliOsduClient(MOCK_CONFIG)
response = client.cli_put_returning_json("config", "/path", "data")
mock_put.assert_called_once()
mock_put.assert_called_with("https://dummy.com/core_config/path", "data", None)
self.assertEqual(response_mock, response)
# endregion test cli_put_returning_json
if __name__ == "__main__":
import nose2
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment