def GenerateReportMessage(self, requested, executed): """Uploads the result to the web service. Requires the feature to be enabled; no-op otherwise. Args: requested: list, A list of test case records requested to run executed: list, A list of test case records that were executed Returns: binary string, serialized report message. None if web is not enabled. """ if not self.enabled: return None # Handle case when runner fails, tests aren't executed if (not getattr(self, keys.ConfigKeys.RUN_AS_VTS_SELFTEST, False) and executed and executed[-1].test_name == "setup_class"): # Test failed during setup, all tests were not executed start_index = 0 else: # Runner was aborted. Remaining tests weren't executed start_index = len(executed) for test in requested[start_index:]: msg = self.report_msg.test_case.add() msg.name = test.test_name msg.start_timestamp = feature_utils.GetTimestamp() msg.end_timestamp = msg.start_timestamp msg.test_result = ReportMsg.TEST_CASE_RESULT_FAIL self.report_msg.end_timestamp = feature_utils.GetTimestamp() build = getattr(self, keys.ConfigKeys.IKEY_BUILD) if keys.ConfigKeys.IKEY_BUILD_ID in build: build_id = str(build[keys.ConfigKeys.IKEY_BUILD_ID]) self.report_msg.build_info.id = build_id logging.info("_tearDownClass hook: start (username: %s)", getpass.getuser()) if len(self.report_msg.test_case) == 0: logging.info("_tearDownClass hook: skip uploading (no test case)") return '' post_msg = ReportMsg.DashboardPostMessage() post_msg.test_report.extend([self.report_msg]) self.rest_client.AddAuthToken(post_msg) message_b = base64.b64encode(post_msg.SerializeToString()) logging.info('Result proto message generated. size: %s', len(message_b)) logging.info("_tearDownClass hook: status upload time stamp %s", str(self.report_msg.start_timestamp)) return message_b
def _OutputCoverageReport(self, isGlobal, coverage_report_msg=None): logging.info("Outputing coverage data") timestamp_seconds = str(int(time.time() * 1000000)) coverage_report_file_name = "coverage_report_" + timestamp_seconds + ".txt" if self._coverage_report_file_prefix: coverage_report_file_name = "coverage_report_" + self._coverage_report_file_prefix + ".txt" coverage_report_file = None if (self._coverage_report_dir): if not os.path.exists(self._coverage_report_dir): os.makedirs(self._coverage_report_dir) coverage_report_file = os.path.join(self._coverage_report_dir, coverage_report_file_name) else: coverage_report_file = os.path.join(self.local_coverage_path, coverage_report_file_name) logging.info("Storing coverage report to: %s", coverage_report_file) if self.web and self.web.enabled: coverage_report_msg = ReportMsg.TestReportMessage() if isGlobal: for c in self.web.report_msg.coverage: coverage = coverage_report_msg.coverage.add() coverage.CopyFrom(c) else: for c in self.web.current_test_report_msg.coverage: coverage = coverage_report_msg.coverage.add() coverage.CopyFrom(c) if coverage_report_msg is not None: with open(coverage_report_file, "w+") as f: f.write(str(coverage_report_msg))
def __init__(self, user_params): """Initializes the web feature. Parses the arguments and initializes the web functionality. Args: user_params: A dictionary from parameter name (String) to parameter value. """ self.ParseParameters(toggle_param_name=self._TOGGLE_PARAM, required_param_names=self._REQUIRED_PARAMS, optional_param_names=self._OPTIONAL_PARAMS, user_params=user_params) if not self.enabled: return # Initialize the dashboard client post_cmd = getattr(self, keys.ConfigKeys.IKEY_DASHBOARD_POST_COMMAND) service_json_path = str( getattr(self, keys.ConfigKeys.IKEY_SERVICE_JSON_PATH)) self.rest_client = dashboard_rest_client.DashboardRestClient( post_cmd, service_json_path) if not self.rest_client.Initialize(): self.enabled = False self.report_msg = ReportMsg.TestReportMessage() self.report_msg.test = str( getattr(self, keys.ConfigKeys.KEY_TESTBED_NAME)) if getattr(self, keys.ConfigKeys.IKEY_ENABLE_PROFILING, False): logging.info("Profiling test") self.report_msg.test += "Profiling" self.report_msg.test_type = ReportMsg.VTS_HOST_DRIVEN_STRUCTURAL self.report_msg.start_timestamp = feature_utils.GetTimestamp() self.report_msg.host_info.hostname = socket.gethostname() android_devices = getattr(self, keys.ConfigKeys.IKEY_ANDROID_DEVICE, None) if not android_devices or not isinstance(android_devices, list): logging.warn("android device information not available") return for device_spec in android_devices: dev_info = self.report_msg.device_info.add() for elem in [ keys.ConfigKeys.IKEY_PRODUCT_TYPE, keys.ConfigKeys.IKEY_PRODUCT_VARIANT, keys.ConfigKeys.IKEY_BUILD_FLAVOR, keys.ConfigKeys.IKEY_BUILD_ID, keys.ConfigKeys.IKEY_BRANCH, keys.ConfigKeys.IKEY_BUILD_ALIAS, keys.ConfigKeys.IKEY_API_LEVEL, keys.ConfigKeys.IKEY_SERIAL ]: if elem in device_spec: setattr(dev_info, elem, str(device_spec[elem])) # TODO: get abi information differently for multi-device support. setattr(dev_info, keys.ConfigKeys.IKEY_ABI_NAME, str(getattr(self, keys.ConfigKeys.IKEY_ABI_NAME))) setattr(dev_info, keys.ConfigKeys.IKEY_ABI_BITNESS, str(getattr(self, keys.ConfigKeys.IKEY_ABI_BITNESS)))
def GenerateReportMessage(self, requested, executed): """Uploads the result to the web service. Requires the feature to be enabled; no-op otherwise. Args: requested: list, A list of test case records requested to run executed: list, A list of test case records that were executed Returns: binary string, serialized report message. None if web is not enabled. """ if not self.enabled: return None for test in requested[len(executed):]: msg = self.report_msg.test_case.add() msg.name = test.test_name msg.start_timestamp = feature_utils.GetTimestamp() msg.end_timestamp = msg.start_timestamp msg.test_result = ReportMsg.TEST_CASE_RESULT_FAIL self.report_msg.end_timestamp = feature_utils.GetTimestamp() build = getattr(self, keys.ConfigKeys.IKEY_BUILD) if keys.ConfigKeys.IKEY_BUILD_ID in build: build_id = str(build[keys.ConfigKeys.IKEY_BUILD_ID]) self.report_msg.build_info.id = build_id logging.debug("_tearDownClass hook: start (username: %s)", getpass.getuser()) if len(self.report_msg.test_case) == 0: logging.warn("_tearDownClass hook: skip uploading (no test case)") return '' post_msg = ReportMsg.DashboardPostMessage() post_msg.test_report.extend([self.report_msg]) self.rest_client.AddAuthToken(post_msg) message_b = base64.b64encode(post_msg.SerializeToString()) logging.debug('Result proto message generated. size: %s', len(message_b)) logging.debug("_tearDownClass hook: status upload time stamp %s", str(self.report_msg.start_timestamp)) return message_b
def Upload(self, requested, executed): """Uploads the result to the web service. Requires the feature to be enabled; no-op otherwise. Args: requested: list, A list of test case names requested to run executed: list, A list of test case names that were executed """ if not self.enabled: return # Handle case when runner fails, tests aren't executed if (executed and executed[-1].test_name == "setup_class"): # Test failed during setup, all tests were not executed start_index = 0 else: # Runner was aborted. Remaining tests weren't executed start_index = len(executed) for test in requested[start_index:]: msg = self.report_msg.test_case.add() msg.name = test msg.start_timestamp = feature_utils.GetTimestamp() msg.end_timestamp = msg.start_timestamp msg.test_result = ReportMsg.TEST_CASE_RESULT_FAIL self.report_msg.end_timestamp = feature_utils.GetTimestamp() build = getattr(self, keys.ConfigKeys.IKEY_BUILD) if keys.ConfigKeys.IKEY_BUILD_ID in build: build_id = str(build[keys.ConfigKeys.IKEY_BUILD_ID]) self.report_msg.build_info.id = build_id logging.info("_tearDownClass hook: start (username: %s)", getpass.getuser()) if len(self.report_msg.test_case) > 0: post_msg = ReportMsg.DashboardPostMessage() post_msg.test_report.extend([self.report_msg]) # Post new data to the dashboard self.rest_client.PostData(post_msg) logging.info("_tearDownClass hook: status upload time stamp %s", str(self.report_msg.start_timestamp)) else: logging.info("_tearDownClass hook: skip uploading (no test case)")
def _OutputCoverageReport(self, isGlobal): logging.info("outputing coverage data") timestamp_seconds = str(int(time.time() * 1000000)) coverage_report_file = os.path.join( self.local_coverage_path, "coverage_report_" + timestamp_seconds + ".txt") logging.info("Storing coverage report to: %s", coverage_report_file) coverage_report_msg = ReportMsg.TestReportMessage() if isGlobal: for c in self.web.report_msg.coverage: coverage = coverage_report_msg.coverage.add() coverage.CopyFrom(c) else: for c in self.web.current_test_report_msg.coverage: coverage = coverage_report_msg.coverage.add() coverage.CopyFrom(c) with open(coverage_report_file, 'w+') as f: f.write(str(coverage_report_msg))
def _AutoProcess(self, cov_zip, revision_dict, gcda_dict, isGlobal): """Process coverage data and appends coverage reports to the report message. Matches gcno files with gcda files and processes them into a coverage report with references to the original source code used to build the system image. Coverage information is appended as a CoverageReportMessage to the provided report message. Git project information is automatically extracted from the build info and the source file name enclosed in each gcno file. Git project names must resemble paths and may differ from the paths to their project root by at most one. If no match is found, then coverage information will not be be processed. e.g. if the project path is test/vts, then its project name may be test/vts or <some folder>/test/vts in order to be recognized. Args: cov_zip: the ZipFile object containing the gcno coverage artifacts. revision_dict: the dictionary from project name to project version. gcda_dict: the dictionary of gcda basenames to gcda content (binary string) isGlobal: boolean, True if the coverage data is for the entire test, False if only for the current test case. """ checksum_gcno_dict = self._GetChecksumGcnoDict(cov_zip) output_coverage_report = getattr( self, keys.ConfigKeys.IKEY_OUTPUT_COVERAGE_REPORT, False) exclude_coverage_path = getattr( self, keys.ConfigKeys.IKEY_EXCLUDE_COVERAGE_PATH, []) for idx, path in enumerate(exclude_coverage_path): base_name = os.path.basename(path) if base_name and "." not in base_name: path = path if path.endswith("/") else path + "/" exclude_coverage_path[idx] = path exclude_coverage_path.extend(self._DEFAULT_EXCLUDE_PATHS) coverage_dict = dict() coverage_report_message = ReportMsg.TestReportMessage() for gcda_name in gcda_dict: if GEN_TAG in gcda_name: # skip coverage measurement for intermediate code. logging.warn("Skip for gcda file: %s", gcda_name) continue gcda_stream = io.BytesIO(gcda_dict[gcda_name]) gcda_file_parser = gcda_parser.GCDAParser(gcda_stream) file_name = gcda_name.rsplit(".", 1)[0] if not gcda_file_parser.checksum in checksum_gcno_dict: logging.info("No matching gcno file for gcda: %s", gcda_name) continue gcno_file_parsers = checksum_gcno_dict[gcda_file_parser.checksum] gcno_summary = self._FindGcnoSummary(file_name, gcno_file_parsers) if gcno_summary is None: logging.error("No gcno file found for gcda %s.", gcda_name) continue # Process and merge gcno/gcda data try: gcda_file_parser.Parse(gcno_summary) except FileFormatError: logging.error("Error parsing gcda file %s", gcda_name) continue coverage_report.GenerateLineCoverageVector( gcno_summary, exclude_coverage_path, coverage_dict) for src_file_path in coverage_dict: # Get the git project information # Assumes that the project name and path to the project root are similar revision = None for project_name in revision_dict: # Matches cases when source file root and project name are the same if src_file_path.startswith(str(project_name)): git_project_name = str(project_name) git_project_path = str(project_name) revision = str(revision_dict[project_name]) logging.debug("Source file '%s' matched with project '%s'", src_file_path, git_project_name) break parts = os.path.normpath(str(project_name)).split(os.sep, 1) # Matches when project name has an additional prefix before the # project path root. if len(parts) > 1 and src_file_path.startswith(parts[-1]): git_project_name = str(project_name) git_project_path = parts[-1] revision = str(revision_dict[project_name]) logging.debug("Source file '%s' matched with project '%s'", src_file_path, git_project_name) break if not revision: logging.info("Could not find git info for %s", src_file_path) continue coverage_vec = coverage_dict[src_file_path] total_count, covered_count = coverage_report.GetCoverageStats( coverage_vec) if self.web and self.web.enabled: self.web.AddCoverageReport(coverage_vec, src_file_path, git_project_name, git_project_path, revision, covered_count, total_count, isGlobal) else: coverage = coverage_report_message.coverage.add() coverage.total_line_count = total_count coverage.covered_line_count = covered_count coverage.line_coverage_vector.extend(coverage_vec) src_file_path = os.path.relpath(src_file_path, git_project_path) coverage.file_path = src_file_path coverage.revision = revision coverage.project_name = git_project_name if output_coverage_report: self._OutputCoverageReport(isGlobal, coverage_report_message)