Ejemplo n.º 1
0
 def __enter__(self):
     self.dispatcher = CallbackDispatcher(self.messagebus,
                                          self.return_result)
     self.dispatcher.register([CONNECTIONCHECK_RUN_CHECK],
                              [MOCK_CONNECTION_CHECK_ENDPOINT],
                              [self.entity])
     return self
Ejemplo n.º 2
0
    def register_dispatchers(self, messagebus):
        if self._enabled:
            self._messagebus = messagebus
            self._start_blocking_dispatcher = SequentialDispatcher(
                messagebus, self.start_blocking)
            self._start_blocking_dispatcher.register(
                [START_BLOCKING_ON_MESSAGE], [BLOCKER_ENDPOINT])

            self._after_command_dispatcher = CallbackDispatcher(
                messagebus, self.after_command)
            self._after_command_dispatcher.register([AFTER_COMMAND],
                                                    [APPLICATION_ENDPOINT])

            if self._init_enabled:
                print('INITING BLOCKER')
                self._start_blocking(StartBlockingInfo(
                    BEFORE_COMMAND,
                    APPLICATION_ENDPOINT,
                    entity=None,
                    timeout=self._init_timeout),
                                     id='init',
                                     priority=100)

            if self._exit_enabled:
                print('EXITING BLOCKER')
                self._start_blocking(StartBlockingInfo(
                    AFTER_COMMAND,
                    APPLICATION_ENDPOINT,
                    entity=None,
                    timeout=self._exit_timeout),
                                     id='exit',
                                     priority=100)
Ejemplo n.º 3
0
class MockConnectionCheck(object):
    def __init__(self, messagebus, success, required, entity):
        self.messagebus = messagebus
        self.success = success
        self.required = required
        self.entity = entity
        self.dispatcher = None

        self.executed = False

    def __enter__(self):
        self.dispatcher = CallbackDispatcher(self.messagebus,
                                             self.return_result)
        self.dispatcher.register([CONNECTIONCHECK_RUN_CHECK],
                                 [MOCK_CONNECTION_CHECK_ENDPOINT],
                                 [self.entity])
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.dispatcher:
            self.dispatcher.destroy()

    def return_result(self, message):
        self.executed = True
        return ConnectionCheckResult('mockcc', self.success, self.required,
                                     'message')
Ejemplo n.º 4
0
    def register_dispatchers(self, messagebus):
        self.messagebus = messagebus

        self._generate_metrics_report_dispatcher = CallbackDispatcher(
            messagebus, self._handle_generate_metrics_report_wrapper)
        self._generate_metrics_report_dispatcher.register(
            [GENERATE_METRICS_REPORT])
class PrintRunQueueAfterEachTest(AbstractExtension):
    def register_dispatchers(self, messagebus):
        self._messagebus = messagebus
        self._dispatcher = CallbackDispatcher(
            messagebus, self.log_run_queue_on_test_case_finished)
        self._dispatcher.register([TEST_CASE_FINISHED], [RUNNER_ENDPOINT])

    def destroy(self):
        self._dispatcher.destroy()

    def log_run_queue_on_test_case_finished(self, message):
        fs = self._messagebus.send_request(GET_CURRENT_RUN_QUEUE)
        print('Run queue: {run_queue}'.format(run_queue=fs[0].result()))
Ejemplo n.º 6
0
        class Extension(AbstractExtension):
            def register_dispatchers(self, messagebus):
                self._dispatcher = CallbackDispatcher(
                    messagebus, self.my_manual_dispatcher)
                self._dispatcher.register(None)

            def my_manual_dispatcher(self):
                pass

            @concurrent_dispatcher(None)
            def my_decorated_dispatcher(self):
                pass

            def destroy(self):
                self._dispatcher.destroy()
Ejemplo n.º 7
0
def create_harness(test_cases):
    harness = ExtensionTestHarness(TestScheduler,
                                   endpoints_and_messages={
                                       FINDER_ENDPOINT: [FIND_TEST_CASES],
                                       RUNNER_ENDPOINT: [ABORT],
                                       K2_APPLICATION_ENDPOINT:
                                       [ABORT, CRITICAL_ABORT],
                                   })

    def find_test_cases(message):
        return test_cases

    finder_dispatcher = CallbackDispatcher(harness.messagebus, find_test_cases)
    finder_dispatcher.register([FIND_TEST_CASES], [FINDER_ENDPOINT])

    return harness
Ejemplo n.º 8
0
    def test_triggers_sut_recovery_perform_on_failed_health_check(self):
        with TestHealthMonitor.create_harness() as harness:

            def handler(message):
                raise HealthCheckError('Nope!')

            dispatcher = CallbackDispatcher(harness.messagebus, handler)
            harness.messagebus.register_dispatcher(dispatcher,
                                                   [PERFORM_HEALTH_CHECK],
                                                   entities=['mysut'])

            with LocalMessageQueue(harness.messagebus,
                                   message_ids=[SUT_RECOVERY_PERFORM],
                                   endpoint_ids=[MOCK_ENDPOINT],
                                   entities=['mysut'
                                             ]) as sut_recovery_perform_queue:
                data = Mock()
                data.verdict = Verdict.FAILED
                harness.trigger_event(TEST_CASE_FINISHED,
                                      MOCK_ENDPOINT,
                                      data=data,
                                      entity='mysut')

                harness.messagebus.wait_for_not_active()
                assert not sut_recovery_perform_queue.empty()
Ejemplo n.º 9
0
    def test_that_run_queue_is_empty_is_triggered(self):
        with create_harness([]) as harness:
            global run_queue_empty_called
            run_queue_empty_called = False

            def handle_run_queue_empty(message):
                global run_queue_empty_called
                run_queue_empty_called = True

            run_queue_empty_dispatcher = CallbackDispatcher(
                harness.messagebus, handle_run_queue_empty)
            run_queue_empty_dispatcher.register([RUN_QUEUE_EMPTY],
                                                [SCHEDULER_ENDPOINT])

            harness.send_request(SCHEDULE_NEXT_TEST,
                                 SCHEDULER_ENDPOINT).wait()[0].result()
            assert run_queue_empty_called
Ejemplo n.º 10
0
    def test_that_its_possible_to_add_tests_when_dispatching_scheduling_next_test_in_callback(
            self):
        with create_harness([]) as harness:

            def handle_scheduling_next_test(message):
                harness.send_request(ADD_TEST_CASES,
                                     SCHEDULER_ENDPOINT,
                                     data=[test1]).wait()[0].result()

            run_queue_empty_dispatcher = CallbackDispatcher(
                harness.messagebus, handle_scheduling_next_test)
            run_queue_empty_dispatcher.register([SCHEDULING_NEXT_TEST],
                                                [SCHEDULER_ENDPOINT])

            actual_test = harness.send_request(
                SCHEDULE_NEXT_TEST, SCHEDULER_ENDPOINT).wait()[0].result()
            self.assertEqual(actual_test, test1)
Ejemplo n.º 11
0
    def test_that_scheduling_next_test_is_triggered(self):
        with create_harness([]) as harness:
            global scheduling_next_test_count
            scheduling_next_test_count = 0

            def handle_scheduling_next_test(message):
                global scheduling_next_test_count
                scheduling_next_test_count += 1

            run_queue_empty_dispatcher = CallbackDispatcher(
                harness.messagebus, handle_scheduling_next_test)
            run_queue_empty_dispatcher.register([SCHEDULING_NEXT_TEST],
                                                [SCHEDULER_ENDPOINT])

            harness.send_request(SCHEDULE_NEXT_TEST,
                                 SCHEDULER_ENDPOINT).wait()[0].result()
            assert run_queue_empty_called
Ejemplo n.º 12
0
    def test_that_run_queue_initialized_is_triggered(self):
        with create_harness([test1, test2]) as harness:
            global run_queue
            run_queue = None

            def handle_run_queue_initialized(message):
                global run_queue
                run_queue = message.data

            run_queue_empty_dispatcher = CallbackDispatcher(
                harness.messagebus, handle_run_queue_initialized)
            run_queue_empty_dispatcher.register([RUN_QUEUE_INITIALIZED],
                                                [SCHEDULER_ENDPOINT])

            harness.send_request(SCHEDULE_NEXT_TEST,
                                 SCHEDULER_ENDPOINT).wait()[0].result()
            self.assertEqual(run_queue, [test1, test2])
Ejemplo n.º 13
0
    def test_that_run_queue_modified_is_triggered_from_remove_test_cases(self):
        with create_harness([test1, test2]) as harness:
            global run_queue
            run_queue = None

            def handle_run_queue_modified(message):
                global run_queue
                run_queue = message.data

            run_queue_empty_dispatcher = CallbackDispatcher(
                harness.messagebus, handle_run_queue_modified)
            run_queue_empty_dispatcher.register([RUN_QUEUE_MODIFIED],
                                                [SCHEDULER_ENDPOINT])

            harness.send_request(REMOVE_TEST_CASES,
                                 SCHEDULER_ENDPOINT,
                                 data=[test1]).wait()[0].result()
            self.assertEqual(run_queue, [test2])
Ejemplo n.º 14
0
class AbstractMetricsReportExtension(AbstractExtension, metaclass=abc.ABCMeta):
    def __init__(self, config, instances):
        self._generate_metrics_report_dispatcher = None

    def register_dispatchers(self, messagebus):
        self.messagebus = messagebus

        self._generate_metrics_report_dispatcher = CallbackDispatcher(
            messagebus, self._handle_generate_metrics_report_wrapper)
        self._generate_metrics_report_dispatcher.register(
            [GENERATE_METRICS_REPORT])

    def _handle_generate_metrics_report_wrapper(self, message):
        try:
            self.handle_generate_metrics_report(message)
        except Exception:
            msg = 'Could not generate metrics report: {reporter}'.format(
                reporter=str(self))
            logger.debug(msg, exc_info=True)
            logger.warning(msg)

    @abc.abstractmethod
    def handle_generate_metrics_report(self, message):
        pass

    def destroy(self):
        if self._generate_metrics_report_dispatcher is not None:
            self._generate_metrics_report_dispatcher.destroy()

        self._generate_metrics_report_dispatcher = None

    def parse_regex_option(self, config, option):
        regex_string = config.get(option)
        if regex_string is None:
            return None
        else:
            try:
                return re.compile(regex_string)
            except re.error:
                raise ConfigException(
                    "Error parsing regex '{regex}' for config option '{option}'"
                    .format(regex=config.get(option), option=option.key))
Ejemplo n.º 15
0
 def test_additional_options_from_other_extensions_are_included_in_run_command(
         self):
     with _create_harness(env=self.env_mock) as harness, \
             patch('tempfile.TemporaryDirectory', return_value=self.tempdir), \
             patch('os.makedirs'), \
             patch('shutil.copy'):
         CallbackDispatcher(harness.messagebus,
                            lambda m: 'additional options').register(
                                [GET_ASCIIDOCTOR_OPTIONS],
                                [OPTIONS_ENDPOINT])
         futures = harness.messagebus.send_request(
             GENERATE_DOC,
             ASCIIDOCTOR_ENDPOINT,
             data=AsciidoctorCommand('output_path'))
         futures.wait(timeout=1)
         self.assertIn('additional options',
                       self.env_mock.run.call_args[0][0])
Ejemplo n.º 16
0
 def register_dispatchers(self, messagebus):
     self._messagebus = messagebus
     if self._loopduration or self._looprepeats:
         self._run_queue_initialized_dispatcher = CallbackDispatcher(
             messagebus, self.handle_initialized)
         self._run_queue_initialized_dispatcher.register(
             [RUN_QUEUE_INITIALIZED])
     if self._loopduration:
         self._test_run_started_dispatcher = CallbackDispatcher(
             messagebus, self.handle_started)
         self._test_run_started_dispatcher.register([TEST_RUN_STARTED])
         self._run_queue_empty_dispatcher = CallbackDispatcher(
             messagebus, self.handle_empty)
         self._run_queue_empty_dispatcher.register([RUN_QUEUE_EMPTY])
Ejemplo n.º 17
0
    def _start_blocking(self, blocking_info, id=None):
        logger.debug('Starting to block on {data}'.format(data=blocking_info))

        def blocking_callback(id, timeout, message):
            """Block until STOP_BLOCKING_ON_MESSAGE is received in the blocker LocalMessageQueue."""
            logger.debug(
                'Blocker received message {name}, waiting for stop blocking for {timeout} seconds'
                .format(name=message.message_id.name, timeout=timeout))
            self._messagebus.trigger_event(BLOCKING_STARTED,
                                           BLOCKER_ENDPOINT,
                                           entity=id)
            blocker_state = self._ongoing_blockers[id]
            blocker_state.set_started()
            try:
                blocker_state.blocker.get(timeout=timeout)
                logger.debug(
                    'Blocker no longer blocks on message {name}'.format(
                        name=message.message_id.name))
                self._messagebus.trigger_event(BLOCKING_COMPLETED,
                                               BLOCKER_ENDPOINT,
                                               entity=id)
            except Exception:
                logger.warning(
                    'Blocker timed out when blocking on message {name}'.format(
                        name=message.message_id.name))
                self._messagebus.trigger_event(BLOCKING_TIMED_OUT,
                                               BLOCKER_ENDPOINT,
                                               entity=id)
            finally:
                blocker_state.cleanup()
                del self._ongoing_blockers[id]

        # Creates an ID for the specific instance of blocking. Is used in all messages communication.
        if id is None:
            id = str(uuid4())

        # Creates a blocking message queue.
        # This can be used to block until a STOP_BLOCKING_ON_MESSAGE is received with entity=id.
        blocker = LocalMessageQueue(self._messagebus,
                                    [STOP_BLOCKING_ON_MESSAGE],
                                    entities=[id])

        # Starts the blocker message queue
        blocker.__enter__()

        # Creates the blocking dispatcher that listens to the message described in the received StartBlockingInfo
        blocking_dispatcher = CallbackDispatcher(
            self._messagebus,
            functools.partial(blocking_callback, id, blocking_info.timeout))
        blocking_dispatcher.register(
            message_ids=[blocking_info.message_id],
            endpoint_ids=[blocking_info.endpoint_id]
            if blocking_info.endpoint_id else None,
            entities=[blocking_info.entity] if blocking_info.entity else None)

        self._ongoing_blockers[id] = BlockerState(id, blocker,
                                                  blocking_dispatcher)

        # Return the id so that the user can use it when sending STOP_BLOCKING_ON_MESSAGE
        # or to listen for BLOCKING_STARTED, BLOCKING_COMPLETED and/or BLOCKING_TIMED_OUT
        return id
 def register_dispatchers(self, messagebus):
     self._messagebus = messagebus
     self._dispatcher = CallbackDispatcher(
         messagebus, self.log_run_queue_on_test_case_finished)
     self._dispatcher.register([TEST_CASE_FINISHED], [RUNNER_ENDPOINT])
Ejemplo n.º 19
0
    def register_dispatchers(self, messagebus):
        self._messagebus = messagebus

        self._run_dispatcher = CallbackDispatcher(messagebus, self._run)
        self._run_dispatcher.register(message_ids=[TEST_SUBRUN],
                                      endpoint_ids=[MULTI_RUNNER_ENDPOINT])
Ejemplo n.º 20
0
class GtestBinaryRunner(AbstractExtension):
    def __init__(self, config, instances):
        self._entity = instances[GTEST_binaryid]
        self._binary = config.get(GTEST_BINARY_PATH)
        self._timeout = config.get(GTEST_TIMEOUT)
        self._xml_report_path = config.get(GTEST_XML_REPORT_PATH)
        self._filter = config.get(GTEST_FILTER)
        self._messagebus = None
        self._run_dispatcher = None
        self._serial = config.get(GTEST_USE_SERIAL)
        self._endmark = config.get(GTEST_SERIAL_ENDMARK)
        self._create_run()

    def _create_run(self):
        if self._serial:
            can = ['serial']
            params = {'prefix_output': False, 'endmark': self._endmark}
        else:
            can = ['telnet']
            params = {}

        @requires(exec='Exec', can=can, scope='session')
        @requires(messagebus='MessageBus')
        def _run(message, exec, messagebus):
            output = self._run_gtest_binary_on_sut(exec, self._binary,
                                                   self._filter, params)
            self._log_output(output)
            if self._xml_report_path is not None:
                self._write_gtest_xml_report(
                    self._collect_gtest_xml_report(exec).strip())
                return None
            else:
                return self._parse_gtest_standard_output(messagebus, output)

        self._run = _run

    def register_dispatchers(self, messagebus):
        self._messagebus = messagebus

        self._run_dispatcher = CallbackDispatcher(messagebus, self._run)
        self._run_dispatcher.register(message_ids=[TEST_SUBRUN],
                                      endpoint_ids=[MULTI_RUNNER_ENDPOINT])

    def destroy(self):
        if self._run_dispatcher is not None:
            self._run_dispatcher.destroy()
            self._run_dispatcher = None

    def _write_gtest_xml_report(self, report):
        os.makedirs(os.path.dirname(self._xml_report_path), exist_ok=True)
        with open(self._xml_report_path, 'w') as f:
            f.write(report)

    def _collect_gtest_xml_report(self, exec):
        try:
            return exec.send_line('cat /dev/shm/report.xml')
        finally:
            exec.send_line('rm /dev/shm/report.xml')

    def _parse_gtest_standard_output(self, messagebus, output):
        run_verdict = Verdict.PASSED
        for name, error_message, verdict in self._parse_test_cases(output):
            id = uuid.uuid1()
            messagebus.trigger_event(TEST_CASE_STARTED,
                                     MULTI_RUNNER_ENDPOINT,
                                     data=TestCaseStarted(
                                         id, name, name, datetime.now()))
            messagebus.trigger_event(TEST_CASE_FINISHED,
                                     MULTI_RUNNER_ENDPOINT,
                                     data=TestCaseFinished(
                                         id,
                                         name,
                                         datetime.now(),
                                         verdict,
                                         stacktrace=error_message))
            run_verdict = run_verdict.combine(verdict)
        return run_verdict

    def _parse_test_cases(self, output):
        test_regex = re.compile(
            r"""
                    ^\[\sRUN\s+\]\s(?P<name>\S+)\s*$\s   # start of test and name
                    (?P<message>.*?)?                    # optional multiline message
                    \[\s+(?P<verdict>OK|FAILED)\s+\]     # verdict
                    """, re.VERBOSE | re.MULTILINE | re.DOTALL)

        for match in test_regex.finditer(output):
            yield match.group('name'), match.group(
                'message'), self._map_verdict(match.group('verdict'))

    def _log_output(self, output):
        logger.info('----  gtest output begins  ----')
        for line in output.split('\n'):
            logger.info(line)
        logger.info('----  gtest output ends  ----')

    def _run_gtest_binary_on_sut(self, exec, binary, filter, params):
        xml_report_flag = ''
        if self._xml_report_path is not None:
            xml_report_flag = '--gtest_output=xml:/dev/shm/report.xml'
        filter_flag = '' if not filter else '--gtest_filter={filter}'.format(
            filter=filter)

        command = '{binary} --gtest_color=no --gtest_print_time=0 {filter} {xml_report_flag}'.format(
            binary=binary,
            filter=filter_flag,
            xml_report_flag=xml_report_flag,
        )

        logger.info('Executing gtest: {command}'.format(command=command))
        return exec.send_line(command, timeout=self._timeout, **params)

    def _map_verdict(self, gtest_verdict):
        if gtest_verdict == 'OK':
            return Verdict.PASSED
        elif gtest_verdict == 'FAILED':
            return Verdict.FAILED
        return Verdict.ERROR
Ejemplo n.º 21
0
 def register_dispatchers(self, messagebus):
     if self._enabled:
         self.dispatcher = CallbackDispatcher(messagebus, self.run_check)
         self.dispatcher.register([CONNECTIONCHECK_RUN_CHECK],
                                  [SERIAL_CONNECTION_CHECK_ENDPOINT],
                                  entities=self._suts)
Ejemplo n.º 22
0
class SerialConnectionCheck(AbstractExtension):
    """Serial connection check."""
    def __init__(self, config, instances):
        self._enabled = config.get(SERIAL_ENABLED) and config.get(
            SERIAL_CONNECTION_CHECK_ENABLED)
        self._required = config.get(SERIAL_CONNECTION_CHECK_REQUIRED)
        self._entity = instances.get(SERIAL_PORT_IDS)
        self._timeout = config.get(SERIAL_TIMEOUT)

        self._suts = [
            sut for sut in config.get(SUT)
            if self._entity in config.get(SUT_SERIAL_PORTS, entity=sut)
        ]

        if self._enabled and not self._suts:
            msg = "Error: connection check enabled for '{port}' but no suts who listens".format(
                port=self._entity)
            raise MissingConditionalConfigOption(msg)

    def register_dispatchers(self, messagebus):
        if self._enabled:
            self.dispatcher = CallbackDispatcher(messagebus, self.run_check)
            self.dispatcher.register([CONNECTIONCHECK_RUN_CHECK],
                                     [SERIAL_CONNECTION_CHECK_ENDPOINT],
                                     entities=self._suts)

    @requires(messagebus='MessageBus')
    def run_check(self, message, messagebus):
        logger.info(
            'Running serial connection check for entity {entity}'.format(
                entity=self._entity))

        client = SerialClient(messagebus, self._entity, timeout=self._timeout)

        result = self._perform_check(client)
        if result.success:
            return result

        try:
            logger.debug(
                'Trigger reconnect of serial connection for entity {entity}.'.
                format(entity=self._entity))
            messagebus.send_request(SERIAL_RECONNECT,
                                    SERIAL_ENDPOINT,
                                    entity=self._entity).wait(
                                        self._timeout)[0].result()
        except Exception as e:
            logger.debug(
                'Reconnect of serial connection failed for entity {entity}.'.
                format(entity=self._entity),
                exc_info=True)

            return ConnectionCheckResult(
                self.name,
                success=False,
                required=self._required,
                message=
                'Serial connection check failed to reconnect serial connection: {error}'
                .format(error=str(e)))

        return self._perform_check(client)

    def _perform_check(self, client):
        try:
            client.send_line('echo test')
            logger.info(
                'Serial connection check for port {entity} was successful'.
                format(entity=self._entity))
            return ConnectionCheckResult(self.name,
                                         success=True,
                                         required=self._required,
                                         message='')

        except Exception as e:
            self._check_if_member_of_dialout_group()
            msg = 'Serial connection check failed for {entity}: {error}'.format(
                entity=self._entity, error=str(e))
            logger.debug(msg, exc_info=True)
            return ConnectionCheckResult(self.name,
                                         success=False,
                                         required=self._required,
                                         message=msg)

    def _check_if_member_of_dialout_group(self):
        try:
            dialout_gid = grp.getgrnam('dialout').gr_gid
        except KeyError:
            # The dialout group does not exist.
            # Do nothing, as we are most likely not running on a Debian style system.
            return
        if dialout_gid not in os.getgroups():
            msg = (
                'The user running this K2 process is not a member of the "dialout" group. '
                'This will most likely lead to the serial port being inaccessible. '
                'Make sure to add the current user to the "dialout" group to remedy this issue.'
            )
            logger.warning(msg)
Ejemplo n.º 23
0
class Looper(AbstractExtension):
    """Repeats test case executions to meet duration or repetition configuration."""
    def __init__(self, config, instances):
        self._loopduration = parse_time(config.get(LOOP_DURATION))
        self._looprepeats = config.get(LOOP_REPEATS)
        if self._loopduration and self._looprepeats:
            raise MutuallyExclusiveConfigOptions(
                'schedule.duration and schedule.repeats cannot be combined')
        self._messagebus = None
        self._run_queue_empty_dispatcher = None
        self._test_run_started_dispatcher = None
        self._run_queue_initialized_dispatcher = None
        self._original_run_queue = None
        self._cycle_run_queue = None
        self._start_time = None

    def register_dispatchers(self, messagebus):
        self._messagebus = messagebus
        if self._loopduration or self._looprepeats:
            self._run_queue_initialized_dispatcher = CallbackDispatcher(
                messagebus, self.handle_initialized)
            self._run_queue_initialized_dispatcher.register(
                [RUN_QUEUE_INITIALIZED])
        if self._loopduration:
            self._test_run_started_dispatcher = CallbackDispatcher(
                messagebus, self.handle_started)
            self._test_run_started_dispatcher.register([TEST_RUN_STARTED])
            self._run_queue_empty_dispatcher = CallbackDispatcher(
                messagebus, self.handle_empty)
            self._run_queue_empty_dispatcher.register([RUN_QUEUE_EMPTY])

    def destroy(self):
        if self._run_queue_empty_dispatcher:
            self._run_queue_empty_dispatcher.destroy()
        if self._run_queue_initialized_dispatcher:
            self._run_queue_initialized_dispatcher.destroy()
        if self._test_run_started_dispatcher:
            self._test_run_started_dispatcher.destroy()

    def handle_initialized(self, message):
        self._original_run_queue = message.data
        self._cycle_run_queue = itertools.cycle(message.data)
        if self._looprepeats:
            self.schedule_repeats()

    def handle_started(self, message):
        self._start_time = time.time()

    def schedule_repeats(self):
        if self._looprepeats > 1:
            self._messagebus.send_request(ADD_TEST_CASES,
                                          SCHEDULER_ENDPOINT,
                                          data=self._original_run_queue *
                                          (self._looprepeats - 1)).wait()

    def handle_empty(self, message):
        if time.time() - self._start_time < self._loopduration:
            self._messagebus.send_request(ADD_TEST_CASES,
                                          SCHEDULER_ENDPOINT,
                                          data=[next(self._cycle_run_queue)
                                                ]).wait()
Ejemplo n.º 24
0
 def register_dispatchers(self, messagebus):
     self._dispatcher = CallbackDispatcher(
         messagebus, self.my_manual_dispatcher)
     self._dispatcher.register(None)
Ejemplo n.º 25
0
class Blocker(AbstractExtension):
    """Blocker implementation."""
    def __init__(self, config, instances):
        self._enabled = config.get(BLOCKER_ENABLED)

        self._init_enabled = config.get(BLOCKER_INIT_ENABLED)
        self._init_timeout = config.get(BLOCKER_INIT_TIMEOUT)

        self._ongoing_blockers = {}

        self._start_blocking_dispatcher = None
        self._after_command_dispatcher = None

    def register_dispatchers(self, messagebus):
        if self._enabled:
            self._messagebus = messagebus
            self._start_blocking_dispatcher = SequentialDispatcher(
                messagebus, self.start_blocking)
            self._start_blocking_dispatcher.register(
                [START_BLOCKING_ON_MESSAGE], [BLOCKER_ENDPOINT])

            self._after_command_dispatcher = CallbackDispatcher(
                messagebus, self.after_command)
            self._after_command_dispatcher.register([AFTER_COMMAND],
                                                    [APPLICATION_ENDPOINT])

            if self._init_enabled:
                print('INITING BLOCKER')
                self._start_blocking(StartBlockingInfo(
                    BEFORE_COMMAND,
                    APPLICATION_ENDPOINT,
                    entity=None,
                    timeout=self._init_timeout),
                                     id='init')

    def start_blocking(self, message):
        return self._start_blocking(blocking_info=message.data)

    def _start_blocking(self, blocking_info, id=None):
        logger.debug('Starting to block on {data}'.format(data=blocking_info))

        def blocking_callback(id, timeout, message):
            """Block until STOP_BLOCKING_ON_MESSAGE is received in the blocker LocalMessageQueue."""
            logger.debug(
                'Blocker received message {name}, waiting for stop blocking for {timeout} seconds'
                .format(name=message.message_id.name, timeout=timeout))
            self._messagebus.trigger_event(BLOCKING_STARTED,
                                           BLOCKER_ENDPOINT,
                                           entity=id)
            blocker_state = self._ongoing_blockers[id]
            blocker_state.set_started()
            try:
                blocker_state.blocker.get(timeout=timeout)
                logger.debug(
                    'Blocker no longer blocks on message {name}'.format(
                        name=message.message_id.name))
                self._messagebus.trigger_event(BLOCKING_COMPLETED,
                                               BLOCKER_ENDPOINT,
                                               entity=id)
            except Exception:
                logger.warning(
                    'Blocker timed out when blocking on message {name}'.format(
                        name=message.message_id.name))
                self._messagebus.trigger_event(BLOCKING_TIMED_OUT,
                                               BLOCKER_ENDPOINT,
                                               entity=id)
            finally:
                blocker_state.cleanup()
                del self._ongoing_blockers[id]

        # Creates an ID for the specific instance of blocking. Is used in all messages communication.
        if id is None:
            id = str(uuid4())

        # Creates a blocking message queue.
        # This can be used to block until a STOP_BLOCKING_ON_MESSAGE is received with entity=id.
        blocker = LocalMessageQueue(self._messagebus,
                                    [STOP_BLOCKING_ON_MESSAGE],
                                    entities=[id])

        # Starts the blocker message queue
        blocker.__enter__()

        # Creates the blocking dispatcher that listens to the message described in the received StartBlockingInfo
        blocking_dispatcher = CallbackDispatcher(
            self._messagebus,
            functools.partial(blocking_callback, id, blocking_info.timeout))
        blocking_dispatcher.register(
            message_ids=[blocking_info.message_id],
            endpoint_ids=[blocking_info.endpoint_id]
            if blocking_info.endpoint_id else None,
            entities=[blocking_info.entity] if blocking_info.entity else None)

        self._ongoing_blockers[id] = BlockerState(id, blocker,
                                                  blocking_dispatcher)

        # Return the id so that the user can use it when sending STOP_BLOCKING_ON_MESSAGE
        # or to listen for BLOCKING_STARTED, BLOCKING_COMPLETED and/or BLOCKING_TIMED_OUT
        return id

    def after_command(self, message):
        self.destroy()

    def destroy(self):
        try:
            if self._start_blocking_dispatcher:
                self._start_blocking_dispatcher.destroy()

            if self._after_command_dispatcher:
                self._after_command_dispatcher.destroy()

            for id, blocker_state in self._ongoing_blockers.items():
                if blocker_state.started:
                    # Just puts something in the blockers queue to make it stop
                    # If a blocker is running at destroy time we don't want to raise exceptions
                    logger.debug(
                        'Deregister blocker dispatcher by adding stop message')
                    blocker_state.blocker.handle_message('stop')
                else:
                    blocker_state.cleanup()
                    del self._ongoing_blockers[id]
        finally:
            self._start_blocking_dispatcher = None
            self._after_command_dispatcher = None
            self._ongoing_blockers = {}