From 0ea52eb33d3de79d80b3d295411da90b52c164bd Mon Sep 17 00:00:00 2001 From: Jonathan Karr Date: Wed, 13 Jan 2021 18:16:45 -0500 Subject: [PATCH 1/2] added call to dispatch API to refresh Singularity image for simulator --- biosimulators_test_suite/exec_gh_action.py | 72 +++++++++++++++++----- tests/test_exec_gh_action.py | 22 ++++++- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/biosimulators_test_suite/exec_gh_action.py b/biosimulators_test_suite/exec_gh_action.py index fff7f7d..9869c2a 100644 --- a/biosimulators_test_suite/exec_gh_action.py +++ b/biosimulators_test_suite/exec_gh_action.py @@ -60,8 +60,18 @@ class ValidateCommitSimulatorGitHubAction(GitHubAction): issue_number (:obj:`str`): number of GitHub issue which triggered the action """ BIOSIMULATORS_AUTH_ENDPOINT = 'https://auth.biosimulations.org/oauth/token' - BIOSIMULATORS_AUDIENCE = os.getenv('BIOSIMULATORS_AUDIENCE', 'api.biosimulators.org') - BIOSIMULATORS_API_ENDPOINT = os.getenv('BIOSIMULATORS_API_ENDPOINT', 'https://api.biosimulators.org/') + BIOSIMULATORS_AUDIENCE = os.getenv( + 'BIOSIMULATORS_AUDIENCE', + 'api.biosimulators.org') + RUNBIOSIMULATIONS_AUDIENCE = os.getenv( + 'RUNBIOSIMULATIONS_AUDIENCE', + 'dispatch.biosimulations.org') + BIOSIMULATORS_API_ENDPOINT = os.getenv( + 'BIOSIMULATORS_API_ENDPOINT', + 'https://api.biosimulators.org/') + RUNBIOSIMULATIONS_API_ENDPOINT = os.getenv( + 'RUNBIOSIMULATIONS_API_ENDPOINT', + 'https://run.api.biosimulations.dev/') DOCKER_REGISTRY_URL = 'ghcr.io' DOCKER_REGISTRY_IMAGE_URL_PATTERN = 'ghcr.io/biosimulators/{}:{}' DEFAULT_SPECIFICATIONS_VERSION = '1.0.0' @@ -293,10 +303,14 @@ def commit_simulator(self, submission, specifications, existing_version_specific existing_version_specifications (:obj:`list` of :obj:`dict`): specifications of other versions of simulation tool test_results (:obj:`list` of :obj:`TestCaseResults`): results of test cases """ - # copy image to BioSimulators namespace of Docker registry (GitHub Container Registry) + # commit image if submission.validate_image: + # copy image to BioSimulators namespace of Docker registry (GitHub Container Registry) self.push_image(specifications, existing_version_specifications) + # instruct runBioSimulations to generate a Singularity image for the Docker image + self.trigger_conversion_of_docker_image_to_singularity(specifications) + # commit submission to BioSimulators database if 'biosimulators' not in specifications: specifications['biosimulators'] = {} @@ -370,6 +384,22 @@ def is_submission_latest_version_of_simulator(self, specifications, existing_ver return False return True + def trigger_conversion_of_docker_image_to_singularity(self, specifications): + """ Post the simulation to the BioSimulators database + + Args: + specifications (:obj:`dict`): specifications of a simulation tool + """ + auth_headers = self.get_auth_headers_for_biosimulations_api(self.RUNBIOSIMULATIONS_AUDIENCE) + + response = requests.post(self.RUNBIOSIMULATIONS_API_ENDPOINT + 'images/refresh', + headers=auth_headers, + json={ + 'simulator': specifications['id'], + 'version': specifications['version'], + }) + response.raise_for_status() + def post_entry_to_biosimulators_api(self, specifications, existing_version_specifications): """ Post the simulation to the BioSimulators database @@ -377,18 +407,7 @@ def post_entry_to_biosimulators_api(self, specifications, existing_version_speci specifications (:obj:`dict`): specifications of a simulation tool existing_version_specifications (:obj:`list` of :obj:`dict`): specifications of other versions of simulation tool """ - api_id = os.getenv('BIOSIMULATORS_API_CLIENT_ID') - api_secret = os.getenv('BIOSIMULATORS_API_CLIENT_SECRET') - - response = requests.post(self.BIOSIMULATORS_AUTH_ENDPOINT, json={ - 'client_id': api_id, - 'client_secret': api_secret, - 'audience': self.BIOSIMULATORS_AUDIENCE, - "grant_type": "client_credentials", - }) - response.raise_for_status() - response_data = response.json() - auth_headers = {'Authorization': response_data['token_type'] + ' ' + response_data['access_token']} + auth_headers = self.get_auth_headers_for_biosimulations_api(self.BIOSIMULATORS_AUDIENCE) existing_versions = [existing_version_spec['version'] for existing_version_spec in existing_version_specifications] update_simulator = specifications['version'] in existing_versions @@ -400,3 +419,26 @@ def post_entry_to_biosimulators_api(self, specifications, existing_version_speci requests_method = requests.post response = requests_method(endpoint, headers=auth_headers, json=specifications) response.raise_for_status() + + def get_auth_headers_for_biosimulations_api(self, audience): + """ Get authorization headers for using one of the BioSimulations REST APIs + (BioSimulators, runBioSimulations, etc.). + + Args: + audience (:obj:`str`): API audience + + Returns: + :obj:`dict`: authorization headers + """ + api_id = os.getenv('BIOSIMULATORS_API_CLIENT_ID') + api_secret = os.getenv('BIOSIMULATORS_API_CLIENT_SECRET') + + response = requests.post(self.BIOSIMULATORS_AUTH_ENDPOINT, json={ + 'client_id': api_id, + 'client_secret': api_secret, + 'audience': audience, + "grant_type": "client_credentials", + }) + response.raise_for_status() + response_data = response.json() + return {'Authorization': response_data['token_type'] + ' ' + response_data['access_token']} diff --git a/tests/test_exec_gh_action.py b/tests/test_exec_gh_action.py index 2d66083..490a2a2 100644 --- a/tests/test_exec_gh_action.py +++ b/tests/test_exec_gh_action.py @@ -344,14 +344,14 @@ def put(self, url, json=None, headers=None, auth=None): with mock.patch('requests.post', side_effect=requests_mock.post): with mock.patch.object(exec_gh_action.ValidateCommitSimulatorGitHubAction, 'push_image', return_value=None): action.commit_simulator(SimulatorSubmission(validate_image=True), specs, existing_version_specs, []) - self.assertEqual(requests_mock.n_post, 4) + self.assertEqual(requests_mock.n_post, 6) existing_version_specs = [{'id': 'tellurium', 'version': '2.1.6'}] with mock.patch.dict(os.environ, self.env): with mock.patch('requests.post', side_effect=requests_mock.post): with mock.patch('requests.put', side_effect=requests_mock.put): action.commit_simulator(SimulatorSubmission(validate_image=False), specs, existing_version_specs, []) - self.assertEqual(requests_mock.n_post, 5) + self.assertEqual(requests_mock.n_post, 7) self.assertEqual(requests_mock.n_put, 1) def test_run(self): @@ -365,6 +365,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(requests_mock.simulator_versions, []) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Invalid'])) self.assertEqual(len(requests_mock.issue_messages), 2) self.assertRegex(requests_mock.issue_messages[-1], 'Specifications must be adhere to the BioSimulators schema') @@ -381,6 +382,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(requests_mock.simulator_versions, []) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated'])) self.assertEqual(len(requests_mock.issue_messages), 2) self.assertEqual(requests_mock.issue_messages[-1], 'The specifications of your simulator is valid!') @@ -398,6 +400,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(requests_mock.simulator_versions, []) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Invalid'])) self.assertEqual(len(requests_mock.issue_messages), 3) self.assertRegex(requests_mock.issue_messages[-1], 'Singularity error') @@ -415,6 +418,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(requests_mock.simulator_versions, []) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Invalid'])) self.assertEqual(len(requests_mock.issue_messages), 4) self.assertRegex(requests_mock.issue_messages[-2], 'Passed 0 test cases') @@ -432,6 +436,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(requests_mock.simulator_versions, []) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Invalid'])) self.assertEqual(len(requests_mock.issue_messages), 4) self.assertRegex(requests_mock.issue_messages[-1], 'No test cases are applicable') @@ -448,6 +453,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(requests_mock.simulator_versions, []) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated'])) self.assertEqual(len(requests_mock.issue_messages), 4) self.assertRegex(requests_mock.issue_messages[-2], 'Passed 1 test cases:') @@ -465,6 +471,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'closed') self.assertEqual(set(v['version'] for v in requests_mock.simulator_versions), set(['2.1.6'])) + self.assertEqual(requests_mock.refreshed_images, [{'simulator': 'tellurium', 'version': '2.1.6'}]) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated', 'Approved'])) self.assertEqual(len(requests_mock.issue_messages), 5) self.assertRegex(requests_mock.issue_messages[-1], 'Your submission was committed to the BioSimulators registry.') @@ -489,6 +496,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(set(v['version'] for v in requests_mock.simulator_versions), set([])) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated'])) self.assertEqual(len(requests_mock.issue_messages), 5) self.assertRegex(requests_mock.issue_messages[-1], 'A member of the BioSimulators team will review your submission') @@ -509,6 +517,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'open') self.assertEqual(set(v['version'] for v in requests_mock.simulator_versions), set(['2.1.5'])) + self.assertEqual(requests_mock.refreshed_images, []) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated'])) self.assertEqual(len(requests_mock.issue_messages), 5) self.assertRegex(requests_mock.issue_messages[-1], 'A member of the BioSimulators team will review your submission') @@ -529,6 +538,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'closed') self.assertEqual(set(v['version'] for v in requests_mock.simulator_versions), set(['2.1.5', '2.1.6'])) + self.assertEqual(requests_mock.refreshed_images, [{'simulator': 'tellurium', 'version': '2.1.6'}]) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated', 'Approved'])) self.assertEqual(len(requests_mock.issue_messages), 5) self.assertRegex(requests_mock.issue_messages[-1], 'Your submission was committed to the BioSimulators registry.') @@ -554,6 +564,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'closed') self.assertEqual(set(v['version'] for v in requests_mock.simulator_versions), set(['2.1.5', '2.1.4'])) + self.assertEqual(requests_mock.refreshed_images, [{'simulator': 'tellurium', 'version': '2.1.4'}]) self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated', 'Approved'])) self.assertEqual(len(requests_mock.issue_messages), 5) self.assertRegex(requests_mock.issue_messages[-1], 'Your submission was committed to the BioSimulators registry.') @@ -577,6 +588,7 @@ def test_run(self): self._exec_run_mock_objs(requests_mock, docker_mock, validation_run_results) self.assertEqual(requests_mock.issue_state, 'closed') self.assertEqual(set(v['version'] for v in requests_mock.simulator_versions), set(['2.1.5'])) + self.assertEqual(requests_mock.refreshed_images, [{'simulator': 'tellurium', 'version': '2.1.5'}]) self.assertEqual(len(requests_mock.simulator_versions[-1]['biosimulators']['validationTests']['results']), 1) self.assertEqual(requests_mock.simulator_versions[-1]['biosimulators']['validationTests']['results'][0]['case']['id'], 'sedml.case-passed') self.assertEqual(requests_mock.issue_labels, set(['Validate/commit simulator', 'Validated', 'Approved'])) @@ -618,6 +630,8 @@ def __init__(self, submitted_version='2.1.6', new_simulator=True, previous_versi }, ] + self.refreshed_images = [] + self.issue_labels = set(['Validate/commit simulator']) if previous_run_valid == True: self.issue_labels.add('Validated') @@ -687,6 +701,10 @@ def post(self, url, json=None, auth=None, headers=None): else: error = 'Specs are invalid' response = None + elif url == exec_gh_action.ValidateCommitSimulatorGitHubAction.RUNBIOSIMULATIONS_API_ENDPOINT + 'images/refresh': + self.refreshed_images.append(json) + error = None + response = None elif url == 'https://api.github.com/repos/biosimulators/Biosimulators/issues/11/labels': for label in json['labels']: self.issue_labels.add(label) From 4b43c141531a24f54dcd3e4e35d26a9923994fcb Mon Sep 17 00:00:00 2001 From: Jonathan Karr Date: Wed, 13 Jan 2021 19:10:59 -0500 Subject: [PATCH 2/2] incrementing version --- biosimulators_test_suite/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/biosimulators_test_suite/_version.py b/biosimulators_test_suite/_version.py index ac1125f..b7e15fa 100644 --- a/biosimulators_test_suite/_version.py +++ b/biosimulators_test_suite/_version.py @@ -1 +1 @@ -__version__ = '0.1.15' +__version__ = '0.1.16'