Commit 1ad7a072 by Jonah Ryan-Davis Committed by Commit Bot

Clean up unexpected passed/failed test behavior for generate_stats

The lists of tests can't be added to the sheets if more than 50,000 lines. Since the goal is to get rid of all unexpected passes/failures, it's reasonable to clip the lists by length. Other formatting changes too. Bug: angleproject:3398 Change-Id: Ice461862fb4266e0ad1280f20de85224fc6d7e97 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1585612Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>
parent 6f691fbb
[style]
based_on_style = chromium
column_limit = 99
\ No newline at end of file
...@@ -42,8 +42,7 @@ try: ...@@ -42,8 +42,7 @@ try:
from googleapiclient.discovery import build from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow from google_auth_oauthlib.flow import InstalledAppFlow
except ImportError: except ImportError:
print('ERROR: Missing prerequisites. ' print('ERROR: Missing prerequisites. Follow the quickstart guide:\n'
'Follow the quickstart guide:\n'
'https://devsite.googleplex.com/sheets/api/quickstart/python') 'https://devsite.googleplex.com/sheets/api/quickstart/python')
exit(1) exit(1)
...@@ -90,8 +89,7 @@ INFO_TAG = '*RESULT' ...@@ -90,8 +89,7 @@ INFO_TAG = '*RESULT'
# Info contains the build_name, time, date, angle_revision, and chrome revision # Info contains the build_name, time, date, angle_revision, and chrome revision
# Uses: bb ls '<botname>' -n 1 -status success -A # Uses: bb ls '<botname>' -n 1 -status success -A
def get_latest_success_build_info(bot_name): def get_latest_success_build_info(bot_name):
bb = subprocess.Popen( bb = subprocess.Popen(['bb', 'ls', bot_name, '-n', '1', '-status', 'success', '-A'],
['bb', 'ls', bot_name, '-n', '1', '-status', 'success', '-A'],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
LOGGER.debug("Ran [bb ls '" + bot_name + "' -n 1 -status success -A]") LOGGER.debug("Ran [bb ls '" + bot_name + "' -n 1 -status success -A]")
...@@ -99,8 +97,7 @@ def get_latest_success_build_info(bot_name): ...@@ -99,8 +97,7 @@ def get_latest_success_build_info(bot_name):
if err: if err:
raise ValueError("Unexpected error from bb ls: '" + err + "'") raise ValueError("Unexpected error from bb ls: '" + err + "'")
if not out: if not out:
raise ValueError("Unexpected empty result from bb ls of bot '" + bot_name + raise ValueError("Unexpected empty result from bb ls of bot '" + bot_name + "'")
"'")
# Example output (line 1): # Example output (line 1):
# ci.chromium.org/b/8915280275579996928 SUCCESS 'chromium/ci/Win10 FYI dEQP Release (NVIDIA)/26877' # ci.chromium.org/b/8915280275579996928 SUCCESS 'chromium/ci/Win10 FYI dEQP Release (NVIDIA)/26877'
# ... # ...
...@@ -119,8 +116,7 @@ def get_latest_success_build_info(bot_name): ...@@ -119,8 +116,7 @@ def get_latest_success_build_info(bot_name):
# ... # ...
# Created today at 12:26:39, waited 2.056319s, started at 12:26:41, ran for 1h16m48.14963s, ended at 13:43:30 # Created today at 12:26:39, waited 2.056319s, started at 12:26:41, ran for 1h16m48.14963s, ended at 13:43:30
# ... # ...
info['time'] = re.findall(r'[0-9]{1,2}:[0-9]{2}:[0-9]{2}', info['time'] = re.findall(r'[0-9]{1,2}:[0-9]{2}:[0-9]{2}', line.split(',', 1)[0])[0]
line.split(',', 1)[0])[0]
# Format today's date in US format so Sheets can read it properly # Format today's date in US format so Sheets can read it properly
info['date'] = datetime.datetime.now().strftime('%m/%d/%y') info['date'] = datetime.datetime.now().strftime('%m/%d/%y')
if 'got_angle_revision' in line: if 'got_angle_revision' in line:
...@@ -182,17 +178,12 @@ def validate_step_info(step_info, build_name, step_name): ...@@ -182,17 +178,12 @@ def validate_step_info(step_info, build_name, step_name):
return False return False
if 'Total' in step_info: if 'Total' in step_info:
partial_sum_keys = [ partial_sum_keys = ['Passed', 'Failed', 'Skipped', 'Not Supported', 'Exception', 'Crashed']
'Passed', 'Failed', 'Skipped', 'Not Supported', 'Exception', 'Crashed' partial_sum_values = [int(step_info[key]) for key in partial_sum_keys if key in step_info]
]
partial_sum_values = [
int(step_info[key]) for key in partial_sum_keys if key in step_info
]
computed_total = sum(partial_sum_values) computed_total = sum(partial_sum_values)
if step_info['Total'] != computed_total: if step_info['Total'] != computed_total:
LOGGER.warning('Step info does not sum to total for ' + print_name + LOGGER.warning('Step info does not sum to total for ' + print_name + ' | Total: ' +
' | Total: ' + str(step_info['Total']) + str(step_info['Total']) + ' - Computed total: ' + str(computed_total) + '\n')
' - Computed total: ' + str(computed_total) + '\n')
return True return True
...@@ -208,8 +199,8 @@ def get_step_info(build_name, step_name): ...@@ -208,8 +199,8 @@ def get_step_info(build_name, step_name):
LOGGER.debug("Ran [bb log '" + build_name + "' '" + step_name + "']") LOGGER.debug("Ran [bb log '" + build_name + "' '" + step_name + "']")
out, err = bb.communicate() out, err = bb.communicate()
if err: if err:
LOGGER.warning("Unexpected error from bb log '" + build_name + "' '" + LOGGER.warning("Unexpected error from bb log '" + build_name + "' '" + step_name + "': '" +
step_name + "': '" + err + "'") err + "'")
return None return None
step_info = {} step_info = {}
# Example output (relevant lines of stdout): # Example output (relevant lines of stdout):
...@@ -223,6 +214,7 @@ def get_step_info(build_name, step_name): ...@@ -223,6 +214,7 @@ def get_step_info(build_name, step_name):
# *RESULT: Crashed: 0 # *RESULT: Crashed: 0
# *RESULT: Unexpected Passed: 12 # *RESULT: Unexpected Passed: 12
# ... # ...
append_errors = []
for line in out.splitlines(): for line in out.splitlines():
if INFO_TAG not in line: if INFO_TAG not in line:
continue continue
...@@ -232,13 +224,35 @@ def get_step_info(build_name, step_name): ...@@ -232,13 +224,35 @@ def get_step_info(build_name, step_name):
LOGGER.warning("Line improperly formatted: '" + line + "'\n") LOGGER.warning("Line improperly formatted: '" + line + "'\n")
continue continue
key = line_columns[1].strip() key = line_columns[1].strip()
# If the value is clearly an int, sum it. Otherwise, concatenate it as a
# string
isInt = False
intVal = 0
try:
intVal = int(line_columns[2])
if intVal is not None:
isInt = True
except Exception as error:
isInt = False
if isInt:
if key not in step_info: if key not in step_info:
step_info[key] = 0 step_info[key] = 0
val = int(filter(str.isdigit, line_columns[2])) step_info[key] += intVal
if val is not None: else:
step_info[key] += val if key not in step_info:
step_info[key] = line_columns[2].strip()
else:
append_string = '\n' + line_columns[2].strip()
# Sheets has a limit of 50000 characters per cell, so make sure to
# stop appending below this limit
if len(step_info[key]) + len(append_string) < 50000:
step_info[key] += append_string
else: else:
step_info[key] += ', ' + line_columns[2] if key not in append_errors:
append_errors.append(key)
LOGGER.warning("Too many characters in column '" + key + "'. Output capped.")
if validate_step_info(step_info, build_name, step_name): if validate_step_info(step_info, build_name, step_name):
return step_info return step_info
return None return None
...@@ -262,8 +276,7 @@ def get_bot_info(bot_name): ...@@ -262,8 +276,7 @@ def get_bot_info(bot_name):
# Get an individual spreadsheet based on the spreadsheet id. Returns the result # Get an individual spreadsheet based on the spreadsheet id. Returns the result
# of spreadsheets.get(), or throws an exception if the sheet could not open. # of spreadsheets.get(), or throws an exception if the sheet could not open.
def get_spreadsheet(service, spreadsheet_id): def get_spreadsheet(service, spreadsheet_id):
LOGGER.debug("Called [spreadsheets.get(spreadsheetId='" + spreadsheet_id + LOGGER.debug("Called [spreadsheets.get(spreadsheetId='" + spreadsheet_id + "')]")
"')]")
request = service.get(spreadsheetId=spreadsheet_id) request = service.get(spreadsheetId=spreadsheet_id)
spreadsheet = request.execute() spreadsheet = request.execute()
if not spreadsheet: if not spreadsheet:
...@@ -340,24 +353,16 @@ def batch_update(service, spreadsheet_id, updates): ...@@ -340,24 +353,16 @@ def batch_update(service, spreadsheet_id, updates):
batch_update_request_body = { batch_update_request_body = {
'requests': updates, 'requests': updates,
} }
LOGGER.debug("Called [spreadsheets.batchUpdate(spreadsheetId='" + LOGGER.debug("Called [spreadsheets.batchUpdate(spreadsheetId='" + spreadsheet_id + "', body=" +
spreadsheet_id + "', body=" + str(batch_update_request_body) + str(batch_update_request_body) + ')]')
')]') request = service.batchUpdate(spreadsheetId=spreadsheet_id, body=batch_update_request_body)
request = service.batchUpdate(
spreadsheetId=spreadsheet_id, body=batch_update_request_body)
request.execute() request.execute()
# Creates sheets given a service and spreadsheed id based on a list of sheet # Creates sheets given a service and spreadsheed id based on a list of sheet
# names input # names input
def create_sheets(service, spreadsheet_id, sheet_names): def create_sheets(service, spreadsheet_id, sheet_names):
updates = [{ updates = [{'addSheet': {'properties': {'title': sheet_name,}}} for sheet_name in sheet_names]
'addSheet': {
'properties': {
'title': sheet_name,
}
}
} for sheet_name in sheet_names]
batch_update(service, spreadsheet_id, updates) batch_update(service, spreadsheet_id, updates)
...@@ -366,10 +371,9 @@ def create_sheets(service, spreadsheet_id, sheet_names): ...@@ -366,10 +371,9 @@ def create_sheets(service, spreadsheet_id, sheet_names):
# sheet_name. # sheet_name.
def get_headers(service, spreadsheet_id, sheet_names): def get_headers(service, spreadsheet_id, sheet_names):
header_ranges = [sheet_name + '!A1:Z' for sheet_name in sheet_names] header_ranges = [sheet_name + '!A1:Z' for sheet_name in sheet_names]
LOGGER.debug("Called [spreadsheets.values().batchGet(spreadsheetId='" + LOGGER.debug("Called [spreadsheets.values().batchGet(spreadsheetId='" + spreadsheet_id +
spreadsheet_id + ', ranges=' + str(header_ranges) + "')]") ', ranges=' + str(header_ranges) + "')]")
request = service.values().batchGet( request = service.values().batchGet(spreadsheetId=spreadsheet_id, ranges=header_ranges)
spreadsheetId=spreadsheet_id, ranges=header_ranges)
response = request.execute() response = request.execute()
headers = {} headers = {}
for k, sheet_name in enumerate(sheet_names): for k, sheet_name in enumerate(sheet_names):
...@@ -388,9 +392,8 @@ def batch_update_values(service, spreadsheet_id, data): ...@@ -388,9 +392,8 @@ def batch_update_values(service, spreadsheet_id, data):
'valueInputOption': 'USER_ENTERED', # Helps with formatting of dates 'valueInputOption': 'USER_ENTERED', # Helps with formatting of dates
'data': data, 'data': data,
} }
LOGGER.debug("Called [spreadsheets.values().batchUpdate(spreadsheetId='" + LOGGER.debug("Called [spreadsheets.values().batchUpdate(spreadsheetId='" + spreadsheet_id +
spreadsheet_id + "', body=" + "', body=" + str(batch_update_values_request_body) + ')]')
str(batch_update_values_request_body) + ')]')
request = service.values().batchUpdate( request = service.values().batchUpdate(
spreadsheetId=spreadsheet_id, body=batch_update_values_request_body) spreadsheetId=spreadsheet_id, body=batch_update_values_request_body)
request.execute() request.execute()
...@@ -439,10 +442,9 @@ def append_values(service, spreadsheet_id, sheet_name, values): ...@@ -439,10 +442,9 @@ def append_values(service, spreadsheet_id, sheet_name, values):
'majorDimension': 'ROWS', 'majorDimension': 'ROWS',
'values': [values], 'values': [values],
} }
LOGGER.debug("Called [spreadsheets.values().append(spreadsheetId='" + LOGGER.debug("Called [spreadsheets.values().append(spreadsheetId='" + spreadsheet_id +
spreadsheet_id + "', body=" + str(append_values_request_body) + "', body=" + str(append_values_request_body) + ", range='" + header_range +
", range='" + header_range + "', insertDataOption='" + "', insertDataOption='" + insert_data_option + "', valueInputOption='" +
insert_data_option + "', valueInputOption='" +
value_input_option + "')]") value_input_option + "')]")
request = service.values().append( request = service.values().append(
spreadsheetId=spreadsheet_id, spreadsheetId=spreadsheet_id,
...@@ -472,7 +474,10 @@ def update_values(service, spreadsheet_id, headers, info): ...@@ -472,7 +474,10 @@ def update_values(service, spreadsheet_id, headers, info):
else: else:
values.append('') values.append('')
LOGGER.info("Appending new rows to sheet '" + sheet_name + "'...") LOGGER.info("Appending new rows to sheet '" + sheet_name + "'...")
try:
append_values(service, spreadsheet_id, sheet_name, values) append_values(service, spreadsheet_id, sheet_name, values)
except Exception as error:
LOGGER.warning('%s\n' % str(error))
# Updates the given spreadsheed_id with the info struct passed in. # Updates the given spreadsheed_id with the info struct passed in.
...@@ -506,8 +511,7 @@ def get_sheets_service(auth_path): ...@@ -506,8 +511,7 @@ def get_sheets_service(auth_path):
LOGGER.info("Creating auth dir '" + auth_path + "'") LOGGER.info("Creating auth dir '" + auth_path + "'")
os.makedirs(auth_path) os.makedirs(auth_path)
if not os.path.exists(credentials_path): if not os.path.exists(credentials_path):
raise Exception( raise Exception('Missing credentials.json.\n'
'Missing credentials.json.\n'
'Go to: https://developers.google.com/sheets/api/quickstart/python\n' 'Go to: https://developers.google.com/sheets/api/quickstart/python\n'
"Under Step 1, click 'ENABLE THE GOOGLE SHEETS API'\n" "Under Step 1, click 'ENABLE THE GOOGLE SHEETS API'\n"
"Click 'DOWNLOAD CLIENT CONFIGURATION'\n" "Click 'DOWNLOAD CLIENT CONFIGURATION'\n"
...@@ -603,8 +607,8 @@ def main(): ...@@ -603,8 +607,8 @@ def main():
LOGGER.error('%s\n' % str(error)) LOGGER.error('%s\n' % str(error))
quit(1) quit(1)
LOGGER.info('Info was successfully parsed to sheet: ' LOGGER.info('Info was successfully parsed to sheet: https://docs.google.com/spreadsheets/d/' +
'https://docs.google.com/spreadsheets/d/' + args.spreadsheet) args.spreadsheet)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -432,23 +432,21 @@ class dEQPTest : public testing::TestWithParam<size_t> ...@@ -432,23 +432,21 @@ class dEQPTest : public testing::TestWithParam<size_t>
if (!gUnexpectedPasses.empty()) if (!gUnexpectedPasses.empty())
{ {
std::cout << GetTestStatLine("Unexpected Passed", std::cout << GetTestStatLine("Unexpected Passed Count",
std::to_string(gUnexpectedPasses.size())); std::to_string(gUnexpectedPasses.size()));
std::cout << "\nSome tests unexpectedly passed:\n";
for (const std::string &testName : gUnexpectedPasses) for (const std::string &testName : gUnexpectedPasses)
{ {
std::cout << GetTestStatLine("Unexpected Passed Test", testName); std::cout << GetTestStatLine("Unexpected Passed Tests", testName);
} }
} }
if (!gUnexpectedFailed.empty()) if (!gUnexpectedFailed.empty())
{ {
std::cout << GetTestStatLine("Unexpected Failed", std::cout << GetTestStatLine("Unexpected Failed Count",
std::to_string(gUnexpectedFailed.size())); std::to_string(gUnexpectedFailed.size()));
std::cout << "\nSome tests unexpectedly failed:\n";
for (const std::string &testName : gUnexpectedFailed) for (const std::string &testName : gUnexpectedFailed)
{ {
std::cout << GetTestStatLine("Unexpected Failed Test", testName); std::cout << GetTestStatLine("Unexpected Failed Tests", testName);
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment