Scripts to upload CTS-M/CTS-V results to buckets.
BUG=b:62536312
TEST=./cts_upload.py <build_id> <results_dir_path>
TEST=./cts_upload_verifier.py <build_id> <results_dir_path>
Change-Id: I08a1806d4b2395469261545f7b92d30759d50850
Reviewed-on: https://chromium-review.googlesource.com/658321
Commit-Ready: Nita Nair <nnita@chromium.org>
Tested-by: Nita Nair <nnita@chromium.org>
Reviewed-by: Rohit Makasana <rohitbm@chromium.org>
diff --git a/provingground/cts/lib/__init__.py b/provingground/cts/lib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/provingground/cts/lib/__init__.py
diff --git a/provingground/cts/lib/upload_utils.py b/provingground/cts/lib/upload_utils.py
new file mode 100755
index 0000000..23c911e
--- /dev/null
+++ b/provingground/cts/lib/upload_utils.py
@@ -0,0 +1,298 @@
+#!/usr/bin/env python3
+#
+# 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 has helper methods to facilitate CTS/CTS-V upload."""
+
+from __future__ import print_function
+from subprocess import check_call
+
+import os
+import shutil
+import zipfile
+
+
+class UploadUtils(object):
+ """Internal Helper for CTS and CTS Verifier Upload scripts."""
+
+ SPACE_COUNT_CTSV_BOARD_NAME = 14
+ SPACE_COUNT_CTSV_BUILD_VERSION = 22
+ SPACE_COUNT_VERIFIER_VERSION = 18
+ SPACE_COUNT_TIMESTAMP = 17
+ SPACE_COUNT_CTS_BOARD_NAME = 13
+ SPACE_COUNT_CTS_BUILD_VERSION = 12
+ SPACE_COUNT_CTS_BOARD_ABI = 13
+ SPACE_COUNT_PACKAGE_NAME = 30
+ SPACE_COUNT_FAILED_TESTS = 6
+ SPACE_COUNT_PASSED_TESTS = 6
+ C_PURPLE = '\033[95m'
+ C_RED = '\033[91m'
+ C_BLACK = '\033[98m'
+ BOLD = '\033[1m'
+ C_END = '\033[00m'
+ TABLE_HEADER_CTS = (' Time Stamp : Board :'
+ 'Build Version : Board ABI : '
+ 'TEST PACKAGE / MODULE NAME : FAILED :'
+ ' PASSED')
+ TABLE_HEADER_CTSV = (' Build Board Name : '
+ 'Build Board Version : '
+ 'CTS VERIFIER VERSION')
+ def __init__(self):
+ self.build_info_list = []
+ self.obsolete_file_count = 0
+ self.untested_file_count = 0
+ self.build_mismatch_file_count = 0
+
+ def PrintObsoleteFolderCount(self):
+ """Prints obsolete file count in case of build id mismatch."""
+ if not self.build_mismatch_file_count == 0:
+ err_msg = ('Build ID Mismatch!Pushed {0} invalid files to BuildID'
+ ' Mismatch Folder'.format(self.build_mismatch_file_count))
+ print(self.BOLD + self.C_RED + err_msg +self.BOLD+ self.C_END)
+
+ def PrintUntestedFolderCount(self):
+ """Prints untested file count if untested tests exist."""
+ if not self.untested_file_count == 0:
+ err_msg = ('Untested Test(s) Detected!Pushed {0} files to Untested'
+ ' Tests Folder'.format(self.untested_file_count))
+ print(self.BOLD + self.C_RED + err_msg +self.BOLD+ self.C_END)
+
+ def ExtractZipFile(self, zipped_file, dir_path):
+ """Extracts Zip File contents to current working directory.
+
+ Args:
+ zipped_file: Input zip file.
+ dir_path: Results directory path.
+ """
+ with zipfile.ZipFile(zipped_file, 'r') as zf:
+ zf.extractall(dir_path)
+
+ def CopyFileToDestination(self, src_path, src_file_name,
+ dest_path, dest_file_name):
+ """Copies file from source path to destination path
+
+ Args:
+ src_path: source file path.
+ src_file_name: source file name.
+ dest_path: destination file path.
+ dest_file_name: destination file name.
+ """
+ src_file = os.path.join(src_path, src_file_name)
+ dest_file = os.path.join(dest_path, dest_file_name)
+ try:
+ shutil.copy(src_file, dest_file)
+ except IOError as e:
+ print('Unable to copy file. %s' % e)
+
+ def SplitFileName(self, file_path):
+ """Splits file to create file names with different extensions.
+
+ Args:
+ file_path: Input file path.
+ Sample Input File: ~/Downloads/Manual/2017.09.22_14.27.09.zip
+
+ Returns:
+ List of base file names with different extensions.
+ Sample base file names returned in split_file_list:
+ base: 2017.09.22_14.27.09.zip
+ basename: 2017.09.22_14.27.09
+ basename_xml_file: 2017.09.22_14.27.09.xml
+ basename_xml_gz_file: 2017.09.22_14.27.09.xml.gz
+ """
+ base = os.path.basename(file_path)
+ basename = os.path.splitext(base)[0]
+ basename_xml_file = '%s%s' % (basename, '.xml')
+ basename_xml_gz_file = '%s%s%s' % (basename, '.xml', '.gz')
+ return [base,
+ basename,
+ basename_xml_file,
+ basename_xml_gz_file]
+
+ def PrintFormattedDataCtsv(self, item):
+ """Prints build information in a tabular form to the terminal.
+
+ Sample table printed to terminal:
+ Build Board Name : Build Board Version : CTS VERIFIER VERSION
+ : relm : R62-9901.20.0 : 7.1_r9
+
+ Args:
+ item: Information list to be printed to terminal.
+ """
+ print(('{:^%s}'%self.SPACE_COUNT_CTSV_BOARD_NAME).format(item[1]),
+ ('{:>%s}'%self.SPACE_COUNT_CTSV_BUILD_VERSION).format(item[2]),
+ ('{:>%s}'%self.SPACE_COUNT_VERIFIER_VERSION).format(item[3]))
+
+ def PrintFormattedDataCts(self, item):
+ """Prints build information in a tabular form to the terminal.
+
+ Sample table printed to terminal:
+ : Time Stamp : Build Board Name : Build Version: Build BOARD ABI
+ : PACKAGE NAME : FAILED : PASSED
+ : 2017.09.22_14.27.09: relm : R62-9901.20.0: x86
+ : CtsUsageStatsTestCases : 0 : 1
+
+ Args:
+ item: Information List to be printed to terminal.
+ """
+ print(('{:>%s}'%self.SPACE_COUNT_TIMESTAMP).format(item[0]),
+ ('{:^%s}'%self.SPACE_COUNT_CTS_BOARD_NAME).format(item[1]),
+ ('{:^%s}'%self.SPACE_COUNT_CTS_BUILD_VERSION).format(item[2]),
+ ('{:>%s}'%self.SPACE_COUNT_CTS_BOARD_ABI).format(item[3]),
+ ('{:^%s}'%self.SPACE_COUNT_PACKAGE_NAME).format(item[4]),
+ ('{:<%s}'%self.SPACE_COUNT_FAILED_TESTS).format(item[5]),
+ ('{:<%s}'%self.SPACE_COUNT_PASSED_TESTS).format(item[6]))
+
+ def GetXmlTagNamesCtsv(self):
+ """Get xml tag names.
+
+ Returns:
+ tag_list: List of xml tag names.
+ """
+ BUILD_N = 'Build'
+ RESULT = 'Result'
+ SUITE_VERSION = 'suite_version'
+ BUILD_BOARD = 'build_board'
+ BUILD_ID_N = 'build_id'
+ TEST = 'Test'
+ return [BUILD_N,
+ RESULT,
+ SUITE_VERSION,
+ BUILD_BOARD,
+ BUILD_ID_N,
+ TEST]
+
+ def GetXmlTagNamesCts(self, test_result_filename):
+ """Get xml tag names from M/N test result xml file.
+
+ Args:
+ test_result_filename: M/N Build Test Result file name.
+
+ Returns:
+ tag_list: List of xml tag names.
+ """
+ TEST_RESULT_FILENAME_M_BUILD = 'testResult.xml'
+ SUMMARY = 'Summary'
+ BUILD_M = 'BuildInfo'
+ BUILD_N = 'Build'
+ BUILD_BOARD_VERSION = 'build_board'
+ BUILD_ID_M = 'buildID'
+ BUILD_ID_N = 'build_id'
+ TEST_PACKAGE_LIST_M = 'TestPackage'
+ TEST_PACKAGE_LIST_N = 'Module'
+ TEST_PACKAGE_NAME_M = 'appPackageName'
+ TEST_PACKAGE_NAME_N = 'name'
+ BUILD_ABI_TYPE = 'abi'
+ FAILED = 'failed'
+ PASSED = 'pass'
+ if test_result_filename == TEST_RESULT_FILENAME_M_BUILD:
+ BUILD_VERSION = BUILD_M
+ BUILD_ID_TYPE = BUILD_ID_M
+ TEST_PACKAGE_LIST_VERSION = TEST_PACKAGE_LIST_M
+ TEST_PACKAGE_NAME_VERSION = TEST_PACKAGE_NAME_M
+ else:
+ BUILD_VERSION = BUILD_N
+ BUILD_ID_TYPE = BUILD_ID_N
+ TEST_PACKAGE_LIST_VERSION = TEST_PACKAGE_LIST_N
+ TEST_PACKAGE_NAME_VERSION = TEST_PACKAGE_NAME_N
+ return [SUMMARY,
+ BUILD_VERSION,
+ BUILD_BOARD_VERSION,
+ BUILD_ID_TYPE,
+ TEST_PACKAGE_LIST_VERSION,
+ TEST_PACKAGE_NAME_VERSION,
+ BUILD_ABI_TYPE,
+ FAILED,
+ PASSED]
+
+ def UpdateBuildInfoList(self, obj):
+ """Appends object to list.
+
+ Args:
+ obj: Contents to be appended to list.
+ """
+ self.build_info_list.append(obj)
+
+ def CreateApfeFolder(self, filename, dir_path):
+ """Creates hierarchy for uploading result files to APFE bucket.
+
+ Args:
+ filename: Valid file to upload to APFE folder.
+ dir_path: Results directory path.
+ """
+ build_board = ''
+ build_id = ''
+ split_file_list = self.SplitFileName(filename)
+ base = split_file_list[0]
+ build_board = self.build_info_list[-1][1]
+ build_id = self.build_info_list[-1][2]
+ release_folder = '%s-release' % build_board
+ build_folder = '%s' % build_id
+ manual_folder = 'manual'
+ apfe_path = os.path.join(dir_path, release_folder, build_folder,
+ manual_folder)
+ if not os.path.exists(apfe_path):
+ os.makedirs(apfe_path)
+ self.CopyFileToDestination(dir_path, base, apfe_path, base)
+
+ def CreateCtsFolder(self, filename, dir_path):
+ """Creates hierarchy for upload to CTS Dashboard bucket.
+
+ Args:
+ filename: Input File to be added to CTS folder.
+ dir_path: Results directory path.
+ """
+ build_id = None
+ build_board = None
+ build_board = self.build_info_list[-1][1]
+ build_id = self.build_info_list[-1][2]
+ split_file_list = self.SplitFileName(filename)
+ basename_xml_file = split_file_list[2]
+ basename_xml_gz_file = split_file_list[3]
+ build_id_board_folder = '%s_%s' % (build_id, build_board)
+ cts_path = os.path.join(dir_path, build_id_board_folder)
+ if not os.path.exists(cts_path):
+ os.makedirs(cts_path)
+ gzip_file_path = os.path.join(dir_path, basename_xml_file)
+ check_call(['gzip', gzip_file_path])
+ self.CopyFileToDestination(dir_path,
+ basename_xml_gz_file,
+ cts_path,
+ basename_xml_gz_file)
+
+ def CreateUntestedFolder(self, filename, dir_path):
+ """Creates Untested Folder to save files if there are UnTested Tests.
+
+ Args:
+ filename: Input file name.
+ dir_path: Results directory path.
+ """
+ split_file_list = self.SplitFileName(filename)
+ base = split_file_list[0]
+ if self.untested_tests_exist is True:
+ self.untested_file_count = self.untested_file_count + 1
+ untested_folder = 'Untested Tests'
+ untested_path = os.path.join(dir_path, untested_folder)
+ if not os.path.exists(untested_path):
+ os.makedirs(untested_path)
+ self.CopyFileToDestination(dir_path, base, untested_path, base)
+
+ def CreateObsoleteFolder(self, filename, dir_path):
+ """Creates Obsolete Folder to save files if there is a BUILDID mismatch.
+
+ Args:
+ filename: Input file name.
+ dir_path: Results directory path.
+ """
+ split_file_list = self.SplitFileName(filename)
+ base = split_file_list[0]
+ if self.build_mismatch_exist is True:
+ self.build_mismatch_file_count = self.build_mismatch_file_count + 1
+ if self.untested_tests_exist is True:
+ self.untested_file_count = self.untested_file_count + 1
+ obsolete_folder = 'BuildID Mismatch Folder'
+ obsolete_path = os.path.join(dir_path, obsolete_folder)
+ if not os.path.exists(obsolete_path):
+ os.makedirs(obsolete_path)
+ self.CopyFileToDestination(dir_path, base, obsolete_path, base)
diff --git a/provingground/cts/upload_cts.py b/provingground/cts/upload_cts.py
new file mode 100755
index 0000000..f21cbac
--- /dev/null
+++ b/provingground/cts/upload_cts.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python3
+#
+# 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 __future__ import print_function
+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
+
+ 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:
+ 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]
+ self.PrintFormattedDataCts(item)
+ print('\n')
+
+ def PrintGsutilLinks(self, dir_path):
+ """Prints gsutil links to upload results to CTS and APFE buckets.
+
+ Args:
+ dir_path: Results directory path.
+ """
+ for item in self.build_info_list:
+ if self.test_board_name != item[1]:
+ print('gsutil cp -r {0}/{1}-release/ gs://chromeos-cts-apfe/'
+ .format(dir_path, item[1]))
+ print('gsutil cp -r {0}/{1}_{2}/ '
+ 'gs://chromeos-cts-results/manual'
+ .format(dir_path, item[2], item[1]))
+ self.test_board_name = item[1]
+
+
+ def ParseXmlFile(self, abs_input_file_path, test_result_filename, dir_path):
+ """Gets build information for M or N Builds.
+
+ 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: M/N build test result file name.
+ Eg: testResult.xml(M) or test_result.xml(N)
+ dir_path: Results directory path.
+ Eg: ~/Downloads/Manual
+ """
+ self.GetXmlTagNamesCts(test_result_filename)
+ tag_list = self.GetXmlTagNamesCts(test_result_filename)
+ summary = tag_list[0]
+ build_version = tag_list[1]
+ build_board_version = tag_list[2]
+ build_id_type = tag_list[3]
+ test_package_list = tag_list[4]
+ test_package_v = tag_list[5]
+ build_abi_type = tag_list[6]
+ failed = tag_list[7]
+ passed = tag_list[8]
+ 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)
+ 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_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
+ self.UpdateBuildInfoList([timestamp,
+ build_board,
+ build_id,
+ build_abi,
+ test_package,
+ failed,
+ passed])
+
+ def ProcessFilesToUpload(self, input_build_id, dir_path):
+ """Process Files to Upload to CTS and APFE Buckets.
+
+ Checks if Test Result File has M build or N Build and parses the
+ corresponding 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'
+ test_result_filename_m_build = 'testResult.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)
+ split_file_list = self.SplitFileName(full_file_path)
+ basename = split_file_list[1]
+ full_base_name = os.path.join(dir_path, basename)
+ src_file = os.path.join(full_base_name,
+ test_result_filename_m_build)
+ is_m_build = os.path.isfile(src_file)
+ if is_m_build is True:
+ self.ParseXmlFile(full_file_path,
+ test_result_filename_m_build,
+ dir_path)
+
+ else:
+ self.ParseXmlFile(full_file_path,
+ test_result_filename_n_build,
+ dir_path)
+
+ for item in self.build_info_list:
+ build_id = item[2]
+
+ 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:])
diff --git a/provingground/cts/upload_cts_verifier.py b/provingground/cts/upload_cts_verifier.py
new file mode 100755
index 0000000..12e8e84
--- /dev/null
+++ b/provingground/cts/upload_cts_verifier.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python3
+#
+# 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 Verifier results to CTS Dashboard."""
+
+from __future__ import print_function
+from lib.upload_utils import UploadUtils
+from xml.dom import minidom
+
+import argparse
+import getopt
+import os.path
+import sys
+
+
+class UploadCtsVerifier(UploadUtils):
+ """Helps upload CTS-V results to gs:// buckets.
+
+ Prints CTS-V test results with their pass/fail status to terminal.
+ Prints gsutil links to the terminal to upload CTS-V results to gs:// buckets
+ to get the results in the tooling.
+
+ Attributes:
+ build_mismatch_exist: A boolean indicating if build mismatch exists.
+ failed_tests_exist: A boolean indicating if failed tests exist.
+ valid_files_exist: A boolean indicating if any valid file with the
+ correct build version exists.
+ untested_tests_exist: A boolean indicating if untested tests exist.
+ test_board_name_list: List of test board names.
+ """
+
+ def __init__(self):
+ super(UploadCtsVerifier, self).__init__()
+ self.build_mismatch_exist = False
+ self.failed_tests_exist = False
+ self.valid_files_exist = False
+ self.untested_tests_exist = False
+ self.test_board_name_list = []
+
+ 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:
+ if item[1] not in self.test_board_name_list:
+ title_msg = 'List of files for %s' % item[1]
+ table_column_header = self.TABLE_HEADER_CTSV
+ 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.test_board_name_list.append(item[1])
+ self.PrintFormattedDataCtsv(item)
+ print('\n')
+
+ def PrintGsutilLinks(self, dir_path):
+ """Prints gsutil links to upload results to CTS-V dashboard bucket.
+
+ Args:
+ dir_path: Results directory path.
+ """
+ for item in self.build_info_list:
+ gsutil_msg = ('gsutil cp -r {0}/{1}_{2}/ '
+ 'gs://chromeos-cts-results/ctsVerifier'
+ .format(dir_path, item[2], item[1]))
+ print(self.BOLD + self.C_PURPLE + gsutil_msg + self.BOLD + self.C_END)
+
+ def PrintIfAllTestsPassed(self):
+ """Print message to terminal if all tests have passed."""
+ if not self.failed_tests_exist and self.build_mismatch_file_count == 0:
+ print('All Cts Verifier Tests passed!')
+
+ def PrintFailedTestResults(self, tests):
+ """Prints failed results if any to the terminal.
+
+ Args:
+ tests: CTS Verifier Test Results.
+ """
+ test_title = ' '
+ result = ' '
+ for test in tests:
+ test_title = test.getAttribute('name')
+ result = test.getAttribute('result')
+ if result == 'fail' or result == 'not-executed':
+ self.failed_tests_exist = True
+ print('Test Title:%s, Result:%s' % (test_title, result))
+ print('\n')
+
+ def ParseXmlFile(self, abs_input_file_path, dir_path):
+ """Gets build information from CTS Verifier xml file.
+
+ Parses the CTS Verifier Xml File to obtain Build Information such as
+ basename, build_board, build_id, suite_version.
+
+ Args:
+ abs_input_file_path: Absolute Input file path.
+ Eg: ~/Downloads/ctsv/2017.09.21_17.13.04-
+ CTS_VERIFIER-google-relm-relm_cheets-R62-9901.20.0
+ dir_path: Results directory path.
+ Eg: ~/Downloads/Manual
+
+ Returns:
+ tests: CTS Verifier Test Results.
+ """
+ test_result_filename_n_build = 'test_result.xml'
+ tag_list = self.GetXmlTagNamesCtsv()
+ build_version = tag_list[0]
+ result = tag_list[1]
+ suite_version = tag_list[2]
+ build_board = tag_list[3]
+ build_id_n = tag_list[4]
+ test = tag_list[5]
+ 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)
+ self.CopyFileToDestination(full_base_name,
+ test_result_filename_n_build,
+ dir_path,
+ basename_xml_file)
+ xml_doc = minidom.parse(absolute_base_xml_file)
+ build = xml_doc.getElementsByTagName(build_version)
+ verifier_info = xml_doc.getElementsByTagName(result)
+ suite_version = verifier_info[0].attributes[suite_version].value
+ build_board = build[0].attributes[build_board].value
+ build_id = build[0].attributes[build_id_n].value
+ tests = xml_doc.getElementsByTagName(test)
+ self.UpdateBuildInfoList(
+ [basename, build_board, build_id, suite_version])
+ return tests
+
+ def ProcessFilesToUpload(self, input_build_id, dir_path):
+ """Process Files to Upload to CTS Verifier Bucket.
+
+ Parses the test_result.xml file to obtain build information.
+ Pushes valid files to appropriate folders to upload to CTS-V bucket.
+ Pushes invalid files to Obsolete Folder.
+ Print Build results to terminal.
+
+ Args:
+ input_build_id: Build ID for which results are to be uploaded.
+ dir_path: Results directory path.
+ """
+ build_id = ' '
+ item = ' '
+ for the_file in os.listdir(dir_path):
+ if the_file.endswith('.zip'):
+ full_file = os.path.join(dir_path, the_file)
+ self.ExtractZipFile(full_file, dir_path)
+ tests = self.ParseXmlFile(the_file, dir_path)
+ for item in self.build_info_list:
+ build_id = item[2]
+ if build_id == input_build_id:
+ self.valid_files_exist = True
+ self.failed_tests_exist = False
+ self.CreateCtsFolder(full_file, dir_path)
+ self.PrintBuildInfoList()
+ self.PrintFailedTestResults(tests)
+ self.PrintIfAllTestsPassed()
+ else:
+ self.build_mismatch_exist = True
+ self.build_info_list.remove(item)
+ self.CreateObsoleteFolder(full_file, dir_path)
+
+def main(argv):
+ """Processes result files and prints gsutil links to upload CTS-V results.
+
+ Displays help message when script is called without expected arguments.
+ Displays Usage: upload_cts_verifier.py <build_id> <results_dir_path>
+ """
+ parser = argparse.ArgumentParser()
+ parser.add_argument('build_id',
+ help='Usage: upload_cts_verifier.py'
+ '<build_id>'
+ '<results_dir_path>')
+ parser.add_argument('dir_path',
+ help='Usage: upload_cts_verifier.py'
+ '<build_id>'
+ '<results_dir_path>')
+ args = parser.parse_args()
+ input_build_id = args.build_id
+ dir_path = args.dir_path
+ if len(sys.argv) == 1:
+ parser.print_help()
+ sys.exit(1)
+ parser.parse_args()
+ try:
+ opts, args = getopt.getopt(argv, 'hb:', ['buildID='])
+ except getopt.GetoptError:
+ print('upload_cts_verifier.py <build_id> <results_dir_path>')
+ sys.exit(2)
+ ctsv = UploadCtsVerifier()
+ for opt in opts:
+ if opt == '-h':
+ ctsv.usage()
+ sys.exit()
+ ctsv.ProcessFilesToUpload(input_build_id, dir_path)
+ if ctsv.valid_files_exist is True:
+ ctsv.PrintGsutilLinks(dir_path)
+ if ctsv.build_mismatch_exist is True:
+ ctsv.PrintObsoleteFolderCount()
+
+if __name__ == '__main__':
+ main(sys.argv[1:])