def individual_device_set_up(device, host_device_tuples):
      steps = []

      if self._test_instance.replace_system_package:
        @trace_event.traced
        def replace_package(dev):
          # We need the context manager to be applied before modifying any
          # shared preference files in case the replacement APK needs to be
          # set up, and it needs to be applied while the test is running.
          # Thus, it needs to be applied early during setup, but must still be
          # applied during _RunTest, which isn't possible using 'with' without
          # applying the context manager up in test_runner. Instead, we
          # manually invoke its __enter__ and __exit__ methods in setup and
          # teardown.
          self._replace_package_contextmanager = system_app.ReplaceSystemApp(
              dev, self._test_instance.replace_system_package.package,
              self._test_instance.replace_system_package.replacement_apk)
          # Pylint is not smart enough to realize that this field has
          # an __enter__ method, and will complain loudly.
          # pylint: disable=no-member
          self._replace_package_contextmanager.__enter__()
          # pylint: enable=no-member

        steps.append(replace_package)

      if self._test_instance.use_webview_provider:
        @trace_event.traced
        def use_webview_provider(dev):
          # We need the context manager to be applied before modifying any
          # shared preference files in case the replacement APK needs to be
          # set up, and it needs to be applied while the test is running.
          # Thus, it needs to be applied early during setup, but must still be
          # applied during _RunTest, which isn't possible using 'with' without
          # applying the context manager up in test_runner. Instead, we
          # manually invoke its __enter__ and __exit__ methods in setup and
          # teardown.
          self._use_webview_contextmanager = webview_app.UseWebViewProvider(
              dev, self._test_instance.use_webview_provider)
          # Pylint is not smart enough to realize that this field has
          # an __enter__ method, and will complain loudly.
          # pylint: disable=no-member
          self._use_webview_contextmanager.__enter__()
          # pylint: enable=no-member

        steps.append(use_webview_provider)

      def install_helper(apk, permissions):
        @instrumentation_tracing.no_tracing
        @trace_event.traced("apk_path")
        def install_helper_internal(d, apk_path=apk.path):
          # pylint: disable=unused-argument
          d.Install(apk, permissions=permissions)
        return install_helper_internal

      def incremental_install_helper(apk, json_path, permissions):
        @trace_event.traced("apk_path")
        def incremental_install_helper_internal(d, apk_path=apk.path):
          # pylint: disable=unused-argument
          installer.Install(d, json_path, apk=apk, permissions=permissions)
        return incremental_install_helper_internal

      if self._test_instance.apk_under_test:
        permissions = self._test_instance.apk_under_test.GetPermissions()
        if self._test_instance.apk_under_test_incremental_install_json:
          steps.append(incremental_install_helper(
                           self._test_instance.apk_under_test,
                           self._test_instance.
                               apk_under_test_incremental_install_json,
                           permissions))
        else:
          steps.append(install_helper(self._test_instance.apk_under_test,
                                      permissions))

      permissions = self._test_instance.test_apk.GetPermissions()
      if self._test_instance.test_apk_incremental_install_json:
        steps.append(incremental_install_helper(
                         self._test_instance.test_apk,
                         self._test_instance.
                             test_apk_incremental_install_json,
                         permissions))
      else:
        steps.append(install_helper(self._test_instance.test_apk,
                                    permissions))

      steps.extend(install_helper(apk, None)
                   for apk in self._test_instance.additional_apks)

      @trace_event.traced
      def set_debug_app(dev):
        # Set debug app in order to enable reading command line flags on user
        # builds
        package_name = None
        if self._test_instance.apk_under_test:
          package_name = self._test_instance.apk_under_test.GetPackageName()
        elif self._test_instance.test_apk:
          package_name = self._test_instance.test_apk.GetPackageName()
        else:
          logging.error("Couldn't set debug app: no package name found")
          return
        cmd = ['am', 'set-debug-app', '--persistent']
        if self._test_instance.wait_for_java_debugger:
          cmd.append('-w')
        cmd.append(package_name)
        dev.RunShellCommand(cmd, check_return=True)

      @trace_event.traced
      def edit_shared_prefs(dev):
        for setting in self._test_instance.edit_shared_prefs:
          shared_pref = shared_prefs.SharedPrefs(
              dev, setting['package'], setting['filename'],
              use_encrypted_path=setting.get('supports_encrypted_path', False))
          pref_to_restore = copy.copy(shared_pref)
          pref_to_restore.Load()
          self._shared_prefs_to_restore.append(pref_to_restore)

          shared_preference_utils.ApplySharedPreferenceSetting(
              shared_pref, setting)

      @trace_event.traced
      def set_vega_permissions(dev):
        # Normally, installation of VrCore automatically grants storage
        # permissions. However, since VrCore is part of the system image on
        # the Vega standalone headset, we don't install the APK as part of test
        # setup. Instead, grant the permissions here so that it can take
        # screenshots.
        if dev.product_name == 'vega':
          dev.GrantPermissions('com.google.vr.vrcore', [
              'android.permission.WRITE_EXTERNAL_STORAGE',
              'android.permission.READ_EXTERNAL_STORAGE'
          ])

      @instrumentation_tracing.no_tracing
      def push_test_data(dev):
        device_root = posixpath.join(dev.GetExternalStoragePath(),
                                     'chromium_tests_root')
        host_device_tuples_substituted = [
            (h, local_device_test_run.SubstituteDeviceRoot(d, device_root))
            for h, d in host_device_tuples]
        logging.info('instrumentation data deps:')
        for h, d in host_device_tuples_substituted:
          logging.info('%r -> %r', h, d)
        dev.PushChangedFiles(host_device_tuples_substituted,
                             delete_device_stale=True)
        if not host_device_tuples_substituted:
          dev.RunShellCommand(['rm', '-rf', device_root], check_return=True)
          dev.RunShellCommand(['mkdir', '-p', device_root], check_return=True)

      @trace_event.traced
      def create_flag_changer(dev):
        if self._test_instance.flags:
          self._CreateFlagChangerIfNeeded(dev)
          logging.debug('Attempting to set flags: %r',
                        self._test_instance.flags)
          self._flag_changers[str(dev)].AddFlags(self._test_instance.flags)

        valgrind_tools.SetChromeTimeoutScale(
            dev, self._test_instance.timeout_scale)

      steps += [
          set_debug_app, edit_shared_prefs, push_test_data, create_flag_changer,
          set_vega_permissions
      ]

      def bind_crash_handler(step, dev):
        return lambda: crash_handler.RetryOnSystemCrash(step, dev)

      steps = [bind_crash_handler(s, device) for s in steps]

      try:
        if self._env.concurrent_adb:
          reraiser_thread.RunAsync(steps)
        else:
          for step in steps:
            step()
        if self._test_instance.store_tombstones:
          tombstones.ClearAllTombstones(device)
      except device_errors.CommandFailedError:
        # A bugreport can be large and take a while to generate, so only capture
        # one if we're using a remote manager.
        if isinstance(
            self._env.output_manager,
            remote_output_manager.RemoteOutputManager):
          logging.error(
              'Error when setting up device for tests. Taking a bugreport for '
              'investigation. This may take a while...')
          report_name = '%s.bugreport' % device.serial
          with self._env.output_manager.ArchivedTempfile(
              report_name, 'bug_reports') as report_file:
            device.TakeBugReport(report_file.name)
          logging.error('Bug report saved to %s', report_file.Link())
        raise
示例#2
0
        def individual_device_set_up(dev, host_device_tuples):
            def install_apk():
                if self._test_instance.apk_under_test:
                    if self._test_instance.apk_under_test_incremental_install_script:
                        local_device_test_run.IncrementalInstall(
                            dev, self._test_instance.apk_under_test,
                            self._test_instance.
                            apk_under_test_incremental_install_script)
                    else:
                        permissions = self._test_instance.apk_under_test.GetPermissions(
                        )
                        dev.Install(self._test_instance.apk_under_test,
                                    permissions=permissions)

                if self._test_instance.test_apk_incremental_install_script:
                    local_device_test_run.IncrementalInstall(
                        dev, self._test_instance.test_apk, self._test_instance.
                        test_apk_incremental_install_script)
                else:
                    permissions = self._test_instance.test_apk.GetPermissions()
                    dev.Install(self._test_instance.test_apk,
                                permissions=permissions)

                for apk in self._test_instance.additional_apks:
                    dev.Install(apk)

                # Set debug app in order to enable reading command line flags on user
                # builds
                if self._test_instance.flags:
                    if not self._test_instance.package_info:
                        logging.error(
                            "Couldn't set debug app: no package info")
                    elif not self._test_instance.package_info.package:
                        logging.error(
                            "Couldn't set debug app: no package defined")
                    else:
                        dev.RunShellCommand([
                            'am', 'set-debug-app', '--persistent',
                            self._test_instance.package_info.package
                        ],
                                            check_return=True)

            def edit_shared_prefs():
                for pref in self._test_instance.edit_shared_prefs:
                    prefs = shared_prefs.SharedPrefs(dev, pref['package'],
                                                     pref['filename'])
                    prefs.Load()
                    for key in pref.get('remove', []):
                        try:
                            prefs.Remove(key)
                        except KeyError:
                            logging.warning(
                                "Attempted to remove non-existent key %s", key)
                    for key, value in pref.get('set', {}).iteritems():
                        if isinstance(value, bool):
                            prefs.SetBoolean(key, value)
                        elif isinstance(value, basestring):
                            prefs.SetString(key, value)
                        elif isinstance(value, long) or isinstance(value, int):
                            prefs.SetLong(key, value)
                        elif isinstance(value, list):
                            prefs.SetStringSet(key, value)
                        else:
                            raise ValueError(
                                "Given invalid value type %s for key %s" %
                                (str(type(value)), key))
                    prefs.Commit()

            def push_test_data():
                device_root = posixpath.join(dev.GetExternalStoragePath(),
                                             'chromium_tests_root')
                host_device_tuples_substituted = [
                    (h,
                     local_device_test_run.SubstituteDeviceRoot(
                         d, device_root)) for h, d in host_device_tuples
                ]
                logging.info('instrumentation data deps:')
                for h, d in host_device_tuples_substituted:
                    logging.info('%r -> %r', h, d)
                dev.PushChangedFiles(host_device_tuples_substituted,
                                     delete_device_stale=True)
                if not host_device_tuples_substituted:
                    dev.RunShellCommand(['rm', '-rf', device_root],
                                        check_return=True)
                    dev.RunShellCommand(['mkdir', '-p', device_root],
                                        check_return=True)

            def create_flag_changer():
                if self._test_instance.flags:
                    if not self._test_instance.package_info:
                        logging.error("Couldn't set flags: no package info")
                    elif not self._test_instance.package_info.cmdline_file:
                        logging.error("Couldn't set flags: no cmdline_file")
                    else:
                        self._CreateFlagChangerIfNeeded(dev)
                        logging.debug('Attempting to set flags: %r',
                                      self._test_instance.flags)
                        self._flag_changers[str(dev)].AddFlags(
                            self._test_instance.flags)

                valgrind_tools.SetChromeTimeoutScale(
                    dev, self._test_instance.timeout_scale)

            steps = (install_apk, edit_shared_prefs, push_test_data,
                     create_flag_changer)
            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(steps)
            else:
                for step in steps:
                    step()
            if self._test_instance.store_tombstones:
                tombstones.ClearAllTombstones(dev)
示例#3
0
        def individual_device_set_up(device, host_device_tuples):
            steps = []

            if self._test_instance.replace_system_package:

                @trace_event.traced
                def replace_package(dev):
                    # We need the context manager to be applied before modifying any
                    # shared preference files in case the replacement APK needs to be
                    # set up, and it needs to be applied while the test is running.
                    # Thus, it needs to be applied early during setup, but must still be
                    # applied during _RunTest, which isn't possible using 'with' without
                    # applying the context manager up in test_runner. Instead, we
                    # manually invoke its __enter__ and __exit__ methods in setup and
                    # teardown.
                    self._replace_package_contextmanager = system_app.ReplaceSystemApp(
                        dev,
                        self._test_instance.replace_system_package.package,
                        self._test_instance.replace_system_package.
                        replacement_apk)
                    self._replace_package_contextmanager.__enter__()

                steps.append(replace_package)

            def install_helper(apk, permissions):
                @instrumentation_tracing.no_tracing
                @trace_event.traced("apk_path")
                def install_helper_internal(d, apk_path=apk.path):
                    # pylint: disable=unused-argument
                    d.Install(apk, permissions=permissions)

                return install_helper_internal

            def incremental_install_helper(apk, json_path):
                @trace_event.traced("apk_path")
                def incremental_install_helper_internal(d, apk_path=apk.path):
                    # pylint: disable=unused-argument
                    installer.Install(d, json_path, apk=apk)

                return incremental_install_helper_internal

            if self._test_instance.apk_under_test:
                if self._test_instance.apk_under_test_incremental_install_json:
                    steps.append(
                        incremental_install_helper(
                            self._test_instance.apk_under_test,
                            self._test_instance.
                            apk_under_test_incremental_install_json))
                else:
                    permissions = self._test_instance.apk_under_test.GetPermissions(
                    )
                    steps.append(
                        install_helper(self._test_instance.apk_under_test,
                                       permissions))

            if self._test_instance.test_apk_incremental_install_json:
                steps.append(
                    incremental_install_helper(
                        self._test_instance.test_apk,
                        self._test_instance.test_apk_incremental_install_json))
            else:
                permissions = self._test_instance.test_apk.GetPermissions()
                steps.append(
                    install_helper(self._test_instance.test_apk, permissions))

            steps.extend(
                install_helper(apk, None)
                for apk in self._test_instance.additional_apks)

            @trace_event.traced
            def set_debug_app(dev):
                # Set debug app in order to enable reading command line flags on user
                # builds
                if self._test_instance.flags:
                    if not self._test_instance.package_info:
                        logging.error(
                            "Couldn't set debug app: no package info")
                    elif not self._test_instance.package_info.package:
                        logging.error(
                            "Couldn't set debug app: no package defined")
                    else:
                        dev.RunShellCommand([
                            'am', 'set-debug-app', '--persistent',
                            self._test_instance.package_info.package
                        ],
                                            check_return=True)

            @trace_event.traced
            def edit_shared_prefs(dev):
                for setting in self._test_instance.edit_shared_prefs:
                    shared_pref = shared_prefs.SharedPrefs(
                        dev, setting['package'], setting['filename'])
                    shared_preference_utils.ApplySharedPreferenceSetting(
                        shared_pref, setting)

            @instrumentation_tracing.no_tracing
            def push_test_data(dev):
                device_root = posixpath.join(dev.GetExternalStoragePath(),
                                             'chromium_tests_root')
                host_device_tuples_substituted = [
                    (h,
                     local_device_test_run.SubstituteDeviceRoot(
                         d, device_root)) for h, d in host_device_tuples
                ]
                logging.info('instrumentation data deps:')
                for h, d in host_device_tuples_substituted:
                    logging.info('%r -> %r', h, d)
                dev.PushChangedFiles(host_device_tuples_substituted,
                                     delete_device_stale=True)
                if not host_device_tuples_substituted:
                    dev.RunShellCommand(['rm', '-rf', device_root],
                                        check_return=True)
                    dev.RunShellCommand(['mkdir', '-p', device_root],
                                        check_return=True)

            @trace_event.traced
            def create_flag_changer(dev):
                if self._test_instance.flags:
                    if not self._test_instance.package_info:
                        logging.error("Couldn't set flags: no package info")
                    elif not self._test_instance.package_info.cmdline_file:
                        logging.error("Couldn't set flags: no cmdline_file")
                    else:
                        self._CreateFlagChangerIfNeeded(dev)
                        logging.debug('Attempting to set flags: %r',
                                      self._test_instance.flags)
                        self._flag_changers[str(dev)].AddFlags(
                            self._test_instance.flags)

                valgrind_tools.SetChromeTimeoutScale(
                    dev, self._test_instance.timeout_scale)

            @trace_event.traced
            def setup_ui_capture_dir(dev):
                # Make sure the UI capture directory exists and is empty by deleting
                # and recreating it.
                # TODO (aberent) once DeviceTempDir exists use it here.
                self._ui_capture_dir[dev] = posixpath.join(
                    dev.GetExternalStoragePath(), *UI_CAPTURE_DIRS)

                if dev.PathExists(self._ui_capture_dir[dev]):
                    dev.RunShellCommand(
                        ['rm', '-rf', self._ui_capture_dir[dev]])
                dev.RunShellCommand(['mkdir', self._ui_capture_dir[dev]])

            steps += [
                set_debug_app, edit_shared_prefs, push_test_data,
                create_flag_changer, setup_ui_capture_dir
            ]

            def bind_crash_handler(step, dev):
                return lambda: crash_handler.RetryOnSystemCrash(step, dev)

            steps = [bind_crash_handler(s, device) for s in steps]

            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(steps)
            else:
                for step in steps:
                    step()
            if self._test_instance.store_tombstones:
                tombstones.ClearAllTombstones(device)
    def individual_device_set_up(dev, host_device_tuples):
      def install_apk():
        if self._test_instance.apk_under_test:
          if self._test_instance.apk_under_test_incremental_install_script:
            local_device_test_run.IncrementalInstall(
                dev,
                self._test_instance.apk_under_test,
                self._test_instance.apk_under_test_incremental_install_script)
          else:
            permissions = self._test_instance.apk_under_test.GetPermissions()
            dev.Install(self._test_instance.apk_under_test,
                        permissions=permissions)

        if self._test_instance.test_apk_incremental_install_script:
          local_device_test_run.IncrementalInstall(
              dev,
              self._test_instance.test_apk,
              self._test_instance.test_apk_incremental_install_script)
        else:
          permissions = self._test_instance.test_apk.GetPermissions()
          dev.Install(self._test_instance.test_apk, permissions=permissions)

        for apk in self._test_instance.additional_apks:
          dev.Install(apk)

        # Set debug app in order to enable reading command line flags on user
        # builds
        if self._test_instance.flags:
          if not self._test_instance.package_info:
            logging.error("Couldn't set debug app: no package info")
          elif not self._test_instance.package_info.package:
            logging.error("Couldn't set debug app: no package defined")
          else:
            dev.RunShellCommand(['am', 'set-debug-app', '--persistent',
                                  self._test_instance.package_info.package],
                                check_return=True)

      def push_test_data():
        device_root = posixpath.join(dev.GetExternalStoragePath(),
                                     'chromium_tests_root')
        host_device_tuples_substituted = [
            (h, substitute_device_root(d, device_root))
            for h, d in host_device_tuples]
        logging.info('instrumentation data deps:')
        for h, d in host_device_tuples_substituted:
          logging.info('%r -> %r', h, d)
        dev.PushChangedFiles(host_device_tuples_substituted,
                             delete_device_stale=True)
        if not host_device_tuples_substituted:
          dev.RunShellCommand(['rm', '-rf', device_root], check_return=True)
          dev.RunShellCommand(['mkdir', '-p', device_root], check_return=True)

      def create_flag_changer():
        if self._test_instance.flags:
          if not self._test_instance.package_info:
            logging.error("Couldn't set flags: no package info")
          elif not self._test_instance.package_info.cmdline_file:
            logging.error("Couldn't set flags: no cmdline_file")
          else:
            self._CreateFlagChangerIfNeeded(dev)
            logging.debug('Attempting to set flags: %r',
                          self._test_instance.flags)
            self._flag_changers[str(dev)].AddFlags(self._test_instance.flags)

        valgrind_tools.SetChromeTimeoutScale(
            dev, self._test_instance.timeout_scale)

      steps = (install_apk, push_test_data, create_flag_changer)
      if self._env.concurrent_adb:
        reraiser_thread.RunAsync(steps)
      else:
        for step in steps:
          step()
      if self._test_instance.store_tombstones:
        tombstones.ClearAllTombstones(dev)
    def _RunTest(self, device, test):
        # Run the test.
        with contextlib_ext.Optional(self._env.Tracing(),
                                     self._env.trace_output):
            timeout = (self._test_instance.shard_timeout *
                       self.GetTool(device).GetTimeoutScale())
            if self._test_instance.store_tombstones:
                tombstones.ClearAllTombstones(device)
            with device_temp_file.DeviceTempFile(
                    adb=device.adb,
                    dir=self._delegate.ResultsDirectory(device),
                    suffix='.xml') as device_tmp_results_file:

                flags = self._test_instance.test_arguments or ''
                if self._test_instance.enable_xml_result_parsing:
                    flags += ' --gtest_output=xml:%s' % device_tmp_results_file.name
                if self._test_instance.gtest_also_run_disabled_tests:
                    flags += ' --gtest_also_run_disabled_tests'

                with contextlib_ext.Optional(trace_event.trace(str(test)),
                                             self._env.trace_output):
                    output = self._delegate.Run(test,
                                                device,
                                                flags=flags,
                                                timeout=timeout,
                                                retries=0)

                if self._test_instance.enable_xml_result_parsing:
                    gtest_xml = device.ReadFile(device_tmp_results_file.name,
                                                as_root=True)

        for s in self._servers[str(device)]:
            s.Reset()
        if self._test_instance.app_files:
            self._delegate.PullAppFiles(device, self._test_instance.app_files,
                                        self._test_instance.app_file_dir)
        if not self._env.skip_clear_data:
            self._delegate.Clear(device)

        # Parse the output.
        # TODO(jbudorick): Transition test scripts away from parsing stdout.
        if self._test_instance.enable_xml_result_parsing:
            results = gtest_test_instance.ParseGTestXML(gtest_xml)
        else:
            results = gtest_test_instance.ParseGTestOutput(output)

        # Check whether there are any crashed testcases.
        self._crashes.update(
            r.GetName() for r in results
            if r.GetType() == base_test_result.ResultType.CRASH)

        if self._test_instance.store_tombstones:
            tombstones_url = None
            for result in results:
                if result.GetType() == base_test_result.ResultType.CRASH:
                    if not tombstones_url:
                        resolved_tombstones = tombstones.ResolveTombstones(
                            device,
                            resolve_all_tombstones=True,
                            include_stack_symbols=False,
                            wipe_tombstones=True)
                        stream_name = 'tombstones_%s_%s' % (time.strftime(
                            '%Y%m%dT%H%M%S', time.localtime()), device.serial)
                        tombstones_url = tombstones.LogdogTombstones(
                            resolved_tombstones, stream_name)
                    result.SetTombstonesUrl(tombstones_url)

        not_run_tests = set(test).difference(set(r.GetName() for r in results))
        return results, list(not_run_tests)
示例#6
0
  def _RunTest(self, device, test):
    # Run the test.
    timeout = (self._test_instance.shard_timeout
               * self.GetTool(device).GetTimeoutScale())
    if self._test_instance.wait_for_java_debugger:
      timeout = None
    if self._test_instance.store_tombstones:
      tombstones.ClearAllTombstones(device)
    test_perf_output_filename = next(self._test_perf_output_filenames)

    with device_temp_file.DeviceTempFile(
        adb=device.adb,
        dir=self._delegate.ResultsDirectory(device),
        suffix='.xml') as device_tmp_results_file:
      with contextlib_ext.Optional(
          device_temp_file.NamedDeviceTemporaryDirectory(
              adb=device.adb, dir='/sdcard/'),
          self._test_instance.gs_test_artifacts_bucket) as test_artifacts_dir:
        with (contextlib_ext.Optional(
            device_temp_file.DeviceTempFile(
                adb=device.adb, dir=self._delegate.ResultsDirectory(device)),
            test_perf_output_filename)) as isolated_script_test_perf_output:

          flags = list(self._test_instance.flags)
          if self._test_instance.enable_xml_result_parsing:
            flags.append('--gtest_output=xml:%s' % device_tmp_results_file.name)

          if self._test_instance.gs_test_artifacts_bucket:
            flags.append('--test_artifacts_dir=%s' % test_artifacts_dir.name)

          if test_perf_output_filename:
            flags.append('--isolated_script_test_perf_output=%s'
                         % isolated_script_test_perf_output.name)

          logging.info('flags:')
          for f in flags:
            logging.info('  %s', f)

          stream_name = 'logcat_%s_%s_%s' % (
              hash(tuple(test)),
              time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()),
              device.serial)

          with self._env.output_manager.ArchivedTempfile(
              stream_name, 'logcat') as logcat_file:
            with logcat_monitor.LogcatMonitor(
                device.adb,
                filter_specs=local_device_environment.LOGCAT_FILTERS,
                output_file=logcat_file.name,
                check_error=False) as logmon:
              with contextlib_ext.Optional(
                  trace_event.trace(str(test)),
                  self._env.trace_output):
                output = self._delegate.Run(
                    test, device, flags=' '.join(flags),
                    timeout=timeout, retries=0)
            logmon.Close()

          if logcat_file.Link():
            logging.info('Logcat saved to %s', logcat_file.Link())

          if self._test_instance.enable_xml_result_parsing:
            try:
              gtest_xml = device.ReadFile(
                  device_tmp_results_file.name,
                  as_root=True)
            except device_errors.CommandFailedError as e:
              logging.warning(
                  'Failed to pull gtest results XML file %s: %s',
                  device_tmp_results_file.name,
                  str(e))
              gtest_xml = None

          if test_perf_output_filename:
            try:
              device.PullFile(isolated_script_test_perf_output.name,
                              test_perf_output_filename)
            except device_errors.CommandFailedError as e:
              logging.warning(
                  'Failed to pull chartjson results %s: %s',
                  isolated_script_test_perf_output.name, str(e))

          test_artifacts_url = self._UploadTestArtifacts(device,
                                                         test_artifacts_dir)

    for s in self._servers[str(device)]:
      s.Reset()
    if self._test_instance.app_files:
      self._delegate.PullAppFiles(device, self._test_instance.app_files,
                                  self._test_instance.app_file_dir)
    if not self._env.skip_clear_data:
      self._delegate.Clear(device)

    for l in output:
      logging.info(l)

    # Parse the output.
    # TODO(jbudorick): Transition test scripts away from parsing stdout.
    if self._test_instance.enable_xml_result_parsing:
      results = gtest_test_instance.ParseGTestXML(gtest_xml)
    else:
      results = gtest_test_instance.ParseGTestOutput(
          output, self._test_instance.symbolizer, device.product_cpu_abi)

    tombstones_url = None
    for r in results:
      if logcat_file:
        r.SetLink('logcat', logcat_file.Link())

      if self._test_instance.gs_test_artifacts_bucket:
        r.SetLink('test_artifacts', test_artifacts_url)

      if r.GetType() == base_test_result.ResultType.CRASH:
        self._crashes.add(r.GetName())
        if self._test_instance.store_tombstones:
          if not tombstones_url:
            resolved_tombstones = tombstones.ResolveTombstones(
                device,
                resolve_all_tombstones=True,
                include_stack_symbols=False,
                wipe_tombstones=True)
            stream_name = 'tombstones_%s_%s' % (
                time.strftime('%Y%m%dT%H%M%S', time.localtime()),
                device.serial)
            tombstones_url = logdog_helper.text(
                stream_name, '\n'.join(resolved_tombstones))
          r.SetLink('tombstones', tombstones_url)

    tests_stripped_disabled_prefix = set()
    for t in test:
      tests_stripped_disabled_prefix.add(
          gtest_test_instance.TestNameWithoutDisabledPrefix(t))
    not_run_tests = tests_stripped_disabled_prefix.difference(
        set(r.GetName() for r in results))
    return results, list(not_run_tests) if results else None
    def _RunTest(self, device, test):
        # Run the test.
        timeout = (self._test_instance.shard_timeout *
                   self.GetTool(device).GetTimeoutScale())
        if self._test_instance.store_tombstones:
            tombstones.ClearAllTombstones(device)
        with device_temp_file.DeviceTempFile(
                adb=device.adb,
                dir=self._delegate.ResultsDirectory(device),
                suffix='.xml') as device_tmp_results_file:

            flags = list(self._test_instance.flags)
            if self._test_instance.enable_xml_result_parsing:
                flags.append('--gtest_output=xml:%s' %
                             device_tmp_results_file.name)

            logging.info('flags:')
            for f in flags:
                logging.info('  %s', f)

            with contextlib_ext.Optional(trace_event.trace(str(test)),
                                         self._env.trace_output):
                output = self._delegate.Run(test,
                                            device,
                                            flags=' '.join(flags),
                                            timeout=timeout,
                                            retries=0)

            if self._test_instance.enable_xml_result_parsing:
                gtest_xml = device.ReadFile(device_tmp_results_file.name,
                                            as_root=True)

        for s in self._servers[str(device)]:
            s.Reset()
        if self._test_instance.app_files:
            self._delegate.PullAppFiles(device, self._test_instance.app_files,
                                        self._test_instance.app_file_dir)
        if not self._env.skip_clear_data:
            self._delegate.Clear(device)

        for l in output:
            logging.info(l)

        # Parse the output.
        # TODO(jbudorick): Transition test scripts away from parsing stdout.
        if self._test_instance.enable_xml_result_parsing:
            results = gtest_test_instance.ParseGTestXML(gtest_xml)
        else:
            results = gtest_test_instance.ParseGTestOutput(output)

        # Check whether there are any crashed testcases.
        self._crashes.update(
            r.GetName() for r in results
            if r.GetType() == base_test_result.ResultType.CRASH)

        if self._test_instance.store_tombstones:
            tombstones_url = None
            for result in results:
                if result.GetType() == base_test_result.ResultType.CRASH:
                    if not tombstones_url:
                        resolved_tombstones = tombstones.ResolveTombstones(
                            device,
                            resolve_all_tombstones=True,
                            include_stack_symbols=False,
                            wipe_tombstones=True)
                        stream_name = 'tombstones_%s_%s' % (time.strftime(
                            '%Y%m%dT%H%M%S', time.localtime()), device.serial)
                        tombstones_url = logdog_helper.text(
                            stream_name, '\n'.join(resolved_tombstones))
                    result.SetLink('tombstones', tombstones_url)

        tests_stripped_disabled_prefix = set()
        for t in test:
            tests_stripped_disabled_prefix.add(
                gtest_test_instance.TestNameWithoutDisabledPrefix(t))
        not_run_tests = tests_stripped_disabled_prefix.difference(
            set(r.GetName() for r in results))
        return results, list(not_run_tests) if results else None