def test_retrieving_triggers_from_action_block(): """All trigger instructions should be returned.""" action_block_dict = { 'trigger': [ { 'block': 'on_startup' }, { 'block': 'on_modified', 'path': 'test.template' }, ], } action_block = ActionBlock( action_block=action_block_dict, directory=Path('/'), replacer=lambda x: x, context_store=Context(), ) startup_trigger, on_modified_trigger = action_block.triggers() assert startup_trigger.block == 'on_startup' assert on_modified_trigger.block == 'on_modified' assert on_modified_trigger.specified_path == 'test.template' assert on_modified_trigger.relative_path == Path('test.template') assert on_modified_trigger.absolute_path == Path('/test.template')
def test_executing_action_block_with_one_action( global_modules_config, test_config_directory, tmpdir, ): """Action block behaviour with only one action specified.""" temp_dir = Path(tmpdir) touched = temp_dir / 'touched.tmp' action_block_dict = { 'run': [{ 'shell': 'touch ' + str(touched) }], } action_block = ActionBlock( action_block=action_block_dict, directory=test_config_directory, replacer=lambda x: x, context_store=Context(), global_modules_config=global_modules_config, module_name='test', ) action_block.execute(default_timeout=1) assert touched.is_file()
def test_executing_several_action_blocks(test_config_directory, tmpdir): """Invoking execute() should execute all actions.""" temp_dir = Path(tmpdir) target = temp_dir / 'target.tmp' touched = temp_dir / 'touched.tmp' action_block_dict = { 'import_context': { 'from_path': 'context/mercedes.yml' }, 'compile': [{ 'content': 'templates/a_car.template', 'target': str(target), }], 'run': { 'shell': 'touch ' + str(touched) }, 'trigger': { 'block': 'on_startup' }, } context_store = Context() action_block = ActionBlock( action_block=action_block_dict, directory=test_config_directory, replacer=lambda x: x, context_store=context_store, ) action_block.execute(default_timeout=1) assert context_store == {'car': {'manufacturer': 'Mercedes'}} assert target.read_text() == 'My car is a Mercedes' assert touched.is_file()
def test_null_object_pattern(): """An empty action block should have no behaviour.""" action_block = ActionBlock( action_block={}, directory=Path('/'), replacer=lambda x: x, context_store=Context(), ) action_block.execute(default_timeout=1)
def test_retrieving_triggers_from_action_block_without_triggers(): """Action block with no triggers should return empty tuple.""" action_block = ActionBlock( action_block={}, directory=Path('/'), replacer=lambda x: x, context_store=Context(), ) assert action_block.triggers() == tuple()
def test_null_object_pattern(global_modules_config): """An empty action block should have no behaviour.""" action_block = ActionBlock( action_block={}, directory=Path('/'), replacer=lambda x: x, context_store=Context(), global_modules_config=global_modules_config, module_name='test', ) action_block.execute(default_timeout=1)
def _action_block_factory( import_context={}, compile={}, copy={}, run={}, stow={}, symlink={}, directory=test_config_directory, replacer=lambda x: x, context_store=Context(), ): """Return module with given parameters.""" config = { 'import_context': import_context, 'compile': compile, 'copy': copy, 'run': run, 'stow': stow, 'symlink': symlink, } return ActionBlock( action_block=config, directory=directory, replacer=replacer, context_store=context_store, )
def test_retrieving_all_compiled_templates(template_directory, tmpdir): """All earlier compilations should be retrievable.""" template1 = template_directory / 'empty.template' template2 = template_directory / 'no_context.template' temp_dir = Path(tmpdir) target1 = temp_dir / 'target1.tmp' target2 = temp_dir / 'target2.tmp' target3 = temp_dir / 'target3.tmp' action_block_dict = { 'compile': [ {'source': str(template1), 'target': str(target1)}, {'source': str(template1), 'target': str(target2)}, {'source': str(template2), 'target': str(target3)}, ], } action_block = ActionBlock( action_block=action_block_dict, directory=template_directory, replacer=lambda x: x, context_store={}, ) assert action_block.performed_compilations() == {} action_block.execute(default_timeout=1) assert action_block.performed_compilations() == { template1: {target1, target2}, template2: {target3}, }
def __init__( self, name: str, module_config: ModuleConfigDict, module_directory: Path, replacer: Callable[[str], str] = lambda string: string, context_store: Context = Context(), global_modules_config: Optional[GlobalModulesConfig] = None, dry_run: bool = False, ) -> None: """ Initialize Module object with a section from a config dictionary. Section name must be [module/*], where * is the module name. In addition, the enabled option must be set to "true", or not set at all. module_config example: {'name': 'enabled': True, 'event_listener': {'type': 'weekday'}, 'on_startup': {'run': ['echo weekday is {event}']}, } """ self.name = name # The source directory for the module, determining how to interpret # relative paths in the module config self.directory = module_directory # All user string options should be processed by the replacer self.replace = replacer # Use static event_listener if no event_listener is specified self.event_listener: EventListener = \ event_listener_factory( module_config.get( 'event_listener', {'type': 'static'}, ), ) self.context_store = context_store # Move root actions to 'on_startup' block module_config = self.prepare_on_startup_block( module_name=self.name, module_config=module_config, ) # Create action block object for each available action block type action_blocks: ModuleActionBlocks = {'on_modified': {}} # type: ignore params = { 'module_name': self.name, 'directory': self.directory, 'replacer': self.interpolate_string, 'context_store': self.context_store, 'global_modules_config': global_modules_config, } # Create special case setup action block, it removes any action already # performed. action_blocks['on_setup'] = SetupActionBlock( action_block=module_config.get('on_setup', {}), **params, ) # Create normal action blocks for block_name in ('on_startup', 'on_event', 'on_exit'): action_blocks[block_name] = ActionBlock( # type: ignore action_block=module_config.get( # type: ignore block_name, {}, ), **params, ) for path_string, action_block_dict in module_config.get( 'on_modified', {}, ).items(): modified_path = expand_path( path=Path(path_string), config_directory=self.directory, ) action_blocks['on_modified'][modified_path] = \ ActionBlock( action_block=action_block_dict, **params, ) self.action_blocks = action_blocks requirements = cast_to_list(module_config.get('requires', [])) self.depends_on = tuple( # type: ignore requirement['module'] for requirement in requirements if 'module' in requirement )
def __init__( self, module_config: ModuleConfig, module_directory: Path, replacer: Callable[[str], str] = lambda string: string, context_store: compiler.Context = {}, ) -> None: """ Initialize Module object with a section from a config dictionary. Section name must be [module/*], where * is the module name. In addition, the enabled option must be set to "true", or not set at all. module_config example: {'module/name': 'enabled': True, 'event_listener': {'type': 'weekday'}, 'on_startup': {'run': ['echo weekday is {event}']}, } """ # Can only initialize one module at a time assert len(module_config) == 1 section: str = next(iter(module_config.keys())) self.name: str = section[7:] # The source directory for the module, determining how to interpret # relative paths in the module config self.directory = module_directory # All user string options should be processed by the replacer self.replace = replacer # Extract configuration content module_config_content: ModuleConfigDict = module_config[section] # Use static event_listener if no event_listener is specified self.event_listener: EventListener = \ event_listener_factory( module_config_content.get( 'event_listener', {'type': 'static'}, ), ) self.context_store = context_store # Create action block object for each available action block type action_blocks: ModuleActionBlocks = {'on_modified': {}} # type: ignore for block_name in ('on_startup', 'on_event', 'on_exit'): action_blocks[block_name] = ActionBlock( # type: ignore action_block=module_config_content.get( # type: ignore block_name, {}, ), directory=self.directory, replacer=self.interpolate_string, context_store=self.context_store, ) for path_string, action_block_dict \ in module_config_content.get('on_modified', {}).items(): modified_path = expand_path( path=Path(path_string), config_directory=self.directory, ) action_blocks['on_modified'][modified_path] = \ ActionBlock( action_block=action_block_dict, directory=self.directory, replacer=self.interpolate_string, context_store=self.context_store, ) self.action_blocks = action_blocks