def test_copying_in_on_modified_block(
    action_block_factory,
    create_temp_files,
    module_factory,
):
    """Module should copy properly."""
    file1, file2, file3, file4 = create_temp_files(4)
    file2.write_text('original')
    file4.write_text('some other content')

    action_block = action_block_factory(copy=[
        {
            'content': str(file1),
            'target': str(file2)
        },
        {
            'content': str(file3),
            'target': str(file4)
        },
    ], )
    module = module_factory(on_modified=action_block, path=Path('/a/b/c'))

    module_manager = ModuleManager()
    module_manager.modules = {'test': module}
    module_manager.on_modified(Path('/a/b/c'))

    # Check if content has been copied
    assert file2.read_text() == file1.read_text()
    assert file4.read_text() == file3.read_text()
Beispiel #2
0
    def test_missing_template_file(
        self,
        default_global_options,
        _runtime,
        caplog,
    ):
        application_config = {
            'module/test_module': {
                'on_startup': {
                    'compile': [
                        {
                            'source': '/not/existing'
                        },
                    ],
                },
            },
        }

        application_config.update(default_global_options)
        application_config.update(_runtime)

        module_manager = ModuleManager(application_config)

        caplog.clear()
        module_manager.finish_tasks()
        assert 'Could not compile template "/not/existing" '\
               'to target "' in caplog.record_tuples[0][2]
def test_symlinking_in_on_startup_block(
    action_block_factory,
    module_factory,
    create_temp_files,
):
    """ModuleManager should symlink properly."""
    file1, file2, file3, file4 = create_temp_files(4)
    file2.write_text('original')

    action_block = action_block_factory(symlink=[
        {
            'content': str(file1),
            'target': str(file2)
        },
        {
            'content': str(file3),
            'target': str(file4)
        },
    ], )
    module = module_factory(on_startup=action_block)

    module_manager = ModuleManager()
    module_manager.modules = {'test': module}
    module_manager.finish_tasks()

    assert file2.is_symlink()
    assert file2.resolve() == file1
    assert file4.is_symlink()
    assert file4.resolve() == file3
Beispiel #4
0
def test_that_shell_filter_is_run_from_config_directory(test_config_directory):
    shell_filter_template = Path(__file__).parents[1] \
        / 'templates' / 'shell_filter_working_directory.template'
    shell_filter_template_target = Path(
        '/tmp/astrality/shell_filter_working_directory.template',
    )
    modules = {
        'A': {
            'on_startup': {
                'compile': [
                    {
                        'content': str(shell_filter_template),
                        'target': str(shell_filter_template_target),
                    },
                ],
            },
        },
    }

    module_manager = ModuleManager(modules=modules)
    module_manager.execute(action='compile', block='on_startup')

    with open(shell_filter_template_target) as compiled:
        assert compiled.read() == str(test_config_directory)

    os.remove(shell_filter_template_target)
Beispiel #5
0
    def test_compilation_of_template(
        self,
        simple_application_config,
        module,
        conf,
        caplog,
    ):
        simple_application_config['module/test_module']['event_listener'][
            'type'] = 'solar'
        compiled_template_content = 'some text\n' + os.environ[
            'USER'] + '\nFuraMono Nerd Font'
        module_manager = ModuleManager(simple_application_config)
        directory = module_manager.config_directory

        caplog.clear()
        module_manager.compile_templates('on_startup')

        template_file = str(
            (directory / '../templates/test_template.conf').resolve())
        compiled_template = str(
            list(
                module_manager.modules['test_module']\
                    .performed_compilations()[Path(template_file)]\
            )[0]
        )

        with open('/tmp/compiled_result', 'r') as file:
            compiled_result = file.read()

        assert compiled_template_content == compiled_result
        assert caplog.record_tuples == [
            ('astrality', logging.INFO,
             f'[Compiling] Template: "{template_file}" -> Target: "{compiled_template}"'
             ),
        ]
Beispiel #6
0
def test_that_shell_filter_is_run_from_config_directory(
    default_global_options,
    _runtime,
    test_config_directory,
):
    shell_filter_template = Path(__file__).parents[
        1] / 'templates' / 'shell_filter_working_directory.template'
    shell_filter_template_target = Path(
        '/tmp/astrality/shell_filter_working_directory.template')
    config = {
        'module/A': {
            'on_startup': {
                'compile': [{
                    'source': str(shell_filter_template),
                    'target': str(shell_filter_template_target),
                }],
            },
        },
    }
    config.update(default_global_options)
    config.update(_runtime)
    module_manager = ModuleManager(config)
    module_manager.compile_templates('on_startup')

    with open(shell_filter_template_target) as compiled:
        assert compiled.read() == str(test_config_directory)

    os.remove(shell_filter_template_target)
Beispiel #7
0
def test_compiling_template_with_specific_permissions(
    test_config_directory,
    tmpdir,
    specified_permission,
    expected_permission,
):
    template = test_config_directory / 'templates' / 'empty.template'
    target = Path(tmpdir) / 'target'

    modules = {
        'test': {
            'on_startup': {
                'compile': {
                    'content': str(template),
                    'target': str(target),
                    'permissions': specified_permission,
                },
            },
        },
    }

    module_manager = ModuleManager(modules=modules, )
    module_manager.finish_tasks()

    assert (target.stat().st_mode & 0o777) == expected_permission
Beispiel #8
0
def test_direct_invocation_of_modifed_method_of_module_manager(modules_config):
    (
        modules,
        empty_template,
        empty_template_target,
        touch_target,
        secondary_template,
        secondary_template_target,
    ) = modules_config

    module_manager = ModuleManager(modules=modules)

    # PS: Disabling the directory watcher is not necessary, as it is done in
    # the startup method.

    # Now write new text to the template
    empty_template.write_text('new content')

    # And trigger the modified method manually
    module_manager.file_system_modified(empty_template)

    # And assert that the new template has been compiled
    assert empty_template_target.is_file()
    with open(empty_template_target) as file:
        assert file.read() == 'new content'

    # And that the new file has been touched
    assert Retry()(lambda: touch_target.is_file())
Beispiel #9
0
def test_stowing(
    action_block_factory,
    create_temp_files,
    module_factory,
):
    """ModuleManager should stow properly."""
    template, target = create_temp_files(2)
    template.write_text('{{ env.EXAMPLE_ENV_VARIABLE }}')
    symlink_target = template.parent / 'symlink_me'
    symlink_target.touch()

    action_block = action_block_factory(stow={
        'content': str(template.parent),
        'target': str(target.parent),
        'templates': r'file(0).temp',
        'non_templates': 'symlink',
    }, )
    module = module_factory(on_exit=action_block, )

    module_manager = ModuleManager()
    module_manager.modules = {'test': module}
    module_manager.exit()

    # Check if template has been compiled
    assert Path(target.parent / '0').read_text() == 'test_value'

    # Check if non_template has been symlinked
    assert (template.parent / 'symlink_me').resolve() == symlink_target
Beispiel #10
0
def test_compiling_template_with_specific_permissions(
    default_global_options,
    _runtime,
    test_config_directory,
    tmpdir,
    specified_permission,
    expected_permission,
):
    template = test_config_directory / 'templates' / 'empty.template'
    target = Path(tmpdir) / 'target'

    application_config = {
        'module/test': {
            'on_startup': {
                'compile': {
                    'source': str(template),
                    'target': str(target),
                    'permissions': specified_permission,
                },
            },
        },
    }
    application_config.update(default_global_options)
    application_config.update(_runtime)

    module_manager = ModuleManager(application_config)
    module_manager.finish_tasks()

    assert (target.stat().st_mode & 0o777) == expected_permission
Beispiel #11
0
def test_hot_reloading(
    test_template_targets,
    test_config_directory,
):
    template_target1, template_target2 = test_template_targets
    config1 = test_config_directory / 'modules1.yml'
    config2 = test_config_directory / 'modules2.yml'
    target_config = test_config_directory / 'modules.yml'

    # Copy the first configuration into place
    shutil.copy(str(config1), str(target_config))

    modules1 = utils.compile_yaml(
        config1,
        context={},
    )

    application_config1 = {'astrality': {'hot_reload_config': True}}
    module_manager = ModuleManager(
        config=application_config1,
        modules=modules1,
        directory=test_config_directory,
    )

    # Before beginning, the template should not be compiled
    assert not template_target1.is_file()

    # But when we finalize tasks, it should be compiled
    module_manager.finish_tasks()
    assert template_target1.is_file()

    # Also check that the filewatcher has been started
    assert module_manager.directory_watcher.observer.is_alive()

    # We now "edit" the configuration file
    shutil.copy(str(config2), str(target_config))

    # Since hot reloading is enabled, the new template target should be
    # compiled, and the old one cleaned up
    retry = Retry()
    assert retry(lambda: template_target2.is_file())
    assert retry(lambda: not template_target1.is_file())

    # And we switch back again
    shutil.copy(str(config1), str(target_config))
    assert retry(lambda: template_target1.is_file())
    assert retry(lambda: not template_target2.is_file())

    # Cleanup config file
    if target_config.is_file():
        os.remove(target_config)

    # Stop the filewatcher
    module_manager.directory_watcher.stop()
Beispiel #12
0
def test_that_running_processes_causes_keep_running():
    """If shell commands are running, keep_running should be True."""
    module_manager = ModuleManager(modules={
        'A': {
            'run': {
                'shell': 'sleep 10'
            }
        },
    }, )
    module_manager.finish_tasks()
    assert module_manager.keep_running is True
Beispiel #13
0
def test_that_cleanup_cli_works(
    method,
    create_temp_files,
    patch_xdg_directory_standard,
):
    """--cleanup module_name, all module created files should be deleted"""
    (
        template1,
        template2,
        template3,
        target1,
        target2,
        target3,
    ) = create_temp_files(6)

    for template in (template1, template2, template3):
        template.write_text('new content')

    for target in (target1, target2, target3):
        target.write_text('original content')

    modules = {
        'A': {
            method: [
                {
                    'content': str(template1),
                    'target': str(target1),
                },
                {
                    'content': str(template2),
                    'target': str(target2),
                },
            ],
        },
        'B': {
            method: {
                'content': str(template3),
                'target': str(target3),
            },
        },
    }
    module_manager = ModuleManager(modules=modules)
    module_manager.finish_tasks()

    for target in (target1, target2, target3):
        assert target.resolve().read_text() == 'new content'

    bin_script = str(Path(__file__).parents[3] / 'bin' / 'astrality')
    data_home = 'XDG_DATA_HOME="' + str(patch_xdg_directory_standard) + '/.." '
    command = data_home + bin_script + ' --cleanup A --cleanup B'
    os.system(command)

    for target in (target1, target2, target3):
        assert target.resolve().read_text() == 'original content'
Beispiel #14
0
def test_that_only_startup_event_block_is_run_on_startup(
    two_test_file_paths,
    test_config_directory,
    default_global_options,
    _runtime,
    freezer,
):
    thursday = datetime(
        year=2018,
        month=2,
        day=15,
        hour=12,
    )
    freezer.move_to(thursday)

    test_file1, test_file2 = two_test_file_paths
    application_config = {
        'module/A': {
            'event_listener': {
                'type': 'weekday'
            },
            'on_startup': {
                'run': [{
                    'shell': 'touch ' + str(test_file1)
                }],
            },
            'on_event': {
                'run': [{
                    'shell': 'touch ' + str(test_file2)
                }],
            },
        },
    }
    application_config.update(default_global_options)
    application_config.update(_runtime)
    module_manager = ModuleManager(application_config)

    # Before call to finish_tasks, no actions should have been performed
    assert not test_file1.is_file() and not test_file2.is_file()

    # Now call finish_tasks for the first time, only startup event block should
    # be run
    module_manager.finish_tasks()
    time.sleep(0.5)
    assert test_file1.is_file()
    assert not test_file2.is_file()

    friday = datetime(
        year=2018,
        month=2,
        day=16,
        hour=12,
    )
Beispiel #15
0
 def test_using_finish_tasks_on_example_configuration(
     self,
     conf,
     modules,
     context,
 ):
     module_manager = ModuleManager(
         config=conf,
         modules=modules,
         context=context,
     )
     module_manager.finish_tasks()
Beispiel #16
0
    def test_compilation_of_template(
        self,
        valid_module_section,
        simple_application_config,
        module,
        conf,
        caplog,
    ):
        valid_module_section[
            'test_module'
        ][
            'event_listener'
        ][
            'type'
        ] = 'solar'

        compiled_template_content = 'some text\n' + os.environ['USER'] \
            + '\nFuraMono Nerd Font'
        module_manager = ModuleManager(
            config=simple_application_config,
            modules=valid_module_section,
            context=Context({
                'fonts': {1: 'FuraMono Nerd Font'},
            }),
        )
        directory = module_manager.config_directory

        caplog.clear()
        module_manager.execute(action='compile', block='on_startup')

        template_file = str(
            (directory / '../templates/test_template.conf').resolve(),
        )
        compiled_template = str(
            list(
                module_manager.modules['test_module']
                .performed_compilations()[Path(template_file)],
            )[0],
        )

        with open('/tmp/compiled_result', 'r') as file:
            compiled_result = file.read()

        assert compiled_template_content == compiled_result
        assert caplog.record_tuples == [
            (
                'astrality.compiler',
                logging.INFO,
                f'[Compiling] Template: "{template_file}" '
                f'-> Target: "{compiled_template}"',
            ),
        ]
def test_that_setup_block_is_only_executed_once(tmpdir):
    """Setup blocks in modules should only be performed once."""
    touched = Path(tmpdir, 'touched.tmp')
    modules = {
        'A': {
            'on_setup': {
                'run': {
                    'shell': f'touch {touched}',
                },
            },
        },
    }
    module_manager = ModuleManager(modules=modules)

    # The touched file should not exist before we have done anything
    assert not touched.exists()

    # After finishing tasks, the file should be touched
    module_manager.finish_tasks()
    assert touched.exists()

    # We now create a new object lifetime
    del module_manager
    touched.unlink()

    # The setup block should now *not* be executed
    module_manager = ModuleManager(modules=modules)
    module_manager.finish_tasks()
    assert not touched.exists()
Beispiel #18
0
def test_hot_reloading(test_template_targets, default_global_options, _runtime,
                       test_config_directory):
    template_target1, template_target2 = test_template_targets
    config1 = test_config_directory / 'astrality1.yml'
    config2 = test_config_directory / 'astrality2.yml'
    target_config = test_config_directory / 'astrality.yml'
    temp_directory = Path('/tmp/astrality')

    # Copy the first configuration into place
    shutil.copy(str(config1), str(target_config))

    application_config1 = dict_from_config_file(
        config1,
        context={},
    )
    application_config1.update(default_global_options)
    application_config1.update(_runtime)
    application_config1['config/astrality']['hot_reload_config'] = True

    module_manager = ModuleManager(application_config1)

    # Before beginning, the template should not be compiled
    assert not template_target1.is_file()

    # But when we finalize tasks, it should be compiled
    module_manager.finish_tasks()
    assert template_target1.is_file()

    # Also check that the filewatcher has been started
    assert module_manager.directory_watcher.observer.is_alive()

    # We now "edit" the configuration file
    shutil.copy(str(config2), str(target_config))
    time.sleep(0.7)

    # Since hot reloading is enabled, the new template target should be
    # compiled, and the old one cleaned up
    assert template_target2.is_file()
    assert not template_target1.is_file()

    # And we switch back again
    shutil.copy(str(config1), str(target_config))
    time.sleep(0.7)
    assert template_target1.is_file()
    assert not template_target2.is_file()

    # Cleanup config file
    if target_config.is_file():
        os.remove(target_config)
Beispiel #19
0
def test_correct_relative_paths_used_in_external_module(
    temp_test_files,
    test_config_directory,
):
    application_config = {
        'modules': {
            'modules_directory': 'test_modules',
            'enabled_modules': [{
                'name': 'using_all_actions::*'
            }],
        },
    }
    module_manager = ModuleManager(config=application_config)

    (
        compile_target,
        touch_target,
        watch_touch_target,
        watched_file,
    ) = temp_test_files

    # Sanity check before testing
    for file in (
            compile_target,
            touch_target,
            watch_touch_target,
    ):
        assert not file.is_file()

    # Finish task and see if context import, compilation, and run has been
    # correctly run relative to the module directory path
    module_manager.finish_tasks()
    with open(compile_target, 'r') as file:
        assert file.read() == "Vietnam's capitol is Ho Chi Minh City"
    assert touch_target.is_file()

    # Now modify the observed file, and see if on_modified is triggered
    watched_file.write_text('This watched file has been modified')

    retry = Retry()
    assert retry(
        lambda: compile_target.read_text() == "Vietnam's capitol is Hanoi", )
    assert retry(lambda: watch_touch_target.is_file())

    touch_target.unlink()
    compile_target.unlink()
    watch_touch_target.unlink()
    watched_file.write_text('')
Beispiel #20
0
def test_not_using_list_when_specifiying_trigger_action(
    conf_path,
    default_global_options,
):
    application_config = {
        'module/A': {
            'on_startup': {
                'trigger': {
                    'block': 'on_event',
                },
            },
            'on_event': {
                'run': [{
                    'shell': 'echo on_event'
                }],
            },
        },
        '_runtime': {
            'config_directory': conf_path,
            'temp_directory': Path('/tmp/astrality'),
        },
    }
    application_config.update(default_global_options)
    module_manager = ModuleManager(application_config)

    # Check that all run commands have been imported into startup block
    result = module_manager.modules['A'].run('on_startup', default_timeout=1)
    assert result == ((
        'echo on_event',
        'on_event',
    ), )
Beispiel #21
0
    def _module_manager_factory(
            *modules,
            context=Context(),
    ) -> ModuleManager:
        """Return ModuleManager object with given modules and context."""
        module_manager = ModuleManager(context=context, )
        module_manager.modules = {module.name: module for module in modules}

        # Insert correct context for all actions
        for module in modules:
            for block in module.all_action_blocks():
                for action_type in ActionBlock.action_types:
                    for actions in getattr(block, f'_{action_type}_actions'):
                        actions.context_store = context

        return module_manager
Beispiel #22
0
    def test_missing_template_file(self, caplog):
        modules = {
            'test_module': {
                'on_startup': {
                    'compile': [
                        {'content': '/not/existing'},
                    ],
                },
            },
        }
        module_manager = ModuleManager(modules=modules)

        caplog.clear()
        module_manager.finish_tasks()
        assert 'Could not compile template "/not/existing" '\
               'to target "' in caplog.record_tuples[0][2]
Beispiel #23
0
def test_not_using_list_when_specifiying_trigger_action(conf_path):
    modules = {
        'A': {
            'on_startup': {
                'trigger': {'block': 'on_event'},
            },
            'on_event': {
                'run': [{'shell': 'echo on_event'}],
            },
        },
    }

    module_manager = ModuleManager(
        modules=modules,
        directory=conf_path,
    )

    # Check that all run commands have been imported into startup block
    result = module_manager.modules['A'].execute(
        action='run',
        block='on_startup',
    )
    assert result == (
        ('echo on_event', 'on_event'),
    )
def test_enabling_of_modules_defined_different_places(
    default_global_options,
    _runtime,
):
    application_config = {
        'config/modules': {
            'modules_directory':
            'freezed_modules',
            'enabled_modules': [
                {
                    'name': 'south_america::brazil'
                },
                {
                    'name': 'india'
                },
            ],
        },
        'module/india': {},  # Enabled
        'module/pakistan': {},  # Not enabled
    }
    application_config.update(default_global_options)
    application_config.update(_runtime)

    module_manager = ModuleManager(application_config)

    assert len(module_manager.modules) == 2
    assert 'south_america::brazil' in module_manager.modules
    assert 'india' in module_manager.modules
Beispiel #25
0
def test_using_three_different_module_sources(
    test_config_directory,
    delete_jakobgm,
):
    modules_directory = test_config_directory / 'freezed_modules'

    application_config = {
        'modules': {
            'modules_directory': str(modules_directory),
            'enabled_modules': [
                {'name': 'north_america::*'},
                {'name': 'github::jakobgm/test-module.astrality'},
                {'name': 'italy'},
            ],
        },
    }

    modules = {
        'italy': {},
        'spain': {},
    }
    module_manager = ModuleManager(
        config=application_config,
        modules=modules,
    )

    assert len(module_manager.modules) == 4
    assert 'north_america::USA' in module_manager.modules
    assert 'github::jakobgm/test-module.astrality::botswana' \
        in module_manager.modules
    assert 'github::jakobgm/test-module.astrality::ghana' \
        in module_manager.modules
    assert 'italy' in module_manager.modules
Beispiel #26
0
def test_that_external_modules_are_brought_in(
    test_config_directory,
    default_global_options,
    _runtime,
):
    application_config = {
        'config/modules': {
            'modules_directory': 'test_modules',
            'enabled_modules': [
                {
                    'name': 'thailand::thailand'
                },
                {
                    'name': '*'
                },
            ],
        },
        'module/cambodia': {
            'enabled_modules': True,
        },
    }
    application_config.update(default_global_options)
    application_config.update(_runtime)

    module_manager = ModuleManager(application_config)

    thailand_path = test_config_directory / 'test_modules' / 'thailand'
    assert tuple(module_manager.modules.keys()) == (
        'thailand::thailand',
        'cambodia',
    )
Beispiel #27
0
def test_that_external_module_contexts_are_imported_correctly(
    test_config_directory, ):
    application_config = {
        'modules': {
            'modules_directory': 'test_modules',
            'enabled_modules': [{
                'name': 'module_with_context::*'
            }],
        },
    }

    context = Context({
        'china': {
            'capitol': 'beijing',
        },
    })
    module_manager = ModuleManager(
        config=application_config,
        context=context,
    )

    expected_context = Context({
        'laos': {
            'capitol': 'vientiane'
        },
        'china': {
            'capitol': 'beijing'
        },
    })
    assert module_manager.application_context == expected_context
Beispiel #28
0
def test_that_external_modules_are_brought_in(test_config_directory):
    application_config = {
        'modules': {
            'modules_directory': 'test_modules',
            'enabled_modules': [
                {
                    'name': 'thailand::thailand'
                },
                {
                    'name': '*'
                },
            ],
        },
    }

    modules = {
        'cambodia': {
            'enabled_modules': True,
        },
    }
    module_manager = ModuleManager(
        config=application_config,
        modules=modules,
    )

    assert tuple(module_manager.modules.keys()) == (
        'thailand::thailand',
        'cambodia',
    )
Beispiel #29
0
def test_enabling_of_modules_defined_different_places():
    application_config = {
        'modules': {
            'modules_directory':
            'freezed_modules',
            'enabled_modules': [
                {
                    'name': 'south_america::brazil'
                },
                {
                    'name': 'india'
                },
            ],
        },
    }
    modules = {
        'india': {},  # Enabled
        'pakistan': {},  # Not enabled
    }
    module_manager = ModuleManager(
        config=application_config,
        modules=modules,
    )

    assert len(module_manager.modules) == 2
    assert 'south_america::brazil' in module_manager.modules
    assert 'india' in module_manager.modules
Beispiel #30
0
def test_that_external_module_contexts_are_imported_correctly(
    test_config_directory,
    default_global_options,
    _runtime,
):
    application_config = {
        'config/modules': {
            'modules_directory': 'test_modules',
            'enabled_modules': [{
                'name': 'module_with_context::*',
            }],
        },
        'context/china': {
            'capitol': 'beijing',
        },
    }
    application_config.update(default_global_options)
    application_config.update(_runtime)

    module_manager = ModuleManager(application_config)

    expected_context = {
        'laos': {
            'capitol': 'vientiane'
        },
        'china': {
            'capitol': 'beijing'
        },
    }
    assert len(module_manager.application_context) == 2
    for key, value in expected_context.items():
        assert module_manager.application_context[key] == value