-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #411 from dcs4cop/forman-xxx-gen2_python_client
xcube generator service CLI and Python API
- Loading branch information
Showing
26 changed files
with
1,153 additions
and
267 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,36 @@ | ||
from test.cli.helpers import CliTest | ||
import warnings | ||
|
||
import pytest | ||
from click import command | ||
|
||
import xcube.cli.main | ||
from warnings import warn | ||
import pytest | ||
from test.cli.helpers import CliTest | ||
|
||
|
||
class ClickMainTest(CliTest): | ||
|
||
WARNING_MESSAGE = 'This is a test warning.' | ||
USER_WARNING_MESSAGE = 'This is a user warning.' | ||
DEPRECATION_WARNING_MESSAGE = 'This is a deprecation warning.' | ||
RUNTIME_WARNING_MESSAGE = 'This is a runtime warning.' | ||
|
||
def setUp(self): | ||
@command(name='test_warnings') | ||
def test_warnings(): | ||
warn(self.WARNING_MESSAGE) | ||
warnings.warn(self.USER_WARNING_MESSAGE) | ||
warnings.warn(self.DEPRECATION_WARNING_MESSAGE, category=DeprecationWarning) | ||
warnings.warn(self.RUNTIME_WARNING_MESSAGE, category=RuntimeWarning) | ||
|
||
xcube.cli.main.cli.add_command(test_warnings) | ||
|
||
def test_warnings_not_issued_by_default(self): | ||
with pytest.warns(None) as record: | ||
self.invoke_cli(['test_warnings']) | ||
self.assertEqual(0, len(record.list)) | ||
self.assertEqual(['This is a user warning.'], | ||
list(map(lambda r: str(r.message), record.list))) | ||
|
||
def test_warnings_issued_when_enabled(self): | ||
with pytest.warns(UserWarning, match=self.WARNING_MESSAGE): | ||
with pytest.warns(None) as record: | ||
self.invoke_cli(['--warnings', 'test_warnings']) | ||
self.assertEqual(['This is a user warning.', | ||
'This is a deprecation warning.', | ||
'This is a runtime warning.'], | ||
list(map(lambda r: str(r.message), record.list))) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import unittest | ||
|
||
from xcube.core.gen2.service.config import ServiceConfig | ||
|
||
|
||
class ServiceConfigTest(unittest.TestCase): | ||
|
||
def test_from_json_instance(self): | ||
json_instance = dict(endpoint_url='https://stage.xcube-gen.brockmann-consult.de/api/v2', | ||
access_token='02945ugjhklojg908ijr023jgbpij202jbv00897v0798v65472') | ||
service_config = ServiceConfig.get_schema().from_instance(json_instance) | ||
self.assertIsInstance(service_config, ServiceConfig) | ||
self.assertEqual('https://stage.xcube-gen.brockmann-consult.de/api/v2/', service_config.endpoint_url) | ||
self.assertEqual('02945ugjhklojg908ijr023jgbpij202jbv00897v0798v65472', service_config.access_token) | ||
self.assertEqual(None, service_config.client_id) | ||
self.assertEqual(None, service_config.client_secret) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import unittest | ||
|
||
import requests_mock | ||
|
||
from test.util.test_progress import TestProgressObserver | ||
from xcube.core.gen2 import CubeGeneratorError | ||
from xcube.core.gen2.request import CubeGeneratorRequest | ||
from xcube.core.gen2.service import CubeGeneratorService | ||
from xcube.core.gen2.service import ServiceConfig | ||
from xcube.core.gen2.service.response import CubeInfoWithCosts | ||
from xcube.util.progress import new_progress_observers | ||
|
||
|
||
def result(worked, total_work, failed=False, traceback: str = None): | ||
json = { | ||
"result": { | ||
"cubegen_id": "93", | ||
"status": { | ||
"failed": True if failed else None, | ||
"succeeded": True if worked == total_work else None, | ||
"active": 1 if worked != total_work else None, | ||
}, | ||
"progress": { | ||
"worked": worked, "total_work": total_work, | ||
} | ||
} | ||
} | ||
if traceback: | ||
json.update(traceback=traceback) | ||
return dict(json=json) | ||
|
||
|
||
class CubeGeneratorServiceTest(unittest.TestCase): | ||
ENDPOINT_URL = 'https://xcube-gen.com/api/v2/' | ||
|
||
CUBE_GEN_CONFIG = dict(input_config=dict(store_id='memory', | ||
data_id='S2L2A'), | ||
cube_config=dict(variable_names=['B01', 'B02', 'B03'], | ||
crs='WGS84', | ||
bbox=[12.2, 52.1, 13.9, 54.8], | ||
spatial_res=0.05, | ||
time_range=['2018-01-01', None], | ||
time_period='4D'), | ||
output_config=dict(store_id='memory', | ||
data_id='CHL')) | ||
|
||
def setUp(self) -> None: | ||
self.service = CubeGeneratorService(CubeGeneratorRequest.from_dict(self.CUBE_GEN_CONFIG), | ||
ServiceConfig(endpoint_url=self.ENDPOINT_URL, | ||
client_id='itzibitzispider', | ||
client_secret='g3ergd36fd2983457fhjder'), | ||
progress_period=0, | ||
verbose=True) | ||
|
||
@requests_mock.Mocker() | ||
def test_generate_cube_success(self, m: requests_mock.Mocker): | ||
m.post(f'{self.ENDPOINT_URL}oauth/token', | ||
json={ | ||
"access_token": "4ccsstkn983456jkfde", | ||
"token_type": "bearer" | ||
}) | ||
|
||
m.put(f'{self.ENDPOINT_URL}cubegens', | ||
response_list=[ | ||
result(0, 4), | ||
]) | ||
|
||
m.get(f'{self.ENDPOINT_URL}cubegens/93', | ||
response_list=[ | ||
result(1, 4), | ||
result(2, 4), | ||
result(3, 4), | ||
result(4, 4), | ||
]) | ||
|
||
observer = TestProgressObserver() | ||
with new_progress_observers(observer): | ||
self.service.generate_cube() | ||
|
||
self.assertEqual( | ||
[ | ||
('begin', [('Generating cube', 0.0, False)]), | ||
('update', [('Generating cube', 0.25, False)]), | ||
('update', [('Generating cube', 0.5, False)]), | ||
('update', [('Generating cube', 0.75, False)]), | ||
('end', [('Generating cube', 0.75, True)]) | ||
], | ||
observer.calls) | ||
|
||
@requests_mock.Mocker() | ||
def test_generate_cube_failure(self, m: requests_mock.Mocker): | ||
m.post(f'{self.ENDPOINT_URL}oauth/token', | ||
json={ | ||
"access_token": "4ccsstkn983456jkfde", | ||
"token_type": "bearer" | ||
}) | ||
|
||
m.put(f'{self.ENDPOINT_URL}cubegens', | ||
response_list=[ | ||
result(0, 4), | ||
]) | ||
|
||
m.get(f'{self.ENDPOINT_URL}cubegens/93', | ||
response_list=[ | ||
result(1, 4), | ||
result(2, 4, failed=True, traceback='1.that\n2.was\n3.bad'), | ||
]) | ||
|
||
observer = TestProgressObserver() | ||
with new_progress_observers(observer): | ||
with self.assertRaises(CubeGeneratorError) as cm: | ||
self.service.generate_cube() | ||
self.assertEqual('Cube generation failed', f'{cm.exception}') | ||
self.assertEqual('1.that\n2.was\n3.bad', cm.exception.remote_traceback) | ||
|
||
print(observer.calls) | ||
self.assertEqual( | ||
[ | ||
('begin', [('Generating cube', 0.0, False)]), | ||
('update', [('Generating cube', 0.25, False)]), | ||
('end', [('Generating cube', 0.25, True)]) | ||
], | ||
observer.calls) | ||
|
||
@requests_mock.Mocker() | ||
def test_get_cube_info(self, m: requests_mock.Mocker): | ||
m.post(f'{self.ENDPOINT_URL}oauth/token', | ||
json={ | ||
"access_token": "4ccsstkn983456jkfde", | ||
"token_type": "bearer" | ||
}) | ||
|
||
m.post(f'{self.ENDPOINT_URL}cubegens/info', | ||
json=dict(dims=dict(time=10 * 365, lat=720, lon=1440), | ||
chunks=dict(time=10, lat=720, lon=1440), | ||
data_vars=dict(CHL=dict(long_name='chlorophyll_concentration', | ||
units='mg/m^-1')), | ||
cost_info=dict(punits_input=300, | ||
punits_output=400, | ||
punits_combined=500))) | ||
|
||
cube_info = self.service.get_cube_info() | ||
self.assertIsInstance(cube_info, CubeInfoWithCosts) | ||
self.assertEqual(dict(time=10 * 365, lat=720, lon=1440), | ||
cube_info.dims) | ||
self.assertEqual(dict(time=10, lat=720, lon=1440), | ||
cube_info.chunks) | ||
self.assertEqual(dict(CHL=dict(long_name='chlorophyll_concentration', | ||
units='mg/m^-1')), | ||
cube_info.data_vars) | ||
self.assertEqual( | ||
{ | ||
"punits_input": 300, | ||
"punits_output": 400, | ||
"punits_combined": 500 | ||
}, | ||
cube_info.cost_info.additional_properties) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.