Example #1
0
  def extract_test_data(self):
    """Extracts data emitted by the test."""
    if hasattr(self, 'use_clang_coverage') and self.use_clang_coverage:
      file_util.move_raw_coverage_data(self.udid, self.out_dir)

    # Find the Documents directory of the test app. The app directory names
    # don't correspond with any known information, so we have to examine them
    # all until we find one with a matching CFBundleIdentifier.
    apps_dir = os.path.join(
        self.homedir, 'Containers', 'Data', 'Application')
    if os.path.exists(apps_dir):
      for appid_dir in os.listdir(apps_dir):
        docs_dir = os.path.join(apps_dir, appid_dir, 'Documents')
        metadata_plist = os.path.join(
            apps_dir,
            appid_dir,
            '.com.apple.mobile_container_manager.metadata.plist',
        )
        if os.path.exists(docs_dir) and os.path.exists(metadata_plist):
          cfbundleid = subprocess.check_output([
              '/usr/libexec/PlistBuddy',
              '-c', 'Print:MCMMetadataIdentifier',
              metadata_plist,
          ]).rstrip()
          if cfbundleid == self.cfbundleid:
            shutil.copytree(docs_dir, os.path.join(self.out_dir, 'Documents'))
            return
Example #2
0
 def test_move_raw_coverage_data(self):
   """Tests if file_util can correctly move raw coverage data"""
   self.create_origin_profraw_file_if_not_exist()
   self.assertTrue(os.path.exists(self.origin_profraw_file_path))
   self.assertFalse(os.path.exists(self.expected_profraw_output_path))
   file_util.move_raw_coverage_data(self.existing_udid, self.output_folder)
   self.assertFalse(os.path.exists(self.origin_profraw_file_path))
   self.assertTrue(os.path.exists(self.expected_profraw_output_path))
   os.remove(self.expected_profraw_output_path)
Example #3
0
  def test_move_raw_coverage_data_origin_not_exist(self):
    """Ensures that file_util won't break when raw coverage data folder or
    file doesn't exist
    """
    # Tests origin directory doesn't exist.
    file_util.move_raw_coverage_data(self.not_existing_udid, self.output_folder)
    self.assertFalse(os.path.exists(self.expected_profraw_output_path))

    # Tests profraw file doesn't exist.
    if os.path.exists(self.origin_profraw_file_path):
      os.remove(self.origin_profraw_file_path)
    self.assertFalse(os.path.exists(self.origin_profraw_file_path))
    self.assertFalse(os.path.exists(self.expected_profraw_output_path))
    file_util.move_raw_coverage_data(self.existing_udid, self.output_folder)
    self.assertFalse(os.path.exists(self.expected_profraw_output_path))
Example #4
0
    def launch(self):
        """Launches tests using xcodebuild."""
        self.test_results['attempts'] = []
        cancelled_statuses = {'TESTS_DID_NOT_START', 'BUILD_INTERRUPTED'}
        shards = self.shards
        running_tests = set(self.egtests_app.get_all_tests())
        # total number of attempts is self.retries+1
        for attempt in range(self.retries + 1):
            # Erase all simulators per each attempt
            if iossim_util.is_device_with_udid_simulator(self.udid):
                # kill all running simulators to prevent possible memory leaks
                test_runner.SimulatorTestRunner.kill_simulators()
                shutdown_all_simulators()
                shutdown_all_simulators(XTDEVICE_FOLDER)
                erase_all_simulators()
                erase_all_simulators(XTDEVICE_FOLDER)
            outdir_attempt = os.path.join(self.out_dir, 'attempt_%d' % attempt)
            cmd_list = self.egtests_app.command(outdir_attempt,
                                                'id=%s' % self.udid, shards)
            # TODO(crbug.com/914878): add heartbeat logging to xcodebuild_runner.
            LOGGER.info('Start test attempt #%d for command [%s]' %
                        (attempt, ' '.join(cmd_list)))
            output = self.launch_attempt(cmd_list)

            if hasattr(self, 'use_clang_coverage') and self.use_clang_coverage:
                # out_dir of LaunchCommand object is the TestRunner out_dir joined with
                # UDID. Use os.path.dirname to retrieve the TestRunner out_dir.
                file_util.move_raw_coverage_data(self.udid,
                                                 os.path.dirname(self.out_dir))
            self.test_results['attempts'].append(
                self._log_parser.collect_test_results(outdir_attempt, output))

            # Do not exit here when no failed test from parsed log and parallel
            # testing is enabled (shards > 1), because when one of the shards fails
            # before tests start , the tests not run don't appear in log at all.
            if (self.retries == attempt
                    or (shards == 1
                        and not self.test_results['attempts'][-1]['failed'])):
                break

            # Exclude passed tests in next test attempt.
            self.egtests_app.excluded_tests += self.test_results['attempts'][
                -1]['passed']
            # crbug.com/987664 - for the case when
            # all tests passed but build was interrupted,
            # excluded(passed) tests are equal to tests to run.
            if set(self.egtests_app.excluded_tests) == running_tests:
                for status in cancelled_statuses:
                    failure = self.test_results['attempts'][-1]['failed'].pop(
                        status, None)
                    if failure:
                        LOGGER.info('Failure for passed tests %s: %s' %
                                    (status, failure))
                break

            # If tests are not completed(interrupted or did not start)
            # re-run them with the same number of shards,
            # otherwise re-run with shards=1 and exclude passed tests.
            cancelled_attempt = cancelled_statuses.intersection(
                self.test_results['attempts'][-1]['failed'].keys())

            # Item in cancelled_statuses is used to config for next attempt. The usage
            # should be confined in this method. Real tests affected by these statuses
            # will be marked timeout in results.
            for status in cancelled_statuses:
                self.test_results['attempts'][-1]['failed'].pop(status, None)

            if (not cancelled_attempt
                    # If need to re-run less than 20 tests, 1 shard should be enough.
                    or
                (len(running_tests) - len(self.egtests_app.excluded_tests) <=
                 MAXIMUM_TESTS_PER_SHARD_FOR_RERUN)):
                shards = 1

        self.summary_log()

        return {'test_results': self.test_results, 'logs': self.logs}
    def launch(self):
        """Launches tests using xcodebuild."""
        overall_launch_command_result = ResultCollection()
        shards = self.shards
        running_tests = set(self.egtests_app.get_all_tests())
        # total number of attempts is self.retries+1
        for attempt in range(self.retries + 1):
            # Erase all simulators per each attempt
            if iossim_util.is_device_with_udid_simulator(self.udid):
                # kill all running simulators to prevent possible memory leaks
                test_runner.SimulatorTestRunner.kill_simulators()
                shutdown_all_simulators()
                shutdown_all_simulators(XTDEVICE_FOLDER)
                erase_all_simulators()
                erase_all_simulators(XTDEVICE_FOLDER)
            outdir_attempt = os.path.join(self.out_dir, 'attempt_%d' % attempt)
            cmd_list = self.egtests_app.command(outdir_attempt,
                                                'id=%s' % self.udid, shards)
            # TODO(crbug.com/914878): add heartbeat logging to xcodebuild_runner.
            LOGGER.info('Start test attempt #%d for command [%s]' %
                        (attempt, ' '.join(cmd_list)))
            output = self.launch_attempt(cmd_list)

            if hasattr(self, 'use_clang_coverage') and self.use_clang_coverage:
                # out_dir of LaunchCommand object is the TestRunner out_dir joined with
                # UDID. Use os.path.dirname to retrieve the TestRunner out_dir.
                file_util.move_raw_coverage_data(self.udid,
                                                 os.path.dirname(self.out_dir))

            result = self._log_parser.collect_test_results(
                outdir_attempt, output)

            tests_selected_at_runtime = _tests_decided_at_runtime(
                self.egtests_app.test_app_path)
            # For most suites, only keep crash status from last attempt since retries
            # will cover any missing tests. For these decided at runtime, retain
            # crashes from all attempts and a dummy "crashed" result will be reported
            # to indicate some tests might never ran.
            # TODO(crbug.com/1235871): Switch back to excluded tests and set
            # |overall_crash| to always True.
            overall_launch_command_result.add_result_collection(
                result, overwrite_crash=not tests_selected_at_runtime)
            result.report_to_result_sink()

            tests_to_include = set()
            # |running_tests| are compiled tests in target intersecting with swarming
            # sharding. For some suites, they are more than what's needed to run.
            if not tests_selected_at_runtime:
                tests_to_include = tests_to_include | (
                    running_tests -
                    overall_launch_command_result.expected_tests())
            # Add failed tests from last rounds for runtime decided suites and device
            # suites.
            tests_to_include = (
                tests_to_include
                | overall_launch_command_result.never_expected_tests())
            self.egtests_app.included_tests = list(tests_to_include)

            # Nothing to run in retry.
            if not self.egtests_app.included_tests:
                break

            # If tests are not completed(interrupted or did not start) and there are
            # >= 20 remaining tests, run them with the same number of shards.
            # otherwise re-run with shards=1.
            if (not result.crashed
                    # If need to re-run less than 20 tests, 1 shard should be enough.
                    or (len(running_tests) -
                        len(overall_launch_command_result.expected_tests()) <=
                        MAXIMUM_TESTS_PER_SHARD_FOR_RERUN)):
                shards = 1

        return overall_launch_command_result