예제 #1
0
파일: box_binary.py 프로젝트: dDoom/volta
class VoltaBoxStm32(VoltaBoxBinary):
    """
    Same as VoltaBoxBinary, but doesn't wait for handshake
    """
    def start_test(self, results):
        """ Grab stage - starts grabber thread and puts data to results queue
        + handshake w/ device, get samplerate

            pipeline
                read source data ->
                chop by samplerate w/ ratio ->
                make pandas DataFrame ->
                drain DataFrame to queue `results`

        Args:
            results: object answers to put() and get() methods
        """
        self.grabber_q = results

        self.reader = BoxBinaryReader(self.data_source, self.sample_rate,
                                      self.slope, self.offset,
                                      self.power_voltage, self.precision)
        self.pipeline = Drain(
            TimeChopper(self.reader, self.sample_rate, self.chop_ratio),
            self.grabber_q)
        logger.info('Starting grab thread...')
        self.pipeline.start()
        logger.debug('Waiting grabber thread finish...')
예제 #2
0
파일: box500hz.py 프로젝트: dDoom/volta
class VoltaBox500Hz(VoltaBox):
    """ VoltaBox500Hz - works with plain-text 500hz box, grabs data and stores data to queue

    Attributes:
        source (string): path to data source, should be able to be opened by resource manager
            may be url, e.g. 'http://myhost.tld/path/to/file'
            may be device, e.g. '/dev/cu.wchusbserial1420'
            may be path to file, e.g. '/home/users/netort/path/to/file.data'
        sample_rate (int): volta box sample rate - depends on software and which type of volta box you use
        chop_ratio (int): chop ratio for incoming data, 1 means 1 second (500 for sample_rate 500)
        baud_rate (int): baud rate for device if device specified in source
        grab_timeout (int): timeout for grabber
    """
    def __init__(self, config):
        VoltaBox.__init__(self, config)
        self.source = config.get_option('volta', 'source')
        self.chop_ratio = config.get_option('volta', 'chop_ratio')
        self.sample_rate = config.get_option('volta', 'sample_rate', 500)
        self.baud_rate = config.get_option('volta', 'baud_rate', 115200)
        self.grab_timeout = config.get_option('volta', 'grab_timeout')
        # initialize data source
        try:
            self.source_opener = resource.get_opener(self.source)
        except:
            raise RuntimeError(
                'Device %s not found. Please check VoltaBox USB connection',
                self.source)
        self.source_opener.baud_rate = self.baud_rate
        self.source_opener.read_timeout = self.grab_timeout
        self.data_source = self.source_opener()
        logger.debug('Data source initialized: %s', self.data_source)
        self.pipeline = None
        self.grabber_q = None
        self.process_currents = None

    def start_test(self, results):
        """ Grab stage - starts grabber thread and puts data to results queue
        +clean up dirty buffer

            pipeline
                read source data ->
                chop by samplerate w/ ratio ->
                make pandas DataFrame ->
                drain DataFrame to queue `results`
        """
        self.grabber_q = results

        # clean up dirty buffer
        for _ in range(self.sample_rate):
            self.data_source.readline()

        self.reader = BoxPlainTextReader(self.data_source, self.sample_rate)
        self.pipeline = Drain(
            TimeChopper(self.reader, self.sample_rate, self.chop_ratio),
            self.grabber_q)
        logger.info('Starting grab thread...')
        self.pipeline.start()
        logger.debug('Waiting grabber thread finish...')

    def end_test(self):
        self.reader.close()
        self.pipeline.close()
        self.pipeline.join(10)
        self.data_source.close()

    def get_info(self):
        data = {}
        if self.pipeline:
            data['grabber_alive'] = self.pipeline.isAlive()
        if self.grabber_q:
            data['grabber_queue_size'] = self.grabber_q.qsize()
        return data
예제 #3
0
class VoltaBoxBinary(VoltaBox):
    """ VoltaBoxBinary - works with binary box, grabs data and stores data to queue

    Attributes:
        source (string): path to data source, should be able to be opened by resource manager
            may be url, e.g. 'http://myhost.tld/path/to/file'
            may be device, e.g. '/dev/cu.wchusbserial1420'
            may be path to file, e.g. '/home/users/netort/path/to/file.data'
        sample_rate (int): volta box sample rate - depends on software and which type of volta box you use
        chop_ratio (int): chop ratio for incoming data, 1 means 1 second (500 for sample_rate 500)
        baud_rate (int): baud rate for device if device specified in source
        grab_timeout (int): timeout for grabber
    """
    def __init__(self, config):
        VoltaBox.__init__(self, config)
        self.source = config.get_option('volta', 'source')
        self.sample_rate = config.get_option('volta', 'sample_rate', 10000)
        self.chop_ratio = config.get_option('volta', 'chop_ratio')
        self.baud_rate = config.get_option('volta', 'baud_rate', 230400)
        self.grab_timeout = config.get_option('volta', 'grab_timeout')
        self.slope = config.get_option('volta', 'slope')
        self.offset = config.get_option('volta', 'offset')
        self.power_voltage = config.get_option('volta', 'power_voltage')
        # initialize data source
        self.source_opener = resource.get_opener(self.source)
        self.source_opener.baud_rate = self.baud_rate
        self.source_opener.read_timeout = self.grab_timeout
        self.data_source = self.source_opener()
        logger.debug('Data source initialized: %s', self.data_source)
        self.pipeline = None
        self.grabber_q = None
        self.process_currents = None

    def start_test(self, results):
        """ Grab stage - starts grabber thread and puts data to results queue
        + handshake w/ device, get samplerate

            pipeline
                read source data ->
                chop by samplerate w/ ratio ->
                make pandas DataFrame ->
                drain DataFrame to queue `results`

        Args:
            results: object answers to put() and get() methods
        """
        self.grabber_q = results

        # handshake
        while self.data_source.readline() != "VOLTAHELLO\n":
            pass

        volta_spec = json.loads(self.data_source.readline())
        self.sample_rate = volta_spec["sps"]
        logger.info('Sample rate handshake success: %s', self.sample_rate)

        while self.data_source.readline() != "DATASTART\n":
            pass

        self.reader = BoxBinaryReader(self.data_source, self.sample_rate,
                                      self.slope, self.offset)
        self.pipeline = Drain(
            TimeChopper(self.reader, self.sample_rate, self.chop_ratio),
            self.grabber_q)
        logger.info('Starting grab thread...')
        self.pipeline.start()
        logger.debug('Waiting grabber thread finish...')

    def end_test(self):
        self.reader.close()
        self.pipeline.close()
        self.pipeline.join(10)
        self.data_source.close()

    def get_info(self):
        data = {}
        if self.pipeline:
            data['grabber_alive'] = self.pipeline.isAlive()
        if self.grabber_q:
            data['grabber_queue_size'] = self.grabber_q.qsize()
        return data
예제 #4
0
class AndroidOldPhone(Phone):
    """ Android Old phone worker class - work w/ phone, read phone logs, run test apps and store data

    Attributes:
        source (string): path to data source, phone id (adb devices)
        unplug_type (string): type of test execution
            `auto`: disable battery charge (by software) or use special USB cord limiting charge over USB
            `manual`: disable phone from USB by your own hands during test exection and click your test
        lightning_apk_path (string, optional): path to lightning app
            may be url, e.g. 'http://myhost.tld/path/to/file'
            may be path to file, e.g. '/home/users/netort/path/to/file.apk'
        lightning_apk_class (string, optional): lightning class
        test_apps (list, optional): list of apps to be installed to device for test
        test_class (string, optional): app class to be started during test execution
        test_package (string, optional): app package to be started during test execution
        test_runner (string, optional): app runner to be started during test execution

    Todo:
        unplug_type manual - remove raw_input()
    """
    def __init__(self, config):
        """
        Args:
            config (VoltaConfig): module configuration data
        """
        Phone.__init__(self, config)
        self.logcat_stdout_reader = None
        self.logcat_stderr_reader = None
        # mandatory options
        self.source = config.get_option('phone', 'source')
        #self.unplug_type = config.get('unplug_type', 'auto')
        # lightning app configuration
        self.lightning_apk_path = config.get_option(
            'phone', 'lightning',
            pkg_resources.resource_filename('volta.providers.phones',
                                            'binary/lightning-new3.apk'))
        self.lightning_apk_class = config.get_option('phone',
                                                     'lightning_class')
        self.lightning_apk_fname = None
        # test app configuration
        self.test_apps = config.get_option('phone', 'test_apps')
        self.test_class = config.get_option('phone', 'test_class')
        self.test_package = config.get_option('phone', 'test_package')
        self.test_runner = config.get_option('phone', 'test_runner')
        self.cleanup_apps = config.get_option('phone', 'cleanup_apps')
        self.regexp = config.get_option('phone', 'event_regexp', event_regexp)
        try:
            self.compiled_regexp = re.compile(self.regexp,
                                              re.VERBOSE | re.IGNORECASE)
        except:
            logger.debug('Unable to parse specified regexp', exc_info=True)
            raise RuntimeError("Unable to parse specified regexp")
        self.test_performer = None

    def prepare(self):
        """ Phone preparements stage: install apps etc

        pipeline:
            install lightning
            install apks
            clean log
        """
        # apps cleanup
        for apk in self.cleanup_apps:
            execute("adb -s {device_id} uninstall {app}".format(
                device_id=self.source, app=apk))

        # install lightning
        self.lightning_apk_fname = resource.get_opener(
            self.lightning_apk_path).get_filename
        logger.info('Installing lightning apk...')
        execute("adb -s {device_id} install -r -d -t {apk}".format(
            device_id=self.source, apk=self.lightning_apk_fname))

        # install apks
        for apk in self.test_apps:
            apk_fname = resource.get_opener(apk).get_filename
            execute("adb -s {device_id} install -r -d -t {apk}".format(
                device_id=self.source, apk=apk_fname))

        # clean logcat
        execute("adb -s {device_id} logcat -c".format(device_id=self.source))

        # unplug device or start logcat
        #if self.unplug_type == 'manual':
        #    logger.info('Detach the phone %s from USB and press enter to continue...', self.source)
        #    # TODO make API and remove this
        #    raw_input()

    def start(self, results):
        """ Grab stage: starts log reader, make sync w/ flashlight

        pipeline:
            if uplug_type is manual:
                remind user to start flashlight app
            if unplug_type is auto:
                start async logcat reader
                start lightning flashes

        Args:
            results (queue-like object): Phone should put there dataframes, format: ['sys_uts', 'message']
        """
        self.phone_q = results

        #if self.unplug_type == 'manual':
        #    logger.info("It's time to start flashlight app!")
        #    return

        #if self.unplug_type == 'auto':
        self.__start_async_logcat()
        # start flashes app
        execute(
            "adb -s {device_id} shell am start -n {package}/{runner}.MainActivity"
            .format(device_id=self.source,
                    package=self.lightning_apk_class,
                    runner=self.lightning_apk_class))
        logger.info('Waiting 15 seconds till flashlight app end its work...')
        time.sleep(15)
        return

    def __start_async_logcat(self):
        """ Start logcat read in subprocess and make threads to read its stdout/stderr to queues """
        cmd = "adb -s {device_id} logcat -v time".format(device_id=self.source)
        logger.debug("Execute : %s", cmd)
        self.logcat_process = popen(cmd)

        self.logcat_reader_stdout = LogReader(self.logcat_process.stdout,
                                              self.compiled_regexp)
        self.drain_logcat_stdout = Drain(self.logcat_reader_stdout,
                                         self.phone_q)
        self.drain_logcat_stdout.start()

        self.phone_q_err = q.Queue()
        self.logcat_reader_stderr = LogReader(self.logcat_process.stderr,
                                              self.compiled_regexp)
        self.drain_logcat_stderr = Drain(self.logcat_reader_stderr,
                                         self.phone_q_err)
        self.drain_logcat_stderr.start()

    def run_test(self):
        """ App stage: run app/phone tests """
        if self.test_package:
            command = "adb -s {device_id} shell am instrument -w -e class {test_class} {test_package}/{test_runner}".format(
                test_class=self.test_class,
                device_id=self.source,
                test_package=self.test_package,
                test_runner=self.test_runner)
        else:
            logger.info(
                'Infinite loop for volta because there are no tests specified, waiting for SIGINT'
            )
            command = 'while [ 1 ]; do sleep 1; done'
        self.test_performer = PhoneTestPerformer(command)
        self.test_performer.start()
        return

    def end(self):
        """ Stop test and grabbers """
        if self.test_performer:
            self.test_performer.close()
        self.logcat_reader_stdout.close()
        self.logcat_reader_stderr.close()
        self.logcat_process.kill()
        self.drain_logcat_stdout.close()
        self.drain_logcat_stderr.close()

        # apps cleanup
        for apk in self.cleanup_apps:
            execute("adb -s {device_id} uninstall {app}".format(
                device_id=self.source, app=apk))
        return

    def get_info(self):
        data = {}
        if self.drain_logcat_stdout:
            data['grabber_alive'] = self.drain_logcat_stdout.isAlive()
        if self.phone_q:
            data['grabber_queue_size'] = self.phone_q.qsize()
        if self.test_performer:
            data['test_performer_alive'] = self.test_performer.isAlive()
        return data
예제 #5
0
파일: android.py 프로젝트: nettorta/volta
class AndroidPhone(Phone):
    """ Android phone worker class - work w/ phone, read phone logs, run test apps and store data

    Attributes:
        source (string): path to data source, phone id (adb devices)
        lightning_apk_path (string, optional): path to lightning app
            may be url, e.g. 'http://myhost.tld/path/to/file'
            may be path to file, e.g. '/home/users/netort/path/to/file.apk'
        lightning_apk_class (string, optional): lightning class
        test_apps (list, optional): list of apps to be installed to device for test
        test_class (string, optional): app class to be started during test execution
        test_package (string, optional): app package to be started during test execution
        test_runner (string, optional): app runner to be started during test execution

    """
    def __init__(self, config):
        """
        Args:
            config (VoltaConfig): module configuration data
        """
        Phone.__init__(self, config)
        self.logcat_stdout_reader = None
        self.logcat_stderr_reader = None
        # mandatory options
        self.source = config.get_option('phone', 'source')
        # lightning app configuration
        self.lightning_apk_path = config.get_option(
            'phone', 'lightning',
            pkg_resources.resource_filename('volta.providers.phones',
                                            'binary/lightning-new3.apk'))
        self.lightning_apk_class = config.get_option('phone',
                                                     'lightning_class')
        self.lightning_apk_fname = None
        # test app configuration
        self.test_apps = config.get_option('phone', 'test_apps')
        self.test_class = config.get_option('phone', 'test_class')
        self.test_package = config.get_option('phone', 'test_package')
        self.test_runner = config.get_option('phone', 'test_runner')
        self.regexp = config.get_option('phone', 'event_regexp', event_regexp)
        try:
            self.compiled_regexp = re.compile(self.regexp,
                                              re.VERBOSE | re.IGNORECASE)
        except:
            logger.debug('Unable to parse specified regexp', exc_info=True)
            raise RuntimeError("Unable to parse specified regexp")
        self.drain_logcat_stdout = None
        self.test_performer = None

    def prepare(self):
        """ Phone preparements stage: install apps etc

        pipeline:
            install lightning
            install apks
            clean log
        """
        # install lightning
        self.lightning_apk_fname = resource.get_opener(
            self.lightning_apk_path).get_filename
        logger.info('Installing lightning apk...')
        execute("adb -s {device_id} install -r -d -t {apk}".format(
            device_id=self.source, apk=self.lightning_apk_fname))

        # install apks
        for apk in self.test_apps:
            apk_fname = resource.get_opener(apk).get_filename
            execute("adb -s {device_id} install -r -d -t {apk}".format(
                device_id=self.source, apk=apk_fname))

        # clean logcat
        execute("adb -s {device_id} logcat -c".format(device_id=self.source))

    def start(self, results):
        """ Grab stage: starts log reader, make sync w/ flashlight
        Args:
            results (queue-like object): Phone should put there dataframes, format: ['sys_uts', 'message']
        """
        self.phone_q = results
        self.__start_async_logcat()
        # start flashes app
        execute(
            "adb -s {device_id} shell am start -n {package}/{runner}.MainActivity"
            .format(device_id=self.source,
                    package=self.lightning_apk_class,
                    runner=self.lightning_apk_class))
        return

    def __start_async_logcat(self):
        """ Start logcat read in subprocess and make threads to read its stdout/stderr to queues """
        cmd = "adb -s {device_id} logcat".format(device_id=self.source)
        logger.debug("Execute : %s", cmd)
        self.logcat_process = popen(cmd)

        self.logcat_reader_stdout = LogReader(self.logcat_process.stdout,
                                              self.compiled_regexp)
        self.drain_logcat_stdout = Drain(self.logcat_reader_stdout,
                                         self.phone_q)
        self.drain_logcat_stdout.start()

        self.phone_q_err = q.Queue()
        self.logcat_reader_stderr = LogReader(self.logcat_process.stderr,
                                              self.compiled_regexp)
        self.drain_logcat_stderr = Drain(self.logcat_reader_stderr,
                                         self.phone_q_err)
        self.drain_logcat_stderr.start()

    def run_test(self):
        """ App stage: run app/phone tests """
        if self.test_package:
            command = "adb -s {device_id} shell am instrument -w -e class {test_class} {test_package}/{test_runner}".format(
                test_class=self.test_class,
                device_id=self.source,
                test_package=self.test_package,
                test_runner=self.test_runner)
        else:
            logger.info(
                'Infinite loop for volta because there are no tests specified, waiting for SIGINT'
            )
            command = 'while [ 1 ]; do sleep 1; done'
        self.test_performer = PhoneTestPerformer(command)
        self.test_performer.start()
        return

    def end(self):
        """ Stop test and grabbers """
        if self.test_performer:
            self.test_performer.close()
        self.logcat_reader_stdout.close()
        self.logcat_reader_stderr.close()
        self.logcat_process.kill()
        self.drain_logcat_stdout.close()
        self.drain_logcat_stderr.close()
        return

    def get_info(self):
        data = {}
        if self.drain_logcat_stdout:
            data['grabber_alive'] = self.drain_logcat_stdout.isAlive()
        if self.phone_q:
            data['grabber_queue_size'] = self.phone_q.qsize()
        if self.test_performer:
            data['test_performer_alive'] = self.test_performer.isAlive()
        return data
예제 #6
0
class iPhone(Phone):
    """ iPhone worker class - work w/ phone, read phone logs, store data

    Attributes:
        source (string): path to data source, cfgutil id for iphones
        unplug_type (string, optional): type of test execution - NOT available at the moment for now
            `auto`: disable battery charge (by software) or use special USB cord limiting charge over USB
        path_to_util (string, optional): path to Apple Configurators' cfgutil

    Todo:
        unlug_type manual
    """
    def __init__(self, config):
        """
        Args:
            config (dict): module configuration data
        """
        Phone.__init__(self, config)
        self.log_stdout_reader = None
        self.log_stderr_reader = None
        self.drain_log_stdout = None
        self.path_to_util = config.get_option('phone', 'util')
        self.source = config.get_option('phone', 'source')
        # self.test_performer = None

    def prepare(self):
        """ this method skipped by iphone - instruments do the thing """
        return

    def start(self, results):
        """ Grab stage: starts log reader

        pipeline:
            start async logcat reader

        Args:
            results (queue-like object): Phone should put there dataframes, format: ['sys_uts', 'message']
        """

        self.phone_q = results
        self.__start_async_log()

    def run_test(self):
        """ App stage: run app/phone tests """
        pass
        # logger.info('Infinite loop for volta because there are no tests specified, waiting for SIGINT')
        # command = 'while [ 1 ]; do sleep 1; done'
        # self.test_performer = PhoneTestPerformer(command)
        # self.test_performer.start()

    def end(self):
        """ pipeline: stop async log process, readers and queues """
        # if self.test_performer:
        #     self.test_performer.close()
        self.log_reader_stdout.close()
        self.log_reader_stderr.close()
        self.log_process.kill()
        self.drain_log_stdout.close()
        self.drain_log_stderr.close()

    def __start_async_log(self):
        """ Start logcat read in subprocess and make threads to read its stdout/stderr to queues """
        cmd = "{path}cfgutil -e {device_id} syslog".format(
            path=self.path_to_util, device_id=self.source)
        logger.debug("Execute : %s", cmd)
        self.log_process = popen(cmd)

        self.log_reader_stdout = LogReader(self.log_process.stdout,
                                           iphone_logevent_re)
        self.drain_log_stdout = Drain(self.log_reader_stdout, self.phone_q)
        self.drain_log_stdout.start()

        self.phone_q_err = q.Queue()
        self.log_reader_stderr = LogReader(self.log_process.stderr,
                                           iphone_logevent_re)
        self.drain_log_stderr = Drain(self.log_reader_stderr, self.phone_q_err)
        self.drain_log_stderr.start()

    def get_info(self):
        data = {}
        if self.drain_log_stdout:
            data['grabber_alive'] = self.drain_log_stdout.isAlive()
        if self.phone_q:
            data['grabber_queue_size'] = self.phone_q.qsize()
        # if self.test_performer:
        #     data['test_performer_alive'] = self.test_performer.isAlive()
        return data
예제 #7
0
파일: android.py 프로젝트: ratatoskrr/volta
class AndroidPhone(Phone):
    """ Android phone worker class - work w/ phone, read phone logs, run test apps and store data

    Attributes:
        source (string): path to data source, phone id (adb devices)
        unplug_type (string): type of test execution
            `auto`: disable battery charge (by software) or use special USB cord limiting charge over USB
            `manual`: disable phone from USB by your own hands during test exection and click your test
        lightning_apk_path (string, optional): path to lightning app
            may be url, e.g. 'http://myhost.tld/path/to/file'
            may be path to file, e.g. '/home/users/netort/path/to/file.apk'
        lightning_apk_class (string, optional): lightning class
        test_apps (list, optional): list of apps to be installed to device for test
        test_class (string, optional): app class to be started during test execution
        test_package (string, optional): app package to be started during test execution
        test_runner (string, optional): app runner to be started during test execution

    Todo:
        unplug_type manual - remove raw_input()
    """
    def __init__(self, config):
        """
        Args:
            config (dict): module configuration data
        """
        Phone.__init__(self, config)
        self.logcat_stdout_reader = None
        self.logcat_stderr_reader = None
        # mandatory options
        self.source = config.get('source', '00dc3419957ba583')
        self.unplug_type = config.get('unplug_type', 'auto')
        # lightning app configuration
        self.lightning_apk_path = config.get(
            'lightning',
            pkg_resources.resource_filename('volta.providers.phones',
                                            'binary/lightning-new3.apk'))
        self.lightning_apk_class = config.get('lightning_class',
                                              'net.yandex.overload.lightning')
        self.lightning_apk_fname = None
        # test app configuration
        self.test_apps = config.get('test_apps', [])
        self.test_class = config.get('test_class', '')
        self.test_package = config.get('test_package', '')
        self.test_runner = config.get('test_runner', '')

    def prepare(self):
        """ Phone preparements stage: install apps etc

        pipeline:
            install lightning
            install apks
            clean log
        """

        # install lightning
        self.lightning_apk_fname = resource.get_opener(
            self.lightning_apk_path).get_filename
        logger.info('Installing lightning apk...')
        execute("adb -s {device_id} install -r -d -t {apk}".format(
            device_id=self.source, apk=self.lightning_apk_fname))

        # install apks
        for apk in self.test_apps:
            apk_fname = resource.get_opener(apk).get_filename
            execute("adb -s {device_id} install -r -d -t {apk}".format(
                device_id=self.source, apk=apk_fname))

        # clean logcat
        execute("adb -s {device_id} logcat -c".format(device_id=self.source))

        # unplug device or start logcat
        if self.unplug_type == 'manual':
            logger.info(
                'Detach the phone %s from USB and press enter to continue...',
                self.source)
            # TODO make API and remove this
            raw_input()

    def start(self, results):
        """ Grab stage: starts log reader, make sync w/ flashlight

        pipeline:
            if uplug_type is manual:
                remind user to start flashlight app
            if unplug_type is auto:
                start async logcat reader
                start lightning flashes

        Args:
            results (queue-like object): Phone should put there dataframes, format: ['sys_uts', 'message']
        """
        self.phone_q = results

        if self.unplug_type == 'manual':
            logger.info("It's time to start flashlight app!")
            return

        if self.unplug_type == 'auto':
            self.__start_async_logcat()
            # start flashes app
            execute(
                "adb -s {device_id} shell am start -n {package}/{runner}.MainActivity"
                .format(device_id=self.source,
                        package=self.lightning_apk_class,
                        runner=self.lightning_apk_class))
            return

    def __start_async_logcat(self):
        """ Start logcat read in subprocess and make threads to read its stdout/stderr to queues """
        cmd = "adb -s {device_id} logcat".format(device_id=self.source)
        logger.debug("Execute : %s", cmd)
        self.logcat_process = popen(cmd)

        self.logcat_reader_stdout = LogReader(self.logcat_process.stdout,
                                              android_logevent_re)
        self.drain_logcat_stdout = Drain(self.logcat_reader_stdout,
                                         self.phone_q)
        self.drain_logcat_stdout.start()

        self.phone_q_err = q.Queue()
        self.logcat_reader_stderr = LogReader(self.logcat_process.stderr,
                                              android_logevent_re)
        self.drain_logcat_stderr = Drain(self.logcat_reader_stderr,
                                         self.phone_q_err)
        self.drain_logcat_stderr.start()

    def run_test(self):
        """ App stage: run app/phone tests,

        pipeline:
            if unplug_type is auto:
                run test
            if unplug_type is manual:
                skip
        """

        if self.unplug_type == 'manual':
            return

        if self.unplug_type == 'auto':
            execute(
                "adb shell am instrument -w -e class {test_class} {test_package}/{test_runner}"
                .format(test_class=self.test_class,
                        test_package=self.test_package,
                        test_runner=self.test_runner))
            return

    def end(self):
        """ Stop test and grabbers

        pipeline:
            if uplug_type is manual:
                ask user to plug device in
                get logcat dump from device
            if unplug_type is auto:
                stop async logcat process, readers and queues
        """

        if self.unplug_type == 'manual':
            logger.warning(
                "Plug the phone in and press `enter` to continue...")
            # TODO make API and remove this
            raw_input()

            _, stdout, stderr = execute(
                "adb -s {device_id} logcat -d".format(device_id=self.source),
                catch_out=True)
            logger.debug('Recieved %d logcat data', len(stdout))
            self.phone_q.put(chunk_to_df(stdout, android_logevent_re))
            return

        if self.unplug_type == 'auto':
            self.logcat_reader_stdout.close()
            self.logcat_reader_stderr.close()
            self.logcat_process.kill()
            self.drain_logcat_stdout.close()
            self.drain_logcat_stderr.close()
            return
예제 #8
0
class iPhone(Phone):
    """ iPhone worker class - work w/ phone, read phone logs, store data

    Attributes:
        source (string): path to data source, cfgutil id for iphones
        unplug_type (string, optional): type of test execution - NOT available at the moment for now
            `auto`: disable battery charge (by software) or use special USB cord limiting charge over USB
        path_to_util (string, optional): path to Apple Configurators' cfgutil

    Todo:
        unlug_type manual
    """
    def __init__(self, config):
        """
        Args:
            config (dict): module configuration data
        """
        Phone.__init__(self, config)
        self.log_stdout_reader = None
        self.log_stderr_reader = None
        self.path_to_util = config.get(
            'util', "/Applications/Apple\ Configurator\ 2.app/Contents/MacOS/")
        self.source = config.get('source', '0x6382910F98C26')
        # self.unplug_type = config.get('unplug_type', 'auto')

    def prepare(self):
        """ this method skipped by iphone - instruments do the thing """
        return

    def start(self, results):
        """ Grab stage: starts log reader

        pipeline:
            start async logcat reader

        Args:
            results (queue-like object): Phone should put there dataframes, format: ['sys_uts', 'message']
        """

        self.phone_q = results
        self.__start_async_log()

    def run_test(self):
        """ this method skipped by iphone because instruments do the thing """
        return

    def end(self):
        """ pipeline: stop async log process, readers and queues """
        self.log_reader_stdout.close()
        self.log_reader_stderr.close()
        self.log_process.kill()
        self.drain_log_stdout.close()
        self.drain_log_stderr.close()

    def __start_async_log(self):
        """ Start logcat read in subprocess and make threads to read its stdout/stderr to queues """
        cmd = "{path}cfgutil -e {device_id} syslog".format(
            path=self.path_to_util, device_id=self.source)
        logger.debug("Execute : %s", cmd)
        self.log_process = popen(cmd)

        self.log_reader_stdout = LogReader(self.log_process.stdout,
                                           iphone_logevent_re)
        self.drain_log_stdout = Drain(self.log_reader_stdout, self.phone_q)
        self.drain_log_stdout.start()

        self.phone_q_err = q.Queue()
        self.log_reader_stderr = LogReader(self.log_process.stderr,
                                           iphone_logevent_re)
        self.drain_log_stderr = Drain(self.log_reader_stderr, self.phone_q_err)
        self.drain_log_stderr.start()
예제 #9
0
class Nexus4(Phone):
    """ Android phone worker class - work w/ phone, read phone logs, run test apps and store data

    Attributes:
        source (string): path to data source, phone id (adb devices)
        unplug_type (string): type of test execution
            `auto`: disable battery charge (by software) or use special USB cord limiting charge over USB
            `manual`: disable phone from USB by your own hands during test exection and click your test
        lightning_apk_path (string, optional): path to lightning app
            may be url, e.g. 'http://myhost.tld/path/to/file'
            may be path to file, e.g. '/home/users/netort/path/to/file.apk'
        lightning_apk_class (string, optional): lightning class
        test_apps (list, optional): list of apps to be installed to device for test
        test_class (string, optional): app class to be started during test execution
        test_package (string, optional): app package to be started during test execution
        test_runner (string, optional): app runner to be started during test execution

    Todo:
        unplug_type manual - remove raw_input()
    """

    def __init__(self, config):
        """
        Args:
            config (dict): module configuration data
        """
        Phone.__init__(self, config)
        self.logcat_stdout_reader = None
        self.logcat_stderr_reader = None
        # mandatory options
        self.source = config.get('source', '01dd6e7352c97826')
        self.unplug_type = config.get('unplug_type', 'auto')
        # lightning app configuration
        self.lightning_apk_path = config.get('lightning', pkg_resources.resource_filename(
            'volta.providers.phones', 'binary/lightning-new3.apk')
        )
        logger.info('lightning_apk_path '+self.lightning_apk_path)
        self.blink_delay = config.get('blink_delay', 0)
        self.blink_toast = config.get('blink_toast', 0)
        self.lightning_apk_class = config.get('lightning_class', 'net.yandex.overload.lightning')
        self.lightning_apk_fname = None
        # test app configuration
        self.test_apps = config.get('test_apps', [])
        self.test_class = config.get('test_class', '')
        self.test_package = config.get('test_package', '')
        self.test_runner = config.get('test_runner', '')

    def prepare(self):
        """ Phone preparements stage: install apps etc

        pipeline:
            install lightning
            install apks
            clean log
        """

        # install lightning
        self.lightning_apk_fname = resource.get_opener(self.lightning_apk_path).get_filename
        logger.info('Installing lightning apk '+self.lightning_apk_fname)
        execute("adb -s {device_id} install -r -d -t {apk}".format(device_id=self.source, apk=self.lightning_apk_fname))

        # install apks
        for apk in self.test_apps:
            apk_fname = resource.get_opener(apk).get_filename
            execute("adb -s {device_id} install -r -d -t {apk}".format(device_id=self.source, apk=apk_fname))

        # clean logcat
        execute("adb -s {device_id} logcat -c".format(device_id=self.source))

    def start(self, results):
        """ Grab stage: starts log reader, make sync w/ flashlight

        pipeline:
            if unplug_type is manual:
                remind user to start flashlight app
            if unplug_type is auto:
                start async logcat reader
                start lightning flashes

        Args:
            results (queue-like object): Phone should put there dataframes, format: ['sys_uts', 'message']
        """
        self.phone_q = results

        self.__start_async_logcat()
        # start flashes app
        execute(
            "adb -s {device_id} shell am startservice -a BLINK --ei DELAY 10000 -n com.yandex.pmu_blinker/.PmuIntentService".format(
                device_id=self.source,
            )
        )
        return

    def __start_async_logcat(self):
        """ Start logcat read in subprocess and make threads to read its stdout/stderr to queues """
        cmd = "adb -s {device_id} logcat -v time".format(device_id=self.source)
        logger.debug("Execute : %s", cmd)
        self.logcat_process = popen(cmd)

        self.logcat_reader_stdout = LogReader(self.logcat_process.stdout, android_logevent_re)
        self.drain_logcat_stdout = Drain(self.logcat_reader_stdout, self.phone_q)
        self.drain_logcat_stdout.start()

        self.phone_q_err=q.Queue()
        self.logcat_reader_stderr = LogReader(self.logcat_process.stderr, android_logevent_re)
        self.drain_logcat_stderr = Drain(self.logcat_reader_stderr, self.phone_q_err)
        self.drain_logcat_stderr.start()

    def run_test(self):
        """ App stage: run app/phone tests,

        pipeline:
            if unplug_type is auto:
                run test
            if unplug_type is manual:
                skip
        """
        #execute(
        #    "adb shell am instrument -w -e class {test_class} {test_package}/{test_runner}".format(
        #        test_class=self.test_class,
        #        test_package=self.test_package,
        #        test_runner=self.test_runner
        #    )
        #)
        return

    def end(self):
        """ Stop test and grabbers

        pipeline:
            if uplug_type is manual:
                ask user to plug device in
                get logcat dump from device
            if unplug_type is auto:
                stop async logcat process, readers and queues
        """

        self.logcat_reader_stdout.close()
        self.logcat_reader_stderr.close()
        self.logcat_process.kill()
        self.drain_logcat_stdout.close()
        self.drain_logcat_stderr.close()
        return