def test_get_config_does_not_create_config_when_not_enabled(self): config = ConfigManager() config.set_default_values([ANSIBLE_NODES, ANSIBLE_NODE]) config.set(ANSIBLE_NODES, ['1', '2', '3']) config.set(ANSIBLE_ENABLED, False) ansible_suts = AnsibleSuts(None, None) self.assertNotIn('suts.ids', ansible_suts.get_config(config, [], {}).config)
def test_get_config_uses_ansible_node_as_suts_when_set(self): config = ConfigManager() config.set_default_values([ANSIBLE_NODES, ANSIBLE_NODE]) config.set(ANSIBLE_NODES, ['1', '2', '3']) config.set(ANSIBLE_NODE, ['2', '3']) config.set(ANSIBLE_ENABLED, True) ansible_suts = AnsibleSuts(None, None) self.assertCountEqual( ansible_suts.get_config(config, [], {}).config['suts.ids'], ['2', '3'])
class TestPartialParsers(unittest.TestCase): def setUp(self): self.plugin = ClickInitPluginPath({}, {}) self.config = ConfigManager() self.config.set_default_values([PLUGINS_PATHS]) self.option = ConfigOption(PLUGINS_PATHS, required=False) def test_plugin_paths_returned_when_exists(self): # PLUGINS_PATH checks that paths exist path = __file__ path2 = os.getcwd() with patch('sys.argv', ['zaf', '--plugins-paths', path, '--plugins-paths', path2]): extension_config = self.plugin.get_config(self.config, [self.option], {}) self.assertEqual(extension_config.config['plugins.paths'], (path, path2)) def test_plugin_paths_not_returned_if_same_as_default(self): with patch('sys.argv', ['zaf']): extension_config = self.plugin.get_config(self.config, [self.option], {}) self.assertNotIn('plugins-paths', extension_config.config)
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)