blob: 6c3cab296de9beaddc43262d7502c4de956e3633 [file] [log] [blame] [edit]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This script can be used to upload CTS results to CTS and APFE buckets."""
from lib.upload_utils import UploadUtils
from xml.dom import minidom
import argparse
import getopt
import os.path
import sys
class UploadCts(UploadUtils):
"""Helps upload CTS results to gs:// buckets.
Prints CTS test results with their pass/fail status to terminal.
Prints gsutil links to the terminal to upload CTS results to gs:// buckets
to get the results in the tooling.
Attributes:
test_board_name: Test board name.
current_test_board_name: Temporary string to hold current test board name.
build_mismatch_exist: A boolean indicating if build mismatch exists.
failed_tests_exist: A boolean indicating if failed tests exist.
valid_exist: A boolean indicating if any valid file with the
correct build version exists.
untested_tests_exist: A boolean indicating if untested tests exist.
"""
def __init__(self, input_build_id, dir_path):
super(UploadCts, self).__init__()
self.test_board_name = None
self.current_test_board_name = None
self.build_mismatch_exist = False
self.valid_exist = False
self.untested_tests_exist = False
self.obsolete_files_exist = False
self.input_build_id = input_build_id
self.dir_path = dir_path
self.nextelem = 0
self.idx = 0
def PrintBuildInfoList(self):
"""Sorts build information by build board and prints to the terminal."""
self.build_info_list.sort(key=lambda x: x[1])
for item in self.build_info_list:
self.idx = (self.idx + 1) % len(self.build_info_list)
self.nextelem = self.build_info_list[self.idx]
if self.current_test_board_name != item[1]:
title_msg = 'List of files for %s' % item[1]
table_column_header = self.TABLE_HEADER_CTS
print(self.BOLD +
self.C_PURPLE +
title_msg +
self.BOLD +
self.C_END)
print(self.BOLD +
self.C_BLACK +
table_column_header +
self.BOLD +
self.C_END)
self.current_test_board_name = item[1]
if self.failed_list:
self.failed_list.clear()
if self.passed_list:
self.passed_list.clear()
self.row_count = 0
self.SegregateCtsDataToPrint(item)
#Print failed result if there is only one item in the list.
if len(self.build_info_list) == 1:
if self.failed_list:
for i in range(len(self.failed_list)):
self.PrintCtsResults(self.failed_list[i])
#If there is a mix of passed & failed results, print only valid failures.
if self.failed_list:
if self.passed_list:
#If a test has passed at least once, the results are not printed.
for i in range(len(self.failed_list)):
for j in range(len(self.passed_list)):
if(self.failed_list[i][1] == self.passed_list[j][1] and
self.failed_list[i][3] == self.passed_list[j][3] and
self.failed_list[i][5] == self.passed_list[j][5]):
self.found = 1
else:
if self.found != 1:
self.found = 0
#Check no more results to parse for board and print valid failure.
if self.found == 0 and self.nextelem[1] != item[1]:
for i in range(len(self.failed_list)):
self.PrintCtsResults(self.failed_list[i])
print('\n')
def PrintGsutilLinks(self, dir_path):
"""Prints gsutil links to upload results to CTS and APFE buckets.
Sample APFE:board.board for non-unibuild.
Sample APFE:model.board for unibuild.
Append veyron_ and auron_ to model name for veyron and auron boards.
Sample:auron_yuna.auron_yuna-release,veyron_mighty.veyron_mighty-release
Args:
dir_path: Results directory path.
"""
for item in self.build_info_list:
if self.test_board_name != item[1]:
if item[1].startswith('veyron') or item[1].startswith('auron'):
print('gsutil cp -r {0}/{1}.{2}-release/ '
'gs://chromeos-cts-apfe/'
.format(dir_path, item[1], item[1]))
else:
print('gsutil cp -r {0}/{1}.{2}-release/ gs://chromeos-cts-apfe/'
.format(dir_path, item[2], item[1]))
print('gsutil cp -r {0}/{1}_{2}/ '
'gs://chromeos-cts-results/manual'
.format(dir_path, item[3], item[1]))
self.test_board_name = item[1]
def ParseXmlFile(self, abs_input_file_path, test_result_filename, dir_path):
"""Gets build information from test_result.xml file.
Parses the test result xml file to obtain build information. Adds build
information to a list. Handles Untested tests if they exist. Untested
tests may not have complete build information or may have partial
build information in the test_result.xml file.
Args:
abs_input_file_path: Absolute input file path.
Eg: ~/Downloads/Manual/2017.09.22_14.27.09.zip
test_result_filename: test result file name.
Eg: test_result.xml
dir_path: Results directory path.
Eg: ~/Downloads/Manual
"""
self.GetXmlTagNamesCts()
tag_list = self.GetXmlTagNamesCts()
summary = tag_list[0]
build_version = tag_list[1]
build_board_version = tag_list[2]
build_model_version = tag_list[3]
build_id_type = tag_list[4]
test_package_list = tag_list[5]
test_package_v = tag_list[6]
build_abi_type = tag_list[7]
failed = tag_list[8]
passed = tag_list[9]
test = tag_list[10]
name = tag_list[11]
split_file_list = self.SplitFileName(abs_input_file_path)
basename = split_file_list[1]
full_base_name = os.path.join(dir_path, basename)
basename_xml_file = split_file_list[2]
absolute_base_xml_file = os.path.join(dir_path, basename_xml_file)
timestamp = basename
self.CopyFileToDestination(full_base_name,
test_result_filename,
dir_path,
basename_xml_file)
xml_doc = minidom.parse(absolute_base_xml_file)
summary = xml_doc.getElementsByTagName(summary)
build_info = xml_doc.getElementsByTagName(build_version)
test_package_list = xml_doc.getElementsByTagName(test_package_list)
test = xml_doc.getElementsByTagName(test)
if not build_info:
self.UpdateBuildInfoList([timestamp,
'null',
'null',
'null',
'null',
'0',
'0'])
self.untested_tests_exist = True
elif not build_info[0].hasAttribute(build_board_version):
self.UpdateBuildInfoList([timestamp,
'null',
'null',
'null',
'null',
'0',
'0'])
self.untested_tests_exist = True
elif not test_package_list:
self.UpdateBuildInfoList([timestamp,
'null',
'null',
'null',
'null',
'0',
'0'])
self.untested_tests_exist = True
else:
build_board = build_info[0].attributes[build_board_version].value
build_model = build_info[0].attributes[build_model_version].value
build_id = build_info[0].attributes[build_id_type].value
test_package = test_package_list[0].attributes[test_package_v].value
build_abi = test_package_list[0].attributes[build_abi_type].value
failed = summary[0].attributes[failed].value
passed = summary[0].attributes[passed].value
test = test[0].attributes[name].value
self.UpdateBuildInfoList([timestamp,
build_board,
build_model,
build_id,
build_abi,
test_package,
test,
failed,
passed])
def ProcessFilesToUpload(self, input_build_id, dir_path):
"""Process Files to Upload to CTS and APFE Buckets.
Parses the test_result.xml file to obtain build information.Checks for file
validity by comparing with provided input BuildID. Pushes valid files to
appropriate folders to upload to APFE and CTS buckets.Pushes invalid
files to Obsolete Folder.Pushes untested files if any to UnTested
Folder.
Args:
input_build_id: BuildID command line argument.
dir_path: Results directory path.
"""
test_result_filename_n_build = 'test_result.xml'
build_id = ' '
item = ' '
for the_file in os.listdir(dir_path):
if the_file.endswith('.zip'):
full_file_path = os.path.join(dir_path, the_file)
self.ExtractZipFile(full_file_path, dir_path)
self.ParseXmlFile(full_file_path,
test_result_filename_n_build,
dir_path)
for item in self.build_info_list:
build_id = item[3]
if build_id == input_build_id:
self.valid_exist = True
self.CreateApfeFolder(full_file_path, dir_path)
self.CreateCtsFolder(full_file_path, dir_path)
else:
self.obsolete_files_exist = True
if self.untested_tests_exist is True:
self.build_info_list.remove(item)
self.CreateUntestedFolder(full_file_path, dir_path)
self.untested_tests_exist = False
else:
self.build_mismatch_exist = True
self.build_info_list.remove(item)
self.CreateObsoleteFolder(full_file_path, dir_path)
def PrintData(self, dir_path):
"""Print results/gsutil links or error message if invalid files exist."""
if not self.obsolete_files_exist:
self.PrintBuildInfoList()
self.PrintGsutilLinks(dir_path)
if self.build_mismatch_exist is True and self.valid_exist is True:
self.PrintBuildInfoList()
self.PrintGsutilLinks(dir_path)
self.PrintObsoleteFolderCount()
if self.untested_file_count > 0 and self.valid_exist is True:
self.PrintBuildInfoList()
self.PrintGsutilLinks(dir_path)
self.PrintUntestedFolderCount()
if self.obsolete_files_exist is True and not self.valid_exist:
self.PrintObsoleteFolderCount()
self.PrintUntestedFolderCount()
def main(argv):
"""Processes result files and prints gsutil links to upload CTS results.
Displays help message when script is called without expected arguments.
Displays Usage: upload_cts.py <build_id> <results_dir_path>.
"""
parser = argparse.ArgumentParser()
parser.add_argument('build_id',
help='upload_cts.py <build_id> <results_dir_path>')
parser.add_argument('dir_path',
help='upload_cts.py <build_id> <results_dir_path>')
args = parser.parse_args()
cts = UploadCts(args.build_id, args.dir_path)
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
parser.parse_args()
try:
opts, args = getopt.getopt(argv, 'hb:', ['build_id='])
except getopt.GetoptError:
sys.exit(2)
for opt in opts:
if opt == '-h':
cts.usage()
sys.exit()
cts.ProcessFilesToUpload(cts.input_build_id, cts.dir_path)
os.system('stty cols 120')
cts.PrintData(cts.dir_path)
if __name__ == '__main__':
main(sys.argv[1:])