def test_one_failed_step_is_preventing_next_steps_from_execution_and_result_is_marked_as_failure(self):
        """Check the correctness of error handling"""

        io = IO()
        str_io = StringIO()
        buffered = BufferedSystemIO()

        task_declaration = get_test_declaration()
        BasicTestingCase.satisfy_task_dependencies(task_declaration.get_task_to_execute(), io=buffered)

        ctx = ExecutionContext(task_declaration)
        executor = DeclarativeExecutor()
        executor.add_step('python', 'this.io().outln("Peter Kropotkin"); return True', task_name=':first', rkd_path='', envs={})
        executor.add_step('bash', 'echo "Buenaventura Durruti"; exit 1', task_name=':second', rkd_path='', envs={})
        executor.add_step('python', 'this.io().outln("This one will not show"); return True', task_name=':third', rkd_path='', envs={})

        with io.capture_descriptors(target_files=[], stream=str_io, enable_standard_out=False):
            final_result = executor.execute_steps_one_by_one(ctx, task_declaration.get_task_to_execute())

        output = str_io.getvalue() + buffered.get_value()

        self.assertIn('Peter Kropotkin', output)
        self.assertIn('Buenaventura Durruti', output)
        self.assertNotIn('This one will not show', output)
        self.assertEqual(False, final_result)
Exemplo n.º 2
0
    def mock_execution_context(
            task: TaskInterface,
            args: Dict[str, str] = None,
            env: Dict[str, str] = None,
            defined_args: Dict[str, dict] = None) -> ExecutionContext:
        """
        Prepares a simplified rkd.api.contract.ExecutionContext instance

        :param task:
        :param args:
        :param env:
        :param defined_args:
        :return:
        """

        if args is None:
            args = {}

        if env is None:
            env = {}

        if defined_args is None:
            defined_args = {}

        if args and not defined_args:
            for name, passed_value in args.items():
                defined_args[name] = {'default': ''}

        return ExecutionContext(TaskDeclaration(task),
                                parent=None,
                                args=args,
                                env=env,
                                defined_args=defined_args)
    def test_functional_hooks_are_executed_when_exists_and_files_with_extension_only_are_skipped(
            self):
        """Given we have an example hooks in pre-upgrade/whoami.sh and in post-upgrade/history.sh
        And we try to run those hooks using hooks_executed()
        Then we will see output produced by those scripts
        And .dotfiles will be ignored
        """

        self._prepare_test_data()

        buffer = StringIO()
        hooks_capturing_io = IO()

        task = TestTask()
        task._io = BufferedSystemIO()
        ctx = ExecutionContext(TaskDeclaration(task), args={}, env={})

        with hooks_capturing_io.capture_descriptors(stream=buffer,
                                                    enable_standard_out=True):
            with task.hooks_executed(ctx, 'upgrade'):
                pass

        self.assertIn('>> This is a whoami.sh hook, test:',
                      buffer.getvalue(),
                      msg='Expected pre-upgrade hook to be ran')

        self.assertIn('25 June 1978 the rainbow flag was first flown',
                      buffer.getvalue(),
                      msg='Expected post-upgrade hook to be ran')

        self.assertIn('pre-upgrade/whoami.sh', task._io.get_value())
        self.assertNotIn('.gitkeep', task._io.get_value())
Exemplo n.º 4
0
    def execute_mocked_task_and_get_output(self,
                                           task: TaskInterface,
                                           args=None,
                                           env=None) -> str:
        """
        Run a single task, capturing it's output in a simplified way.
        There is no whole RKD bootstrapped in this operation.

        :param TaskInterface task:
        :param dict args:
        :param dict env:
        :return:
        """

        if args is None:
            args = {}

        if env is None:
            env = {}

        ctx = ApplicationContext([], [], '')
        ctx.io = BufferedSystemIO()

        task.internal_inject_dependencies(
            io=ctx.io,
            ctx=ctx,
            executor=OneByOneTaskExecutor(ctx=ctx),
            temp_manager=TempManager())

        merged_env = deepcopy(os.environ)
        merged_env.update(env)

        r_io = IO()
        str_io = StringIO()

        defined_args = {}

        for arg, arg_value in args.items():
            defined_args[arg] = {'default': ''}

        with r_io.capture_descriptors(enable_standard_out=True, stream=str_io):
            try:
                # noinspection PyTypeChecker
                result = task.execute(
                    ExecutionContext(TaskDeclaration(task),
                                     args=args,
                                     env=merged_env,
                                     defined_args=defined_args))
            except Exception:
                self._restore_standard_out()
                print(ctx.io.get_value() + "\n" + str_io.getvalue())
                raise

        return ctx.io.get_value() + "\n" + str_io.getvalue(
        ) + "\nTASK_EXIT_RESULT=" + str(result)
Exemplo n.º 5
0
    def _get_prepared_compose_driver(self,
                                     args: dict = {},
                                     env: dict = {}) -> ComposeDriver:
        merged_env = deepcopy(os.environ)
        merged_env.update(env)

        task = self.satisfy_task_dependencies(TestTask(), BufferedSystemIO())
        declaration = TaskDeclaration(task)
        ctx = ExecutionContext(declaration, args=args, env=merged_env)

        return ComposeDriver(task, ctx, TEST_PROJECT_NAME)
    def test_non_existing_dir_is_skipped(self):
        """Assert that non-existing directory does not cause exception, but will be skipped"""

        task = TestTask()
        task._io = BufferedSystemIO()
        task._io.set_log_level('debug')
        ctx = ExecutionContext(TaskDeclaration(task), args={}, env={})

        task.execute_hooks(ctx, 'non-existing-directory')
        self.assertIn(
            'Hooks dir "./hooks.d//non-existing-directory/" not present, skipping',
            task._io.get_value())
Exemplo n.º 7
0
    def test_stop_task_executes_stop_task_multiple_times(self):
        """Test that StopTask will call Driver.stop() multiple times"""

        task = StopTask()
        recorded_calls = []

        ctx = ExecutionContext(TaskDeclaration(task), args={}, env={})
        task.containers(
            ctx
        ).stop = lambda service_name, args='', capture=False: recorded_calls.append(
            service_name)

        self.execute_mocked_task_and_get_output(task, args={'--profile': ''})

        self.assertIn('gateway', recorded_calls)
        self.assertIn('gateway_letsencrypt', recorded_calls)
        self.assertIn('gateway_proxy_gen', recorded_calls)
Exemplo n.º 8
0
    def _prepare_test_for_forking_process(task: TaskInterface = None):
        if not task:
            task = TestTask()

        io = IO()
        string_io = StringIO()

        temp = TempManager(chdir='/tmp/')
        container = ApplicationContext([], [], '')
        container.io = BufferedSystemIO()
        executor = OneByOneTaskExecutor(container)

        declaration = get_test_declaration(task)
        task._io = io
        task._io.set_log_level('debug')
        ctx = ExecutionContext(declaration)

        return string_io, task, executor, io, ctx, temp
Exemplo n.º 9
0
    def test_restart_calls_driver_restart_method_on_matched_services(self):
        """Test calls restart on expected services in expected order"""

        task = RestartTask()
        restarted_services = []

        ctx = ExecutionContext(TaskDeclaration(task), args={}, env={})
        task.containers(
            ctx
        ).restart = lambda service_name, args='': restarted_services.append(
            service_name)

        self.execute_mocked_task_and_get_output(task,
                                                args={
                                                    '--profile': 'profile1',
                                                    '--with-image': False
                                                })

        self.assertEqual(['gateway', 'website'], restarted_services)
    def test_executing_multiple_steps_one_by_one_the_order_is_preserved(self):
        """Assert that execution order is preserved - as we register steps"""

        io = IO()
        str_io = StringIO()

        task_declaration = get_test_declaration()
        BasicTestingCase.satisfy_task_dependencies(task_declaration.get_task_to_execute(), io=io)

        ctx = ExecutionContext(task_declaration)
        executor = DeclarativeExecutor()
        executor.add_step('python', 'this.io().outln("First"); return True', task_name=':first', rkd_path='', envs={})
        executor.add_step('bash', 'echo "Second"; exit 0', task_name=':second', rkd_path='', envs={})
        executor.add_step('python', 'this.io().outln("Third"); return True', task_name=':third', rkd_path='', envs={})

        with io.capture_descriptors(target_files=[], stream=str_io, enable_standard_out=False):
            executor.execute_steps_one_by_one(ctx, task_declaration.get_task_to_execute())

        self.assertEqual("First\nSecond\r\nThird\n", str_io.getvalue())
    def test_functional_execute_hooks_executes_post_upgrade_hooks(self):
        """Assert that post-upgrade/history.sh is executed"""

        self._prepare_test_data()

        buffer = StringIO()
        hooks_capturing_io = IO()

        task = TestTask()
        task._io = BufferedSystemIO()
        ctx = ExecutionContext(TaskDeclaration(task), args={}, env={})

        with hooks_capturing_io.capture_descriptors(stream=buffer,
                                                    enable_standard_out=True):
            task.execute_hooks(ctx, 'post-upgrade')

        self.assertIn('25 June 1978 the rainbow flag was first flown',
                      buffer.getvalue(),
                      msg='Expected post-upgrade hook to be ran')
    def test_requirements_are_written(self):
        """Verify that basic requirements list is written into requirements.txt file"""

        backup_dir_path = os.getcwd()

        try:
            with tempfile.TemporaryDirectory() as dir_path:
                os.chdir(dir_path)

                task = CreateHarborStructureTask()
                task._io = IO()
                task.on_requirements_txt_write(ExecutionContext(get_test_declaration()))

                with open(dir_path + '/requirements.txt', 'rb') as requirements_txt:
                    content = requirements_txt.read().decode('utf-8')

                    self.assertIn('ansible>=2.8', content, msg='Expected Ansible defined in requirements.txt')
                    self.assertIn('rkd-harbor==', content, msg='Expected rkd-harbor to be defined in requirements.txt')

        finally:
            os.chdir(backup_dir_path)
    def _create_callable_tester(code: str, language: str, io: IO = None) -> bool:
        if not io:
            io = IO()

        executor = DeclarativeExecutor()
        declaration = get_test_declaration()
        declaration.get_task_to_execute()._io = io
        ctx = ExecutionContext(declaration)

        step = Step(
            language=language,
            task_name=':test',
            code=code,
            envs={},
            task_num=1,
            rkd_path=''
        )

        if language == 'python':
            return executor.execute_python_step(ctx, declaration.get_task_to_execute(), step)
        else:
            return executor.execute_bash_step(ctx, declaration.get_task_to_execute(), step)