class TestFlowController(BaseControllersTest): """ Unit tests for FlowController """ def setup_method(self): """ Sets up the environment for testing; creates a `FlowController` """ self.init() self.flow_c = FlowController() self.burst_c = SimulatorController() self.operation_service = OperationService() def teardown_method(self): """ Cleans up the testing environment """ self.cleanup() self.clean_database() def test_context_selected(self): """ Remove the project from CherryPy session and check that you are redirected to projects page. """ del cherrypy.session[common.KEY_PROJECT] self._expect_redirect('/project/viewall', self.flow_c.step_analyzers) def test_valid_step(self): """ For all algorithm categories check that a submenu is generated and the result page has it's title given by category name. """ result_dict = self.flow_c.step_analyzers() assert common.KEY_SUBMENU_LIST in result_dict, \ "Expect to have a submenu with available algorithms for category." assert result_dict["section_name"] == 'analyze' def test_step_connectivity(self): """ Check that the correct section name and connectivity sub-menu are returned for the connectivity step. """ result_dict = self.flow_c.step_connectivity() assert result_dict['section_name'] == 'connectivity' assert result_dict['submenu_list'] == self.flow_c.connectivity_submenu def test_default(self): """ Test default method from step controllers. Check that the submit link is ok, that a mainContent is present in result dict and that the isAdapter flag is set to true. """ cherrypy.request.method = "GET" categories = dao.get_algorithm_categories() for categ in categories: # Ignore creators, as those won't go through this flow if categ.displayname in [ CreateAlgorithmCategoryConfig.category_name ]: continue algo_groups = dao.get_adapters_from_categories([categ.id]) for algo in algo_groups: result_dict = self.flow_c.default(categ.id, algo.id) assert result_dict[common.KEY_SUBMIT_LINK] == '/flow/%i/%i' % ( categ.id, algo.id) assert 'mainContent' in result_dict assert result_dict['isAdapter'] def test_default_cancel(self): """ On cancel we should get a redirect to the back page link. """ cherrypy.request.method = "POST" categories = dao.get_algorithm_categories() algo_groups = dao.get_adapters_from_categories([categories[0].id]) self._expect_redirect('/project/viewoperations/%i' % self.test_project.id, self.flow_c.default, categories[0].id, algo_groups[0].id, cancel=True, back_page='operations') def test_default_invalid_key(self): """ Pass invalid keys for adapter and step and check you get redirect to tvb entry page with error set. """ self._expect_redirect('/tvb?error=True', self.flow_c.default, 'invalid', 'invalid') def test_read_datatype_attribute(self, dummy_datatype_index_factory): """ Read an attribute from a datatype. """ dt = dummy_datatype_index_factory(row1='This is stored data') dt.subject = "test_subject" dt.state = "RAW_STATE" returned_data = self.flow_c.read_datatype_attribute(dt.gid, "row1") assert returned_data == '"This is stored data"' def test_read_datatype_attribute_method_call(self, dummy_datatype_index_factory): """ Call method on given datatype. """ dt = dummy_datatype_index_factory(row1='This is stored data') args = {'length': 101} returned_data = self.flow_c.read_datatype_attribute( dt.gid, 'return_test_data', **args) assert returned_data.replace('"', '') == " ".join( str(x) for x in range(101)) def test_get_simple_adapter_interface(self, test_adapter_factory): algo = test_adapter_factory() form = TestAdapter1Form() adapter = TestFactory.create_adapter( 'tvb.tests.framework.adapters.testadapter1', 'TestAdapter1') adapter.submit_form(form) result = self.flow_c.get_simple_adapter_interface(algo.id) expected_interface = adapter.get_form() found_form = result['adapter_form']['adapter_form'] assert isinstance(result['adapter_form'], dict) assert isinstance(found_form, TestAdapter1Form) assert found_form.test1_val1.value == expected_interface.test1_val1.value assert found_form.test1_val2.value == expected_interface.test1_val2.value def test_stop_burst_operation(self, simulation_launch): operation = simulation_launch(self.test_user, self.test_project, 1000) assert not operation.has_finished self.flow_c.cancel_or_remove_operation(operation.id, 0, False) operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED def test_stop_burst_operation_group(self, simulation_launch): first_op = simulation_launch(self.test_user, self.test_project, 1000, True) operations_group_id = first_op.fk_operation_group assert not first_op.has_finished self.flow_c.cancel_or_remove_operation(operations_group_id, 1, False) operations = dao.get_operations_in_group(operations_group_id) for operation in operations: operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED def test_remove_burst_operation(self, simulation_launch): operation = simulation_launch(self.test_user, self.test_project, 1000) assert not operation.has_finished self.flow_c.cancel_or_remove_operation(operation.id, 0, True) operation = dao.try_get_operation_by_id(operation.id) assert operation is None def test_remove_burst_operation_group(self, simulation_launch): first_op = simulation_launch(self.test_user, self.test_project, 1000, True) operations_group_id = first_op.fk_operation_group assert not first_op.has_finished self.flow_c.cancel_or_remove_operation(operations_group_id, 1, True) operations = dao.get_operations_in_group(operations_group_id) for operation in operations: operation = dao.try_get_operation_by_id(operation.id) assert operation is None def _asynch_launch_simple_op(self): adapter = TestFactory.create_adapter( 'tvb.tests.framework.adapters.testadapter1', 'TestAdapter1') view_model = TestModel() view_model.test1_val1 = 5 view_model.test1_val2 = 6 algo = adapter.stored_adapter operation = self.operation_service.prepare_operation( self.test_user.id, self.test_project, algo, view_model=view_model) self.operation_service._send_to_cluster(operation, adapter) return operation def test_stop_operation(self): operation = self._asynch_launch_simple_op() operation = dao.get_operation_by_id(operation.id) assert not operation.has_finished self.flow_c.cancel_or_remove_operation(operation.id, 0, False) operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED def test_stop_operations_group(self, test_adapter_factory, datatype_group_factory): group = datatype_group_factory(status=STATUS_STARTED, store_vm=True) operations = dao.get_operations_in_group(group.fk_from_operation) operation_group_id = 0 for operation in operations: operation = dao.get_operation_by_id(operation.id) assert not operation.has_finished operation_group_id = operation.fk_operation_group self.flow_c.cancel_or_remove_operation(operation_group_id, 1, False) for operation in operations: operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED
class TestFlowContoller(BaseControllersTest): """ Unit tests for FlowController """ def setup_method(self): """ Sets up the environment for testing; creates a `FlowController` """ self.init() self.flow_c = FlowController() self.burst_c = BurstController() self.operation_service = OperationService() def teardown_method(self): """ Cleans up the testing environment """ self.cleanup() self.clean_database() @pytest.fixture() def long_burst_launch(self, connectivity_factory): def build(is_range=False): self.burst_c.index() connectivity = connectivity_factory[1] launch_params = copy.deepcopy(SIMULATOR_PARAMETERS) launch_params['connectivity'] = dao.get_datatype_by_id(connectivity.id).gid launch_params['simulation_length'] = '10000' if is_range: launch_params['conduction_speed'] = '[10,15,20]' launch_params[RANGE_PARAMETER_1] = 'conduction_speed' launch_params = {"simulator_parameters": json.dumps(launch_params)} burst_id = json.loads(self.burst_c.launch_burst("new", "test_burst", **launch_params))['id'] return dao.get_burst_by_id(burst_id) return build def test_context_selected(self): """ Remove the project from CherryPy session and check that you are redirected to projects page. """ del cherrypy.session[common.KEY_PROJECT] self._expect_redirect('/project/viewall', self.flow_c.step_analyzers) def test_valid_step(self): """ For all algorithm categories check that a submenu is generated and the result page has it's title given by category name. """ result_dict = self.flow_c.step_analyzers() assert common.KEY_SUBMENU_LIST in result_dict,\ "Expect to have a submenu with available algorithms for category." assert result_dict["section_name"] == 'analyze' def test_step_connectivity(self): """ Check that the correct section name and connectivity sub-menu are returned for the connectivity step. """ result_dict = self.flow_c.step_connectivity() assert result_dict['section_name'] == 'connectivity' assert result_dict['submenu_list'] == self.flow_c.connectivity_submenu def test_default(self): """ Test default method from step controllers. Check that the submit link is ok, that a mainContent is present in result dict and that the isAdapter flag is set to true. """ cherrypy.request.method = "GET" categories = dao.get_algorithm_categories() for categ in categories: algo_groups = dao.get_adapters_from_categories([categ.id]) for algo in algo_groups: result_dict = self.flow_c.default(categ.id, algo.id) assert result_dict[common.KEY_SUBMIT_LINK] == '/flow/%i/%i' % (categ.id, algo.id) assert 'mainContent' in result_dict assert result_dict['isAdapter'] def test_default_cancel(self): """ On cancel we should get a redirect to the back page link. """ cherrypy.request.method = "POST" categories = dao.get_algorithm_categories() algo_groups = dao.get_adapters_from_categories([categories[0].id]) self._expect_redirect('/project/viewoperations/%i' % self.test_project.id, self.flow_c.default, categories[0].id, algo_groups[0].id, cancel=True, back_page='operations') def test_default_invalid_key(self): """ Pass invalid keys for adapter and step and check you get redirect to tvb entry page with error set. """ self._expect_redirect('/tvb?error=True', self.flow_c.default, 'invalid', 'invalid') def test_read_datatype_attribute(self, datatype_with_storage_factory): """ Read an attribute from a datatype. """ dt = datatype_with_storage_factory("test_subject", "RAW_STATE", 'this is the stored data'.split()) returned_data = self.flow_c.read_datatype_attribute(dt.gid, "string_data") assert returned_data == '["this", "is", "the", "stored", "data"]' def test_read_datatype_attribute_method_call(self, datatype_with_storage_factory): """ Call method on given datatype. """ dt =datatype_with_storage_factory("test_subject", "RAW_STATE", 'this is the stored data'.split()) args = {'length': 101} returned_data = self.flow_c.read_datatype_attribute(dt.gid, 'return_test_data', **args) assert returned_data == str(list(range(101))) def test_get_simple_adapter_interface(self): adapter = dao.get_algorithm_by_module('tvb.tests.framework.adapters.testadapter1', 'TestAdapter1') result = self.flow_c.get_simple_adapter_interface(adapter.id) expected_interface = TestAdapter1().get_input_tree() assert result['inputList'] == expected_interface def _wait_for_burst_ops(self, burst_config): """ sleeps until some operation of the burst is created""" waited = 1 timeout = 50 operations = dao.get_operations_in_burst(burst_config.id) while not len(operations) and waited <= timeout: sleep(1) waited += 1 operations = dao.get_operations_in_burst(burst_config.id) operations = dao.get_operations_in_burst(burst_config.id) return operations def test_stop_burst_operation(self, long_burst_launch): burst_config = long_burst_launch operation = self._wait_for_burst_ops(burst_config)[0] assert not operation.has_finished self.flow_c.stop_burst_operation(operation.id, 0, False) operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED def test_stop_burst_operation_group(self, long_burst_launch): burst_config = long_burst_launch(True) operations = self._wait_for_burst_ops(burst_config) operations_group_id = 0 for operation in operations: assert not operation.has_finished operations_group_id = operation.fk_operation_group self.flow_c.stop_burst_operation(operations_group_id, 1, False) for operation in operations: operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED def test_remove_burst_operation(self, long_burst_launch): burst_config = long_burst_launch operation = self._wait_for_burst_ops(burst_config)[0] assert not operation.has_finished self.flow_c.stop_burst_operation(operation.id, 0, True) operation = dao.try_get_operation_by_id(operation.id) assert operation is None def test_remove_burst_operation_group(self, long_burst_launch): burst_config = long_burst_launch(True) operations = self._wait_for_burst_ops(burst_config) operations_group_id = 0 for operation in operations: assert not operation.has_finished operations_group_id = operation.fk_operation_group self.flow_c.stop_burst_operation(operations_group_id, 1, True) for operation in operations: operation = dao.try_get_operation_by_id(operation.id) assert operation is None def _launch_test_algo_on_cluster(self, **data): adapter = TestFactory.create_adapter("tvb.tests.framework.adapters.testadapter1", "TestAdapter1") algo = adapter.stored_adapter algo_category = dao.get_category_by_id(algo.fk_category) operations, _ = self.operation_service.prepare_operations(self.test_user.id, self.test_project.id, algo, algo_category, {}, **data) self.operation_service._send_to_cluster(operations, adapter) return operations def test_stop_operations(self): data = {"test1_val1": 5, 'test1_val2': 5} operations = self._launch_test_algo_on_cluster(**data) operation = dao.get_operation_by_id(operations[0].id) assert not operation.has_finished self.flow_c.stop_operation(operation.id, 0, False) operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED def test_stop_operations_group(self): data = {RANGE_PARAMETER_1: "test1_val1", "test1_val1": '5,6,7', 'test1_val2': 5} operations = self._launch_test_algo_on_cluster(**data) operation_group_id = 0 for operation in operations: operation = dao.get_operation_by_id(operation.id) assert not operation.has_finished operation_group_id = operation.fk_operation_group self.flow_c.stop_operation(operation_group_id, 1, False) for operation in operations: operation = dao.get_operation_by_id(operation.id) assert operation.status == STATUS_CANCELED
class FlowContollerTest(BaseControllersTest): """ Unit tests for FlowController """ def setUp(self): """ Sets up the environment for testing; creates a `FlowController` """ self.init() self.flow_c = FlowController() self.burst_c = BurstController() self.operation_service = OperationService() def tearDown(self): """ Cleans up the testing environment """ self.cleanup() self.clean_database() def test_context_selected(self): """ Remove the project from CherryPy session and check that you are redirected to projects page. """ del cherrypy.session[common.KEY_PROJECT] self._expect_redirect('/project/viewall', self.flow_c.step) def test_invalid_step(self): """ Pass an invalid step and make sure we are redirected to tvb start page. """ self._expect_redirect('/tvb', self.flow_c.step) def test_valid_step(self): """ For all algorithm categories check that a submenu is generated and the result page has it's title given by category name. """ categories = dao.get_algorithm_categories() for categ in categories: result_dict = self.flow_c.step(categ.id) self.assertTrue(common.KEY_SUBMENU_LIST in result_dict, "Expect to have a submenu with available algorithms for category.") self.assertEqual(result_dict["section_name"], categ.displayname.lower()) def test_step_connectivity(self): """ Check that the correct section name and connectivity sub-menu are returned for the connectivity step. """ result_dict = self.flow_c.step_connectivity() self.assertEqual(result_dict['section_name'], 'connectivity') self.assertEqual(result_dict['submenu_list'], self.flow_c.connectivity_submenu) def test_default(self): """ Test default method from step controllers. Check that the submit link is ok, that a mainContent is present in result dict and that the isAdapter flag is set to true. """ cherrypy.request.method = "GET" categories = dao.get_algorithm_categories() for categ in categories: algo_groups = dao.get_groups_by_categories([categ.id]) for algo in algo_groups: result_dict = self.flow_c.default(categ.id, algo.id) self.assertEqual(result_dict[common.KEY_SUBMIT_LINK], '/flow/%i/%i' % (categ.id, algo.id)) self.assertTrue('mainContent' in result_dict) self.assertTrue(result_dict['isAdapter']) def test_default_cancel(self): """ On cancel we should get a redirect to the back page link. """ cherrypy.request.method = "POST" categories = dao.get_algorithm_categories() algo_groups = dao.get_groups_by_categories([categories[0].id]) self._expect_redirect('/project/viewoperations/%i' % self.test_project.id, self.flow_c.default, categories[0].id, algo_groups[0].id, cancel=True, back_page='operations') def test_default_invalid_key(self): """ Pass invalid keys for adapter and step and check you get redirect to tvb entry page with error set. """ self._expect_redirect('/tvb?error=True', self.flow_c.default, 'invalid', 'invalid') def test_read_datatype_attribute(self): """ Read an attribute from a datatype. """ dt = DatatypesFactory().create_datatype_with_storage("test_subject", "RAW_STATE", 'this is the stored data'.split()) returned_data = self.flow_c.read_datatype_attribute(dt.gid, "string_data") self.assertEqual(returned_data, '["this", "is", "the", "stored", "data"]') def test_read_datatype_attribute_method_call(self): """ Call method on given datatype. """ dt = DatatypesFactory().create_datatype_with_storage("test_subject", "RAW_STATE", 'this is the stored data'.split()) args = {'length': 101} returned_data = self.flow_c.read_datatype_attribute(dt.gid, 'return_test_data', **args) self.assertTrue(returned_data == str(range(101))) def test_get_simple_adapter_interface(self): adapter = dao.find_group('tvb.tests.framework.adapters.testadapter1', 'TestAdapter1') result = self.flow_c.get_simple_adapter_interface(adapter.id) expected_interface = TestAdapter1().get_input_tree() self.assertEqual(result['inputList'], expected_interface) def _long_burst_launch(self, is_range=False): self.burst_c.index() connectivity = DatatypesFactory().create_connectivity()[1] launch_params = copy.deepcopy(SIMULATOR_PARAMETERS) launch_params['connectivity'] = dao.get_datatype_by_id(connectivity.id).gid if not is_range: launch_params['simulation_length'] = '10000' else: launch_params['simulation_length'] = '[10000,10001,10002]' launch_params[model.RANGE_PARAMETER_1] = 'simulation_length' launch_params = {"simulator_parameters": json.dumps(launch_params)} burst_id = json.loads(self.burst_c.launch_burst("new", "test_burst", **launch_params))['id'] return dao.get_burst_by_id(burst_id) def _wait_for_burst_ops(self, burst_config): """ sleeps until some operation of the burst is created""" waited = 1 timeout = 50 operations = dao.get_operations_in_burst(burst_config.id) while not len(operations) and waited <= timeout: sleep(1) waited += 1 operations = dao.get_operations_in_burst(burst_config.id) operations = dao.get_operations_in_burst(burst_config.id) return operations def test_stop_burst_operation(self): burst_config = self._long_burst_launch() operation = self._wait_for_burst_ops(burst_config)[0] self.assertFalse(operation.has_finished) self.flow_c.stop_burst_operation(operation.id, 0, False) operation = dao.get_operation_by_id(operation.id) self.assertEqual(operation.status, model.STATUS_CANCELED) def test_stop_burst_operation_group(self): burst_config = self._long_burst_launch(True) operations = self._wait_for_burst_ops(burst_config) operations_group_id = 0 for operation in operations: self.assertFalse(operation.has_finished) operations_group_id = operation.fk_operation_group self.flow_c.stop_burst_operation(operations_group_id, 1, False) for operation in operations: operation = dao.get_operation_by_id(operation.id) self.assertEqual(operation.status, model.STATUS_CANCELED) def test_remove_burst_operation(self): burst_config = self._long_burst_launch() operation = self._wait_for_burst_ops(burst_config)[0] self.assertFalse(operation.has_finished) self.flow_c.stop_burst_operation(operation.id, 0, True) operation = dao.try_get_operation_by_id(operation.id) self.assertTrue(operation is None) def test_remove_burst_operation_group(self): burst_config = self._long_burst_launch(True) operations = self._wait_for_burst_ops(burst_config) operations_group_id = 0 for operation in operations: self.assertFalse(operation.has_finished) operations_group_id = operation.fk_operation_group self.flow_c.stop_burst_operation(operations_group_id, 1, True) for operation in operations: operation = dao.try_get_operation_by_id(operation.id) self.assertTrue(operation is None) def _launch_test_algo_on_cluster(self, **data): module = "tvb.tests.framework.adapters.testadapter1" class_name = "TestAdapter1" group = dao.find_group(module, class_name) adapter = FlowService().build_adapter_instance(group) algo_group = adapter.algorithm_group algo_category = dao.get_category_by_id(algo_group.fk_category) algo = dao.get_algorithm_by_group(algo_group.id) operations, _ = self.operation_service.prepare_operations(self.test_user.id, self.test_project.id, algo, algo_category, {}, ABCAdapter.LAUNCH_METHOD, **data) self.operation_service._send_to_cluster(operations, adapter) return operations def test_stop_operations(self): data = {"test1_val1": 5, 'test1_val2': 5} operations = self._launch_test_algo_on_cluster(**data) operation = dao.get_operation_by_id(operations[0].id) self.assertFalse(operation.has_finished) self.flow_c.stop_operation(operation.id, 0, False) operation = dao.get_operation_by_id(operation.id) self.assertEqual(operation.status, model.STATUS_CANCELED) def test_stop_operations_group(self): data = {model.RANGE_PARAMETER_1: "test1_val1", "test1_val1": '5,6,7', 'test1_val2': 5} operations = self._launch_test_algo_on_cluster(**data) operation_group_id = 0 for operation in operations: operation = dao.get_operation_by_id(operation.id) self.assertFalse(operation.has_finished) operation_group_id = operation.fk_operation_group self.flow_c.stop_operation(operation_group_id, 1, False) for operation in operations: operation = dao.get_operation_by_id(operation.id) self.assertEqual(operation.status, model.STATUS_CANCELED)