diff --git a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/oidc_http_client.py b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/oidc_http_client.py index 9affe7f84331ce447bfb328ee43aae888c984226..66faf0c9e66950ce188278b8d32077856bac31a3 100644 --- a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/oidc_http_client.py +++ b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/oidc_http_client.py @@ -1,6 +1,7 @@ """ Class which uses the BBP oidc client to do http calls """ from hbp_nrp_virtual_coach.http_client import HTTPClient +import json class OIDCHTTPClient(HTTPClient): @@ -12,34 +13,72 @@ class OIDCHTTPClient(HTTPClient): """ from bbp_client.oidc.client import BBPOIDCClient self.__oidc_client = BBPOIDCClient.implicit_auth(oidc_username) + self.__headers = None def get(self, url): """ :param url: The url to do a request on + :return: the status of the get request and the content + :rtype: integer, string """ - response, _ = self.__oidc_client.request(url) - return response['status'] + response, content = self.__oidc_client.request(url, headers=self.__headers) + return int(response['status']), content def post(self, url, body): """ :param url: The url to do a post to :param body: The content to post to the url + :return: the status of the post request and the content + :rtype: integer, string """ - response, content = self.__oidc_client.request(url, method='POST', body=body) - return response['status'], content + if (type(body) == dict): + response, content = self.__oidc_client.request( + url, method='POST', body=json.dumps(body), headers=self.__headers + ) + else: + response, content = self.__oidc_client.request( + url, method='POST', body=body, headers=self.__headers + ) + return int(response['status']), content def put(self, url, body): """ :param url: The url to do a request to :param body: The content to put to + :return: the status of the put request and the content + :rtype: integer, string """ - response, content = self.__oidc_client.request(url, method='PUT', body=body) - return response['status'], content + if (type(body) == dict): + response, content = self.__oidc_client.request( + url, method='PUT', body=json.dumps(body), headers=self.__headers + ) + else: + response, content = self.__oidc_client.request( + url, method='PUT', body=body, headers=self.__headers + ) + return int(response['status']), content def delete(self, url, body): """ :param url: The url to do a request on :param body: The content to delete + :return: the status of the delete request + :rtype: integer """ - response, _ = self.__oidc_client.request(url, method='DELETE', body=body) - return response['status'] + response, _ = self.__oidc_client.request( + url, method='DELETE', body=json.dumps(body), headers=self.__headers + ) + return int(response['status']) + + def set_headers(self, headers): + """ + :param headers: The content of the headers + Can only be set after authentication + """ + self.__headers = headers + + def get_auth_header(self): + """ + :return: the authorization header + """ + return self.__oidc_client.get_auth_header() diff --git a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/simulation.py b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/simulation.py index 0a05886d147b5fffd79468b990f5abdf7804ae5e..0eeb441b0053b2845c634100684bd640e007736e 100644 --- a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/simulation.py +++ b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/simulation.py @@ -681,7 +681,7 @@ class Simulation(object): self.pause() try: - status_code, _ = self.__http_client.put(url, body=json.dumps(body)) + status_code, _ = self.__http_client.put(url, body=body) if status_code != httplib.OK: raise Exception("Unable to set Brain, HTTP status %s" % status_code) self.__logger.info("Brain successfully updated.") @@ -691,7 +691,7 @@ class Simulation(object): body['data'] = old_brain body['brain_populations'] = old_populations - status_code, _ = self.__http_client.put(url, body=json.dumps(body)) + status_code, _ = self.__http_client.put(url, body=body) if status_code != httplib.OK: raise Exception("Unable to restore Brain, HTTP status %s" % status_code) @@ -759,7 +759,7 @@ class Simulation(object): self.__logger.info("Attempting to reset %s" % reset_type) url = '%s/%s/%s' % (self.__sim_url, self.__experiment_id, self.__config['simulation-services']['reset']) - body = json.dumps({'resetType': self.__config['reset-services'][reset_type]}) + body = {'resetType': self.__config['reset-services'][reset_type]} status_code, _ = self.__http_client.put(url, body=body) # check the return code, this will return OK if the REST call succeeds diff --git a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_simulation.py b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_simulation.py index 3e49b438b4de66fe239ffdadeda4724ec67a4dbb..f21f6afa693a91a82b2ef38fabba4f955a358588 100644 --- a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_simulation.py +++ b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_simulation.py @@ -65,7 +65,8 @@ class TestSimulation(unittest.TestCase): self.assertRaises(AssertionError, self._sim.launch, 'id', 'conf', None, None) self.assertRaises(AssertionError, self._sim.launch, 'id', 'conf', 'server', True) - def test_failed_server_info(self): + @patch('hbp_nrp_virtual_coach.simulation.traceback') + def test_failed_server_info(self, mocked_traceback): # mock HTTP call to throw Exception self.setUpForLaunch() self._sim._Simulation__http_client.get = Mock() @@ -75,20 +76,25 @@ class TestSimulation(unittest.TestCase): self.assertEqual(self._sim.launch('id', 'conf', 'server', None), False) self._sim._Simulation__http_client.get.assert_called_once() self._sim._Simulation__http_client.post.assert_not_called() - - def test_failed_create_conflict(self): + mocked_traceback.print_exec.assert_called_once() + + @patch('hbp_nrp_virtual_coach.simulation.traceback') + def test_failed_create_conflict(self, mocked_traceback): self.setUpForLaunch() self._sim._Simulation__http_client.post = Mock(return_value=(httplib.CONFLICT, '{}')) self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False) self._sim._Simulation__http_client.post.assert_called_once() + mocked_traceback.print_exec.assert_called_once() - def test_failed_create_other(self): + @patch('hbp_nrp_virtual_coach.simulation.traceback') + def test_failed_create_other(self, mocked_traceback): self.setUpForLaunch() self._sim._Simulation__http_client.post = Mock(return_value=(httplib.NOT_FOUND, '{}')) self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False) self._sim._Simulation__http_client.post.assert_called_once() + mocked_traceback.print_exec.assert_called_once() def test_create(self): self.setUpForLaunch() diff --git a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_virtual_coach.py b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_virtual_coach.py index 5732654ba8077b9db9ff333a52402e279af2677a..9b18051f03d75f9eff44af93e3adba3b5e06ff2e 100644 --- a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_virtual_coach.py +++ b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/tests/test_virtual_coach.py @@ -42,10 +42,9 @@ from StringIO import StringIO class TestVirtualCoach(unittest.TestCase): - @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token') @patch('getpass.getpass', return_value='password') - def setUp(self, mock_getpass, mock_login): + def setUp(self, mock_getpass, mock_storage_login): # cause the rospy import to fail since we can't include it as a dependency # (for Collab support and build support without a running roscore) @@ -58,6 +57,7 @@ class TestVirtualCoach(unittest.TestCase): raise ImportError('no ROS for tests') return realimport(name, globals, locals, fromlist, level) builtins.__import__ = rospy_import_fail + self._vc = VirtualCoach(environment='local', storage_username='nrpuser') @@ -134,20 +134,19 @@ class TestVirtualCoach(unittest.TestCase): def test_no_login_credentials(self): self.assertRaises(Exception, VirtualCoach) + + @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token') + @patch('getpass.getpass', return_value='password') + def test_storage_auth(self, mock_getpass, mock_storage_login): + # mocked storage authentication, ensure called if username provided + VirtualCoach(environment='local', storage_username='nrpuser') + mock_storage_login.assert_called_once_with('nrpuser', 'password') + @patch('bbp_client.oidc.client.BBPOIDCClient.implicit_auth') - def test_init_oidc_login(self, mock_login): - + def test_oidc_auth(self, mock_oidc_login): # mocked OIDC authentication, ensure called if username provided - mock_login.returnValue = BBPOIDCClient() - oidc_vc = VirtualCoach(oidc_username='foo') - mock_login.assert_called_once_with('foo') - - @patch('getpass.getpass', return_value='password') - @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token') - def test_init_storage_login(self, mock_login, mock_getpass): - storage_vc = VirtualCoach(storage_username='user') - mock_login.assert_called_once_with('user', 'password') - + VirtualCoach(environment='dev', oidc_username='youknowwho') + mock_oidc_login.assert_called_once_with('youknowwho') @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token') @@ -167,14 +166,14 @@ class TestVirtualCoach(unittest.TestCase): VirtualCoach(environment='local', storage_username='nrpuser') mock_rospy.init_node.assert_called_once_with('virtual_coach') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('sys.stdout', new_callable=StringIO) - def test_print_templates(self, mock_stdout, mock_list, mock_getpass): - # invalid dev option + def test_print_templates(self, mock_stdout, mock_list): + # invalid dev option (should be True or False; it is set to False by default) self.assertRaises(AssertionError, self._vc.print_templates, 'foo') - # mock the OIDC server call + + # mock the server call mock_list.return_value = self._mock_exp_list self._vc.print_templates() @@ -189,12 +188,11 @@ class TestVirtualCoach(unittest.TestCase): """ self.assertEqual(mock_stdout.getvalue().strip(), prod_table.strip()) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('sys.stdout', new_callable=StringIO) - def test_print_templates_dev(self, mock_stdout, mock_list, mock_getpass): + def test_print_templates_dev(self, mock_stdout, mock_list): - # mock the OIDC server call + # mock the Storage server calls mock_list.return_value = self._mock_exp_list self._vc.print_templates(True) @@ -211,11 +209,10 @@ class TestVirtualCoach(unittest.TestCase): """ self.assertEqual(mock_stdout.getvalue().strip(), dev_table.strip()) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('hbp_nrp_virtual_coach.virtual_coach.datetime') @patch('sys.stdout', new_callable=StringIO) - def test_print_running_experiments_local(self, mock_stdout, mock_date, mock_list, mock_getpass): + def test_print_running_experiments_local(self, mock_stdout, mock_date, mock_list): # mock the OIDC server call mock_list.return_value = self._mock_exp_list_local @@ -234,17 +231,15 @@ class TestVirtualCoach(unittest.TestCase): """ self.assertEqual(mock_stdout.getvalue().strip(), running_table.strip()) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('hbp_nrp_virtual_coach.virtual_coach.datetime') @patch('sys.stdout', new_callable=StringIO) - def test_print_running_experiments(self, mock_stdout, mock_date, mock_list, mock_getpass): - + def test_print_running_experiments(self, mock_stdout, mock_date, mock_list): self._vc._VirtualCoach__oidc_username = 'user' - # mock the OIDC server call + # mock the Storage/OIDC server call mock_list.return_value = self._mock_exp_list - # mock the user lookup OIDC call + # mock the user lookup Storage/OIDC call def fake_user_lookup(url): i = url.rsplit('/')[-1] if i == '1': @@ -259,7 +254,6 @@ class TestVirtualCoach(unittest.TestCase): # mock the current time (so that the table prints consistently) mock_date.now = Mock(return_value=parser.parse('Feb 03 12:20:03 UTC 2017')) - self._vc.print_running_experiments() running_table = """ @@ -275,10 +269,9 @@ class TestVirtualCoach(unittest.TestCase): """ self.assertEqual(mock_stdout.getvalue().strip(), running_table.strip()) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list') @patch('sys.stdout', new_callable=StringIO) - def test_print_available_servers(self, mock_stdout, available_servers, mock_getpass): + def test_print_available_servers(self, mock_stdout, available_servers): # mock the GET server call available_servers.return_value = self._mock_available_servers_list @@ -291,10 +284,9 @@ mock-server-5 """ self.assertEqual(mock_stdout.getvalue().strip(), available_servers.strip()) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list') @patch('sys.stdout', new_callable=StringIO) - def test_print_no_available_servers(self, mock_stdout, available_servers, mock_getpass): + def test_print_no_available_servers(self, mock_stdout, available_servers): # mock the HTTP server call available_servers.return_value = [] @@ -303,73 +295,63 @@ mock-server-5 available_servers = 'No available servers.' self.assertEqual(mock_stdout.getvalue().strip(), available_servers.strip()) - @patch('getpass.getpass', return_value='password') - def test_get_experiment_list(self, password): + def test_get_experiment_list(self): - # mock the request + # mock the request (storage) self._vc._VirtualCoach__http_client.get = Mock() self._vc._VirtualCoach__http_client.get.return_value = 'x', json.dumps(self._mock_exp_list) list_json = self._vc._VirtualCoach__get_experiment_list() self.assertEqual(list_json, self._mock_exp_list) - @patch('getpass.getpass', return_value='password') @patch('requests.get') - def test_get_cloned_experiment_list(self, mock_request, mock_getpass): + def test_get_cloned_experiment_list(self, mock_request): mock_response = requests.Response mock_response.content = json.dumps(self._mock_exp_list_cloned) mock_request.return_value = mock_response + expected_list = {'MockExperiment2_0': {'uuid': 'MockExperiment2_0', 'name': 'MockExperiment2_0'}, 'MockExperiment1_0': {'uuid': 'MockExperiment1_0', 'name': 'MockExperiment1_0'}} exp_list = self._vc._VirtualCoach__get_experiment_list(cloned=True) - self.assertEqual(exp_list, {'MockExperiment2_0': {'uuid': 'MockExperiment2_0', 'name': 'MockExperiment2_0'}, 'MockExperiment1_0': {'uuid': 'MockExperiment1_0', 'name': 'MockExperiment1_0'}}) + self.assertEqual(exp_list, expected_list) - @patch('getpass.getpass', return_value='password') - def test_launch_asserts(self, mock_getpass): + def test_launch_asserts(self): self.assertRaises(AssertionError, self._vc.launch_experiment, None) self.assertRaises(AssertionError, self._vc.launch_experiment, 'foo', True) self.assertRaises(AssertionError, self._vc.launch_experiment, 'foo', None, False) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') - def test_launch_invalid_experiment(self, mock_list, mock_getpass): - - # mock the OIDC server call + def test_launch_invalid_experiment(self, mock_list): + # mock the Storage/OIDC server call mock_list.return_value = self._mock_exp_list self.assertRaises(ValueError, self._vc.launch_experiment, 'InvalidExperimentID') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') - def test_launch_invalid_server(self, mock_list, servers_list, mock_getpass): + def test_launch_invalid_server(self, mock_list, servers_list): # mock the experiments and servers call - self._vc._VirtualCoach__storage_username= 'storage_username' mock_list.return_value = self._mock_exp_list servers_list.return_value = self._mock_available_servers_list self.assertRaises(ValueError, self._vc.launch_experiment, 'MockExperiment1', 'invalid-server-1') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') - def test_launch_no_available_servers(self, mock_list, servers_list, mock_getpass): + def test_launch_no_available_servers(self, mock_list, servers_list): - # mock the OIDC server call - self._vc._VirtualCoach__storage_username = 'storage_username' + # mock the Storage server call mock_list.return_value = self._mock_exp_list servers_list.return_value = [] self.assertRaises(ValueError, self._vc.launch_experiment, 'MockExperiment1') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('hbp_nrp_virtual_coach.simulation.Simulation.__init__') @patch('hbp_nrp_virtual_coach.simulation.Simulation.launch') - def test_launch_one_server(self, mock_sim_launch, mock_sim, mock_list, servers_list, mock_getpass): + def test_launch_one_server(self, mock_sim_launch, mock_sim, mock_list, servers_list): # mock sim launch to succeed mock_sim.return_value = None mock_sim_launch.return_value = True - self._vc._VirtualCoach__storage_username = 'storage_username' # mock the GET server call servers_list.return_value = self._mock_available_servers_list @@ -377,17 +359,15 @@ mock-server-5 mock_list.return_value = self._mock_exp_list self._vc.launch_experiment('MockExperiment1', 'mock-server-4') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('hbp_nrp_virtual_coach.simulation.Simulation.__init__') @patch('hbp_nrp_virtual_coach.simulation.Simulation.launch') - def test_launch_any(self, mock_sim_launch, mock_sim, mock_list, servers_list, mock_getpass): + def test_launch_any(self, mock_sim_launch, mock_sim, mock_list, servers_list): # mock sim launch to succeed mock_sim.return_value = None - self._vc._VirtualCoach__storage_username = 'username' - self._vc._VirtualCoach__storage_headers = {'Authorization': 'token'} + self._vc._VirtualCoach__http_headers = {'Authorization': 'token'} def launch(experiment_id, experiment_conf, server, reservation, cloned): if server == 'mock-server-1': @@ -400,73 +380,58 @@ mock-server-5 servers_list.return_value = self._mock_available_servers_list self._vc.launch_experiment('MockExperiment1') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('hbp_nrp_virtual_coach.simulation.Simulation.__init__') @patch('hbp_nrp_virtual_coach.simulation.Simulation.launch') - def test_launch_all_fail(self, mock_sim_launch, mock_sim, mock_list, mock_getpass): + def test_launch_all_fail(self, mock_sim_launch, mock_sim, mock_list): # mock sim launch call to throw exception / etc mock_sim.return_value = None mock_sim_launch.return_value = False - # mock the OIDC server call + # mock the Storage/OIDC server call mock_list.return_value = self._mock_exp_list self.assertRaises(Exception, self._vc.launch_experiment, 'MockExperiment1') - @patch('getpass.getpass', return_value='password') - def test_clone_experiment_to_storage_assert(self, mock_getpass): + def test_clone_experiment_to_storage_assert(self): self.assertRaises(AssertionError, self._vc.clone_experiment_to_storage, 123) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('requests.post') - def test_clone_experiment_to_storage_fail(self, request, mock_list, mock_getpass): + def test_clone_experiment_to_storage_fail(self, request, mock_list): mock_list.return_value = self._mock_exp_list class Request(object): status_code = 477 request.return_value = Request() - self._vc._VirtualCoach__storage_username = 'token' self.assertRaises(Exception, self._vc.clone_experiment_to_storage, 'MockExperiment1') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') - def test_clone_invalid_experiment(self, mock_list, mock_getpass): + def test_clone_invalid_experiment(self, mock_list): mock_list.return_value = self._mock_exp_list self.assertRaises(ValueError, self._vc.clone_experiment_to_storage, 'invalid_configuration') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('hbp_nrp_virtual_coach.virtual_coach.logger.info') - @patch('requests.post') - def test_clone_experiment_to_storage(self, request, mock_logger, mock_list, mock_getpass): + def test_clone_experiment_to_storage(self, mock_logger, mock_list): mock_list.return_value = self._mock_exp_list - - class Request(object): - status_code = 200 - content = 'experiment_id' - - request.return_value = Request() - self._vc._VirtualCoach__storage_username = 'username' + self._vc._VirtualCoach__http_client = Mock(post=Mock(return_value=[200, 'experiment_id'])) self._vc.clone_experiment_to_storage('MockExperiment1') - mock_logger.assert_called_once() + self.assertEqual(mock_logger.call_count, 1) - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') - def test_delete_cloned_experiment_failed(self, mock_list, mock_login, mock_getpass): + def test_delete_cloned_experiment_failed(self, mock_list, mock_login): mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0'] self.assertRaises(ValueError, self._vc.delete_cloned_experiment, 'foo') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') - @patch('requests.delete') - def test_delete_cloned_experiment(self, mock_request, mock_list, mock_getpass): + def test_delete_cloned_experiment(self, mock_list): + self._vc._VirtualCoach__http_client = Mock(delete=Mock()) mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0'] self._vc.delete_cloned_experiment('MockExperiment1_0') - mock_request.assert_called_once() + self.assertEqual(self._vc._VirtualCoach__http_client.delete.call_count, 1) def test_clone_cloned_experiment(self): self.assertRaises(AssertionError, self._vc.clone_cloned_experiment, 123) @@ -476,9 +441,10 @@ mock-server-5 mock_list.return_value = [] self.assertRaises(ValueError, self._vc.clone_cloned_experiment, 'missing_id') + @patch('bbp_client.oidc.client.BBPOIDCClient.implicit_auth') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('requests.post') - def test_clone_cloned_to_storage_fail(self, request, mock_list): + def test_clone_cloned_to_storage_fail(self, request, mock_list, mocked_oidc_login): mock_list.return_value = ['exp_id'] class Request(object): @@ -487,8 +453,10 @@ mock-server-5 request.return_value = Request() self._vc._VirtualCoach__storage_username = None self.assertRaises(ValueError, self._vc.clone_cloned_experiment, 'exp_id') - self._vc._VirtualCoach__storage_username = 'token' - self.assertRaises(Exception, self._vc.clone_cloned_experiment, 'exp_id') + + vc_oidc_username = VirtualCoach(environment='dev', oidc_username='youknowwho') + vc_oidc_username._VirtualCoach__http_client._OIDCHTTPClient__oidc_client.request = Mock(return_value=[{'status': 477}, 'something']) + self.assertRaises(Exception, vc_oidc_username.clone_cloned_experiment, 'exp_id') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('requests.post') @@ -500,14 +468,12 @@ mock-server-5 content = None request.return_value = Request() - self._vc._VirtualCoach__storage_username = 'token' self._vc.clone_cloned_experiment('exp_id') - @patch('getpass.getpass', return_value='password') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @patch('sys.stdout', new_callable=StringIO) - def test_print_cloned_experiments(self, mock_stdout, mock_list, mock_getpass): + def test_print_cloned_experiments(self, mock_stdout, mock_list): self._vc._VirtualCoach__storage_username = 'token' mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0'] self._vc.print_cloned_experiments() @@ -522,14 +488,12 @@ mock-server-5 """ self.assertEqual(mock_stdout.getvalue().strip(), cloned_experiments.strip()) - @patch('getpass.getpass', return_value='password') - def test_get_storage_token_asserts(self, mock_getpass): + def test_get_storage_token_asserts(self): self.assertRaises(AssertionError, self._vc._VirtualCoach__get_storage_token, 123, 'foo') self.assertRaises(AssertionError, self._vc._VirtualCoach__get_storage_token, 'foo', 123) - @patch('getpass.getpass', return_value='password') @patch('requests.post') - def test_get_storage_token_fail(self, mock_request, mock_getpass): + def test_get_storage_token_fail(self, mock_request): class Response(object): status_code = 500 @@ -537,9 +501,8 @@ mock-server-5 mock_request.return_value = Response() self.assertRaises(Exception, self._vc._VirtualCoach__get_storage_token, 'user', 'pass') - @patch('getpass.getpass', return_value='password') @patch('requests.post') - def test_get_storage_token(self, mock_request, mock_getpass): + def test_get_storage_token(self, mock_request): class Response(object): status_code = 200 diff --git a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/virtual_coach.py b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/virtual_coach.py index bfc402cf3d3795d0cd559c999a020088123afaa3..af882789c4cd902788f68721a6fe97b605c32db7 100644 --- a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/virtual_coach.py +++ b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/virtual_coach.py @@ -108,6 +108,13 @@ class VirtualCoach(object): # this will interactively prompt the user for a password in terminal if needed logger.info('Logging into OIDC as: %s', oidc_username) self.__http_client = OIDCHTTPClient(oidc_username) + + authorization = self.__http_client.get_auth_header() + # Set self.__http_headers: it is also used + # as an argument of requests.post() and requests.get() + self.__http_headers = {'Content-Type': 'application/json', + 'Authorization': authorization} + self.__http_client.set_headers(self.__http_headers) # if a Storage Server username is provided, attempt to login elif storage_username: # this will interactively prompt the user for a password in terminal @@ -116,11 +123,12 @@ class VirtualCoach(object): logger.info('Logging into the Storage Server as: %s', storage_username) if not storage_password: storage_password = getpass.getpass() - self.__storage_headers = {'Content-Type': 'application/json', - 'Authorization': 'Bearer %s' % self.__get_storage_token( - storage_username, storage_password)} - - self.__http_client = RequestsClient(self.__storage_headers) + authorization = 'Bearer %s' % self.__get_storage_token( + storage_username, storage_password + ) + self.__http_headers = {'Content-Type': 'application/json', + 'Authorization': authorization} + self.__http_client = RequestsClient(self.__http_headers) else: raise Exception('Virtual Coach instantiated without storage server credentials or oidc' 'credentials. You have to provide either one with the keywords ' @@ -251,8 +259,6 @@ class VirtualCoach(object): # get the experiment configuration details and available servers that can be used available_servers = self.__get_available_server_list() - from pprint import pprint - pprint(available_servers) servers = [available_server['id'] for available_server in available_servers] if cloned: experiment_conf = "" @@ -297,7 +303,6 @@ class VirtualCoach(object): :returns: The ID of the cloned experiment """ assert isinstance(exp_id, str) - exp = self.__get_experiment_list() if exp_id not in exp.keys(): raise ValueError('Experiment ID: "%s" is invalid, please check the list of all ' @@ -345,15 +350,15 @@ class VirtualCoach(object): # Raise Error in case no storage server token available. To get the token, the VC has to be # instantiated with the storage_username parameter - if self.__storage_username is None: - raise ValueError('No Storage Server credentials found.' - 'To be able to clone experiments, you have to instantiate the' - 'Virtual Coach either with the storage_username parameter or' + if self.__storage_username is None and self.__oidc_username is None: + raise ValueError('No Storage Server credentials found. ' + 'To be able to clone experiments, you have to instantiate the ' + 'Virtual Coach either with the storage_username parameter or ' 'the oidc_username parameter and login successfully') res = requests.post('%s/%s' % (self.__config['proxy-services']['experiment-clone'], experiment_id), - headers=self.__storage_headers) + headers=self.__http_headers) if res.status_code != 200: raise Exception('Cloning Experiment failed, Status Code: %s' % res.status_code) else: @@ -399,10 +404,9 @@ class VirtualCoach(object): assert isinstance(cloned, bool) logger.info('Retrieving list of experiments.') - headers = None if self.__oidc_username else self.__storage_headers if cloned: url = self.__config['proxy-services']['storage-experiment-list'] - response = requests.get(url, headers=headers) + response = requests.get(url, headers=self.__http_headers) # return a simple list containing only experiment names since this is the only # information in the dictionary anyway return {experiment['name']: experiment for experiment in json.loads(response.content)}