Richard Barnette | 4afcd93 | 2014-10-06 15:40:39 +0000 | [diff] [blame] | 1 | # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | """Class to wrap building detail table for board/netbook/testcategory.""" |
| 6 | |
| 7 | import os |
| 8 | |
| 9 | import dash_util |
| 10 | |
| 11 | from build_info import BuildInfo |
| 12 | from dash_view import AutotestDashView |
| 13 | |
| 14 | # String resources. |
| 15 | from dash_strings import BVT_TAG |
| 16 | |
| 17 | # Constants |
| 18 | DEFAULT_TEST_NAME_LENGTH = 18 |
| 19 | |
| 20 | |
| 21 | class TableBuilder(object): |
| 22 | """Class manages building header and body for details tables.""" |
| 23 | |
| 24 | def __init__(self, base_dir, netbook, board_type, category): |
| 25 | self._netbook = netbook |
| 26 | self._board_type = board_type |
| 27 | self._category = category |
| 28 | self._build_info = BuildInfo() |
| 29 | self._dash_view = AutotestDashView() |
| 30 | self._test_list = self._dash_view.GetTestNames( |
| 31 | netbook, board_type, category) |
| 32 | self._test_list.sort() |
| 33 | self._build_numbers = self._dash_view.GetBuilds( |
| 34 | netbook, board_type, category) |
| 35 | self._good_set, self._failed_list = self._SplitTestList() |
| 36 | |
| 37 | def _SplitTestList(self): |
| 38 | """Determine and list the tests that passed and failed.""" |
| 39 | good_set = set() |
| 40 | failed_list = [] # Maintains order discovered. |
| 41 | |
| 42 | for build in self._build_numbers: |
| 43 | for test_name in self._test_list: |
| 44 | test_details = self._GetTestDetails(test_name, build) |
| 45 | if test_details: |
| 46 | for t in test_details: |
| 47 | good_status = (t['status'] == 'GOOD') |
| 48 | test_tuple = (test_name, t['experimental']) |
| 49 | if test_tuple in failed_list: |
| 50 | continue |
| 51 | if good_status: |
| 52 | good_set.add(test_tuple) |
| 53 | else: |
| 54 | failed_list.append(test_tuple) |
| 55 | good_set.discard(test_tuple) |
| 56 | return sorted(good_set), failed_list |
| 57 | |
| 58 | def _BuildTableHeader(self, test_list): |
| 59 | """Generate header with test names for columns.""" |
| 60 | table_header = [] |
| 61 | for test_name, experimental in test_list: |
| 62 | test_path = self._dash_view.GetAutotestInfo(test_name)[1] |
| 63 | if len(test_name) > DEFAULT_TEST_NAME_LENGTH: |
| 64 | test_alias = test_name[:DEFAULT_TEST_NAME_LENGTH] + '...' |
| 65 | else: |
| 66 | test_alias = test_name |
| 67 | table_header.append((test_path, test_alias.replace('_', ' '), |
| 68 | test_name, experimental)) |
| 69 | return table_header |
| 70 | |
| 71 | def _GetBuildMetadata(self, build): |
| 72 | """Retrieve info used to populate build header popups.""" |
| 73 | started, finished, elapsed = self._dash_view.GetFormattedJobTimes( |
| 74 | self._netbook, self._board_type, self._category, build) |
| 75 | fstarted, ffinished, felapsed, ffinished_short = ( |
| 76 | self._build_info.GetFormattedBuildTimes(self._board_type, build)) |
| 77 | return (fstarted, ffinished, felapsed, |
| 78 | started, finished, elapsed, |
| 79 | self._dash_view.GetFormattedLastUpdated()) |
| 80 | |
| 81 | def _GetTestDetails(self, test_name, build): |
| 82 | return self._dash_view.GetTestDetails( |
| 83 | self._netbook, self._board_type, self._category, test_name, build) |
| 84 | |
| 85 | def _BuildTableBody(self, test_list): |
| 86 | """Generate table body with test results in cells.""" |
| 87 | table_body = [] |
| 88 | |
| 89 | for build in self._build_numbers: |
| 90 | chrome_version = self._build_info.GetChromeVersion(self._board_type, |
| 91 | build) |
| 92 | test_status_list = [] |
| 93 | for test_name, experimental in test_list: |
| 94 | # Include either the good details or the details of the |
| 95 | # first failure in the list (last chronological failure). |
| 96 | cell_content = [] |
| 97 | test_details = self._GetTestDetails(test_name, build) |
| 98 | if test_details: |
| 99 | total_tests = len(test_details) |
| 100 | passed_tests = 0 |
| 101 | failed_tests = 0 |
| 102 | for t in test_details: |
| 103 | current_fail = False |
| 104 | test_status = t['status'] |
| 105 | if test_status == 'GOOD': |
| 106 | passed_tests += 1 |
| 107 | query = '%(tag)s' % t |
| 108 | else: |
| 109 | failed_tests += 1 |
| 110 | current_fail = True |
| 111 | query = '%(tag)s/%(test_name)s' % t |
| 112 | # Populate the detailed cell popups prudently. |
| 113 | host_info = [] |
| 114 | chrome_version_attr = chrome_version |
| 115 | if chrome_version and len(chrome_version) == 2: |
| 116 | chrome_version_attr = '%s (%s)' % (chrome_version[0], |
| 117 | chrome_version[1]) |
| 118 | priority_attrs = [ |
| 119 | ('Chrome Version', 'chrome-version', chrome_version_attr), |
| 120 | ('ChromeOS Version', 'CHROMEOS_RELEASE_DESCRIPTION', None), |
| 121 | ('Platform', 'host-platform', None), |
| 122 | ('Kernel Version', 'sysinfo-uname', None), |
| 123 | ('Reason', 'reason', None)] |
| 124 | for popup_header, attr_key, default in priority_attrs: |
| 125 | attr_value = t['attr'].get(attr_key, default) |
| 126 | if attr_value: |
| 127 | host_info.append((popup_header, attr_value)) |
| 128 | test_status = test_status[0].upper() |
| 129 | # Treat TEST_NA as WARNING. |
| 130 | if test_status == 'T': |
| 131 | test_status = 'W' |
| 132 | if (not cell_content) or (current_fail and failed_tests == 1): |
| 133 | cell_content = [test_name, t['hostname'], host_info, query, |
| 134 | test_status] |
| 135 | if cell_content: |
| 136 | test_summaries = [passed_tests, total_tests] |
| 137 | test_summaries.extend( |
| 138 | self._dash_view.GetCrashes().GetBuildTestCrashSummary( |
| 139 | self._netbook, self._board_type, build, test_name)) |
| 140 | cell_content.extend(test_summaries) |
| 141 | test_status_list.append(cell_content) |
| 142 | popup = self._GetBuildMetadata(build) |
| 143 | table_body.append(('', build, popup, test_status_list, chrome_version)) |
| 144 | return table_body |
| 145 | |
| 146 | def BuildTables(self): |
| 147 | """Generate table body with test results in cells.""" |
| 148 | good_table_header = self._BuildTableHeader(self._good_set) |
| 149 | good_table_body = self._BuildTableBody(self._good_set) |
| 150 | result = [{'label': 'Good Tests', |
| 151 | 'header': good_table_header, |
| 152 | 'body': good_table_body}] |
| 153 | if self._failed_list: |
| 154 | failed_table_header = self._BuildTableHeader(self._failed_list) |
| 155 | failed_table_body = self._BuildTableBody(self._failed_list) |
| 156 | result.insert(0, {'label': 'Failed Tests', |
| 157 | 'header': failed_table_header, |
| 158 | 'body': failed_table_body}) |
| 159 | return result |
| 160 | |
| 161 | def CountTestList(self): |
| 162 | """Count the number of tests and failed ones.""" |
| 163 | if self._build_numbers: |
| 164 | return len(self._good_set)+len(self._failed_list), len(self._failed_list) |
| 165 | else: |
| 166 | return 0, 0 |