def init_component_handling(self, components): self.component_registry = create_registry() self.component_manager = ComponentManager(self.component_registry) self.component_factory = Factory(self.component_manager) self.messagebus = MessageBus(self.component_factory, Scope('session')) components.append( ComponentMock(name='ComponentFactory', mock=self.component_factory)) components.append( ComponentMock(name='MessageBus', mock=self.messagebus)) components.append(ComponentMock(name='Config', mock=self.config)) components.append( ComponentMock(name='ComponentManager', mock=self.component_manager)) components.append( ComponentMock(name='ExtensionManager', mock=MagicMock())) for comp in components: if type(comp) == ComponentMock: component(name=comp.name, scope=comp.scope, can=comp.can, provided_by_extension=comp.provided_by_extension)( comp, self.component_manager) else: self.component_manager.register_component(comp)
def setUp(self): self.component_manager = ComponentManager() self.component_manager.clear_component_registry() component(scope='session')(TestTestRunnerComponents.Verifier) self.load_components() self.verifier = TestTestRunnerComponents.Verifier() self.parent_scope = Scope('session', None) self.parent_scope.register_instance( _InstanceId(TestTestRunnerComponents.Verifier, ()), self.verifier) self.run_queue = [] self.messagebus = Mock() def send_request(message_id, endpoint_id=None, entities=None, data=None): futures = Mock() if message_id == SCHEDULE_NEXT_TEST: future = Mock() if self.run_queue: future.result.return_value = self.run_queue.pop(0) else: future.result.return_value = None futures.wait.return_value = [future] return futures self.messagebus.send_request.side_effect = send_request self.tr = TestRunner(self.messagebus, Factory(self.component_manager), 'suite-name', parent_scope=self.parent_scope)
def test_enabling_remote_client_registers_component(self): component_manager = ComponentManager() component_manager.clear_component_registry() config = ConfigManager() config.set(REMOTE_CLIENT_ENABLED, True) with ExtensionTestHarness(RemoteClientExtension, config=config): self.assertIn('RemoteClient', component_manager.COMPONENT_REGISTRY)
def setUp(self): self.run_queue = [] messagebus = Mock() def send_request(message_id, endpoint_id=None, entities=None, data=None): futures = Mock() if message_id == SCHEDULE_NEXT_TEST: future = Mock() if self.run_queue: future.result.return_value = self.run_queue.pop(0) else: future.result.return_value = None futures.wait.return_value = [future] return futures messagebus.send_request.side_effect = send_request self.tr = TestRunner(messagebus=messagebus, component_factory=Factory(ComponentManager()), suite_name='suite-name') self.tr.QUEUE_TIMEOUT_SECONDS = 1 self.tr.EXECUTION_PAUSED_TIMEOUT_SECONDS = 1
def test_fail_when_no_serial_connection_is_registered_to_send_command(self): messagebus = MessageBus(Factory(ComponentManager(COMPONENT_REGISTRY))) messagebus.define_endpoints_and_messages({SERIAL_ENDPOINT: [LOG_LINE_RECEIVED]}) client = SerialClient(messagebus, 'entity') with self.assertRaises(SerialError) as error: client.send_line('line', timeout=1) assert 'No serial connection' in error.msg
def setUp(self): self.messagebus = MessageBus(Factory(ComponentManager({}))) self.endpoint = MOCK_ENDPOINT self.sut = Mock() self.sut.entity = 'entity' self.config = Mock() self.config.get = MagicMock(side_effect=config_get_log_sources) self.messagebus.define_endpoints_and_messages( {self.endpoint: [LOG_LINE_RECEIVED]})
def setUp(self): self.messagebus = MessageBus(Factory(ComponentManager({}))) self.sut = MagicMock() self.sut.entity = 'entity1' config = Mock() self.messagebus.define_endpoints_and_messages({ MOCK_ENDPOINT: [SUT_RESET_EXPECTED], SUTEVENTSCOMPONENT_ENDPOINT: [SUT_RESET_EXPECTED, SUT_RESET_DONE] }) self.sut_events = SutEvents(self.messagebus, config, self.sut)
def setUp(self): self.component_manager = ComponentManager() self.component_manager.clear_component_registry() self.load_components()
class TestComponentsOnHandlers(unittest.TestCase): def load_components(self): @component(scope='message') class MessageScoped(object): def __init__(self): self.calls = 0 def __call__(self, *args, **kwargs): self.calls += 1 return self.calls @component(scope='dispatcher') class DispatcherScoped(object): def __init__(self): self.calls = 0 def __call__(self, *args, **kwargs): self.calls += 1 return self.calls @component(scope='session') class SessionScoped(object): def __init__(self): self.calls = 0 def __call__(self, *args, **kwargs): self.calls += 1 return self.calls def setUp(self): self.component_manager = ComponentManager() self.component_manager.clear_component_registry() self.load_components() def test_sequential_dispatcher_requires_component(self): messagebus = create_messagebus() comp_counts = Queue() @requires(comp='MessageScoped') def handle_message(message, comp): comp_counts.put(comp()) dispatcher = SequentialDispatcher(messagebus, handle_message) try: dispatcher.register([defined_message]) messagebus.trigger_event(defined_message, defined_endpoint, data='data1') self.assertEqual(comp_counts.get(timeout=1), 1) finally: dispatcher.destroy() def test_concurrent_dispatcher_requires_component(self): messagebus = create_messagebus() comp_counts = Queue() @requires(comp='MessageScoped') def handle_message(message, comp): comp_counts.put(comp()) dispatcher = ConcurrentDispatcher(messagebus, handle_message) try: dispatcher.register([defined_message]) messagebus.trigger_event(defined_message, defined_endpoint, data='data1') self.assertEqual(comp_counts.get(timeout=1), 1) finally: dispatcher.destroy() def test_callback_dispatcher_requires_component(self): messagebus = create_messagebus() comp_counts = Queue() @requires(comp='MessageScoped') def handle_message(message, comp): comp_counts.put(comp()) dispatcher = CallbackDispatcher(messagebus, handle_message) try: dispatcher.register([defined_message]) messagebus.trigger_event(defined_message, defined_endpoint, data='data1') self.assertEqual(comp_counts.get(timeout=1), 1) finally: dispatcher.destroy() def test_multiple_calls_give_different_message_scoped_components(self): messagebus = create_messagebus() comp_counts = Queue() @requires(comp='MessageScoped') def handle_message(message, comp): comp_counts.put(comp()) dispatcher = CallbackDispatcher(messagebus, handle_message) try: dispatcher.register([defined_message]) messagebus.trigger_event(defined_message, defined_endpoint, data='data1') messagebus.trigger_event(defined_message, defined_endpoint, data='data2') self.assertEqual(comp_counts.get(timeout=1), 1) self.assertEqual(comp_counts.get(timeout=1), 1) finally: dispatcher.destroy() def test_multiple_calls_give_same_dispatcher_scoped_component(self): messagebus = create_messagebus() comp_counts_a = Queue() comp_counts_b = Queue() @requires(comp='DispatcherScoped') def handle_message_a(message, comp): comp_counts_a.put(comp()) @requires(comp='DispatcherScoped') def handle_message_b(message, comp): comp_counts_b.put(comp()) dispatcher_a = CallbackDispatcher(messagebus, handle_message_a) dispatcher_b = CallbackDispatcher(messagebus, handle_message_b) try: try: dispatcher_a.register([defined_message]) dispatcher_b.register([defined_message]) messagebus.trigger_event(defined_message, defined_endpoint, data='data1') messagebus.trigger_event(defined_message, defined_endpoint, data='data2') self.assertEqual(comp_counts_a.get(timeout=1), 1) self.assertEqual(comp_counts_a.get(timeout=1), 2) self.assertEqual(comp_counts_b.get(timeout=1), 1) self.assertEqual(comp_counts_b.get(timeout=1), 2) finally: dispatcher_a.destroy() messagebus.trigger_event(defined_message, defined_endpoint, data='data2') assert comp_counts_a.empty() self.assertEqual(comp_counts_b.get(timeout=1), 3) finally: dispatcher_b.destroy() def test_multiple_calls_give_same_session_scoped_component(self): messagebus = create_messagebus() comp_counts = Queue() @requires(comp='SessionScoped') def handle_message(message, comp): comp_counts.put(comp()) dispatcher = CallbackDispatcher(messagebus, handle_message) try: dispatcher.register([defined_message]) messagebus.trigger_event(defined_message, defined_endpoint, data='data1') messagebus.trigger_event(defined_message, defined_endpoint, data='data2') self.assertEqual(comp_counts.get(timeout=1), 1) self.assertEqual(comp_counts.get(timeout=1), 2) finally: dispatcher.destroy() def test_message_entity_is_used_to_fixate_entities(self): messagebus = create_messagebus() calls = Queue() @component(name='A') class a1(): entity = 'a1' @component(name='A') class a2(): entity = 'a2' @requires(a='A') def handle_message(message, a): calls.put(a.entity) dispatcher = CallbackDispatcher(messagebus, handle_message) try: dispatcher.register([defined_message], entities=['a1', 'a2']) messagebus.trigger_event(defined_message, defined_endpoint, entity='a2', data='data1') self.assertEqual(calls.get(timeout=1), 'a2') messagebus.trigger_event(defined_message, defined_endpoint, entity='a1', data='data2') self.assertEqual(calls.get(timeout=1), 'a1') finally: dispatcher.destroy() def test_combination_of_fixated_and_not_fixated_entities(self): messagebus = create_messagebus() calls = Queue() @component(name='A') class a1(): entity = 'a1' @component(name='A', can=['2']) class a2(): entity = 'a2' @requires(a='A') @requires(a2='A', can=['2'], fixate_entities=False) def handle_message(message, a, a2): calls.put(a.entity) calls.put(a2.entity) dispatcher = CallbackDispatcher(messagebus, handle_message) try: dispatcher.register([defined_message], entities=['a1', 'a2']) messagebus.trigger_event(defined_message, defined_endpoint, entity='a2', data='data1') self.assertEqual(calls.get(timeout=1), 'a2') self.assertEqual(calls.get(timeout=1), 'a2') messagebus.trigger_event(defined_message, defined_endpoint, entity='a1', data='data2') self.assertEqual(calls.get(timeout=1), 'a1') self.assertEqual(calls.get(timeout=1), 'a2') finally: dispatcher.destroy()
class ExtensionTestHarness(object): """ Class that helps testing extensions by creating and configuration the surroundings. It can be used as a context manager and helps with multi threaded tests. .. code-block:: python with ExtensionTestHarness( MyExtension(), {endpoint: [message1, message2]}, {option1: value1, option2: value2}) as harness: with harness.patch('module.to.patch') as m: harness.trigger_event(message1, endpoint, data=MyData()) m.wait_for_call() # Waits for the call to module.to.patch. Needed due to multi threading. m.assert_called_with('the wanted value') """ def __init__(self, constructor, entity=None, endpoints_and_messages=None, config=None, components=None): """ Initialize a new Harness for an extension and defines endpoints_and_messages in the messagebus. :param constructor: the constructor of the extension to test :param entity: If not given and the extension is instantiated on an entity the first entity in the config will be used. Otherwise this can be used to set the wanted entity. :param endpoints_and_messages: endpoints and messages that the extensions wants to subscribe to :param config: Instance of ConfigManager with the wanted config for the extension. :param components: The components to insert into the component registry. List of ComponentMock """ self._constructor = constructor self.config = ConfigManager() if config is None else config self._all_dispatchers = [] self._instances = {} self._entity = None self._entity_option_id = None self.init_component_handling([] if components is None else components) if not isinstance(self._constructor, type): raise Exception( 'Extension should be a constructor of an extension, not an instance.' ) if endpoints_and_messages: self.messagebus.define_endpoints_and_messages( endpoints_and_messages) config_options = self._constructor.config_options config_option_ids = [c.option_id for c in config_options] self.config.set_default_values(config_option_ids) self.init_entity(entity, config_options) self.assert_required_options(config_options, self._entity_option_id) self._config_view = ConfigView(self.config, config_option_ids, self._entity_option_id, self._entity) self._active = _is_extension_active(self._config_view, constructor) def init_entity(self, entity, config_options): self._entity_option_id = None entity_option_ids = [ c.option_id for c in config_options if c.instantiate_on ] if entity_option_ids: self._entity_option_id = entity_option_ids[0] entities = self.config.get(self._entity_option_id) if entity: if entity not in entities: AssertionError( "Entity '{entity}' is not a valid entity for '{option_id}', " "valid options are '{entities}'".format( entity=entity, option_id=self._entity_option_id.key, entities=entities)) self._entity = entity else: self._entity = entities[0] self._instances[self._entity_option_id] = self._entity def init_component_handling(self, components): self.component_registry = create_registry() self.component_manager = ComponentManager(self.component_registry) self.component_factory = Factory(self.component_manager) self.messagebus = MessageBus(self.component_factory, Scope('session')) components.append( ComponentMock(name='ComponentFactory', mock=self.component_factory)) components.append( ComponentMock(name='MessageBus', mock=self.messagebus)) components.append(ComponentMock(name='Config', mock=self.config)) components.append( ComponentMock(name='ComponentManager', mock=self.component_manager)) components.append( ComponentMock(name='ExtensionManager', mock=MagicMock())) for comp in components: if type(comp) == ComponentMock: component(name=comp.name, scope=comp.scope, can=comp.can, provided_by_extension=comp.provided_by_extension)( comp, self.component_manager) else: self.component_manager.register_component(comp) def assert_required_options(self, config_options, entity_option_id): def assert_in_config(option_id, entity=None): if self.config.get(option_id, entity=entity) is None: raise AssertionError( 'Missing required option {option}{for_entity}'.format( option=option.option_id.key, for_entity='for entity {entity}'.format( entity=entity) if entity else '')) for option in config_options: if option.required and not option.option_id.has_default: if option.option_id.at is not None and option.option_id == entity_option_id: assert_in_config(option.option_id, entity=self._entity) elif option.option_id.at is not None: entities = self.config.get(option.option_id.at) if not option.option_id.at.multiple: entities = [entities] for entity in entities: assert_in_config(option.option_id, entity=entity) else: assert_in_config(option.option_id) @property def extension(self): return self._instance def __enter__(self): self._instance = self._constructor(self._config_view, self._instances) self.messagebus.define_endpoints_and_messages( self._instance.endpoints_and_messages) if hasattr(self._instance, 'register_components'): self._instance.register_components(self.component_manager) for method, descriptor in get_dispatcher_descriptors(self._instance): dispatcher = descriptor.dispatcher_constructor( self.messagebus, method) entities = None if descriptor.entity_option_id is not None: entities = [self._instances[descriptor.entity_option_id]] if self._active: dispatcher.register(descriptor.message_ids, endpoint_ids=descriptor.endpoint_ids, entities=entities) self._all_dispatchers.append(dispatcher) self._instance.register_dispatchers(self.messagebus) return self def __exit__(self, *exc_info): for dispatcher in self._all_dispatchers: if self._active: dispatcher.destroy() self._instance.destroy() def trigger_event(self, message_id, sender_endpoint_id, entity=None, data=None): self.messagebus.trigger_event(message_id, sender_endpoint_id, entity, data) def send_request(self, message_id, receiver_endpoint_id=None, entity=None, data=None): return self.messagebus.send_request(message_id, receiver_endpoint_id, entity, data) def any_registered_dispatchers(self, message_id, endpoint_id=None, entity=None): return self.messagebus.has_registered_dispatchers( message_id, endpoint_id, entity) @contextmanager def message_queue(self, message_ids, endpoint_ids=None, entities=None, match=None, priority=0): with LocalMessageQueue(self.messagebus, message_ids, endpoint_ids, entities, match, priority) as q: yield q def patch(self, target, *patch_args, **patch_kwargs): """ Patch with a special multi threaded wait_for_call method. The returned mock stores the arguments when it's called in a queue and then wait_for_call can be used to get the a tuple of *args* and *kwargs* that the mock was called with. The mock is a normal mock so after waiting for a call the normal mock asserts can be called. .. code-block:: python harness = ExtensionTestHarness(...) with harness.patch('function.to.patch') as mock: trigger_something() mock_args, mock_kwargs = mock.wait_for_call(timeout=4) mock.assert_called_once() self.assertEqual(mock_args[0], 'expected_value') :param target: the target :param patch_args: args sent to normal patch :param patch_kwargs: kwargs sent to normal patch :return: a mock with the extra wait_for_call method """ return patch(target, *patch_args, new=SyncMock(), **patch_kwargs)
def setUp(self): self.component_manager = ComponentManager(create_registry(), create_entity_map())
def test_multiple_message_dispatchers_triggered_by_applicable_messages( self): messagebus = MessageBus(Factory(ComponentManager())) message_endpoint = EndpointId('message_endpoint', '') message_endpoint2 = EndpointId('message_endpoint2', '') message_endpoint_entity1 = 'endpoint_entity1' message_endpoint_entity2 = 'endpoint_entity2' sent_from_endpoint = MessageId('sent_from_endpoint', '') sent_from_entity1 = MessageId('sent_from_entity1', '') messagebus.define_endpoint(message_endpoint) messagebus.define_endpoint(message_endpoint2) messagebus.define_message(sent_from_endpoint, message_endpoint) messagebus.define_message(sent_from_entity1, message_endpoint) messagebus.define_message(sent_from_endpoint, message_endpoint2) messagebus.define_message(sent_from_entity1, message_endpoint2) received = { message_endpoint: [], message_endpoint2: [], message_endpoint_entity1: [], message_endpoint_entity2: [] } def endpoint1(message): received[message_endpoint].append(message.message_id) messagebus.register_dispatcher(create_dispatcher(endpoint1), [sent_from_endpoint, sent_from_entity1], [message_endpoint]) def endpoint2(message): received[message_endpoint2].append(message.message_id) messagebus.register_dispatcher(create_dispatcher(endpoint2), [sent_from_endpoint, sent_from_entity1], [message_endpoint2]) def endpoint_entity1(message): received[message_endpoint_entity1].append(message.message_id) messagebus.register_dispatcher(create_dispatcher(endpoint_entity1), [sent_from_endpoint, sent_from_entity1], [message_endpoint], [message_endpoint_entity1]) def endpoint_entity2(message): received[message_endpoint_entity2].append(message.message_id) messagebus.register_dispatcher(create_dispatcher(endpoint_entity2), [sent_from_endpoint, sent_from_entity1], [message_endpoint], [message_endpoint_entity2]) messagebus.trigger_event(sent_from_endpoint, message_endpoint) messagebus.trigger_event(sent_from_entity1, message_endpoint, message_endpoint_entity1) self.assertEqual(received[message_endpoint], [sent_from_endpoint, sent_from_entity1]) self.assertEqual(received[message_endpoint2], []) self.assertEqual(received[message_endpoint_entity1], [sent_from_entity1]) self.assertEqual(received[message_endpoint_entity2], [])
class TestTestRunnerComponents(unittest.TestCase): class Verifier(object): def __init__(self): self.data = [] def load_components(self): @component() @requires(verifier='Verifier') class MyComponent(object): def __init__(self, verifier): self.verifier = verifier def __enter__(self): self.verifier.data.append('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): self.verifier.data.append('exit') def __call__(self, *args, **kwargs): self.verifier.data.append('call') @component() @requires(verifier='Verifier') class MyEnterFailComponent(object): def __init__(self, verifier): self.verifier = verifier def __enter__(self): self.verifier.data.append('enter') raise (Exception('enter fails')) def __exit__(self, exc_type, exc_val, exc_tb): self.verifier.data.append('exit') def __call__(self, *args, **kwargs): self.verifier.data.append('call') @component() @requires(verifier='Verifier') class MyExitFailComponent(object): def __init__(self, verifier): self.verifier = verifier def __enter__(self): self.verifier.data.append('enter') return self def __exit__(self, exc_type, exc_val, exc_tb): self.verifier.data.append('exit') raise (Exception('exit fails')) def __call__(self, *args, **kwargs): self.verifier.data.append('call') def setUp(self): self.component_manager = ComponentManager() self.component_manager.clear_component_registry() component(scope='session')(TestTestRunnerComponents.Verifier) self.load_components() self.verifier = TestTestRunnerComponents.Verifier() self.parent_scope = Scope('session', None) self.parent_scope.register_instance( _InstanceId(TestTestRunnerComponents.Verifier, ()), self.verifier) self.run_queue = [] self.messagebus = Mock() def send_request(message_id, endpoint_id=None, entities=None, data=None): futures = Mock() if message_id == SCHEDULE_NEXT_TEST: future = Mock() if self.run_queue: future.result.return_value = self.run_queue.pop(0) else: future.result.return_value = None futures.wait.return_value = [future] return futures self.messagebus.send_request.side_effect = send_request self.tr = TestRunner(self.messagebus, Factory(self.component_manager), 'suite-name', parent_scope=self.parent_scope) def test_enters_and_exit_called_on_component_with_test_scope(self): @requires(comp='MyComponent', scope='test') def my_test_case(comp): comp() self.run_queue.append(TestCaseDefinition(my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enters_and_exit_called_on_component_with_module_scope(self): @requires(comp='MyComponent', scope='module') def my_test_case(comp): comp() self.run_queue.append(TestCaseDefinition(my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enters_and_exit_called_on_component_with_class_scope(self): class TestMyTestCase(object): @requires(comp='MyComponent', scope='class') def my_test_case(self, comp): comp() self.run_queue.append(TestCaseDefinition( TestMyTestCase().my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enters_and_exit_called_on_component_with_runner_scope(self): @requires(comp='MyComponent', scope='module') def my_test_case(comp): comp() self.run_queue.append(TestCaseDefinition(my_test_case)) self.tr.run() assert 'enter' in self.verifier.data assert 'call' in self.verifier.data assert 'exit' in self.verifier.data def test_enter_and_exit_called_once_on_class_scope_component_for_test_cases_in_same_class( self): class TestMyTestCase(object): @requires(comp='MyComponent', scope='class') def my_test_case1(self, comp): comp() @requires(comp='MyComponent', scope='class') def my_test_case2(self, comp): comp() test_case_class = TestMyTestCase() self.run_queue.extend([ TestCaseDefinition(test_case_class.my_test_case1), TestCaseDefinition(test_case_class.my_test_case2) ]) self.tr.run() assert self.verifier.data.count('enter') == 1 assert self.verifier.data.count('call') == 2 assert self.verifier.data.count('exit') == 1 def test_enter_and_exit_called_once_on_module_scope_component_for_test_cases_in_same_module( self): @requires(comp='MyComponent', scope='module') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='module') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.verifier.data.count('enter') == 1 assert self.verifier.data.count('call') == 2 assert self.verifier.data.count('exit') == 1 def test_enter_and_exit_called_once_on_runner_scope_component(self): @requires(comp='MyComponent', scope='runner') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='runner') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.verifier.data.count('enter') == 1 assert self.verifier.data.count('call') == 2 assert self.verifier.data.count('exit') == 1 def test_enter_fails_sets_test_case_verdict_to_error_and_exit_is_called( self): @requires(comp='MyEnterFailComponent', scope='runner') def my_test_case1(comp): comp() self.run_queue.extend([TestCaseDefinition(my_test_case1)]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.ERROR assert 'enter' in self.verifier.data assert 'call' not in self.verifier.data assert 'exit' in self.verifier.data def test_enter_fails_sets_test_case_verdict_to_error_and_continues_to_next_test_case( self): @requires(comp='MyEnterFailComponent', scope='runner') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='runner') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.ERROR assert self.tr.run_history[1].verdict == Verdict.PASSED def test_exit_fails_on_test_scope_aborts_test_run(self): @requires(comp='MyExitFailComponent', scope='test') def my_test_case1(comp): comp() @requires(comp='MyComponent', scope='runner') def my_test_case2(comp): comp() self.run_queue.extend([ TestCaseDefinition(my_test_case1), TestCaseDefinition(my_test_case2) ]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.PASSED assert self.tr.run_history[1].verdict == Verdict.SKIPPED def test_exit_fails_on_non_test_scope_aborts_test_run(self): class MyTestCase1(object): @requires(comp='MyExitFailComponent', scope='class') def my_test_case1(self, comp): comp() class MyTestCase2(object): @requires(comp='MyComponent', scope='class') def my_test_case2(self, comp): comp() self.run_queue.extend([ TestCaseDefinition(MyTestCase1().my_test_case1), TestCaseDefinition(MyTestCase2().my_test_case2) ]) self.tr.run() assert self.tr.run_history[0].verdict == Verdict.PASSED assert self.tr.run_history[1].verdict == Verdict.SKIPPED
def test_multiple_request_dispatchers_triggered_by_applicable_requests( self): messagebus = MessageBus(Factory(ComponentManager())) request_target = EndpointId('request_target', '') request_target2 = EndpointId('request_target2', '') request_target_entity1 = 'target_entity1' request_target_entity2 = 'target_entity2' sent_to_all = MessageId('request_to_all', '') sent_to_target = MessageId('request_to_target', '') sent_to_entity1 = MessageId('request_to_entity1', '') messagebus.define_endpoint(request_target) messagebus.define_endpoint(request_target2) messagebus.define_message(sent_to_all, request_target) messagebus.define_message(sent_to_target, request_target) messagebus.define_message(sent_to_entity1, request_target) messagebus.define_message(sent_to_all, request_target2) messagebus.define_message(sent_to_target, request_target2) messagebus.define_message(sent_to_entity1, request_target2) received = { request_target: [], request_target2: [], request_target_entity1: [], request_target_entity2: [] } def target1(message): received[request_target].append(message.message_id) messagebus.register_dispatcher( create_dispatcher(target1), [sent_to_all, sent_to_target, sent_to_entity1], [request_target]) def target2(message): received[request_target2].append(message.message_id) messagebus.register_dispatcher( create_dispatcher(target2), [sent_to_all, sent_to_target, sent_to_entity1], [request_target2]) def target_entity1(message): received[request_target_entity1].append(message.message_id) messagebus.register_dispatcher( create_dispatcher(target_entity1), [sent_to_all, sent_to_target, sent_to_entity1], [request_target], [request_target_entity1]) def target_entity2(message): received[request_target_entity2].append(message.message_id) messagebus.register_dispatcher( create_dispatcher(target_entity2), [sent_to_all, sent_to_target, sent_to_entity1], [request_target], [request_target_entity2]) messagebus.send_request(sent_to_all) messagebus.send_request(sent_to_target, request_target) messagebus.send_request(sent_to_entity1, request_target, request_target_entity1) self.assertEqual(received[request_target], [sent_to_all, sent_to_target]) self.assertEqual(received[request_target2], [sent_to_all]) self.assertEqual(received[request_target_entity1], [sent_to_all, sent_to_target, sent_to_entity1]) self.assertEqual(received[request_target_entity2], [sent_to_all, sent_to_target])
class Application(object): def __init__(self, application_config, entry_points=['zaf.addons', 'zaf.local_addons'], signalhandler=None): root_logger = logging.getLogger() # Default config for rootlogger to not spam until logger is correctly configured root_logger.setLevel(logging.INFO) self.app_config = application_config self.signalhandler = signalhandler self.entry_points = entry_points self.extension_manager = ExtensionManager() self.component_manager = ComponentManager() self.component_factory = Factory(self.component_manager) self.session_scope = self.component_factory.enter_scope('session') self.messagebus = MessageBus(self.component_factory, self.session_scope) self.messagebus.define_endpoints_and_messages( {APPLICATION_ENDPOINT: [BEFORE_COMMAND, AFTER_COMMAND]}) self.config = ConfigManager() self.command = None self._exit_code = 1 self.app_config.apply_configuration(self.config) @component(name='MessageBus', scope='session') def messagebus(): """ Access the message bus. The message bus can be used to register dispatchers to specific endpoints, message_ids and entities and to send requests and events to the registered dispatchers. """ return self.messagebus @component(name='ComponentFactory', scope='session') def component_factory(): """ Access the component factory. The component factory can be used to call callables inside a scope and have the correct components instantiated in the scope. """ return self.component_factory @component(name='ComponentManager', scope='session') def component_manager(): """ Access the component manager. The component manager can be used to find out what components are available. """ return self.component_manager @component(name='Config', scope='session') def config(): """ Access the Config Manager. The Config components gives full access to all the config. """ return self.config @component(name='ExtensionManager', scope='session') def extension_manager(): """ Access the extension manager. The extension manager can be used to find out what extensions are loaded. """ return self.extension_manager def run(self): with self as instance: instance._exit_code = instance.execute_command() return instance._exit_code def setup(self): application_config_options = [ ConfigOption(MESSAGEBUS_TIMEOUT, required=False), ConfigOption(CWD, required=True), ] loader = ExtensionLoader(self.extension_manager, self.config, self.messagebus, application_config_options, self.component_manager) self.command = loader.load_extensions(self.entry_points) def teardown(self): try: self.messagebus.wait_for_not_active( timeout=self.config.get(MESSAGEBUS_TIMEOUT)) except MessageBusTimeout as e: logger.critical( 'Waiting for messagebus to be inactive timed out,' ' shutting down anyway. State: {state}'.format(state=e)) finally: logger.debug( 'Dispatchers still registered to the messagebus: {dispatchers}' .format(dispatchers=self.messagebus.get_dispatchers())) self.extension_manager.destroy() for th in threading.enumerate(): try: if th.name != 'MainThread': logger.debug(th) logger.debug('\n'.join( traceback.format_stack( sys._current_frames()[th.ident]))) except KeyError: logger.debug(th) def execute_command(self): logger.debug( 'Executing command {command} for application {application} with version {version}' .format(command=self.command.name, application=self.app_config.name, version=self.app_config.version)) self._activate_signalhandler() self.messagebus.trigger_event(BEFORE_COMMAND, APPLICATION_ENDPOINT, data=self.command.name) result = 0 try: result = self.component_factory.call(self.command.callable, self.session_scope, self) return result if result is not None else 0 finally: logger.debug( 'Command {command} exited with exit code {result}'.format( command=self.command.name, result=result).format(command=self.command.name, application=self.app_config.name, version=self.app_config.version)) self.component_factory.exit_scope(self.session_scope) self.messagebus.trigger_event(AFTER_COMMAND, APPLICATION_ENDPOINT, data=self.command.name) def gather_metadata(self, metadata_filter=None): return ZafMetadata(self.extension_manager.all_extensions, self.component_manager.get_components_info(), self.config, self.app_config.entrypoint, self.extension_manager, metadata_filter) def __enter__(self): try: self.setup() except Exception: self.__exit__(*sys.exc_info()) raise return self def __exit__(self, *args): self.teardown() @property def exit_code(self): return self._exit_code def _activate_signalhandler(self): if self.signalhandler is not None: self.signalhandler.activate(self.messagebus) def _deactivate_signalhandler(self): if self.signalhandler is not None: self.signalhandler.deactivate()
def __init__(self, application_config, entry_points=['zaf.addons', 'zaf.local_addons'], signalhandler=None): root_logger = logging.getLogger() # Default config for rootlogger to not spam until logger is correctly configured root_logger.setLevel(logging.INFO) self.app_config = application_config self.signalhandler = signalhandler self.entry_points = entry_points self.extension_manager = ExtensionManager() self.component_manager = ComponentManager() self.component_factory = Factory(self.component_manager) self.session_scope = self.component_factory.enter_scope('session') self.messagebus = MessageBus(self.component_factory, self.session_scope) self.messagebus.define_endpoints_and_messages( {APPLICATION_ENDPOINT: [BEFORE_COMMAND, AFTER_COMMAND]}) self.config = ConfigManager() self.command = None self._exit_code = 1 self.app_config.apply_configuration(self.config) @component(name='MessageBus', scope='session') def messagebus(): """ Access the message bus. The message bus can be used to register dispatchers to specific endpoints, message_ids and entities and to send requests and events to the registered dispatchers. """ return self.messagebus @component(name='ComponentFactory', scope='session') def component_factory(): """ Access the component factory. The component factory can be used to call callables inside a scope and have the correct components instantiated in the scope. """ return self.component_factory @component(name='ComponentManager', scope='session') def component_manager(): """ Access the component manager. The component manager can be used to find out what components are available. """ return self.component_manager @component(name='Config', scope='session') def config(): """ Access the Config Manager. The Config components gives full access to all the config. """ return self.config @component(name='ExtensionManager', scope='session') def extension_manager(): """ Access the extension manager. The extension manager can be used to find out what extensions are loaded. """ return self.extension_manager
def setUp(self): self.component_manager = ComponentManager(create_registry(), create_entity_map()) self.registry = self.component_manager.COMPONENT_REGISTRY self.builder = DependencyGraphBuilder(self.registry) self.scope = Scope('scope')
def setUp(self): ComponentManager().clear_component_registry()
def setUp(self): component_manager = ComponentManager() component_manager.clear_component_registry() self.registry = component_manager.COMPONENT_REGISTRY self.builder = DependencyGraphBuilder(self.registry)