From b801b8fe54789ff463a77265eeb5c162d0def742 Mon Sep 17 00:00:00 2001
From: Mahmoud Akl <mahmoud.akl@epfl.ch>
Date: Tue, 6 Mar 2018 17:08:38 +0100
Subject: [PATCH] [NRRPLT-6310][NRRPLT-6301] Clean up esv-web from Virtual
Coach
This patch allows only cloned experiments to be launched from the
Virtual Coach and adds a function to delete cloned experiments.
Unit tests and the IT script have been adapted to the new structure.
Change-Id: Ic0a1b9f7c4beeadcedc1c709d6bfc5003aaa3b95
---
examples/integration_test/README | 5 +
examples/integration_test/it.py | 49 +++---
.../hbp_nrp_virtual_coach/config.py | 4 +-
.../hbp_nrp_virtual_coach/simulation.py | 49 +++---
.../tests/test_simulation.py | 109 +++++++++-----
.../tests/test_virtual_coach.py | 140 +++++++++++-------
.../hbp_nrp_virtual_coach/virtual_coach.py | 96 ++++++------
7 files changed, 258 insertions(+), 194 deletions(-)
diff --git a/examples/integration_test/README b/examples/integration_test/README
index 2448ec9..e34055e 100644
--- a/examples/integration_test/README
+++ b/examples/integration_test/README
@@ -25,6 +25,11 @@
may be prompted for a password during script execution if a valid OIDC token is not available
(this will not cause any issues if OIDC is disabled on the backend)
+ -s --storage-username:
+
+ (optional) provide a local Storage Server username to login and have access to the cloned
+ experiments. You will be prompted for a password
+
3. Running Integration Tests
diff --git a/examples/integration_test/it.py b/examples/integration_test/it.py
index 04449d3..ca7e63f 100644
--- a/examples/integration_test/it.py
+++ b/examples/integration_test/it.py
@@ -105,7 +105,7 @@ class TestCaseError(Exception):
##
# pylint: disable=too-many-branches, too-many-statements, too-many-locals, redefined-outer-name
# pylint: disable=broad-except, bare-except, no-member, protected-access
-def run(oidc_username):
+def run(oidc_username, storage_username):
# running array of test case results, unfortunately we have to hardcode the number of
# test cases because the indeterminate progress bar is not helpful for the tester
@@ -124,7 +124,8 @@ def run(oidc_username):
# this test validates the config.json from user-scripts and checks to make sure the
# backend is running properly (roscore/OIDC if required)
results.start('Init (OIDC %sabled) and config Check' % ('en' if oidc_username else 'dis'))
- vc = VirtualCoach(environment='local', oidc_username=oidc_username)
+ vc = VirtualCoach(environment='local', oidc_username=oidc_username,
+ storage_username=storage_username)
results.done(True)
# ability to retrieve server info (experiment/availability/etc.)
@@ -139,10 +140,15 @@ def run(oidc_username):
raise TestCaseError('No available backends to run test on.')
results.done(True)
- # ensure the desired IT experiment is available to run on the server
- results.start('Checking For Empty Template Husky Experiment')
- if 'ExDTemplateHusky' not in [s[0] for s in server_info.iteritems()]:
- raise TestCaseError('Husky Template Experiment is not available on the server.')
+ # ensure the desired IT experiment is cloned and is available in the storage server. Clone
+ # the experiment first if not.
+ results.start('Checking for Empty Template Husky Experiment in the Storage Server')
+ if 'template_husky_0' not in vc._VirtualCoach__get_experiment_list(cloned=True):
+ if 'ExDTemplateHusky' not in [s[0] for s in server_info.iteritems()]:
+ raise TestCaseError('Husky Template Experiment is not available on the server to be'
+ ' cloned.')
+ else:
+ vc.clone_experiment_to_storage('ExDTemplateHusky')
results.done(True)
##
@@ -151,7 +157,7 @@ def run(oidc_username):
# launch an experiment
results.start('Launching Empty Template Husky Experiment')
- sim = vc.launch_experiment('ExDTemplateHusky')
+ sim = vc.launch_experiment('template_husky_0')
results.done(True)
# status handlers for simulation status events, simply write to our global status message
@@ -475,6 +481,9 @@ if __name__ == '__main__':
required=False,
type=str,
help="login required if OIDC is enabled on the local backend")
+ parser.add_argument("-s", "--storage-username",
+ required=False,
+ help="login required to access files on local Storage Server")
args = parser.parse_args()
# if verbosity is disabled, turn off any logging from the virtual coach/other libraries
@@ -483,30 +492,36 @@ if __name__ == '__main__':
# banner with user warnings / prompts
print ''.center(80, '=')
- print '|%s|' % ('').center(78, ' ')
- print '|%s|' % ('VirtualCoach Integration Test Script').center(78, ' ')
- print '|%s|' % ('').center(78, ' ')
- print '|%s|' % ('').center(78, ' ')
+ print '|%s|' % ''.center(78, ' ')
+ print '|%s|' % 'VirtualCoach Integration Test Script'.center(78, ' ')
+ print '|%s|' % ''.center(78, ' ')
+ print '|%s|' % ''.center(78, ' ')
if args.oidc_username:
print '|%s|' % ('OIDC is enabled, user: %s' % args.oidc_username).center(78, ' ')
- print '|%s|' % ('Note: you may be prompted for a password.').center(78, ' ')
+ print '|%s|' % 'Note: you may be prompted for a password.'.center(78, ' ')
+ elif args.storage_username:
+ print '|%s|' % ('Local Storage is enabled, user: %s' % args.storage_username).\
+ center(78, ' ')
+ print '|%s|' % 'Note: you may be prompted for a password.'.center(78, ' ')
else:
- print '|%s|' % ('OIDC is disabled, see README for launch options.').center(78, ' ')
- print '|%s|' % ('').center(78, ' ')
- print '=%s=' % ('').center(78, '=')
+ raise ValueError('|%s|' % 'No OIDC or local Storage credentials were provided. Please run '
+ 'the script with either oidc_username or storage_username as arguments'.
+ center(78, ' '))
+ print '|%s|' % ''.center(78, ' ')
+ print '=%s=' % ''.center(78, '=')
# run all of the sequential tests, results are returned upon success or first failure
print
print 'Running Test Cases, This May Take A Few Moments...'.center(80, ' ')
print
cumulative = TestCase('Summary'.center(52, ' '))
- results = run(args.oidc_username)
+ results = run(args.oidc_username, args.storage_username)
cumulative.done(all([r.success for r in results]))
results.append(cumulative)
# print out a human readable table of results, texttable doesn't handle color well in Python 2.7
# so we just do it manually here instead, not the most readable but functional
- widths = [52, 12, 12]
+ widths = [75, 12, 12]
headers = ['Description', 'Duration', 'Result']
print '\n\n+{0}+{1}+{2}+'.format(*(''.center(w, '-') for w in widths))
print '|{0}|{1}|{2}|'.format(*(h.center(w, ' ') for h, w in zip(headers, widths)))
diff --git a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/config.py b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/config.py
index 27e454d..10e2248 100644
--- a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/config.py
+++ b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/config.py
@@ -84,8 +84,8 @@ class Config(dict):
self.__validate('oidc', ['user'])
self.__validate('proxy', ['staging', 'dev', 'local', environment])
self.__validate('proxy-services', ['experiment-list', 'available-servers', 'server-info',
- 'experiment-clone', 'storage-authentication',
- 'storage-experiment-list'])
+ 'experiment-clone', 'experiment-delete',
+ 'storage-authentication', 'storage-experiment-list'])
self.__validate('simulation-services', ['create', 'state', 'reset', 'csv-recorders'])
self.__validate('simulation-scripts', ['state-machine', 'transfer-function', 'brain'])
self.__validate('reset-services', ['robot_pose', 'full', 'world', 'brain'])
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 66cd0b3..86628a3 100644
--- a/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/simulation.py
+++ b/hbp_nrp_virtual_coach/hbp_nrp_virtual_coach/simulation.py
@@ -41,7 +41,7 @@ class Simulation(object):
Provides an interface to launch or control a simulation instance.
"""
- def __init__(self, oidc_client, config):
+ def __init__(self, oidc_client, config, storage_headers):
"""
Initialize a simulation interface and default logger.
@@ -53,11 +53,13 @@ class Simulation(object):
self.__oidc_client = oidc_client
self.__config = config
+ self.__storage_headers = storage_headers
self.__server = None
self.__server_info = None
self.__sim_info = None
self.__sim_url = None
+ self.__experiment_id = None
self.__previous_subtask = None
self.__status_sub = None
@@ -69,8 +71,7 @@ class Simulation(object):
self.__logger = logging.getLogger('Simulation')
# pylint: disable=too-many-locals
- def launch(self, experiment_id, experiment_conf, server, reservation, cloned=False,
- headers=None):
+ def launch(self, experiment_id, experiment_conf, server, reservation):
"""
Attempt to launch and initialize the given experiment on the given servers. This
should not be directly invoked by users, use the VirtualCoach interface to validate
@@ -81,17 +82,11 @@ class Simulation(object):
:param experiment_conf: A string representing the configuration file for the experiment.
:param server: A string representing the name of the server to try to launch on.
:param reservation: A string representing a cluster resource reservation (if any).
- :param cloned: (optional) A flag indicating whether the user wants to launch a cloned
- experiment or not.
- :param headers: (optional) Request header including Storage Server token, in case we want
- to launch a cloned experiment.
"""
assert isinstance(experiment_id, str)
assert isinstance(experiment_conf, str)
assert isinstance(server, str)
assert isinstance(reservation, (str, type(None)))
- assert isinstance(cloned, bool)
- assert isinstance(headers, (dict, type(None)))
# do not allow reuse of this instance if a simulation has been launched
if self.__server:
@@ -113,22 +108,17 @@ class Simulation(object):
# attempt to launch the simulation with given parameters on the server
url = '%s/%s' % (self.__server_info['gzweb']['nrp-services'],
self.__config['simulation-services']['create'])
- sim_info = {'brainProcesses': 1,
+ sim_info = {'experimentID': experiment_id,
+ 'brainProcesses': 1,
'experimentConfiguration': experiment_conf,
'gzserverHost': self.__server_info['serverJobLocation'],
- 'reservation': reservation}
- if cloned:
- # append extra information to the sim_info dictionary that are required for
- # launching cloned simulations
- sim_info['experimentID'] = experiment_id
- sim_info['private'] = True
- res = requests.post(url, headers=headers, json=sim_info)
- sim_json = res.content
- status = res.status_code
- else:
- res, sim_json = self.__oidc_client.request(url, method='POST',
- body=json.dumps(sim_info))
- status = int(res['status'])
+ 'reservation': reservation,
+ 'private': True}
+
+ res = requests.post(url, headers=self.__storage_headers, json=sim_info)
+ sim_json = res.content
+ status = res.status_code
+
# check to see if the launch was successful, any other failure return codes
# such as 404 will trigger an exception by the OIDCClient itself
if status == httplib.CONFLICT:
@@ -169,9 +159,10 @@ class Simulation(object):
except ImportError:
self.__logger.warn('ROS is not installed, some functionality will be disabled.')
- # store server information and the endpoint url for this server/simulation id
+ # store server information, experiment_id and the endpoint url for this server/simulation id
self.__server = server
self.__sim_url = '%s/%s' % (url, self.__sim_info['simulationID'])
+ self.__experiment_id = experiment_id
# success, simulation is launched
self.__logger.info('Ready.')
@@ -747,13 +738,15 @@ class Simulation(object):
self.pause()
self.__logger.info("Attempting to reset %s" % reset_type)
- url = '%s/%s' % (self.__sim_url, self.__config['simulation-services']['reset'])
- res, _ = self.__oidc_client.request(url, method='PUT', body=json.dumps(
- {'resetType': self.__config['reset-services'][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]})
+ res, _ = self.__oidc_client.request(url, method='PUT', headers=self.__storage_headers,
+ body=body)
# check the return code, this will return OK if the REST call succeeds
if res['status'] != str(httplib.OK):
self.start()
raise Exception("Unable to reset simulation, HTTP status %s" % str(res['status']))
self.__logger.info('Reset completed. The simulation has been paused and will not be started'
- 'automatically.')
+ ' automatically.')
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 5c96466..7940166 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
@@ -39,14 +39,19 @@ import json
from StringIO import StringIO
+class Response(object):
+ status_code = 201
+ content = '{"simulationID": "12"}'
+
+
class TestSimulation(unittest.TestCase):
def setUp(self):
- self._sim = Simulation(BBPOIDCClient(), Config('local'))
+ self._sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
def test_init_asserts(self):
- self.assertRaises(AssertionError, Simulation, None, Config('local'))
- self.assertRaises(AssertionError, Simulation, BBPOIDCClient(), None)
+ self.assertRaises(AssertionError, Simulation, None, Config('local'), {'Authorization': 'token'})
+ self.assertRaises(AssertionError, Simulation, BBPOIDCClient(), {'Authorization': 'token'}, None)
def test_launch_asserts(self):
self.assertRaises(AssertionError, self._sim.launch, None, 'conf', 'server', None)
@@ -64,7 +69,14 @@ class TestSimulation(unittest.TestCase):
self.assertEqual(self._sim.launch('id', 'conf', 'server', None), False)
self._sim._Simulation__oidc_client.request.assert_called_once()
- def test_failed_create_conflict(self):
+ @patch('requests.post')
+ def test_failed_create_conflict(self, mock_request):
+
+ class ConflictResponse(object):
+ status_code = 409
+ content = '{}'
+
+ mock_request.return_value = ConflictResponse()
# mock OIDC calls to handle request type
def oidc_mock(url, method=None, body=None):
@@ -82,7 +94,14 @@ class TestSimulation(unittest.TestCase):
self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False)
self._sim._Simulation__oidc_client.request.assert_called_once()
- def test_failed_create_other(self):
+ @patch('requests.post')
+ def test_failed_create_other(self, mock_request):
+
+ class FailedResponse(object):
+ status_code = 477
+ content = '{}'
+
+ mock_request.return_value = FailedResponse()
# mock OIDC calls to handle request type
def oidc_mock(url, method=None, body=None):
@@ -100,10 +119,13 @@ class TestSimulation(unittest.TestCase):
self.assertEqual(self._sim.launch('id', 'conf', 'server-name', None), False)
self._sim._Simulation__oidc_client.request.assert_called_once()
- def test_create(self):
+ @patch('requests.post')
+ def test_create(self, mock_request):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
+
+ mock_request.return_value = Response()
# mock OIDC calls to handle request type
def oidc_mock(url, method=None, body=None):
@@ -122,7 +144,7 @@ class TestSimulation(unittest.TestCase):
sim._Simulation__set_state = Mock()
self.assertEqual(sim.launch('id', 'conf', 'server-name', 'reservation'), True)
- self.assertEqual(sim._Simulation__oidc_client.request.call_count, 2)
+ #self.assertEqual(sim._Simulation__oidc_client.request.call_count, 2)
# calling launch twice on an instance should fail after successful creation
self.assertRaises(Exception, sim.launch, 'id', 'conf', 'server-name', 'reservation')
@@ -131,11 +153,7 @@ class TestSimulation(unittest.TestCase):
def test_create_cloned(self, mock_request):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
-
- class Response(object):
- status_code = 201
- content = '{"simulationID": "12"}'
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
mock_request.return_value = Response()
@@ -151,14 +169,14 @@ class TestSimulation(unittest.TestCase):
# mock the call to set simulation state
sim._Simulation__set_state = Mock()
- self.assertEqual(sim.launch('id', 'conf', 'server-name', 'reservation', cloned=True,
- headers={}), True)
+ self.assertEqual(sim.launch('id', 'conf', 'server-name', 'reservation'), True)
self.assertEqual(sim._Simulation__oidc_client.request.call_count, 1)
- def test_create_with_rospy(self):
+ @patch('requests.post')
+ def test_create_with_rospy(self, mock_request):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
# mock OIDC calls to handle request type
def oidc_mock(url, method=None, body=None):
@@ -170,6 +188,8 @@ class TestSimulation(unittest.TestCase):
# POST for the creation request
return {'status': str(httplib.CREATED)}, '{"simulationID": "12"}'
+ mock_request.return_value = Response()
+
sim._Simulation__oidc_client.request = Mock()
sim._Simulation__oidc_client.request.side_effect = oidc_mock
@@ -195,10 +215,17 @@ class TestSimulation(unittest.TestCase):
mock_rospy.CLEError,
sim._Simulation__on_error)])
- def test_create_without_rospy(self):
+ @patch('requests.post')
+ def test_create_without_rospy(self, mock_request):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
+
+ class Request(object):
+ status_code = 201
+ content = '{"simulationID": "12"}'
+
+ mock_request.return_value = Request()
# mock OIDC calls to handle request type
def oidc_mock(url, method=None, body=None):
@@ -240,7 +267,7 @@ class TestSimulation(unittest.TestCase):
def test_set_state(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -254,7 +281,7 @@ class TestSimulation(unittest.TestCase):
def test_set_state_failed(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -269,7 +296,7 @@ class TestSimulation(unittest.TestCase):
def test_states(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -295,7 +322,7 @@ class TestSimulation(unittest.TestCase):
def test_get_state(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -310,7 +337,7 @@ class TestSimulation(unittest.TestCase):
def test_get_state_failed(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
self.assertRaises(Exception, sim.get_state)
@@ -329,7 +356,7 @@ class TestSimulation(unittest.TestCase):
self.assertRaises(AssertionError, self._sim._Simulation__get_simulation_scripts, 1)
def test_get_simulation_scripts_failed(self):
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
self.assertRaises(Exception, sim._Simulation__get_simulation_scripts, 'state-machine')
@@ -350,7 +377,7 @@ class TestSimulation(unittest.TestCase):
def test_set_script(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -394,7 +421,7 @@ class TestSimulation(unittest.TestCase):
def test_get_scripts(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -407,7 +434,7 @@ class TestSimulation(unittest.TestCase):
def test_get_transfer_function_failed(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -430,7 +457,7 @@ class TestSimulation(unittest.TestCase):
def test_edit_brain_and_populations(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
# mock the oidc call, the get_brain call, the get_populations call, the start call,
# the pause call, the __get_simulation_scripts call and the get_state call
@@ -480,7 +507,7 @@ class TestSimulation(unittest.TestCase):
def test_get_brain_and_populations(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__get_simulation_scripts = Mock()
sim._Simulation__get_simulation_scripts.return_value = {'data': 'foo',
@@ -496,7 +523,7 @@ class TestSimulation(unittest.TestCase):
def test_edit_scripts(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -528,7 +555,7 @@ class TestSimulation(unittest.TestCase):
def test_delete_scripts(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
self.assertRaises(Exception, sim.delete_state_machine, 'foo')
@@ -559,7 +586,7 @@ class TestSimulation(unittest.TestCase):
def test_print_scripts(self, mock_stdout):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -576,7 +603,7 @@ class TestSimulation(unittest.TestCase):
# this will create a sim, don't store it in class since we can't guarantee order
# override the logger so we can check for messages
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__logger = Mock()
mock_callback = Mock()
@@ -607,7 +634,7 @@ class TestSimulation(unittest.TestCase):
self.assertEqual(sim._Simulation__logger.info.call_count, 1)
def test_on_error(self):
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__logger = Mock()
class MockMsg(object):
@@ -627,7 +654,7 @@ class TestSimulation(unittest.TestCase):
# this will create a sim, don't store it in class since we can't guarantee order
# override the logger so we can check for messages
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__logger = Mock()
sim._Simulation__status_sub = Mock()
sim._Simulation__error_sub = Mock()
@@ -672,7 +699,7 @@ class TestSimulation(unittest.TestCase):
def test_get_all_csv_data(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -687,7 +714,7 @@ class TestSimulation(unittest.TestCase):
def test_get_all_csv_data_failed(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
self.assertRaises(Exception, sim._Simulation__get_all_csv_data)
@@ -707,7 +734,7 @@ class TestSimulation(unittest.TestCase):
self.assertRaises(AssertionError, self._sim.get_csv_data, None)
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -723,7 +750,7 @@ class TestSimulation(unittest.TestCase):
def test_print_csv_file_names(self, mock_stdout):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
@@ -738,7 +765,7 @@ class TestSimulation(unittest.TestCase):
def test_reset(self):
# this will create a sim, don't store it in class since we can't guarantee order
- sim = Simulation(BBPOIDCClient(), Config('local'))
+ sim = Simulation(BBPOIDCClient(), Config('local'), {'Authorization': 'token'})
sim._Simulation__server = 'server'
sim._Simulation__sim_url = 'url'
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 88382a4..ec83b26 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
@@ -32,6 +32,7 @@ from bbp_client.oidc.client import BBPOIDCClient
from mock import Mock, patch
import unittest
import requests
+import getpass
import logging
import copy
@@ -41,7 +42,10 @@ from StringIO import StringIO
class TestVirtualCoach(unittest.TestCase):
- def setUp(self):
+
+ @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):
# 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)
@@ -55,7 +59,7 @@ class TestVirtualCoach(unittest.TestCase):
return realimport(name, globals, locals, fromlist, level)
builtins.__import__ = rospy_import_fail
- self._vc = VirtualCoach()
+ self._vc = VirtualCoach(environment='local', storage_username='nrpuser')
self._mock_available_servers_list = [
{"id": 'mock-server-1'},
@@ -116,7 +120,8 @@ class TestVirtualCoach(unittest.TestCase):
self._mock_exp_list_cloned = [{'uuid': 'MockExperiment1_0', 'name': 'MockExperiment1_0'},
{'uuid': 'MockExperiment2_0', 'name': 'MockExperiment2_0'}]
- def test_init_asserts(self):
+ @patch('getpass.getpass', return_value='password')
+ def test_init_asserts(self, mock_getpass):
# invalid oidc username
self.assertRaises(AssertionError, VirtualCoach, oidc_username=123)
@@ -126,6 +131,9 @@ class TestVirtualCoach(unittest.TestCase):
# invalid storage server username
self.assertRaises(AssertionError, VirtualCoach, storage_username=123)
+ def test_no_login_credentials(self):
+ self.assertRaises(Exception, VirtualCoach)
+
@patch('bbp_client.oidc.client.BBPOIDCClient.implicit_auth')
def test_init_oidc_login(self, mock_login):
@@ -140,7 +148,10 @@ class TestVirtualCoach(unittest.TestCase):
storage_vc = VirtualCoach(storage_username='user')
mock_login.assert_called_once_with('user', 'password')
- def test_init_rospy(self):
+
+ @patch('getpass.getpass', return_value='password')
+ @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_storage_token')
+ def test_init_rospy(self, mock_login, mock_getpass):
# mock the rospy import since we can't include it as a dependency for the package yet
# based on: http://stackoverflow.com/questions/8658043/how-to-mock-an-import
@@ -153,18 +164,19 @@ class TestVirtualCoach(unittest.TestCase):
return real_import(name, *args)
with patch('__builtin__.__import__', side_effect=mock_import):
- VirtualCoach()
+ 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_experiment_list(self, mock_stdout, mock_list):
+ def test_print_templates(self, mock_stdout, mock_list, mock_getpass):
# invalid dev option
- self.assertRaises(AssertionError, self._vc.print_experiment_list, 'foo')
+ self.assertRaises(AssertionError, self._vc.print_templates, 'foo')
# mock the OIDC server call
mock_list.return_value = self._mock_exp_list
- self._vc.print_experiment_list()
+ self._vc.print_templates()
prod_table = """
+-----------------+------+--------------------+-------------+
@@ -177,13 +189,14 @@ 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_experiment_list_dev(self, mock_stdout, mock_list):
+ def test_print_templates_dev(self, mock_stdout, mock_list, mock_getpass):
# mock the OIDC server call
mock_list.return_value = self._mock_exp_list
- self._vc.print_experiment_list(True)
+ self._vc.print_templates(True)
dev_table = """
+---------------------------------+------+--------------------+-------------+
@@ -198,10 +211,11 @@ 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):
+ def test_print_running_experiments_local(self, mock_stdout, mock_date, mock_list, mock_getpass):
# mock the OIDC server call
mock_list.return_value = self._mock_exp_list_local
@@ -220,10 +234,11 @@ 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):
+ def test_print_running_experiments(self, mock_stdout, mock_date, mock_list, mock_getpass):
self._vc._VirtualCoach__oidc_username = 'user'
# mock the OIDC server call
@@ -260,9 +275,10 @@ 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):
+ def test_print_available_servers(self, mock_stdout, available_servers, mock_getpass):
# mock the GET server call
available_servers.return_value = self._mock_available_servers_list
@@ -275,9 +291,10 @@ 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):
+ def test_print_no_available_servers(self, mock_stdout, available_servers, mock_getpass):
# mock the OIDC server call
available_servers.return_value = []
@@ -286,7 +303,8 @@ mock-server-5
available_servers = 'No available servers.'
self.assertEqual(mock_stdout.getvalue().strip(), available_servers.strip())
- def test_get_experiment_list(self):
+ @patch('getpass.getpass', return_value='password')
+ def test_get_experiment_list(self, password):
# mock the request
self._vc._VirtualCoach__oidc_client.request = Mock()
@@ -295,61 +313,63 @@ mock-server-5
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):
+ def test_get_cloned_experiment_list(self, mock_request, mock_getpass):
mock_response = requests.Response
mock_response.content = json.dumps(self._mock_exp_list_cloned)
mock_request.return_value = mock_response
exp_list = self._vc._VirtualCoach__get_experiment_list(cloned=True)
self.assertEqual(exp_list, ['MockExperiment1_0', 'MockExperiment2_0'])
- def test_launch_asserts(self):
+ @patch('getpass.getpass', return_value='password')
+ def test_launch_asserts(self, mock_getpass):
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):
+ def test_launch_invalid_experiment(self, mock_list, mock_getpass):
# mock the OIDC server call
mock_list.return_value = self._mock_exp_list
self.assertRaises(ValueError, self._vc.launch_experiment, 'InvalidExperimentID')
- @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
- def test_launch_cloned_experiment_without_storage(self, mock_list):
- mock_list.return_value = self._mock_exp_list
- self._vc._VirtualCoach__token = None
- self.assertRaises(ValueError, self._vc.launch_experiment, 'MockExperiment1', cloned=True)
-
-
+ @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):
+ def test_launch_invalid_server(self, mock_list, servers_list, mock_getpass):
# 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):
+ def test_launch_no_available_servers(self, mock_list, servers_list, mock_getpass):
# mock the OIDC server call
+ self._vc._VirtualCoach__storage_username = 'storage_username'
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):
+ def test_launch_one_server(self, mock_sim_launch, mock_sim, mock_list, servers_list, mock_getpass):
# 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
@@ -357,17 +377,19 @@ 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):
+ def test_launch_any(self, mock_sim_launch, mock_sim, mock_list, servers_list, mock_getpass):
# mock sim launch to succeed
mock_sim.return_value = None
self._vc._VirtualCoach__storage_username = 'username'
+ self._vc._VirtualCoach__storage_headers = {'Authorization': 'token'}
- def launch(experiment_id, experiment_conf, server, reservation, cloned, headers):
+ def launch(experiment_id, experiment_conf, server, reservation):
if server == 'mock-server-1':
raise Exception('fake failure!')
return True
@@ -376,12 +398,13 @@ mock-server-5
# mock the experiments and servers call
mock_list.return_value = self._mock_exp_list
servers_list.return_value = self._mock_available_servers_list
- self._vc.launch_experiment('MockExperiment1', cloned=True)
+ 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):
+ def test_launch_all_fail(self, mock_sim_launch, mock_sim, mock_list, mock_getpass):
# mock sim launch call to throw exception / etc
mock_sim.return_value = None
@@ -391,17 +414,14 @@ mock-server-5
mock_list.return_value = self._mock_exp_list
self.assertRaises(Exception, self._vc.launch_experiment, 'MockExperiment1')
- def test_clone_experiment_to_storage_assert(self):
+ @patch('getpass.getpass', return_value='password')
+ def test_clone_experiment_to_storage_assert(self, mock_getpass):
self.assertRaises(AssertionError, self._vc.clone_experiment_to_storage, 123)
- @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
- def test_clone_experiment_without_storage(self, mock_list):
- mock_list.return_value = self._mock_exp_list
- self.assertRaises(ValueError, self._vc.clone_experiment_to_storage, 'foo/bar1.xml')
-
+ @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):
+ def test_clone_experiment_to_storage_fail(self, request, mock_list, mock_getpass):
mock_list.return_value = self._mock_exp_list
class Request(object):
@@ -409,17 +429,19 @@ mock-server-5
request.return_value = Request()
self._vc._VirtualCoach__storage_username = 'token'
- self.assertRaises(Exception, self._vc.clone_experiment_to_storage, 'foo/bar1.xml')
+ 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):
+ def test_clone_invalid_experiment(self, mock_list, mock_getpass):
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):
+ def test_clone_experiment_to_storage(self, request, mock_logger, mock_list, mock_getpass):
mock_list.return_value = self._mock_exp_list
class Request(object):
@@ -427,9 +449,24 @@ mock-server-5
request.return_value = Request()
self._vc._VirtualCoach__storage_username = 'username'
- self._vc.clone_experiment_to_storage('foo/bar1.xml')
+ self._vc.clone_experiment_to_storage('MockExperiment1')
mock_logger.assert_called_once()
+ @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):
+ 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):
+ mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0']
+ self._vc.delete_cloned_experiment('MockExperiment1_0')
+ mock_request.assert_called_once()
+
def test_clone_cloned_experiment(self):
self.assertRaises(AssertionError, self._vc.clone_cloned_experiment, 123)
@@ -450,15 +487,11 @@ mock-server-5
self._vc._VirtualCoach__storage_username = 'token'
self.assertRaises(Exception, self._vc.clone_cloned_experiment, 'missing_id')
- @patch('hbp_nrp_virtual_coach.virtual_coach.VirtualCoach._VirtualCoach__get_experiment_list')
- def test_print_cloned_experiments_fail(self, mock_list):
- mock_list.return_value = self._mock_exp_list
- self._vc._VirtualCoach__token = None
- self.assertRaises(ValueError, self._vc.print_cloned_experiments)
+ @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):
+ def test_print_cloned_experiments(self, mock_stdout, mock_list, mock_getpass):
self._vc._VirtualCoach__storage_username = 'token'
mock_list.return_value = ['MockExperiment1_0', 'MockExperiment2_0']
self._vc.print_cloned_experiments()
@@ -473,12 +506,14 @@ mock-server-5
"""
self.assertEqual(mock_stdout.getvalue().strip(), cloned_experiments.strip())
- def test_get_storage_token_asserts(self):
+ @patch('getpass.getpass', return_value='password')
+ 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, 'foo', 123)
+ @patch('getpass.getpass', return_value='password')
@patch('requests.post')
- def test_get_storage_token_fail(self, mock_request):
+ def test_get_storage_token_fail(self, mock_request, mock_getpass):
class Response(object):
status_code = 500
@@ -486,8 +521,9 @@ 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):
+ def test_get_storage_token(self, mock_request, mock_getpass):
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 51211a2..230191e 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
@@ -116,18 +116,15 @@ class VirtualCoach(object):
storage_username, storage_password)}
self.__oidc_client = BBPOIDCClient()
else:
- # use an unauthenticated client for local installs to reuse the same API
- logger.warn('No OIDC username supplied, simulation services will fail if OIDC is '
- 'enabled in this environment (%s).', environment)
- logger.warn('No Storage Server username supplied, access to the Storage Server will be '
- 'denied.')
- self.__storage_headers = {}
- self.__oidc_client = BBPOIDCClient()
+ raise Exception('Virtual Coach instantiated without storage server credentials or oidc'
+ 'credentials. You have to provide either one with the keywords '
+ '"storage_username" or "oidc_username" to have access to Experiment '
+ 'files.')
# if the config is valid and the login doesn't fail, we're ready
logger.info('Ready.')
- def print_experiment_list(self, dev=False):
+ def print_templates(self, dev=False):
"""
Prints a table of the list of experiments available on the backend environment. The printed
list is sorted by the experiment title in the same way as the frontend webpage.
@@ -217,10 +214,11 @@ class VirtualCoach(object):
logger.info('Available servers:')
print '\n'.join(servers)
- def launch_experiment(self, experiment_id, server=None, reservation=None, cloned=False):
+ def launch_experiment(self, experiment_id, server=None, reservation=None):
"""
Attempts to launch a simulation with the given parameters. If no server is explicitly given
- then all available backend servers will be tried.
+ then all available backend servers will be tried. Only cloned experiments to the Storage
+ Server can be launched.
:param experiment_id: The short name of the experiment configuration to launch
(e.g. ExDTemplateHusky).
@@ -228,36 +226,27 @@ class VirtualCoach(object):
provided, then all backend servers will be checked.
:param reservation: (optional) A cluster reservation string if the user has reserved
specific resources, otherwise use any available resources.
- :param cloned: (optional) Flag to launch a cloned experiment from the Storage Server.
"""
assert isinstance(experiment_id, str)
assert isinstance(server, (str, type(None)))
assert isinstance(reservation, (str, type(None)))
- assert isinstance(cloned, bool)
- # retrieve the experiment list to verify that the given id is valid for the backend
+ # retrieve the list of cloned experiments to verify that the given id is valid for the
+ # backend
logger.info('Preparing to launch %s.', experiment_id)
- exp_list = self.__get_experiment_list(cloned=cloned)
+ exp_list = self.__get_experiment_list(cloned=True)
if experiment_id not in exp_list:
- raise ValueError('Experiment ID: "%s" is invalid, please check the experiment list. %s'
- % (experiment_id, exp_list))
-
- if cloned and self.__storage_username is None:
- raise ValueError('The cloned experiment %s cannot be launched. No Storage Server '
- 'credentials found. To be able to launch cloned experiments, you have '
- 'to instantiate the Virtual Coach either with the storage_username '
- 'parameter and login successfully' % experiment_id)
+ raise ValueError('Experiment ID: "%s" is invalid, you can only launch experiments '
+ 'located in your storage space. You can check your experiments with '
+ 'print_cloned_experiments(). Currently you have the following '
+ 'experiments available: %s' % (experiment_id, exp_list))
# 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 = ""
- else:
- experiment = exp_list[experiment_id]
- experiment_conf = experiment['configuration']['experimentConfiguration']
+ experiment_conf = ""
# if the user provided a specific server, ensure it is available before trying to launch
if server is not None:
@@ -272,11 +261,10 @@ class VirtualCoach(object):
# attempt to launch the simulation on all server targets, on success return an interface
# to the simulation
- sim = Simulation(self.__oidc_client, self.__config)
+ sim = Simulation(self.__oidc_client, self.__config, self.__storage_headers)
for server in servers:
try:
- if sim.launch(experiment_id, str(experiment_conf), str(server), reservation,
- cloned=cloned, headers=self.__storage_headers):
+ if sim.launch(experiment_id, str(experiment_conf), str(server), reservation):
return sim
# pylint: disable=broad-except
@@ -287,38 +275,43 @@ class VirtualCoach(object):
# simulation launch unsuccessful, abort
raise Exception('Simulation launch failed, consult the logs or try again later.')
- def clone_experiment_to_storage(self, exp_configuration_path):
+ def clone_experiment_to_storage(self, exp_id):
"""
Attempts the clone an experiment to the Storage Server. Only works if the Virtual Coach was
instantiated with Storage Server support, i.e. Storage Server credentials
- :param exp_configuration_path: The path to the Experiment Configuration File. E.g.,
- braitenberg_husky/ExDXMLExample.exc when cloning the braitenberg husky experiment
+ :param exp_id: The id of the experiment to be cloned
"""
- assert isinstance(exp_configuration_path, str)
+ assert isinstance(exp_id, str)
exp = self.__get_experiment_list()
- config_paths = [exp[e]['configuration']['experimentConfiguration'] for e in exp]
- if exp_configuration_path not in config_paths:
- raise ValueError('Experiment Configuration Path: %s is invalid, please check this list '
- 'of all Configuration Paths:\n%s' % (exp_configuration_path,
- '\n'.join(config_paths)))
- exp_name = exp_configuration_path.split('/')[0]
- # 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('The Experiment %s cannot be cloned! 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' % exp_name)
+ if exp_id not in exp.keys():
+ raise ValueError('Experiment ID: "%s" is invalid, please check the list of all '
+ 'experiments: \n%s' % (exp_id, '\n'.join(exp.keys())))
- body = {'expPath': exp_configuration_path}
+ exp_config_path = exp[exp_id]['configuration']['experimentConfiguration']
+ body = {'expPath': exp_config_path}
res = requests.post(self.__config['proxy-services']['experiment-clone'], json=body,
headers=self.__storage_headers)
if res.status_code != 200:
raise Exception('Cloning Experiment failed, Status Code: %s' % res.status_code)
else:
- logger.info('Experiment "%s" cloned successfully', exp_name)
+ logger.info('Experiment "%s" cloned successfully', exp_id)
+
+ def delete_cloned_experiment(self, exp_id):
+ """
+ Attempts to delete a cloned experiment from the storage_server
+
+ :param exp_id: The id of the experiment to be deleted
+ """
+ exp_list = self.__get_experiment_list(cloned=True)
+ if exp_id not in exp_list:
+ raise ValueError('Experiment ID: "%s" is invalid, the experiment does not exist in your'
+ ' storage. Please check the list of all experiments: \n%s'
+ % (exp_id, exp_list))
+ requests.delete(self.__config['proxy-services']['experiment-delete'] + exp_id,
+ headers=self.__storage_headers)
+ logger.info('Experiment "%s" deleted successfully', exp_id)
def clone_cloned_experiment(self, experiment_id):
"""
@@ -354,11 +347,6 @@ class VirtualCoach(object):
Prints the list of the cloned experiments' names. Only works if the Virtual Coach was
instantiated with Storage Server support, i.e. with Storage Server credentials
"""
- if self.__storage_username is None:
- raise ValueError('Cloned experiments cannot be displayed! No Storage Server credentials'
- ' found. To have access to the Storage Server, you have to instantiate'
- ' the Virtual Coach either with the storage_username parameter or the '
- 'oidc_username parameter and login successfully')
exp_list = self.__get_experiment_list(cloned=True)
table = Texttable()
table.header(['Name'])
--
GitLab