Skip to content
Snippets Groups Projects
Commit 51954950 authored by Luc Guyot's avatar Luc Guyot Committed by Axel von Arnim
Browse files

Merged in NRRPLT-7174 (pull request #7)


[NRRPLT-7174] Fixes the Virtual Coach's HTTP calls that rely on OIDC authorization

* [NRRPLT-7174] Fixes the Virtual Coach's HTTP calls that rely on OIDC authorization

* [NRRPLT-7174] Fixes put and post calls of oidc_http_client

* [NRRPLT-7174] Removes redundant OIDC unit tests

* [NRRPLT-7174] Removes redundant OIDC unit tests (part 2)

* [NRRPLT-7174] Removes redundant OIDC unit tests (part 3)

* [NRRPLT-7174] Removes redundant OIDC unit tests (part 4)

* [NRRPLT-7174] Removes redundant OIDC unit tests (part 5)

* [NRRPLT-7174] Removes redundant OIDC unit tests (part 6)

* [NRRPLT-7174] Reinstate a test for the clone of a cloned experiment with OIDC auth

Approved-by: default avatarSusie Murphy <susie.murphy@epfl.ch>
parent a85264a8
Branches
No related tags found
No related merge requests found
""" Class which uses the BBP oidc client to do http calls """ """ Class which uses the BBP oidc client to do http calls """
from hbp_nrp_virtual_coach.http_client import HTTPClient from hbp_nrp_virtual_coach.http_client import HTTPClient
import json
class OIDCHTTPClient(HTTPClient): class OIDCHTTPClient(HTTPClient):
...@@ -12,34 +13,72 @@ class OIDCHTTPClient(HTTPClient): ...@@ -12,34 +13,72 @@ class OIDCHTTPClient(HTTPClient):
""" """
from bbp_client.oidc.client import BBPOIDCClient from bbp_client.oidc.client import BBPOIDCClient
self.__oidc_client = BBPOIDCClient.implicit_auth(oidc_username) self.__oidc_client = BBPOIDCClient.implicit_auth(oidc_username)
self.__headers = None
def get(self, url): def get(self, url):
""" """
:param url: The url to do a request on :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) response, content = self.__oidc_client.request(url, headers=self.__headers)
return response['status'] return int(response['status']), content
def post(self, url, body): def post(self, url, body):
""" """
:param url: The url to do a post to :param url: The url to do a post to
:param body: The content to post to the url :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) if (type(body) == dict):
return response['status'], content 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): def put(self, url, body):
""" """
:param url: The url to do a request to :param url: The url to do a request to
:param body: The content to put 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) if (type(body) == dict):
return response['status'], content 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): def delete(self, url, body):
""" """
:param url: The url to do a request on :param url: The url to do a request on
:param body: The content to delete :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) response, _ = self.__oidc_client.request(
return response['status'] 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()
...@@ -681,7 +681,7 @@ class Simulation(object): ...@@ -681,7 +681,7 @@ class Simulation(object):
self.pause() self.pause()
try: 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: if status_code != httplib.OK:
raise Exception("Unable to set Brain, HTTP status %s" % status_code) raise Exception("Unable to set Brain, HTTP status %s" % status_code)
self.__logger.info("Brain successfully updated.") self.__logger.info("Brain successfully updated.")
...@@ -691,7 +691,7 @@ class Simulation(object): ...@@ -691,7 +691,7 @@ class Simulation(object):
body['data'] = old_brain body['data'] = old_brain
body['brain_populations'] = old_populations 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: if status_code != httplib.OK:
raise Exception("Unable to restore Brain, HTTP status %s" % status_code) raise Exception("Unable to restore Brain, HTTP status %s" % status_code)
...@@ -759,7 +759,7 @@ class Simulation(object): ...@@ -759,7 +759,7 @@ class Simulation(object):
self.__logger.info("Attempting to reset %s" % reset_type) self.__logger.info("Attempting to reset %s" % reset_type)
url = '%s/%s/%s' % (self.__sim_url, self.__experiment_id, url = '%s/%s/%s' % (self.__sim_url, self.__experiment_id,
self.__config['simulation-services']['reset']) 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) status_code, _ = self.__http_client.put(url, body=body)
# check the return code, this will return OK if the REST call succeeds # check the return code, this will return OK if the REST call succeeds
......
...@@ -65,7 +65,8 @@ class TestSimulation(unittest.TestCase): ...@@ -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', None, None)
self.assertRaises(AssertionError, self._sim.launch, 'id', 'conf', 'server', True) 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 # mock HTTP call to throw Exception
self.setUpForLaunch() self.setUpForLaunch()
self._sim._Simulation__http_client.get = Mock() self._sim._Simulation__http_client.get = Mock()
...@@ -75,20 +76,25 @@ class TestSimulation(unittest.TestCase): ...@@ -75,20 +76,25 @@ class TestSimulation(unittest.TestCase):
self.assertEqual(self._sim.launch('id', 'conf', 'server', None), False) self.assertEqual(self._sim.launch('id', 'conf', 'server', None), False)
self._sim._Simulation__http_client.get.assert_called_once() self._sim._Simulation__http_client.get.assert_called_once()
self._sim._Simulation__http_client.post.assert_not_called() self._sim._Simulation__http_client.post.assert_not_called()
mocked_traceback.print_exec.assert_called_once()
def test_failed_create_conflict(self): @patch('hbp_nrp_virtual_coach.simulation.traceback')
def test_failed_create_conflict(self, mocked_traceback):
self.setUpForLaunch() self.setUpForLaunch()
self._sim._Simulation__http_client.post = Mock(return_value=(httplib.CONFLICT, '{}')) self._sim._Simulation__http_client.post = Mock(return_value=(httplib.CONFLICT, '{}'))
self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False) self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False)
self._sim._Simulation__http_client.post.assert_called_once() 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.setUpForLaunch()
self._sim._Simulation__http_client.post = Mock(return_value=(httplib.NOT_FOUND, '{}')) self._sim._Simulation__http_client.post = Mock(return_value=(httplib.NOT_FOUND, '{}'))
self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False) self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False)
self._sim._Simulation__http_client.post.assert_called_once() self._sim._Simulation__http_client.post.assert_called_once()
mocked_traceback.print_exec.assert_called_once()
def test_create(self): def test_create(self):
self.setUpForLaunch() self.setUpForLaunch()
......
...@@ -42,10 +42,9 @@ from StringIO import StringIO ...@@ -42,10 +42,9 @@ from StringIO import StringIO
class TestVirtualCoach(unittest.TestCase): class TestVirtualCoach(unittest.TestCase):
@patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token')
@patch('getpass.getpass', return_value='password') @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 # 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) # (for Collab support and build support without a running roscore)
...@@ -59,6 +58,7 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -59,6 +58,7 @@ class TestVirtualCoach(unittest.TestCase):
return realimport(name, globals, locals, fromlist, level) return realimport(name, globals, locals, fromlist, level)
builtins.__import__ = rospy_import_fail builtins.__import__ = rospy_import_fail
self._vc = VirtualCoach(environment='local', storage_username='nrpuser') self._vc = VirtualCoach(environment='local', storage_username='nrpuser')
self._mock_available_servers_list = [ self._mock_available_servers_list = [
...@@ -134,20 +134,19 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -134,20 +134,19 @@ class TestVirtualCoach(unittest.TestCase):
def test_no_login_credentials(self): def test_no_login_credentials(self):
self.assertRaises(Exception, VirtualCoach) self.assertRaises(Exception, VirtualCoach)
@patch('bbp_client.oidc.client.BBPOIDCClient.implicit_auth')
def test_init_oidc_login(self, mock_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') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token')
def test_init_storage_login(self, mock_login, mock_getpass): @patch('getpass.getpass', return_value='password')
storage_vc = VirtualCoach(storage_username='user') def test_storage_auth(self, mock_getpass, mock_storage_login):
mock_login.assert_called_once_with('user', 'password') # 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_oidc_auth(self, mock_oidc_login):
# mocked OIDC authentication, ensure called if username provided
VirtualCoach(environment='dev', oidc_username='youknowwho')
mock_oidc_login.assert_called_once_with('youknowwho')
@patch('getpass.getpass', return_value='password') @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_storage_token')
...@@ -167,14 +166,14 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -167,14 +166,14 @@ class TestVirtualCoach(unittest.TestCase):
VirtualCoach(environment='local', storage_username='nrpuser') VirtualCoach(environment='local', storage_username='nrpuser')
mock_rospy.init_node.assert_called_once_with('virtual_coach') 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('sys.stdout', new_callable=StringIO) @patch('sys.stdout', new_callable=StringIO)
def test_print_templates(self, mock_stdout, mock_list, mock_getpass): def test_print_templates(self, mock_stdout, mock_list):
# invalid dev option # invalid dev option (should be True or False; it is set to False by default)
self.assertRaises(AssertionError, self._vc.print_templates, 'foo') 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 mock_list.return_value = self._mock_exp_list
self._vc.print_templates() self._vc.print_templates()
...@@ -189,12 +188,11 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -189,12 +188,11 @@ class TestVirtualCoach(unittest.TestCase):
""" """
self.assertEqual(mock_stdout.getvalue().strip(), prod_table.strip()) 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('sys.stdout', new_callable=StringIO) @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 mock_list.return_value = self._mock_exp_list
self._vc.print_templates(True) self._vc.print_templates(True)
...@@ -211,11 +209,10 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -211,11 +209,10 @@ class TestVirtualCoach(unittest.TestCase):
""" """
self.assertEqual(mock_stdout.getvalue().strip(), dev_table.strip()) 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.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('hbp_nrp_virtual_coach.virtual_coach.datetime') @patch('hbp_nrp_virtual_coach.virtual_coach.datetime')
@patch('sys.stdout', new_callable=StringIO) @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 the OIDC server call
mock_list.return_value = self._mock_exp_list_local mock_list.return_value = self._mock_exp_list_local
...@@ -234,17 +231,15 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -234,17 +231,15 @@ class TestVirtualCoach(unittest.TestCase):
""" """
self.assertEqual(mock_stdout.getvalue().strip(), running_table.strip()) 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.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('hbp_nrp_virtual_coach.virtual_coach.datetime') @patch('hbp_nrp_virtual_coach.virtual_coach.datetime')
@patch('sys.stdout', new_callable=StringIO) @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' 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_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): def fake_user_lookup(url):
i = url.rsplit('/')[-1] i = url.rsplit('/')[-1]
if i == '1': if i == '1':
...@@ -259,7 +254,6 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -259,7 +254,6 @@ class TestVirtualCoach(unittest.TestCase):
# mock the current time (so that the table prints consistently) # 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')) mock_date.now = Mock(return_value=parser.parse('Feb 03 12:20:03 UTC 2017'))
self._vc.print_running_experiments() self._vc.print_running_experiments()
running_table = """ running_table = """
...@@ -275,10 +269,9 @@ class TestVirtualCoach(unittest.TestCase): ...@@ -275,10 +269,9 @@ class TestVirtualCoach(unittest.TestCase):
""" """
self.assertEqual(mock_stdout.getvalue().strip(), running_table.strip()) 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list')
@patch('sys.stdout', new_callable=StringIO) @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 # mock the GET server call
available_servers.return_value = self._mock_available_servers_list available_servers.return_value = self._mock_available_servers_list
...@@ -291,10 +284,9 @@ mock-server-5 ...@@ -291,10 +284,9 @@ mock-server-5
""" """
self.assertEqual(mock_stdout.getvalue().strip(), available_servers.strip()) 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_available_server_list')
@patch('sys.stdout', new_callable=StringIO) @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 # mock the HTTP server call
available_servers.return_value = [] available_servers.return_value = []
...@@ -303,73 +295,63 @@ mock-server-5 ...@@ -303,73 +295,63 @@ mock-server-5
available_servers = 'No available servers.' available_servers = 'No available servers.'
self.assertEqual(mock_stdout.getvalue().strip(), available_servers.strip()) self.assertEqual(mock_stdout.getvalue().strip(), available_servers.strip())
@patch('getpass.getpass', return_value='password') def test_get_experiment_list(self):
def test_get_experiment_list(self, password):
# mock the request # mock the request (storage)
self._vc._VirtualCoach__http_client.get = Mock() self._vc._VirtualCoach__http_client.get = Mock()
self._vc._VirtualCoach__http_client.get.return_value = 'x', json.dumps(self._mock_exp_list) self._vc._VirtualCoach__http_client.get.return_value = 'x', json.dumps(self._mock_exp_list)
list_json = self._vc._VirtualCoach__get_experiment_list() list_json = self._vc._VirtualCoach__get_experiment_list()
self.assertEqual(list_json, self._mock_exp_list) self.assertEqual(list_json, self._mock_exp_list)
@patch('getpass.getpass', return_value='password')
@patch('requests.get') @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 = requests.Response
mock_response.content = json.dumps(self._mock_exp_list_cloned) mock_response.content = json.dumps(self._mock_exp_list_cloned)
mock_request.return_value = mock_response 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) 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):
def test_launch_asserts(self, mock_getpass):
self.assertRaises(AssertionError, self._vc.launch_experiment, None) 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', True)
self.assertRaises(AssertionError, self._vc.launch_experiment, 'foo', None, False) 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') @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
def test_launch_invalid_experiment(self, mock_list, mock_getpass): def test_launch_invalid_experiment(self, mock_list):
# mock the Storage/OIDC server call
# mock the OIDC server call
mock_list.return_value = self._mock_exp_list mock_list.return_value = self._mock_exp_list
self.assertRaises(ValueError, self._vc.launch_experiment, 'InvalidExperimentID') 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_available_server_list')
@patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_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 # mock the experiments and servers call
self._vc._VirtualCoach__storage_username= 'storage_username'
mock_list.return_value = self._mock_exp_list mock_list.return_value = self._mock_exp_list
servers_list.return_value = self._mock_available_servers_list servers_list.return_value = self._mock_available_servers_list
self.assertRaises(ValueError, self._vc.launch_experiment, 'MockExperiment1', 'invalid-server-1') 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_available_server_list')
@patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_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 # mock the Storage server call
self._vc._VirtualCoach__storage_username = 'storage_username'
mock_list.return_value = self._mock_exp_list mock_list.return_value = self._mock_exp_list
servers_list.return_value = [] servers_list.return_value = []
self.assertRaises(ValueError, self._vc.launch_experiment, 'MockExperiment1') 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_available_server_list')
@patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_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.__init__')
@patch('hbp_nrp_virtual_coach.simulation.Simulation.launch') @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 launch to succeed
mock_sim.return_value = None mock_sim.return_value = None
mock_sim_launch.return_value = True mock_sim_launch.return_value = True
self._vc._VirtualCoach__storage_username = 'storage_username'
# mock the GET server call # mock the GET server call
servers_list.return_value = self._mock_available_servers_list servers_list.return_value = self._mock_available_servers_list
...@@ -377,17 +359,15 @@ mock-server-5 ...@@ -377,17 +359,15 @@ mock-server-5
mock_list.return_value = self._mock_exp_list mock_list.return_value = self._mock_exp_list
self._vc.launch_experiment('MockExperiment1', 'mock-server-4') 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_available_server_list')
@patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_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.__init__')
@patch('hbp_nrp_virtual_coach.simulation.Simulation.launch') @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 launch to succeed
mock_sim.return_value = None mock_sim.return_value = None
self._vc._VirtualCoach__storage_username = 'username' self._vc._VirtualCoach__http_headers = {'Authorization': 'token'}
self._vc._VirtualCoach__storage_headers = {'Authorization': 'token'}
def launch(experiment_id, experiment_conf, server, reservation, cloned): def launch(experiment_id, experiment_conf, server, reservation, cloned):
if server == 'mock-server-1': if server == 'mock-server-1':
...@@ -400,73 +380,58 @@ mock-server-5 ...@@ -400,73 +380,58 @@ mock-server-5
servers_list.return_value = self._mock_available_servers_list servers_list.return_value = self._mock_available_servers_list
self._vc.launch_experiment('MockExperiment1') 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.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('hbp_nrp_virtual_coach.simulation.Simulation.__init__') @patch('hbp_nrp_virtual_coach.simulation.Simulation.__init__')
@patch('hbp_nrp_virtual_coach.simulation.Simulation.launch') @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 launch call to throw exception / etc
mock_sim.return_value = None mock_sim.return_value = None
mock_sim_launch.return_value = False 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 mock_list.return_value = self._mock_exp_list
self.assertRaises(Exception, self._vc.launch_experiment, 'MockExperiment1') self.assertRaises(Exception, self._vc.launch_experiment, 'MockExperiment1')
@patch('getpass.getpass', return_value='password') def test_clone_experiment_to_storage_assert(self):
def test_clone_experiment_to_storage_assert(self, mock_getpass):
self.assertRaises(AssertionError, self._vc.clone_experiment_to_storage, 123) 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('requests.post') @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 mock_list.return_value = self._mock_exp_list
class Request(object): class Request(object):
status_code = 477 status_code = 477
request.return_value = Request() request.return_value = Request()
self._vc._VirtualCoach__storage_username = 'token'
self.assertRaises(Exception, self._vc.clone_experiment_to_storage, 'MockExperiment1') 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') @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 mock_list.return_value = self._mock_exp_list
self.assertRaises(ValueError, self._vc.clone_experiment_to_storage, 'invalid_configuration') 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.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('hbp_nrp_virtual_coach.virtual_coach.logger.info') @patch('hbp_nrp_virtual_coach.virtual_coach.logger.info')
@patch('requests.post') def test_clone_experiment_to_storage(self, mock_logger, mock_list):
def test_clone_experiment_to_storage(self, request, mock_logger, mock_list, mock_getpass):
mock_list.return_value = self._mock_exp_list mock_list.return_value = self._mock_exp_list
self._vc._VirtualCoach__http_client = Mock(post=Mock(return_value=[200, 'experiment_id']))
class Request(object):
status_code = 200
content = 'experiment_id'
request.return_value = Request()
self._vc._VirtualCoach__storage_username = 'username'
self._vc.clone_experiment_to_storage('MockExperiment1') 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_storage_token')
@patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list') @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'] mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0']
self.assertRaises(ValueError, self._vc.delete_cloned_experiment, 'foo') 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('requests.delete') def test_delete_cloned_experiment(self, mock_list):
def test_delete_cloned_experiment(self, mock_request, mock_list, mock_getpass): self._vc._VirtualCoach__http_client = Mock(delete=Mock())
mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0'] mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0']
self._vc.delete_cloned_experiment('MockExperiment1_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): def test_clone_cloned_experiment(self):
self.assertRaises(AssertionError, self._vc.clone_cloned_experiment, 123) self.assertRaises(AssertionError, self._vc.clone_cloned_experiment, 123)
...@@ -476,9 +441,10 @@ mock-server-5 ...@@ -476,9 +441,10 @@ mock-server-5
mock_list.return_value = [] mock_list.return_value = []
self.assertRaises(ValueError, self._vc.clone_cloned_experiment, 'missing_id') 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('requests.post') @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'] mock_list.return_value = ['exp_id']
class Request(object): class Request(object):
...@@ -487,8 +453,10 @@ mock-server-5 ...@@ -487,8 +453,10 @@ mock-server-5
request.return_value = Request() request.return_value = Request()
self._vc._VirtualCoach__storage_username = None self._vc._VirtualCoach__storage_username = None
self.assertRaises(ValueError, self._vc.clone_cloned_experiment, 'exp_id') 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('requests.post') @patch('requests.post')
...@@ -500,14 +468,12 @@ mock-server-5 ...@@ -500,14 +468,12 @@ mock-server-5
content = None content = None
request.return_value = Request() request.return_value = Request()
self._vc._VirtualCoach__storage_username = 'token'
self._vc.clone_cloned_experiment('exp_id') 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('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
@patch('sys.stdout', new_callable=StringIO) @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' self._vc._VirtualCoach__storage_username = 'token'
mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0'] mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0']
self._vc.print_cloned_experiments() self._vc.print_cloned_experiments()
...@@ -522,14 +488,12 @@ mock-server-5 ...@@ -522,14 +488,12 @@ mock-server-5
""" """
self.assertEqual(mock_stdout.getvalue().strip(), cloned_experiments.strip()) self.assertEqual(mock_stdout.getvalue().strip(), cloned_experiments.strip())
@patch('getpass.getpass', return_value='password') def test_get_storage_token_asserts(self):
def test_get_storage_token_asserts(self, mock_getpass):
self.assertRaises(AssertionError, self._vc._VirtualCoach__get_storage_token, 123, 'foo') self.assertRaises(AssertionError, self._vc._VirtualCoach__get_storage_token, 123, 'foo')
self.assertRaises(AssertionError, self._vc._VirtualCoach__get_storage_token, 'foo', 123) self.assertRaises(AssertionError, self._vc._VirtualCoach__get_storage_token, 'foo', 123)
@patch('getpass.getpass', return_value='password')
@patch('requests.post') @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): class Response(object):
status_code = 500 status_code = 500
...@@ -537,9 +501,8 @@ mock-server-5 ...@@ -537,9 +501,8 @@ mock-server-5
mock_request.return_value = Response() mock_request.return_value = Response()
self.assertRaises(Exception, self._vc._VirtualCoach__get_storage_token, 'user', 'pass') self.assertRaises(Exception, self._vc._VirtualCoach__get_storage_token, 'user', 'pass')
@patch('getpass.getpass', return_value='password')
@patch('requests.post') @patch('requests.post')
def test_get_storage_token(self, mock_request, mock_getpass): def test_get_storage_token(self, mock_request):
class Response(object): class Response(object):
status_code = 200 status_code = 200
......
...@@ -108,6 +108,13 @@ class VirtualCoach(object): ...@@ -108,6 +108,13 @@ class VirtualCoach(object):
# this will interactively prompt the user for a password in terminal if needed # this will interactively prompt the user for a password in terminal if needed
logger.info('Logging into OIDC as: %s', oidc_username) logger.info('Logging into OIDC as: %s', oidc_username)
self.__http_client = OIDCHTTPClient(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 # if a Storage Server username is provided, attempt to login
elif storage_username: elif storage_username:
# this will interactively prompt the user for a password in terminal # this will interactively prompt the user for a password in terminal
...@@ -116,11 +123,12 @@ class VirtualCoach(object): ...@@ -116,11 +123,12 @@ class VirtualCoach(object):
logger.info('Logging into the Storage Server as: %s', storage_username) logger.info('Logging into the Storage Server as: %s', storage_username)
if not storage_password: if not storage_password:
storage_password = getpass.getpass() storage_password = getpass.getpass()
self.__storage_headers = {'Content-Type': 'application/json', authorization = 'Bearer %s' % self.__get_storage_token(
'Authorization': 'Bearer %s' % self.__get_storage_token( storage_username, storage_password
storage_username, storage_password)} )
self.__http_headers = {'Content-Type': 'application/json',
self.__http_client = RequestsClient(self.__storage_headers) 'Authorization': authorization}
self.__http_client = RequestsClient(self.__http_headers)
else: else:
raise Exception('Virtual Coach instantiated without storage server credentials or oidc' raise Exception('Virtual Coach instantiated without storage server credentials or oidc'
'credentials. You have to provide either one with the keywords ' 'credentials. You have to provide either one with the keywords '
...@@ -251,8 +259,6 @@ class VirtualCoach(object): ...@@ -251,8 +259,6 @@ class VirtualCoach(object):
# get the experiment configuration details and available servers that can be used # get the experiment configuration details and available servers that can be used
available_servers = self.__get_available_server_list() available_servers = self.__get_available_server_list()
from pprint import pprint
pprint(available_servers)
servers = [available_server['id'] for available_server in available_servers] servers = [available_server['id'] for available_server in available_servers]
if cloned: if cloned:
experiment_conf = "" experiment_conf = ""
...@@ -297,7 +303,6 @@ class VirtualCoach(object): ...@@ -297,7 +303,6 @@ class VirtualCoach(object):
:returns: The ID of the cloned experiment :returns: The ID of the cloned experiment
""" """
assert isinstance(exp_id, str) assert isinstance(exp_id, str)
exp = self.__get_experiment_list() exp = self.__get_experiment_list()
if exp_id not in exp.keys(): if exp_id not in exp.keys():
raise ValueError('Experiment ID: "%s" is invalid, please check the list of all ' raise ValueError('Experiment ID: "%s" is invalid, please check the list of all '
...@@ -345,7 +350,7 @@ class VirtualCoach(object): ...@@ -345,7 +350,7 @@ class VirtualCoach(object):
# Raise Error in case no storage server token available. To get the token, the VC has to be # Raise Error in case no storage server token available. To get the token, the VC has to be
# instantiated with the storage_username parameter # instantiated with the storage_username parameter
if self.__storage_username is None: if self.__storage_username is None and self.__oidc_username is None:
raise ValueError('No Storage Server credentials found. ' raise ValueError('No Storage Server credentials found. '
'To be able to clone experiments, you have to instantiate the ' 'To be able to clone experiments, you have to instantiate the '
'Virtual Coach either with the storage_username parameter or ' 'Virtual Coach either with the storage_username parameter or '
...@@ -353,7 +358,7 @@ class VirtualCoach(object): ...@@ -353,7 +358,7 @@ class VirtualCoach(object):
res = requests.post('%s/%s' % (self.__config['proxy-services']['experiment-clone'], res = requests.post('%s/%s' % (self.__config['proxy-services']['experiment-clone'],
experiment_id), experiment_id),
headers=self.__storage_headers) headers=self.__http_headers)
if res.status_code != 200: if res.status_code != 200:
raise Exception('Cloning Experiment failed, Status Code: %s' % res.status_code) raise Exception('Cloning Experiment failed, Status Code: %s' % res.status_code)
else: else:
...@@ -399,10 +404,9 @@ class VirtualCoach(object): ...@@ -399,10 +404,9 @@ class VirtualCoach(object):
assert isinstance(cloned, bool) assert isinstance(cloned, bool)
logger.info('Retrieving list of experiments.') logger.info('Retrieving list of experiments.')
headers = None if self.__oidc_username else self.__storage_headers
if cloned: if cloned:
url = self.__config['proxy-services']['storage-experiment-list'] 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 # return a simple list containing only experiment names since this is the only
# information in the dictionary anyway # information in the dictionary anyway
return {experiment['name']: experiment for experiment in json.loads(response.content)} return {experiment['name']: experiment for experiment in json.loads(response.content)}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment