def individual_device_set_up(dev):
            def install_apk():
                # Install test APK.
                self._delegate.Install(dev)

            def push_test_data():
                # Push data dependencies.
                external_storage = dev.GetExternalStoragePath()
                data_deps = self._test_instance.GetDataDependencies()
                host_device_tuples = [
                    (h, d if d is not None else external_storage)
                    for h, d in data_deps
                ]
                dev.PushChangedFiles(host_device_tuples)

            def init_tool_and_start_servers():
                tool = self.GetTool(dev)
                tool.CopyFiles(dev)
                tool.SetupEnvironment()

                self._servers[str(dev)] = []
                if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
                    self._servers[str(dev)].append(
                        local_test_server_spawner.LocalTestServerSpawner(
                            ports.AllocateTestServerPort(), dev, tool))

                for s in self._servers[str(dev)]:
                    s.SetUp()

            steps = (install_apk, push_test_data, init_tool_and_start_servers)
            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(steps)
            else:
                for step in steps:
                    step()
    def RunTests(self):
        # Affinitize the tests.
        if self._test_instance.trace_output:
            assert not trace_event.trace_is_enabled(
            ), 'Tracing already running.'
            trace_event.trace_enable(self._test_instance.trace_output +
                                     '.json')
        self._SplitTestsByAffinity()
        if not self._test_buckets and not self._no_device_tests:
            raise local_device_test_run.NoTestsError()

        def run_no_devices_tests():
            if not self._no_device_tests:
                return []
            s = HostTestShard(self._env,
                              self._test_instance,
                              self._no_device_tests,
                              retries=3,
                              timeout=self._timeout)
            return [s.RunTestsOnShard()]

        def device_shard_helper(shard_id):
            if device_status.IsBlacklisted(str(self._devices[shard_id]),
                                           self._env.blacklist):
                logging.warning(
                    'Device %s is not active. Will not create shard %s.',
                    str(self._devices[shard_id]), shard_id)
                return None
            s = DeviceTestShard(self._env,
                                self._test_instance,
                                self._devices[shard_id],
                                shard_id,
                                self._test_buckets[shard_id],
                                retries=self._env.max_tries,
                                timeout=self._timeout)
            return s.RunTestsOnShard()

        def run_devices_tests():
            if not self._test_buckets:
                return []
            if self._devices is None:
                self._devices = self._GetAllDevices(
                    self._env.devices, self._test_instance.known_devices_file)

            device_indices = range(
                min(len(self._devices), len(self._test_buckets)))
            shards = parallelizer.Parallelizer(device_indices).pMap(
                device_shard_helper)
            return [x for x in shards.pGet(self._timeout) if x is not None]

        host_test_results, device_test_results = reraiser_thread.RunAsync(
            [run_no_devices_tests, run_devices_tests])
        if self._test_instance.trace_output:
            assert trace_event.trace_is_enabled(), 'Tracing not running.'
            trace_event.trace_disable()
            local_device_test_run.LocalDeviceTestRun._JsonToTrace(
                self._test_instance.trace_output + '.json',
                self._test_instance.trace_output)
        return host_test_results + device_test_results
Example #3
0
        def individual_device_set_up(dev, host_device_tuples):
            def install_apk():
                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)

            def push_test_data():
                external_storage = dev.GetExternalStoragePath()
                host_device_tuples_substituted = [
                    (h, substitute_external_storage(d, external_storage))
                    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)

            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()
Example #4
0
        def individual_device_set_up(device, host_device_tuples):
            def install_apk(dev):
                # Install test APK.
                self._delegate.Install(dev)

            def push_test_data(dev):
                # Push data dependencies.
                device_root = self._delegate.GetTestDataRoot(dev)
                host_device_tuples_substituted = [
                    (h,
                     local_device_test_run.SubstituteDeviceRoot(
                         d, device_root)) for h, d in host_device_tuples
                ]
                local_device_environment.place_nomedia_on_device(
                    dev, device_root)
                dev.PushChangedFiles(
                    host_device_tuples_substituted,
                    delete_device_stale=True,
                    # Some gtest suites, e.g. unit_tests, have data dependencies that
                    # can take longer than the default timeout to push. See
                    # crbug.com/791632 for context.
                    timeout=600)
                if not host_device_tuples:
                    dev.RemovePath(device_root,
                                   force=True,
                                   recursive=True,
                                   rename=True)
                    dev.RunShellCommand(['mkdir', '-p', device_root],
                                        check_return=True)

            def init_tool_and_start_servers(dev):
                tool = self.GetTool(dev)
                tool.CopyFiles(dev)
                tool.SetupEnvironment()

                self._servers[str(dev)] = []
                if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
                    self._servers[str(dev)].append(
                        local_test_server_spawner.LocalTestServerSpawner(
                            ports.AllocateTestServerPort(), dev, tool))

                for s in self._servers[str(dev)]:
                    s.SetUp()

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

            steps = [
                bind_crash_handler(s, device)
                for s in (install_apk, push_test_data,
                          init_tool_and_start_servers)
            ]
            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(steps)
            else:
                for step in steps:
                    step()
    def InnerFunc():
      current_thread_group = timeout_retry.CurrentTimeoutThreadGroup()
      self.assertIsNotNone(current_thread_group)

      def InnerInnerFunc():
        self.assertEqual(current_thread_group,
                         timeout_retry.CurrentTimeoutThreadGroup())
        return True
      return reraiser_thread.RunAsync((InnerInnerFunc,))[0]
Example #6
0
def _Execute(concurrently, *funcs):
    """Calls all functions in |funcs| concurrently or in sequence."""
    timer = time_profile.TimeProfile()
    if concurrently:
        reraiser_thread.RunAsync(funcs)
    else:
        for f in funcs:
            f()
    timer.Stop(log=False)
    return timer
Example #7
0
    def RunTests(self):
        def run_no_devices_tests():
            if not self._no_device_tests:
                return []
            s = HostTestShard(self._env,
                              self._test_instance,
                              self._no_device_tests,
                              retries=3,
                              timeout=self._timeout)
            return [s.RunTestsOnShard()]

        def device_shard_helper(shard_id):
            if device_status.IsBlacklisted(str(self._devices[shard_id]),
                                           self._env.blacklist):
                logging.warning(
                    'Device %s is not active. Will not create shard %s.',
                    str(self._devices[shard_id]), shard_id)
                return None
            s = DeviceTestShard(self._env,
                                self._test_instance,
                                self._devices[shard_id],
                                shard_id,
                                self._test_buckets[shard_id],
                                retries=self._env.max_tries,
                                timeout=self._timeout)
            return s.RunTestsOnShard()

        def run_devices_tests():
            if not self._test_buckets:
                return []
            if self._devices is None:
                self._devices = self._GetAllDevices(
                    self._env.devices, self._test_instance.known_devices_file)

            device_indices = range(
                min(len(self._devices), len(self._test_buckets)))
            shards = parallelizer.Parallelizer(device_indices).pMap(
                device_shard_helper)
            return [x for x in shards.pGet(self._timeout) if x is not None]

        # Run the tests.
        with contextlib_ext.Optional(self._env.Tracing(),
                                     self._env.trace_output):
            # Affinitize the tests.
            self._SplitTestsByAffinity()
            if not self._test_buckets and not self._no_device_tests:
                raise local_device_test_run.NoTestsError()
            host_test_results, device_test_results = reraiser_thread.RunAsync(
                [run_no_devices_tests, run_devices_tests])

        return host_test_results + device_test_results
Example #8
0
        def individual_device_set_up(dev, host_device_tuples):
            def install_apk(d):
                # Install test APK.
                self._delegate.Install(d)

            def push_test_data():
                # Push data dependencies.
                device_root = self._delegate.GetTestDataRoot(dev)
                host_device_tuples_substituted = [
                    (h,
                     local_device_test_run.SubstituteDeviceRoot(
                         d, device_root)) for h, d in host_device_tuples
                ]
                dev.PushChangedFiles(host_device_tuples_substituted,
                                     delete_device_stale=True)
                if not host_device_tuples:
                    dev.RemovePath(device_root,
                                   force=True,
                                   recursive=True,
                                   rename=True)
                    dev.RunShellCommand(['mkdir', '-p', device_root],
                                        check_return=True)

            def init_tool_and_start_servers():
                tool = self.GetTool(dev)
                tool.CopyFiles(dev)
                tool.SetupEnvironment()

                self._servers[str(dev)] = []
                if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
                    self._servers[str(dev)].append(
                        local_test_server_spawner.LocalTestServerSpawner(
                            ports.AllocateTestServerPort(), dev, tool))

                for s in self._servers[str(dev)]:
                    s.SetUp()

            steps = (
                lambda: crash_handler.RetryOnSystemCrash(install_apk, dev),
                push_test_data, init_tool_and_start_servers)
            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(steps)
            else:
                for step in steps:
                    step()
Example #9
0
  def RunTests(self, results):
    def run_no_devices_tests():
      if not self._no_device_tests:
        return []
      s = HostTestShard(self._env, self._test_instance, self._no_device_tests,
                        retries=3, timeout=self._timeout)
      return [s.RunTestsOnShard()]

    def device_shard_helper(shard_id):
      if device_status.IsBlacklisted(
           str(self._devices[shard_id]), self._env.blacklist):
        logging.warning('Device %s is not active. Will not create shard %s.',
                        str(self._devices[shard_id]), shard_id)
        return None
      s = DeviceTestShard(self._env, self._test_instance,
                          self._devices[shard_id], shard_id,
                          self._test_buckets[shard_id],
                          retries=self._env.max_tries, timeout=self._timeout)
      return s.RunTestsOnShard()

    def run_devices_tests():
      if not self._test_buckets:
        return []
      if self._devices is None:
        self._devices = self._GetAllDevices(
            self._env.devices, self._test_instance.known_devices_file)

      device_indices = range(min(len(self._devices), len(self._test_buckets)))
      shards = parallelizer.Parallelizer(device_indices).pMap(
          device_shard_helper)
      return [x for x in shards.pGet(self._timeout) if x is not None]

    # Affinitize the tests.
    self._SplitTestsByAffinity()
    if not self._test_buckets and not self._no_device_tests:
      raise local_device_test_run.NoTestsError()
    host_test_results, device_test_results = reraiser_thread.RunAsync(
        [run_no_devices_tests, run_devices_tests])

    # Ideally, results would be populated as early as possible, so that in the
    # event of an exception or timeout, the caller will still have partially
    # populated results. This looks like it can be done prior to dispatching
    # tests, but will hold off on making this change unless it looks like it
    # might provide utility.
    results.extend(host_test_results + device_test_results)
Example #10
0
    def testCrashDuringCommand(self):
        self.device.EnableRoot()
        with device_temp_file.DeviceTempFile(self.device.adb) as trigger_file:

            trigger_text = 'hello world'

            def victim():
                trigger_cmd = 'echo -n %s > %s; sleep 20' % (
                    cmd_helper.SingleQuote(trigger_text),
                    cmd_helper.SingleQuote(trigger_file.name))
                crash_handler.RetryOnSystemCrash(
                    lambda d: d.RunShellCommand(trigger_cmd,
                                                shell=True,
                                                check_return=True,
                                                retries=1,
                                                as_root=True,
                                                timeout=180),
                    device=self.device)
                self.assertEquals(
                    trigger_text,
                    self.device.ReadFile(trigger_file.name, retries=0).strip())
                return True

            def crasher():
                def ready_to_crash():
                    try:
                        return trigger_text == self.device.ReadFile(
                            trigger_file.name, retries=0).strip()
                    except device_errors.CommandFailedError:
                        return False

                timeout_retry.WaitFor(ready_to_crash,
                                      wait_period=2,
                                      max_tries=10)
                if not ready_to_crash():
                    return False
                self.device.adb.Shell('echo c > /proc/sysrq-trigger',
                                      expect_status=None,
                                      timeout=60,
                                      retries=0)
                return True

        self.assertEquals([True, True],
                          reraiser_thread.RunAsync([crasher, victim]))
        def individual_device_set_up(dev):
            def install_apk():
                # Install test APK.
                self._delegate.Install(dev)

            def push_test_data():
                # Push data dependencies.
                device_root = posixpath.join(dev.GetExternalStoragePath(),
                                             'chromium_tests_root')
                data_deps = self._test_instance.GetDataDependencies()
                host_device_tuples = [(h, d if d is not None else device_root)
                                      for h, d in data_deps]
                dev.PushChangedFiles(host_device_tuples,
                                     delete_device_stale=True)
                if not host_device_tuples:
                    dev.RunShellCommand(['rm', '-rf', device_root],
                                        check_return=True)
                    dev.RunShellCommand(['mkdir', '-p', device_root],
                                        check_return=True)

            def init_tool_and_start_servers():
                tool = self.GetTool(dev)
                tool.CopyFiles(dev)
                tool.SetupEnvironment()

                self._servers[str(dev)] = []
                if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
                    self._servers[str(dev)].append(
                        local_test_server_spawner.LocalTestServerSpawner(
                            ports.AllocateTestServerPort(), dev, tool))

                for s in self._servers[str(dev)]:
                    s.SetUp()

            steps = (install_apk, push_test_data, init_tool_and_start_servers)
            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(steps)
            else:
                for step in steps:
                    step()
Example #12
0
 def testTwoArgs(self):
     a, b = reraiser_thread.RunAsync((lambda: 1, lambda: 2))
     self.assertEqual(1, a)
     self.assertEqual(2, b)
Example #13
0
 def testOneArg(self):
     results = reraiser_thread.RunAsync([lambda: 1])
     self.assertEqual([1], results)
Example #14
0
 def testNoArgs(self):
     results = reraiser_thread.RunAsync([])
     self.assertEqual([], results)
Example #15
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 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, 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 individual_device_set_up(device, host_device_tuples):
            def install_apk(dev):
                # Install test APK.
                self._delegate.Install(dev)

            def push_test_data(dev):
                # Push data dependencies.
                device_root = self._delegate.GetTestDataRoot(dev)
                host_device_tuples_substituted = [
                    (h,
                     local_device_test_run.SubstituteDeviceRoot(
                         d, device_root)) for h, d in host_device_tuples
                ]
                local_device_environment.place_nomedia_on_device(
                    dev, device_root)
                dev.PushChangedFiles(
                    host_device_tuples_substituted,
                    delete_device_stale=True,
                    # Some gtest suites, e.g. unit_tests, have data dependencies that
                    # can take longer than the default timeout to push. See
                    # crbug.com/791632 for context.
                    timeout=600)
                if not host_device_tuples:
                    dev.RemovePath(device_root,
                                   force=True,
                                   recursive=True,
                                   rename=True)
                    dev.RunShellCommand(['mkdir', '-p', device_root],
                                        check_return=True)

            def init_tool_and_start_servers(dev):
                tool = self.GetTool(dev)
                tool.CopyFiles(dev)
                tool.SetupEnvironment()

                try:
                    # See https://crbug.com/1030827.
                    # This is a hack that may break in the future. We're relying on the
                    # fact that adb doesn't use ipv6 for it's server, and so doesn't
                    # listen on ipv6, but ssh remote forwarding does. 5037 is the port
                    # number adb uses for its server.
                    if "[::1]:5037" in subprocess.check_output(
                            "ss -o state listening 'sport = 5037'",
                            shell=True):
                        logging.error(
                            'Test Server cannot be started with a remote-forwarded adb '
                            'server. Continuing anyways, but some tests may fail.'
                        )
                        return
                except subprocess.CalledProcessError:
                    pass

                self._servers[str(dev)] = []
                if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
                    self._servers[str(dev)].append(
                        local_test_server_spawner.LocalTestServerSpawner(
                            ports.AllocateTestServerPort(), dev, tool))

                for s in self._servers[str(dev)]:
                    s.SetUp()

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

            steps = [
                bind_crash_handler(s, device)
                for s in (install_apk, push_test_data,
                          init_tool_and_start_servers)
            ]
            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(steps)
            else:
                for step in steps:
                    step()
Example #17
0
def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('apk_path',
                      help='The path to the APK to install.')
  parser.add_argument('--split',
                      action='append',
                      dest='splits',
                      help='A glob matching the apk splits. '
                           'Can be specified multiple times.')
  parser.add_argument('--lib-dir',
                      help='Path to native libraries directory.')
  parser.add_argument('--dex-files',
                      help='List of dex files to push.',
                      action='append',
                      default=[])
  parser.add_argument('-d', '--device', dest='device',
                      help='Target device for apk to install on.')
  parser.add_argument('--uninstall',
                      action='store_true',
                      default=False,
                      help='Remove the app and all side-loaded files.')
  parser.add_argument('--output-directory',
                      help='Path to the root build directory.')
  parser.add_argument('--no-threading',
                      action='store_true',
                      default=False,
                      help='Do not install and push concurrently')
  parser.add_argument('-v',
                      '--verbose',
                      dest='verbose_count',
                      default=0,
                      action='count',
                      help='Verbose level (multiple times for more)')

  args = parser.parse_args()

  run_tests_helper.SetLogLevel(args.verbose_count)
  constants.SetBuildType('Debug')
  if args.output_directory:
    constants.SetOutputDirectory(args.output_directory)

  main_timer = time_profile.TimeProfile()
  install_timer = time_profile.TimeProfile()
  push_native_timer = time_profile.TimeProfile()
  push_dex_timer = time_profile.TimeProfile()

  if args.device:
    # Retries are annoying when commands fail for legitimate reasons. Might want
    # to enable them if this is ever used on bots though.
    device = device_utils.DeviceUtils(args.device, default_retries=0)
  else:
    devices = device_utils.DeviceUtils.HealthyDevices(default_retries=0)
    if not devices:
      raise device_errors.NoDevicesError()
    elif len(devices) == 1:
      device = devices[0]
    else:
      all_devices = device_utils.DeviceUtils.parallel(devices)
      msg = ('More than one device available.\n'
             'Use --device=SERIAL to select a device.\n'
             'Available devices:\n')
      descriptions = all_devices.pMap(lambda d: d.build_description).pGet(None)
      for d, desc in zip(devices, descriptions):
        msg += '  %s (%s)\n' % (d, desc)
      raise Exception(msg)

  apk_help = apk_helper.ApkHelper(args.apk_path)
  apk_package = apk_help.GetPackageName()
  device_incremental_dir = '/data/local/tmp/incremental-app-%s' % apk_package

  if args.uninstall:
    device.Uninstall(apk_package)
    device.RunShellCommand(['rm', '-rf', device_incremental_dir],
                           check_return=True)
    logging.info('Uninstall took %s seconds.', main_timer.GetDelta())
    return

  if device.build_version_sdk >= version_codes.MARSHMALLOW:
    if apk_help.HasIsolatedProcesses():
      raise Exception('Cannot use perform incremental installs on Android M+ '
                      'without first disabling isolated processes. Use GN arg: '
                      'disable_incremental_isolated_processes=true to do so.')

  # Install .apk(s) if any of them have changed.
  def do_install():
    install_timer.Start()
    if args.splits:
      splits = []
      for split_glob in args.splits:
        splits.extend((f for f in glob.glob(split_glob)))
      device.InstallSplitApk(args.apk_path, splits, reinstall=True,
                             allow_cached_props=True, permissions=())
    else:
      device.Install(args.apk_path, reinstall=True, permissions=())
    install_timer.Stop(log=False)

  # Push .so and .dex files to the device (if they have changed).
  def do_push_files():
    if args.lib_dir:
      push_native_timer.Start()
      device_lib_dir = posixpath.join(device_incremental_dir, 'lib')
      device.PushChangedFiles([(args.lib_dir, device_lib_dir)],
                              delete_device_stale=True)
      push_native_timer.Stop(log=False)

    if args.dex_files:
      push_dex_timer.Start()
      # Put all .dex files to be pushed into a temporary directory so that we
      # can use delete_device_stale=True.
      with build_utils.TempDir() as temp_dir:
        device_dex_dir = posixpath.join(device_incremental_dir, 'dex')
        # Ensure no two files have the same name.
        transformed_names = _TransformDexPaths(args.dex_files)
        for src_path, dest_name in zip(args.dex_files, transformed_names):
          shutil.copyfile(src_path, os.path.join(temp_dir, dest_name))
        device.PushChangedFiles([(temp_dir, device_dex_dir)],
                                delete_device_stale=True)
      push_dex_timer.Stop(log=False)

  # Create 2 lock files:
  # * install.lock tells the app to pause on start-up (until we release it).
  # * firstrun.lock is used by the app to pause all secondary processes until
  #   the primary process finishes loading the .dex / .so files.
  def create_lock_files():
    # Creates or zeros out lock files.
    cmd = ('D="%s";'
           'mkdir -p $D &&'
           'echo -n >$D/install.lock 2>$D/firstrun.lock')
    device.RunShellCommand(cmd % device_incremental_dir, check_return=True)

  # The firstrun.lock is released by the app itself.
  def release_installer_lock():
    device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir,
                           check_return=True)

  create_lock_files()
  # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't
  # been designed for multi-threading. Enabling only because this is a
  # developer-only tool.
  if args.no_threading:
    do_install()
    do_push_files()
  else:
    reraiser_thread.RunAsync((do_install, do_push_files))
  release_installer_lock()
  logging.info('Took %s seconds (install=%s, libs=%s, dex=%s)',
               main_timer.GetDelta(), install_timer.GetDelta(),
               push_native_timer.GetDelta(), push_dex_timer.GetDelta())
Example #18
0
    def _RunTest(self, device, test):
        extras = {}

        # Provide package name under test for apk_under_test.
        if self._test_instance.apk_under_test:
            package_name = self._test_instance.apk_under_test.GetPackageName()
            extras[_EXTRA_PACKAGE_UNDER_TEST] = package_name

        flags_to_add = []
        test_timeout_scale = None
        if self._test_instance.coverage_directory:
            coverage_basename = '%s.exec' % (
                '%s_%s_group' %
                (test[0]['class'], test[0]['method']) if isinstance(
                    test, list) else '%s_%s' % (test['class'], test['method']))
            extras['coverage'] = 'true'
            coverage_directory = os.path.join(device.GetExternalStoragePath(),
                                              'chrome', 'test', 'coverage')
            if not device.PathExists(coverage_directory):
                device.RunShellCommand(['mkdir', '-p', coverage_directory],
                                       check_return=True)
            coverage_device_file = os.path.join(coverage_directory,
                                                coverage_basename)
            extras['coverageFile'] = coverage_device_file
        # Save screenshot if screenshot dir is specified (save locally) or if
        # a GS bucket is passed (save in cloud).
        screenshot_device_file = device_temp_file.DeviceTempFile(
            device.adb, suffix='.png', dir=device.GetExternalStoragePath())
        extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name

        # Set up the screenshot directory. This needs to be done for each test so
        # that we only get screenshots created by that test. It has to be on
        # external storage since the default location doesn't allow file creation
        # from the instrumentation test app on Android L and M.
        ui_capture_dir = device_temp_file.NamedDeviceTemporaryDirectory(
            device.adb, dir=device.GetExternalStoragePath())
        extras[EXTRA_UI_CAPTURE_DIR] = ui_capture_dir.name

        if self._env.trace_output:
            trace_device_file = device_temp_file.DeviceTempFile(
                device.adb,
                suffix='.json',
                dir=device.GetExternalStoragePath())
            extras[EXTRA_TRACE_FILE] = trace_device_file.name

        if isinstance(test, list):
            if not self._test_instance.driver_apk:
                raise Exception('driver_apk does not exist. '
                                'Please build it and try again.')
            if any(t.get('is_junit4') for t in test):
                raise Exception('driver apk does not support JUnit4 tests')

            def name_and_timeout(t):
                n = instrumentation_test_instance.GetTestName(t)
                i = self._GetTimeoutFromAnnotations(t['annotations'], n)
                return (n, i)

            test_names, timeouts = zip(*(name_and_timeout(t) for t in test))

            test_name = ','.join(test_names)
            test_display_name = test_name
            target = '%s/%s' % (self._test_instance.driver_package,
                                self._test_instance.driver_name)
            extras.update(
                self._test_instance.GetDriverEnvironmentVars(
                    test_list=test_names))
            timeout = sum(timeouts)
        else:
            test_name = instrumentation_test_instance.GetTestName(test)
            test_display_name = self._GetUniqueTestName(test)
            if test['is_junit4']:
                target = '%s/%s' % (self._test_instance.test_package,
                                    self._test_instance.junit4_runner_class)
            else:
                target = '%s/%s' % (self._test_instance.test_package,
                                    self._test_instance.junit3_runner_class)
            extras['class'] = test_name
            if 'flags' in test and test['flags']:
                flags_to_add.extend(test['flags'])
            timeout = self._GetTimeoutFromAnnotations(test['annotations'],
                                                      test_display_name)

            test_timeout_scale = self._GetTimeoutScaleFromAnnotations(
                test['annotations'])
            if test_timeout_scale and test_timeout_scale != 1:
                valgrind_tools.SetChromeTimeoutScale(
                    device,
                    test_timeout_scale * self._test_instance.timeout_scale)

        if self._test_instance.wait_for_java_debugger:
            timeout = None
        logging.info('preparing to run %s: %s', test_display_name, test)

        render_tests_device_output_dir = None
        if _IsRenderTest(test):
            # TODO(mikecase): Add DeviceTempDirectory class and use that instead.
            render_tests_device_output_dir = posixpath.join(
                device.GetExternalStoragePath(), 'render_test_output_dir')
            flags_to_add.append('--render-test-output-dir=%s' %
                                render_tests_device_output_dir)

        if flags_to_add:
            self._CreateFlagChangerIfNeeded(device)
            self._flag_changers[str(device)].PushFlags(add=flags_to_add)

        time_ms = lambda: int(time.time() * 1e3)
        start_ms = time_ms()

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

        with ui_capture_dir:
            with self._env.output_manager.ArchivedTempfile(
                    stream_name, 'logcat') as logcat_file:
                logmon = None
                try:
                    with logcat_monitor.LogcatMonitor(
                            device.adb,
                            filter_specs=local_device_environment.
                            LOGCAT_FILTERS,
                            output_file=logcat_file.name,
                            transform_func=self._test_instance.
                            MaybeDeobfuscateLines,
                            check_error=False) as logmon:
                        with _LogTestEndpoints(device, test_name):
                            with contextlib_ext.Optional(
                                    trace_event.trace(test_name),
                                    self._env.trace_output):
                                output = device.StartInstrumentation(
                                    target,
                                    raw=True,
                                    extras=extras,
                                    timeout=timeout,
                                    retries=0)
                finally:
                    if logmon:
                        logmon.Close()

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

            duration_ms = time_ms() - start_ms

            with contextlib_ext.Optional(trace_event.trace('ProcessResults'),
                                         self._env.trace_output):
                output = self._test_instance.MaybeDeobfuscateLines(output)
                # TODO(jbudorick): Make instrumentation tests output a JSON so this
                # doesn't have to parse the output.
                result_code, result_bundle, statuses = (
                    self._test_instance.ParseAmInstrumentRawOutput(output))
                results = self._test_instance.GenerateTestResults(
                    result_code, result_bundle, statuses, start_ms,
                    duration_ms, device.product_cpu_abi,
                    self._test_instance.symbolizer)

            if self._env.trace_output:
                self._SaveTraceData(trace_device_file, device, test['class'])

            def restore_flags():
                if flags_to_add:
                    self._flag_changers[str(device)].Restore()

            def restore_timeout_scale():
                if test_timeout_scale:
                    valgrind_tools.SetChromeTimeoutScale(
                        device, self._test_instance.timeout_scale)

            def handle_coverage_data():
                if self._test_instance.coverage_directory:
                    try:
                        if not os.path.exists(
                                self._test_instance.coverage_directory):
                            os.makedirs(self._test_instance.coverage_directory)
                        device.PullFile(coverage_device_file,
                                        self._test_instance.coverage_directory)
                        device.RemovePath(coverage_device_file, True)
                    except (OSError, base_error.BaseError) as e:
                        logging.warning(
                            'Failed to handle coverage data after tests: %s',
                            e)

            def handle_render_test_data():
                if _IsRenderTest(test):
                    # Render tests do not cause test failure by default. So we have to
                    # check to see if any failure images were generated even if the test
                    # does not fail.
                    try:
                        self._ProcessRenderTestResults(
                            device, render_tests_device_output_dir, results)
                    finally:
                        device.RemovePath(render_tests_device_output_dir,
                                          recursive=True,
                                          force=True)

            def pull_ui_screen_captures():
                screenshots = []
                for filename in device.ListDirectory(ui_capture_dir.name):
                    if filename.endswith('.json'):
                        screenshots.append(pull_ui_screenshot(filename))
                if screenshots:
                    json_archive_name = 'ui_capture_%s_%s.json' % (
                        test_name.replace('#', '.'),
                        time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))
                    with self._env.output_manager.ArchivedTempfile(
                            json_archive_name, 'ui_capture',
                            output_manager.Datatype.JSON) as json_archive:
                        json.dump(screenshots, json_archive)
                    for result in results:
                        result.SetLink('ui screenshot', json_archive.Link())

            def pull_ui_screenshot(filename):
                source_dir = ui_capture_dir.name
                json_path = posixpath.join(source_dir, filename)
                json_data = json.loads(device.ReadFile(json_path))
                image_file_path = posixpath.join(source_dir,
                                                 json_data['location'])
                with self._env.output_manager.ArchivedTempfile(
                        json_data['location'], 'ui_capture',
                        output_manager.Datatype.PNG) as image_archive:
                    device.PullFile(image_file_path, image_archive.name)
                json_data['image_link'] = image_archive.Link()
                return json_data

            # While constructing the TestResult objects, we can parallelize several
            # steps that involve ADB. These steps should NOT depend on any info in
            # the results! Things such as whether the test CRASHED have not yet been
            # determined.
            post_test_steps = [
                restore_flags, restore_timeout_scale, handle_coverage_data,
                handle_render_test_data, pull_ui_screen_captures
            ]
            if self._env.concurrent_adb:
                reraiser_thread.RunAsync(post_test_steps)
            else:
                for step in post_test_steps:
                    step()

        for result in results:
            if logcat_file:
                result.SetLink('logcat', logcat_file.Link())

        # Update the result name if the test used flags.
        if flags_to_add:
            for r in results:
                if r.GetName() == test_name:
                    r.SetName(test_display_name)

        # Add UNKNOWN results for any missing tests.
        iterable_test = test if isinstance(test, list) else [test]
        test_names = set(self._GetUniqueTestName(t) for t in iterable_test)
        results_names = set(r.GetName() for r in results)
        results.extend(
            base_test_result.BaseTestResult(
                u, base_test_result.ResultType.UNKNOWN)
            for u in test_names.difference(results_names))

        # Update the result type if we detect a crash.
        try:
            if DidPackageCrashOnDevice(self._test_instance.test_package,
                                       device):
                for r in results:
                    if r.GetType() == base_test_result.ResultType.UNKNOWN:
                        r.SetType(base_test_result.ResultType.CRASH)
        except device_errors.CommandTimeoutError:
            logging.warning(
                'timed out when detecting/dismissing error dialogs')
            # Attach screenshot to the test to help with debugging the dialog boxes.
            self._SaveScreenshot(device, screenshot_device_file,
                                 test_display_name, results,
                                 'dialog_box_screenshot')

        # Handle failures by:
        #   - optionally taking a screenshot
        #   - logging the raw output at INFO level
        #   - clearing the application state while persisting permissions
        if any(r.GetType() not in (base_test_result.ResultType.PASS,
                                   base_test_result.ResultType.SKIP)
               for r in results):
            self._SaveScreenshot(device, screenshot_device_file,
                                 test_display_name, results,
                                 'post_test_screenshot')

            logging.info('detected failure in %s. raw output:',
                         test_display_name)
            for l in output:
                logging.info('  %s', l)
            if (not self._env.skip_clear_data
                    and self._test_instance.package_info):
                permissions = (
                    self._test_instance.apk_under_test.GetPermissions()
                    if self._test_instance.apk_under_test else None)
                device.ClearApplicationState(
                    self._test_instance.package_info.package,
                    permissions=permissions)
        else:
            logging.debug('raw output from %s:', test_display_name)
            for l in output:
                logging.debug('  %s', l)
        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,
                            tombstone_symbolizer=self._test_instance.symbolizer
                        )
                        tombstone_filename = 'tombstones_%s_%s' % (
                            time.strftime('%Y%m%dT%H%M%S-UTC',
                                          time.gmtime()), device.serial)
                        with self._env.output_manager.ArchivedTempfile(
                                tombstone_filename,
                                'tombstones') as tombstone_file:
                            tombstone_file.write(
                                '\n'.join(resolved_tombstones))
                        result.SetLink('tombstones', tombstone_file.Link())
        return results, None
Example #19
0
        def individual_device_set_up(dev, host_device_tuples):
            steps = []

            if self._test_instance.replace_system_package:
                # 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)
                steps.append(self._replace_package_contextmanager.__enter__)

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

                return lambda: crash_handler.RetryOnSystemCrash(
                    install_helper_internal, dev)

            def incremental_install_helper(apk, script):
                @trace_event.traced("apk_path")
                def incremental_install_helper_internal(d, apk_path=apk.path):
                    # pylint: disable=unused-argument
                    local_device_test_run.IncrementalInstall(d, apk, script)

                return lambda: crash_handler.RetryOnSystemCrash(
                    incremental_install_helper_internal, dev)

            if self._test_instance.apk_under_test:
                if self._test_instance.apk_under_test_incremental_install_script:
                    steps.append(
                        incremental_install_helper(
                            self._test_instance.apk_under_test,
                            self._test_instance.
                            apk_under_test_incremental_install_script))
                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_script:
                steps.append(
                    incremental_install_helper(
                        self._test_instance.test_apk, self._test_instance.
                        test_apk_incremental_install_script))
            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():
                # 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():
                shared_preference_utils.ApplySharedPreferenceSettings(
                    dev, self._test_instance.edit_shared_prefs)

            @trace_event.traced
            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)

            @trace_event.traced
            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)

            @trace_event.traced
            def setup_ui_capture_dir():
                # 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
            ]
            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 individual_device_set_up(dev, host_device_tuples):
            steps = []

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

                return install_helper_internal

            def incremental_install_helper(dev, apk, script):
                @trace_event.traced("apk_path")
                def incremental_install_helper_internal(apk_path=apk.path):
                    # pylint: disable=unused-argument
                    local_device_test_run.IncrementalInstall(dev, apk, script)

                return incremental_install_helper_internal

            if self._test_instance.apk_under_test:
                if self._test_instance.apk_under_test_incremental_install_script:
                    steps.append(
                        incremental_install_helper(
                            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(
                    )
                    steps.append(
                        install_helper(self._test_instance.apk_under_test,
                                       permissions))

            if self._test_instance.test_apk_incremental_install_script:
                steps.append(
                    incremental_install_helper(
                        dev, self._test_instance.test_apk, self._test_instance.
                        test_apk_incremental_install_script))
            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():
                # 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():
                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()

            @trace_event.traced
            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)

            @trace_event.traced
            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 += [
                set_debug_app, 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)
    def RunTests(self):
        with tempfile_ext.NamedTemporaryDirectory() as temp_dir:
            json_file_path = os.path.join(temp_dir, 'results.json')

            # Extract resources needed for test.
            # TODO(mikecase): Investigate saving md5sums of zipfiles, and only
            # extract zipfiles when they change.
            def extract_resource_zip(resource_zip):
                def helper():
                    extract_dest = os.path.join(
                        temp_dir,
                        os.path.splitext(os.path.basename(resource_zip))[0])
                    with zipfile.ZipFile(resource_zip, 'r') as zf:
                        zf.extractall(extract_dest)
                    return extract_dest

                return helper

            resource_dirs = reraiser_thread.RunAsync([
                extract_resource_zip(resource_zip)
                for resource_zip in self._test_instance.resource_zips
                if os.path.exists(resource_zip)
            ])

            java_script = os.path.join(constants.GetOutDirectory(), 'bin',
                                       'helper', self._test_instance.suite)
            command = [java_script]

            # Add Jar arguments.
            jar_args = [
                '-test-jars', self._test_instance.suite + '.jar',
                '-json-results-file', json_file_path
            ]
            if self._test_instance.test_filter:
                jar_args.extend(
                    ['-gtest-filter', self._test_instance.test_filter])
            if self._test_instance.package_filter:
                jar_args.extend(
                    ['-package-filter', self._test_instance.package_filter])
            if self._test_instance.runner_filter:
                jar_args.extend(
                    ['-runner-filter', self._test_instance.runner_filter])
            command.extend(['--jar-args', '"%s"' % ' '.join(jar_args)])

            # Add JVM arguments.
            jvm_args = [
                '-Drobolectric.dependency.dir=%s' %
                self._test_instance.robolectric_runtime_deps_dir,
                '-Ddir.source.root=%s' % constants.DIR_SOURCE_ROOT,
            ]

            if self._test_instance.android_manifest_path:
                jvm_args += [
                    '-Dchromium.robolectric.manifest=%s' %
                    self._test_instance.android_manifest_path
                ]

            if self._test_instance.package_name:
                jvm_args += [
                    '-Dchromium.robolectric.package.name=%s' %
                    self._test_instance.package_name
                ]

            if resource_dirs:
                jvm_args += [
                    '-Dchromium.robolectric.resource.dirs=%s' %
                    ':'.join(resource_dirs)
                ]

            if self._test_instance.coverage_dir:
                if not os.path.exists(self._test_instance.coverage_dir):
                    os.makedirs(self._test_instance.coverage_dir)
                elif not os.path.isdir(self._test_instance.coverage_dir):
                    raise Exception(
                        '--coverage-dir takes a directory, not file path.')
                jvm_args.append(
                    '-Demma.coverage.out.file=%s' %
                    os.path.join(self._test_instance.coverage_dir,
                                 '%s.ec' % self._test_instance.suite))

            if jvm_args:
                command.extend(['--jvm-args', '"%s"' % ' '.join(jvm_args)])

            cmd_helper.RunCmd(command)
            with open(json_file_path, 'r') as f:
                results_list = json_results.ParseResultsFromJson(
                    json.loads(f.read()))

            test_run_results = base_test_result.TestRunResults()
            test_run_results.AddResults(results_list)

            return [test_run_results]
Example #22
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)
                    # 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)

            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)

            @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
            ]

            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
    def RunTests(self, results):
        with tempfile_ext.NamedTemporaryDirectory() as temp_dir:
            json_file_path = os.path.join(temp_dir, 'results.json')

            # Extract resources needed for test.
            # TODO(mikecase): Investigate saving md5sums of zipfiles, and only
            # extract zipfiles when they change.
            def extract_resource_zip(resource_zip):
                def helper():
                    extract_dest = os.path.join(
                        temp_dir,
                        os.path.splitext(os.path.basename(resource_zip))[0])
                    with zipfile.ZipFile(resource_zip, 'r') as zf:
                        zf.extractall(extract_dest)
                    return extract_dest

                return helper

            resource_dirs = reraiser_thread.RunAsync([
                extract_resource_zip(resource_zip)
                for resource_zip in self._test_instance.resource_zips
                if os.path.exists(resource_zip)
            ])

            java_script = os.path.join(constants.GetOutDirectory(), 'bin',
                                       'helper', self._test_instance.suite)
            command = [java_script]

            # Add Jar arguments.
            jar_args = [
                '-test-jars', self._test_instance.suite + '.jar',
                '-json-results-file', json_file_path
            ]
            if self._test_instance.test_filter:
                jar_args.extend(
                    ['-gtest-filter', self._test_instance.test_filter])
            if self._test_instance.package_filter:
                jar_args.extend(
                    ['-package-filter', self._test_instance.package_filter])
            if self._test_instance.runner_filter:
                jar_args.extend(
                    ['-runner-filter', self._test_instance.runner_filter])
            command.extend(['--jar-args', '"%s"' % ' '.join(jar_args)])

            # Add JVM arguments.
            jvm_args = [
                '-Drobolectric.dependency.dir=%s' %
                self._test_instance.robolectric_runtime_deps_dir,
                '-Ddir.source.root=%s' % constants.DIR_SOURCE_ROOT,
            ]

            if self._test_instance.android_manifest_path:
                jvm_args += [
                    '-Dchromium.robolectric.manifest=%s' %
                    self._test_instance.android_manifest_path
                ]

            if self._test_instance.package_name:
                jvm_args += [
                    '-Dchromium.robolectric.package.name=%s' %
                    self._test_instance.package_name
                ]

            if resource_dirs:
                jvm_args += [
                    '-Dchromium.robolectric.resource.dirs=%s' %
                    ':'.join(resource_dirs)
                ]

            if logging.getLogger().isEnabledFor(logging.INFO):
                jvm_args += ['-Drobolectric.logging=stdout']

            if self._test_instance.debug_socket:
                jvm_args += [
                    '-agentlib:jdwp=transport=dt_socket'
                    ',server=y,suspend=y,address=%s' %
                    self._test_instance.debug_socket
                ]

            if self._test_instance.coverage_dir:
                if not os.path.exists(self._test_instance.coverage_dir):
                    os.makedirs(self._test_instance.coverage_dir)
                elif not os.path.isdir(self._test_instance.coverage_dir):
                    raise Exception(
                        '--coverage-dir takes a directory, not file path.')
                jvm_args.append(
                    '-Demma.coverage.out.file=%s' %
                    os.path.join(self._test_instance.coverage_dir,
                                 '%s.ec' % self._test_instance.suite))

            if jvm_args:
                command.extend(['--jvm-args', '"%s"' % ' '.join(jvm_args)])

            cmd_helper.RunCmd(command)
            try:
                with open(json_file_path, 'r') as f:
                    results_list = json_results.ParseResultsFromJson(
                        json.loads(f.read()))
            except IOError:
                # In the case of a failure in the JUnit or Robolectric test runner
                # the output json file may never be written.
                results_list = [
                    base_test_result.BaseTestResult(
                        'Test Runner Failure',
                        base_test_result.ResultType.UNKNOWN)
                ]

            test_run_results = base_test_result.TestRunResults()
            test_run_results.AddResults(results_list)
            results.append(test_run_results)
Example #24
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)
                    # 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,
                               modules=None,
                               fake_modules=None,
                               permissions=None):
                @instrumentation_tracing.no_tracing
                @trace_event.traced
                def install_helper_internal(d, apk_path=None):
                    # pylint: disable=unused-argument
                    logging.info('Start Installing %s', apk.path)
                    d.Install(apk,
                              modules=modules,
                              fake_modules=fake_modules,
                              permissions=permissions)
                    logging.info('Finished Installing %s', apk.path)

                return install_helper_internal

            def incremental_install_helper(apk, json_path, permissions):
                @trace_event.traced
                def incremental_install_helper_internal(d, apk_path=None):
                    # pylint: disable=unused-argument
                    logging.info('Start Incremental Installing %s', apk.path)
                    installer.Install(d,
                                      json_path,
                                      apk=apk,
                                      permissions=permissions)
                    logging.info('Finished Incremental Installing %s',
                                 apk.path)

                return incremental_install_helper_internal

            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=permissions))

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

            # The apk under test needs to be installed last since installing other
            # apks after will unintentionally clear the fake module directory.
            # TODO(wnwen): Make this more robust, fix crbug.com/1010954.
            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,
                                       self._test_instance.modules,
                                       self._test_instance.fake_modules,
                                       permissions))

            @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('Pushing data dependencies.')
                for h, d in host_device_tuples_substituted:
                    logging.debug('  %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
    def individual_device_set_up(device, host_device_tuples):
      def install_apk(dev):
        # Install test APK.
        self._delegate.Install(dev)

      def push_test_data(dev):
        if self._test_instance.use_existing_test_data:
          return
        # Push data dependencies.
        device_root = self._delegate.GetTestDataRoot(dev)
        host_device_tuples_substituted = [
            (h, local_device_test_run.SubstituteDeviceRoot(d, device_root))
            for h, d in host_device_tuples]
        local_device_environment.place_nomedia_on_device(dev, device_root)
        dev.PushChangedFiles(
            host_device_tuples_substituted,
            delete_device_stale=True,
            # Some gtest suites, e.g. unit_tests, have data dependencies that
            # can take longer than the default timeout to push. See
            # crbug.com/791632 for context.
            timeout=600 * math.ceil(_GetDeviceTimeoutMultiplier() / 10))
        if not host_device_tuples:
          dev.RemovePath(device_root, force=True, recursive=True, rename=True)
          dev.RunShellCommand(['mkdir', '-p', device_root], check_return=True)

      def init_tool_and_start_servers(dev):
        tool = self.GetTool(dev)
        tool.CopyFiles(dev)
        tool.SetupEnvironment()

        try:
          # See https://crbug.com/1030827.
          # This is a hack that may break in the future. We're relying on the
          # fact that adb doesn't use ipv6 for it's server, and so doesn't
          # listen on ipv6, but ssh remote forwarding does. 5037 is the port
          # number adb uses for its server.
          if "[::1]:5037" in subprocess.check_output(
              "ss -o state listening 'sport = 5037'", shell=True):
            logging.error(
                'Test Server cannot be started with a remote-forwarded adb '
                'server. Continuing anyways, but some tests may fail.')
            return
        except subprocess.CalledProcessError:
          pass

        self._servers[str(dev)] = []
        if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
          self._servers[str(dev)].append(
              local_test_server_spawner.LocalTestServerSpawner(
                  ports.AllocateTestServerPort(), dev, tool))

        for s in self._servers[str(dev)]:
          s.SetUp()

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

      # Explicitly enable root to ensure that tests run under deterministic
      # conditions. Without this explicit call, EnableRoot() is called from
      # push_test_data() when PushChangedFiles() determines that it should use
      # _PushChangedFilesZipped(), which is only most of the time.
      # Root is required (amongst maybe other reasons) to pull the results file
      # from the device, since it lives within the application's data directory
      # (via GetApplicationDataDirectory()).
      device.EnableRoot()

      steps = [
          bind_crash_handler(s, device)
          for s in (install_apk, push_test_data, init_tool_and_start_servers)]
      if self._env.concurrent_adb:
        reraiser_thread.RunAsync(steps)
      else:
        for step in steps:
          step()