Beispiel #1
0
    def test_result(self):
        if self._test_result is None:
            if self.args.get('attach', False):
                self._test_result = RemoteTestResult(args=self.args)
                self.refresh_rate = 500
            else:
                self._test_result = TestResult(args=self.args)

            # we want to reattach the outputs from Local
            for output in self.outputs:
                self._test_result.add_observer(output)

        return self._test_result
Beispiel #2
0
    def __init__(self, args):
        self.args = args
        self.fqn = args.get('fqn')
        self.test = None
        self.slave = args.get('slave', False)
        self.run_id = None
        self.project_name = args.get('project_name', 'N/A')

        self.outputs = []
        self.stop = False

        (self.total, self.hits, self.duration, self.users, self.agents,
         self.concurrency) = _compute_arguments(args)

        self.args['hits'] = self.hits
        self.args['users'] = self.users
        self.args['agents'] = self.agents
        self.args['total'] = self.total
        self.args['concurrency'] = self.concurrency

        # If we are in slave mode, set the test_result to a 0mq relay
        if self.slave:
            self._test_result = ZMQTestResult(self.args)

        # The normal behavior is to collect the results locally.
        else:
            self._test_result = TestResult(args=self.args)

        if not self.slave:
            for output in self.args.get('output', ['stdout']):
                self.register_output(output)
Beispiel #3
0
    def test_result(self):
        if self._test_result is None:
            if self.args.get('attach', False):
                self._test_result = RemoteTestResult(args=self.args)
                self.refresh_rate = 500
            else:
                self._test_result = TestResult(args=self.args)

        return self._test_result
Beispiel #4
0
    def test_result(self):
        if self._test_result is None:
            # If we are in slave mode, set the test_result to a 0mq relay
            if self.slave:
                if self.args.get('batched', False):
                    self._test_result = ZMQSummarizedTestResult(self.args)
                else:
                    self._test_result = ZMQTestResult(self.args)

            # The normal behavior is to collect the results locally.
            else:
                self._test_result = TestResult(args=self.args)

        return self._test_result
Beispiel #5
0
    def __getattribute__(self, name):
        properties = {'nb_finished_tests': 'stopTest',
                      'nb_hits': 'add_hit',
                      'nb_failures': 'addFailure',
                      'nb_errors': 'addError',
                      'nb_success': 'addSuccess',
                      'nb_tests': 'startTest',
                      'socket': 'socket_open',
                      'socket_data_received': 'socket_message'}

        values = ('errors', 'failures')

        if name in properties:
            return self.counts[properties[name]]
        elif name in values:
            if self.args.get('agents') is None:
                raise NotImplementedError(name)
            return self._get_values(name)

        return TestResult.__getattribute__(self, name)
Beispiel #6
0
    def __getattribute__(self, name):
        properties = {
            'nb_finished_tests': 'stopTest',
            'nb_hits': 'add_hit',
            'nb_failures': 'addFailure',
            'nb_errors': 'addError',
            'nb_success': 'addSuccess',
            'nb_tests': 'startTest',
            'socket': 'socket_open',
            'socket_data_received': 'socket_message'
        }

        values = ('errors', 'failures')

        if name in properties:
            return self.counts[properties[name]]
        elif name in values:
            if self.args.get('agents') is None:
                raise NotImplementedError(name)
            return self._get_values(name)

        return TestResult.__getattribute__(self, name)
Beispiel #7
0
    def __init__(self, args):
        self.args = args
        self.fqn = args.get('fqn')
        self.test = None
        self.slave = args.get('slave', False)
        self.run_id = None

        # Only resolve the name of the test if we're using the default python
        # test-runner.
        if args.get('test_runner') is None and self.fqn:
            self.test = resolve_name(self.fqn)
        else:
            self.test = None

        self.outputs = []
        self.stop = False

        (self.total, self.hits, self.duration, self.users,
         self.agents) = _compute_arguments(args)

        self.args['hits'] = self.hits
        self.args['users'] = self.users
        self.args['agents'] = self.agents
        self.args['total'] = self.total

        # If we are in slave mode, set the test_result to a 0mq relay
        if self.slave:
            self._test_result = ZMQTestResult(self.args)

        # The normal behavior is to collect the results locally.
        else:
            self._test_result = TestResult(args=self.args)

        if not self.slave:
            for output in self.args.get('output', ['stdout']):
                self.register_output(output)
Beispiel #8
0
class DistributedRunner(LocalRunner):
    """Test runner distributing the load on a cluster of agents, collecting the
    results via a ZMQ stream.

    The runner need to have agents already up and running. It will send them
    commands trough the ZMQ pipeline and get back their results, which will be
    in turn sent to the local test_result object.
    """

    name = 'distributed'
    options = {}

    def __init__(self, args):
        super(DistributedRunner, self).__init__(args)
        self.ssh = args.get('ssh')
        self.run_id = None
        self._stopped_agents = 0
        self._nb_agents = args.get('agents')

        # socket where the results are published
        self.context = zmq.Context()
        self.sub = self.context.socket(zmq.SUB)
        self.sub.setsockopt(zmq.SUBSCRIBE, '')
        self.sub.set_hwm(8096 * 10)
        self.sub.setsockopt(zmq.LINGER, -1)
        self.zmq_publisher = None
        self.zstream = None

        # io loop
        self.loop = ioloop.IOLoop()

        self.zstream = zmqstream.ZMQStream(self.sub, self.loop)
        self.zstream.on_recv(self._recv_result)

        self.agents = []
        self._client = None
        self.refresh_rate = 100

    @property
    def client(self):
        if self._client is None:
            self._client = Client(self.args['broker'],
                                  ssh=self.args.get('ssh'))
        return self._client

    @property
    def test_result(self):
        if self._test_result is None:
            if self.args.get('attach', False):
                self._test_result = RemoteTestResult(args=self.args)
                self.refresh_rate = 500
            else:
                self._test_result = TestResult(args=self.args)

            # we want to reattach the outputs from Local
            for output in self.outputs:
                self._test_result.add_observer(output)

        return self._test_result

    def _recv_result(self, msg):
        """When we receive some data from zeromq, send it to the test_result
           for later use."""
        self.loop.add_callback(self._process_result, msg)

    def _process_result(self, msg):
        try:
            data = json.loads(msg[0])
            data_type = data.pop('data_type')
            run_id = data.pop('run_id', None)

            if hasattr(self.test_result, data_type):
                method = getattr(self.test_result, data_type)
                method(**data)

            agent_stopped = (data_type == 'batch'
                             and 'stopTestRun' in data['counts'])
            agent_stopped = agent_stopped or data_type == 'stopTestRun'

            if agent_stopped:
                # Make sure all the agents are finished before stopping the
                # loop.
                self._stopped_agents += 1
                if self._stopped_agents == self._nb_agents:
                    self.test_result.sync(self.run_id)
                    self.loop.stop()
            elif data_type == 'run-finished':
                if run_id == self.run_id:
                    self.test_result.sync(self.run_id)
                    self.loop.stop()
        except Exception:
            self.loop.stop()
            raise

    def _attach_publisher(self):
        zmq_publisher = self.args.get('zmq_publisher')

        if zmq_publisher in (None, DEFAULT_PUBLISHER):
            # if this option is not provided by the command line,
            # we ask the broker about it
            res = self.client.ping()
            endpoint = res['endpoints']['publisher']
            if endpoint.startswith('ipc'):
                # IPC - lets hope we're on the same box
                zmq_publisher = endpoint
            elif endpoint.startswith('tcp'):
                # TCP, let's see what IP & port we have
                splitted = split_endpoint(endpoint)
                if splitted['ip'] == '0.0.0.0':
                    # let's use the broker ip
                    broker = self.args['broker']
                    broker_ip = split_endpoint(broker)['ip']
                    zmq_publisher = 'tcp://%s:%d' % (broker_ip,
                                                     splitted['port'])
                else:
                    # let's use the original ip
                    zmq_publisher = endpoint
            else:
                zmq_publisher = DEFAULT_PUBLISHER

        if not self.ssh:
            self.sub.connect(zmq_publisher)
        else:
            if zmq_publisher == DEFAULT_PUBLISHER:
                zmq_publisher = DEFAULT_SSH_PUBLISHER
            from zmq import ssh
            ssh.tunnel_connection(self.sub, zmq_publisher, self.ssh)

        self.zstream = zmqstream.ZMQStream(self.sub, self.loop)
        self.zstream.on_recv(self._recv_result)
        self.zmq_publisher = zmq_publisher

    def _execute(self):
        # calling the clients now
        self.test_result.startTestRun()
        detached = self.args.get('detach')

        if not detached:
            cb = ioloop.PeriodicCallback(self.refresh, self.refresh_rate,
                                         self.loop)
            cb.start()

        try:
            self._attach_publisher()
            logger.debug('Calling the broker...')
            res = self.client.run(self.args)
            self.run_id = res['run_id']
            self.agents = res['agents']

            if not detached:
                logger.debug('Waiting for results')
                self.loop.start()
            else:
                logger.info('Detached. run --attach to reattach')

        finally:
            if not detached:
                # end..
                cb.stop()
                self.test_result.stopTestRun()
                self.context.destroy()
                self.flush()

    def cancel(self):
        self.client.stop_run(self.run_id)

    def attach(self, run_id, started, counts, args):
        self._attach_publisher()
        self.test_result.args = args
        self.test_result.startTestRun(when=started)
        self.test_result.set_counts(counts)
        for output in self.outputs:
            output.args = args

        cb = ioloop.PeriodicCallback(self.refresh, self.refresh_rate,
                                     self.loop)
        cb.start()

        self.run_id = run_id
        try:
            self.loop.start()
        finally:
            # end
            cb.stop()
            self.test_result.stopTestRun()
            self.context.destroy()
            self.flush()