コード例 #1
0
ファイル: __init__.py プロジェクト: nachandr/cfme_tests
    def pytest_runtestloop(self):
        """pytest runtest loop

        - Disable the master terminal reporter hooks, so we can add our own handlers
          that include the slaveid in the output
        - Send tests to slaves when they ask
        - Log the starting of tests and test results, including slave id
        - Handle clean slave shutdown when they finish their runtest loops
        - Restore the master terminal reporter after testing so we get the final report

        """
        # Build master collection for slave diffing and distribution
        for item in self.session.items:
            is_serial = bool(item.get_closest_marker("serial"))
            if is_serial:
                self.serial_collection.append(item.nodeid)
            else:
                self.collection.append(item.nodeid)

        # Fire up the workers after master collection is complete
        # master and the first slave share an appliance, this is a workaround to prevent a slave
        # from altering an appliance while master collection is still taking place
        for slave in self.slaves.values():
            slave.start()

        try:
            self.print_message(
                f"Waiting for collection on {len(self.slaves)} pytest instances",
                red=True)

            # Turn off the terminal reporter to suppress the builtin logstart printing
            terminalreporter.disable()

            while True:
                # spawn/kill/replace slaves if needed
                self._slave_audit()

                if not self.slaves:
                    # All slaves are killed or errored, we're done with tests
                    self.print_message('all slaves have exited', yellow=True)
                    self.session_finished = True

                if self.session_finished:
                    break

                slave, event_data, event_name = self.recv()
                if event_name == 'message':
                    message = event_data.pop('message')
                    markup = event_data.pop('markup')
                    # messages are special, handle them immediately
                    self.print_message(message, slave, **markup)
                    self.ack(slave, event_name)
                elif event_name == 'collectionfinish':
                    slave_collection = event_data['node_ids']
                    # compare slave collection to the master, all test ids must be the same
                    self.log.debug(f'diffing {slave.id} collection')
                    diff_err = report_collection_diff(
                        slave.id, self.collection + self.serial_collection,
                        slave_collection)
                    if diff_err:
                        self.print_message('collection differs, respawning',
                                           slave.id,
                                           purple=True)
                        self.print_message(diff_err, purple=True)
                        self.log.error(diff_err)
                        self.kill(slave)
                        slave.start()
                    else:
                        self.ack(slave, event_name)
                elif event_name == 'need_tests':
                    self.send_tests(slave)
                    self.log.info('starting master test distribution')
                elif event_name == 'runtest_logstart':
                    self.ack(slave, event_name)
                    self.trdist.runtest_logstart(slave.id,
                                                 event_data['nodeid'],
                                                 event_data['location'])
                elif event_name == 'runtest_logreport':
                    self.ack(slave, event_name)
                    report = unserialize_report(event_data['report'])
                    if report.when in ('call', 'teardown'):
                        slave.tests.discard(report.nodeid)
                    self.trdist.runtest_logreport(slave.id, report)
                elif event_name == 'internalerror':
                    self.ack(slave, event_name)
                    self.print_message(event_data['message'],
                                       slave,
                                       purple=True)
                    self.kill(slave)
                elif event_name == 'shutdown':
                    self.config.hook.pytest_miq_node_shutdown(
                        config=self.config, nodeinfo=slave.appliance.url)
                    self.ack(slave, event_name)
                    del self.slaves[slave.id]
                    self.monitor_shutdown(slave)

                # total slave spawn count * 3, to allow for each slave's initial spawn
                # and then each slave (on average) can fail two times
                if self.slave_spawn_count >= len(self.appliances) * 3:
                    self.print_message('too many slave respawns, exiting',
                                       red=True,
                                       bold=True)
                    raise KeyboardInterrupt(
                        'Interrupted due to slave failures')
        except Exception as ex:
            self.log.exception('Exception in runtest loop:')
            self.print_message(str(ex))
            raise
        finally:
            terminalreporter.enable()

        # Suppress other runtestloop calls
        return True
コード例 #2
0
    def pytest_runtestloop(self):
        """pytest runtest loop

        - Disable the master terminal reporter hooks, so we can add our own handlers
          that include the slaveid in the output
        - Send tests to slaves when they ask
        - Log the starting of tests and test results, including slave id
        - Handle clean slave shutdown when they finish their runtest loops
        - Restore the master terminal reporter after testing so we get the final report

        """
        # Build master collection for slave diffing and distribution
        self.collection = [item.nodeid for item in self.session.items]

        # Fire up the workers after master collection is complete
        # master and the first slave share an appliance, this is a workaround to prevent a slave
        # from altering an appliance while master collection is still taking place
        for slave in self.slaves.values():
            slave.start()

        try:
            self.print_message("Waiting for {} slave collections".format(len(self.slaves)),
                red=True)

            # Turn off the terminal reporter to suppress the builtin logstart printing
            terminalreporter.disable()

            while True:
                # spawn/kill/replace slaves if needed
                self._slave_audit()

                if not self.slaves:
                    # All slaves are killed or errored, we're done with tests
                    self.print_message('all slaves have exited', yellow=True)
                    self.session_finished = True

                if self.session_finished:
                    break

                slave, event_data, event_name = self.recv()
                if event_name == 'message':
                    message = event_data.pop('message')
                    markup = event_data.pop('markup')
                    # messages are special, handle them immediately
                    self.print_message(message, slave, **markup)
                    self.ack(slave, event_name)
                elif event_name == 'collectionfinish':
                    slave_collection = event_data['node_ids']
                    # compare slave collection to the master, all test ids must be the same
                    self.log.debug('diffing {} collection'.format(slave.id))
                    diff_err = report_collection_diff(
                        slave.id, self.collection, slave_collection)
                    if diff_err:
                        self.print_message(
                            'collection differs, respawning', slave.id,
                            purple=True)
                        self.print_message(diff_err, purple=True)
                        self.log.error('{}'.format(diff_err))
                        self.kill(slave)
                        slave.start()
                    else:
                        self.ack(slave, event_name)
                elif event_name == 'need_tests':
                    self.send_tests(slave)
                    self.log.info('starting master test distribution')
                elif event_name == 'runtest_logstart':
                    self.ack(slave, event_name)
                    self.trdist.runtest_logstart(
                        slave.id,
                        event_data['nodeid'],
                        event_data['location'])
                elif event_name == 'runtest_logreport':
                    self.ack(slave, event_name)
                    report = unserialize_report(event_data['report'])
                    if report.when in ('call', 'teardown'):
                        slave.tests.discard(report.nodeid)
                    self.trdist.runtest_logreport(slave.id, report)
                elif event_name == 'internalerror':
                    self.ack(slave, event_name)
                    self.print_message(event_data['message'], slave, purple=True)
                    self.kill(slave)
                elif event_name == 'shutdown':
                    self.config.hook.pytest_miq_node_shutdown(
                        config=self.config, nodeinfo=slave.appliance.url)
                    self.ack(slave, event_name)
                    del self.slaves[slave.id]
                    self.monitor_shutdown(slave)

                # total slave spawn count * 3, to allow for each slave's initial spawn
                # and then each slave (on average) can fail two times
                if self.slave_spawn_count >= len(self.appliances) * 3:
                    self.print_message(
                        'too many slave respawns, exiting',
                        red=True, bold=True)
                    raise KeyboardInterrupt('Interrupted due to slave failures')
        except Exception as ex:
            self.log.error('Exception in runtest loop:')
            self.log.exception(ex)
            self.print_message(str(ex))
            raise
        finally:
            terminalreporter.enable()

        # Suppress other runtestloop calls
        return True