def HandleGet(self): if self.request.path == '/coverage/api/coverage-data': return self._ServePerCLCoverageData() match = _LUCI_PROJECT_REGEX.match(self.request.path) if not match: return BaseHandler.CreateError('Invalid url path %s' % self.request.path, 400) luci_project = match.group(1) host = self.request.get('host', 'chromium.googlesource.com') project = self.request.get('project', 'chromium/src') ref = self.request.get('ref', 'refs/heads/master') revision = self.request.get('revision') path = self.request.get('path') data_type = self.request.get('data_type') platform = self.request.get('platform', 'linux') list_reports = self.request.get('list_reports', False) if isinstance(list_reports, str): list_reports = (list_reports.lower() == 'true') if not data_type and path: if path.endswith('/'): data_type = 'dirs' elif path and '>' in path: data_type = 'components' else: data_type = 'files' logging.info('host=%s', host) logging.info('project=%s', project) logging.info('ref=%s', ref) logging.info('revision=%s', revision) logging.info('data_type=%s', data_type) logging.info('path=%s', path) logging.info('platform=%s', platform) if not project: return BaseHandler.CreateError('Invalid request', 400) logging.info('Servicing coverage data for postsubmit') if platform not in _POSTSUBMIT_PLATFORM_INFO_MAP: return BaseHandler.CreateError('Platform: %s is not supported' % platform, 404) bucket = _POSTSUBMIT_PLATFORM_INFO_MAP[platform]['bucket'] builder = _POSTSUBMIT_PLATFORM_INFO_MAP[platform]['builder'] if list_reports: return self._ServeProjectViewCoverageData( luci_project, host, project, ref, revision, platform, bucket, builder) template = None warning = None if not data_type: data_type = 'dirs' if not revision: query = PostsubmitReport.query( PostsubmitReport.gitiles_commit.server_host == host, PostsubmitReport.gitiles_commit.project == project, PostsubmitReport.bucket == bucket, PostsubmitReport.builder == builder, PostsubmitReport.visible == True).order(-PostsubmitReport.commit_timestamp) entities = query.fetch(limit=1) report = entities[0] revision = report.gitiles_commit.revision else: report = PostsubmitReport.Get( server_host=host, project=project, ref=ref, revision=revision, bucket=bucket, builder=builder) if not report: return BaseHandler.CreateError('Report record not found', 404) template = 'coverage/summary_view.html' if data_type == 'dirs': default_path = '//' elif data_type == 'components': default_path = '>>' else: if data_type != 'files': return BaseHandler.CreateError( 'Expected data_type to be "files", but got "%s"' % data_type, 400) template = 'coverage/file_view.html' path = path or default_path if data_type == 'files': entity = FileCoverageData.Get( server_host=host, project=project, ref=ref, revision=revision, path=path, bucket=bucket, builder=builder) if not entity: warning = ('File "%s" does not exist in this report, defaulting to root' % path) logging.warning(warning) path = '//' data_type = 'dirs' template = 'coverage/summary_view.html' if data_type != 'files': entity = SummaryCoverageData.Get( server_host=host, project=project, ref=ref, revision=revision, data_type=data_type, path=path, bucket=bucket, builder=builder) if not entity: warning = ('Path "%s" does not exist in this report, defaulting to root' % path) logging.warning(warning) path = default_path entity = SummaryCoverageData.Get( server_host=host, project=project, ref=ref, revision=revision, data_type=data_type, path=path, bucket=bucket, builder=builder) metadata = entity.data data = { 'metadata': metadata, } line_to_data = None if data_type == 'files': line_to_data = collections.defaultdict(dict) if 'revision' in metadata: gs_path = _ComposeSourceFileGsPath(report, path, metadata['revision']) file_content = _GetFileContentFromGs(gs_path) if not file_content: # Fetching files from Gitiles is slow, only use it as a backup. file_content = _GetFileContentFromGitiles(report, path, metadata['revision']) else: # If metadata['revision'] is empty, it means that the file is not # a source file. file_content = None if not file_content: line_to_data[1]['line'] = '!!!!No source code available!!!!' line_to_data[1]['count'] = 0 else: file_lines = file_content.splitlines() for i, line in enumerate(file_lines): # According to http://jinja.pocoo.org/docs/2.10/api/#unicode, # Jinja requires passing unicode objects or ASCII-only bytestring, # and given that it is possible for source files to have non-ASCII # chars, thus converting lines to unicode. line_to_data[i + 1]['line'] = unicode(line, 'utf8') line_to_data[i + 1]['count'] = -1 uncovered_blocks = {} if 'uncovered_blocks' in metadata: for line_data in metadata['uncovered_blocks']: uncovered_blocks[line_data['line']] = line_data['ranges'] for line in metadata['lines']: for line_num in range(line['first'], line['last'] + 1): line_to_data[line_num]['count'] = line['count'] if line_num in uncovered_blocks: text = line_to_data[line_num]['line'] regions = _SplitLineIntoRegions(text, uncovered_blocks[line_num]) line_to_data[line_num]['regions'] = regions line_to_data[line_num]['is_partially_covered'] = True else: line_to_data[line_num]['is_partially_covered'] = False line_to_data = list(line_to_data.iteritems()) line_to_data.sort(key=lambda x: x[0]) data['line_to_data'] = line_to_data # Compute the mapping of the name->path mappings in order. path_parts = _GetNameToPathSeparator(path, data_type) path_root, _ = _GetPathRootAndSeparatorFromDataType(data_type) return { 'data': { 'luci_project': luci_project, 'gitiles_commit': { 'host': host, 'project': project, 'ref': ref, 'revision': revision, }, 'path': path, 'platform': platform, 'platform_ui_name': _POSTSUBMIT_PLATFORM_INFO_MAP[platform]['ui_name'], 'path_root': path_root, 'metrics': code_coverage_util.GetMetricsBasedOnCoverageTool( _POSTSUBMIT_PLATFORM_INFO_MAP[platform]['coverage_tool']), 'data': data, 'data_type': data_type, 'path_parts': path_parts, 'platform_select': _MakePlatformSelect(host, project, ref, revision, path, platform), 'banner': _GetBanner(project), 'warning': warning, }, 'template': template, }
def testAndCreateAndGetComponentCoverageData(self): server_host = 'chromium.googlesource.com' project = 'chromium/src' ref = 'refs/heads/master' revision = '99999' data_type = 'components' path = 'Test>Component' bucket = 'coverage' builder = 'linux-code-coverage' data = { 'dirs': [], 'files': [], 'summaries': [{ 'covered': 1, 'total': 1, 'name': 'region' }, { 'covered': 1, 'total': 1, 'name': 'function' }, { 'covered': 1, 'total': 1, 'name': 'line' }], 'path': 'Test>Component', } component_coverage_data = SummaryCoverageData.Create( server_host=server_host, project=project, ref=ref, revision=revision, data_type=data_type, path=path, bucket=bucket, builder=builder, data=data) component_coverage_data.put() # Test key. self.assertEqual( 'chromium.googlesource.com$chromium/src$refs/heads/master$99999$' 'components$Test>Component$coverage$linux-code-coverage', component_coverage_data.key.id()) # Test Create. fetched_component_coverage_data = SummaryCoverageData.query().fetch() self.assertEqual(1, len(fetched_component_coverage_data)) self.assertEqual(component_coverage_data, fetched_component_coverage_data[0]) # Test Get. self.assertEqual( component_coverage_data, SummaryCoverageData.Get( server_host=server_host, project=project, ref=ref, revision=revision, data_type=data_type, path=path, bucket=bucket, builder=builder))