diff options
author | Arthur She <arthur.she@linaro.org> | 2015-10-17 22:53:39 -0700 |
---|---|---|
committer | Arthur She <arthur.she@linaro.org> | 2015-10-17 22:53:39 -0700 |
commit | 329aa6129426668ddb7c14e7e495a727f184b6b3 (patch) | |
tree | 36a73c1c0aa9a3b631281bd89ce952353fcf8111 | |
parent | 7c3752d50b921462e1441370be1ace50690adddd (diff) |
1. Add argument for Jenkins URL, template file, result file.
2. process uncomplete test jobs
3. using logging module
modified: report_automation.py
-rwxr-xr-x | report_automation.py | 177 |
1 files changed, 103 insertions, 74 deletions
diff --git a/report_automation.py b/report_automation.py index f427283..e8b2cb7 100755 --- a/report_automation.py +++ b/report_automation.py @@ -9,17 +9,23 @@ import zipfile import base64 import shutil import argparse +import logging +from argparse import RawTextHelpFormatter +import netrc from StringIO import StringIO import xml.etree.ElementTree as ET from py3o.template import Template from jenkinsapi.jenkins import Jenkins CTS_RESULT_FILE_NAME = "testResult.xml" +logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) +logger = logging.getLogger(__name__) +#logger.setLevel(logging.INFO) class LinaroAndroidBuildSystem(object): def __init__(self, base_url, build_job, username=None, password=None): - print("Jenkins build job: %s" % build_job) + logger.info("Jenkins build job: %s" % build_job) self.base_url = base_url self.build_job = build_job self.username = username @@ -28,19 +34,17 @@ class LinaroAndroidBuildSystem(object): self.jenkins = Jenkins(self.base_url, self.username, self.password) self.project = self.jenkins[self.build_job] except Exception as e: - print("Can not get Jenkins job: %s" % project) - print e + logger.exception("Can not get Jenkins job: %s" % project) def get_build(self, build_no): try: build = self.project.get_build(build_no) return build except Exception as e: - print("Can not get build: #%d" % build_no) - print e + logger.exception("Can not get build: #%d" % build_no) def get_test_job_ids(self, build_no): - print("Querying build #%d test job ids from Jenkins build job: %s" % + logger.info("Querying build #%d test job ids from Jenkins build job: %s" % (build_no, self.build_job)) job_id_list = [] build = self.get_build(build_no) @@ -57,28 +61,32 @@ class LAVA(object): server_url = "https://%s:%s@%sRPC2/" % (self.username, self.token, self.lava_server.split("//")[1]) self.server = xmlrpclib.ServerProxy(server_url) except: - print("Can not connect to LAVA server: %s" % lava_server) + logger.error("Can not connect to LAVA server: %s" % lava_server) + exit(-1) def get_job_info(self, job_no): job_info = {} try: job_status = self.server.scheduler.job_status(job_no) - job_detail = self.server.scheduler.job_details(job_no) - except: - print("Can not get any information for test job: %d" % job_no) + except Exception as e: + logger.exception("Can not get any information for test job: %s" % job_no) - job_info['job_no'] = job_no - job_info['result_link'] = job_detail['_results_link'] - job_info['result_bundle'] = json.loads(self.server.dashboard.get(job_status['bundle_sha1'])['content']) - if any(t['test_id'] == 'bionic_libc_tests' for t in job_info['result_bundle']['test_runs']): - job_info['type'] = "lava_test" - elif any(t['test_id'] == 'cts-host' for t in job_info['result_bundle']['test_runs']): - job_info['type'] = "cts" - elif any(t['test_id'] == 'lava-android-benchmark-target' or t['test_id'] == 'wa2-host-postprocessing' - for t in job_info['result_bundle']['test_runs']): - job_info['type'] = "benchmark" + if job_status['job_status'] != 'Complete': + logger.warning("!!Job #%s is not a complete job.\n\tJob status: %s!! " % (job_no, job_status['job_status'])) else: - job_info['type'] = "other" + job_detail = self.server.scheduler.job_details(job_no) + job_info['job_no'] = job_no + job_info['result_link'] = job_detail['_results_link'] + job_info['result_bundle'] = json.loads(self.server.dashboard.get(job_status['bundle_sha1'])['content']) + if any(t['test_id'] == 'bionic_libc_tests' for t in job_info['result_bundle']['test_runs']): + job_info['type'] = "lava_test" + elif any(t['test_id'] == 'cts-host' for t in job_info['result_bundle']['test_runs']): + job_info['type'] = "cts" + elif any(t['test_id'] == 'lava-android-benchmark-target' or t['test_id'] == 'wa2-host-postprocessing' + for t in job_info['result_bundle']['test_runs']): + job_info['type'] = "benchmark" + else: + job_info['type'] = "other" return job_info @@ -152,7 +160,7 @@ class Report(object): self.kernel_version = kernel_version def parse_lava_test(self, job_info): - print("Parsing lava test job #%s" % job_info['job_no']) + logger.info("Parsing lava test job #%s" % job_info['job_no']) lava_tests = {} lava_tests['result_link'] = job_info['result_link'] lava_tests['test_cases'] = [] @@ -176,7 +184,7 @@ class Report(object): self.lava_tests = lava_tests def parse_benchmark_test(self, job_info): - print("Parsing benchmark test job #%s" % job_info['job_no']) + logger.info("Parsing benchmark test job #%s" % job_info['job_no']) benchmark_test = {} sub_tests = [] try: @@ -185,8 +193,7 @@ class Report(object): t['test_id'] == 'wa2-host-postprocessing').next() src = (s for s in test_run['software_context']['sources'] if 'test_params' in s).next() except Exception as e: - print("Job %s seems not be a completed job." % job_info['job_no']) - print e + logger.exception("\tJob %s seems not be a completed job." % job_info['job_no']) if test_run['test_id'] == 'lava-android-benchmark-host': benchmark_test['test_id'] = ast.literal_eval(src['test_params'])['TEST_NAME'] else: @@ -210,39 +217,41 @@ class Report(object): self.benchmark_tests.append(benchmark_test) def parse_cts(self, job_info): - print("Parsing cts test job #%s" % job_info['job_no']) + logger.info("Parsing cts test job #%s" % job_info['job_no']) + attachment = None try: test_run = (r for r in job_info['result_bundle']['test_runs'] if r['test_id'] == 'cts-host').next() attachment = (a for a in test_run['attachments'] if a['pathname'].startswith('android-cts')).next() except Exception as e: - print("Job %s seems not be a completed job." % job_info['job_no']) - print e - try: - infile = StringIO(attachment['content']) - outfile = StringIO() - base64.decode(infile, outfile) - compressed = zipfile.ZipFile(outfile) - compressed.extractall() - except Exception as e: - print("Can not extract attachment: %s" % attachment['pathname']) - print e - CTS_TEST_RESULT_DIR = "./%s" % attachment['pathname'].split('/')[-1].split('.zip')[0] - CTS_RESULT_FILE = "%s/%s" % (CTS_TEST_RESULT_DIR, CTS_RESULT_FILE_NAME) - tree = ET.parse(CTS_RESULT_FILE) - root = tree.getroot() - for pkg in root.iter("TestPackage"): - cts_test = {} - cts_test['package_name'] = pkg.get('appPackageName') - cts_test['total'] = len(pkg.findall(".//Test")) - cts_test['passed'] = len(pkg.findall(".//Test[@result='pass']")) - cts_test['failed'] = len(pkg.findall(".//Test[@result='fail']")) - cts_test['skipped'] = len(pkg.findall(".//Test[@result='skip']")) - cts_test['pass_rate'] = 100 * cts_test['passed']/cts_test['total'] - self.cts_tests['test_pkgs'].append(cts_test) + logger.exception("\tJob %s seems not be a completed job." % job_info['job_no']) - shutil.rmtree(CTS_TEST_RESULT_DIR) + if attachment is not None: + try: + infile = StringIO(attachment['content']) + outfile = StringIO() + base64.decode(infile, outfile) + compressed = zipfile.ZipFile(outfile) + compressed.extractall() + except Exception as e: + logger.exception("\tCan not extract attachment: %s" % attachment['pathname']) + CTS_TEST_RESULT_DIR = "./%s" % attachment['pathname'].split('/')[-1].split('.zip')[0] + CTS_RESULT_FILE = "%s/%s" % (CTS_TEST_RESULT_DIR, CTS_RESULT_FILE_NAME) + tree = ET.parse(CTS_RESULT_FILE) + root = tree.getroot() + for pkg in root.iter("TestPackage"): + cts_test = {} + cts_test['package_name'] = pkg.get('appPackageName') + cts_test['total'] = len(pkg.findall(".//Test")) + cts_test['passed'] = len(pkg.findall(".//Test[@result='pass']")) + cts_test['failed'] = len(pkg.findall(".//Test[@result='fail']")) + cts_test['skipped'] = len(pkg.findall(".//Test[@result='skip']")) + cts_test['pass_rate'] = 100 * cts_test['passed']/cts_test['total'] + self.cts_tests['test_pkgs'].append(cts_test) + shutil.rmtree(CTS_TEST_RESULT_DIR) + else: + logger.warning("\tNo attachment in it") def to_dict(self): # Calculate numbers of CTS tests @@ -268,53 +277,73 @@ if __name__ == '__main__': JENKINS_URL = "https://android-build.linaro.org/jenkins/" JENKINS_JOB = "linaro-android_lcr-member-juno" - LAVA_USERNAME = "arthur.she" - LAVA_TOKEN = "a6eajjn85bp11n87u30oaxb11ewn687843btsdw63wc3gt10t72rqj4x3bi0bd0czuqotz8rp2w3moa5gja5r03u920f0duux10z78t7fcdslqi8omaxtnsgttgfcfs7" REPORT_TEMPLATE = "py3o_report_juno_template.odt" - REPORT_OUTPUT = "py3o_report_juno_output.odt" + REPORT_OUTPUT = "report_output.odt" - parser = argparse.ArgumentParser() - parser.add_argument("-job", "--jenkins_job_name", type=str, default=JENKINS_JOB, + parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, + description="""This script will collect all data and make a report. +The authentication credential for LAVA server should be put in ~/.netrc +e.g. + machine validation.linaro.org + login USERNAME + password AUTHENTICATION TOKEN""") + parser.add_argument("-u", "--jenkins-url", dest="jenkins_url", default=JENKINS_URL, + help="Specify the Jenkins URL. Default: %s" % JENKINS_URL) + parser.add_argument("-job", "--jenkins-job-name", dest="jenkins_job_name", default=JENKINS_JOB, help="Specify the Jenkins job name. Default: %s" % JENKINS_JOB) - parser.add_argument("-bn", "--build_no", type=int, required=True, + parser.add_argument("-bn", "--build-no", dest="build_no", type=int, required=True, help="Specify the Jenkins build number") - parser.add_argument("-a", "--manual_lava_jobs", nargs = '+', + parser.add_argument("-a", "--manual-lava-jobs", dest="manual_lava_jobs", nargs = '+', help="Specify the test jobs that were submitted manually") - parser.add_argument("-d", "--exclude_lava_jobs", nargs = '+', + parser.add_argument("-d", "--exclude-lava-jobs", dest="exclude_lava_jobs", nargs = '+', help="Specify the test jobs that don't want to be included in the report") + parser.add_argument("-temp", "--template", dest="template_file", default=REPORT_TEMPLATE, + help="Specify the report template. Default: %s" % REPORT_TEMPLATE) + parser.add_argument("-o", "--output", dest="output_file", default=REPORT_OUTPUT, + help="Specify the output file name. Default: %s" % REPORT_OUTPUT) args = parser.parse_args() - t = Template(REPORT_TEMPLATE, REPORT_OUTPUT) + lava_login_info = netrc.netrc().authenticators("validation.linaro.org") + if lava_login_info is None: + logger.error("Can not get authentication credential for LAVA Server from ~/.netrc") + exit(-1) + jenkins_ligin_info = netrc.netrc().authenticators(args.jenkins_url.split('/')[2]) + t = Template(args.template_file, args.output_file) rep_obj = Report() - jenkins = LinaroAndroidBuildSystem(base_url=JENKINS_URL, build_job=args.jenkins_job_name) - lava_server = LAVA(LAVA_USERNAME, LAVA_TOKEN) + if jenkins_ligin_info is not None: + jenkins = LinaroAndroidBuildSystem(base_url=args.jenkins_url, build_job=args.jenkins_job_name, + username=jenkins_ligin_info[0], password=jenkins_ligin_info[2]) + else: + jenkins = LinaroAndroidBuildSystem(base_url=args.jenkins_url, build_job=args.jenkins_job_name) + lava_server = LAVA(lava_login_info[0], lava_login_info[2]) # Query test job IDs test_job_ids = [] test_job_ids = jenkins.get_test_job_ids(args.build_no) if not test_job_ids: - print("There is no test jobs in this build!") + logger.error("There is no test jobs in this build!") exit(-1) - print("Get the test job IDs:") + logger.info("Get the test job IDs:") if args.exclude_lava_jobs: test_job_ids = [id for id in test_job_ids if id not in args.exclude_lava_jobs] if args.manual_lava_jobs: test_job_ids.extend(args.manual_lava_jobs) - print(test_job_ids) - print("Going to parse these test jobs!!") + logger.info(test_job_ids) + logger.info("Going to parse these test jobs!!") for job in test_job_ids: job_info = {} job_info = lava_server.get_job_info(job) - if job_info['type'] == 'lava_test': - rep_obj.parse_lava_test(job_info) - elif job_info['type'] == 'benchmark': - rep_obj.parse_benchmark_test(job_info) - elif job_info['type'] == 'cts': - rep_obj.parse_cts(job_info) + if job_info: + if job_info['type'] == 'lava_test': + rep_obj.parse_lava_test(job_info) + elif job_info['type'] == 'benchmark': + rep_obj.parse_benchmark_test(job_info) + elif job_info['type'] == 'cts': + rep_obj.parse_cts(job_info) - print("Prepare for the report!!") + logger.info("Prepare for the report!!") data = rep_obj.to_dict() t.render(data) - print("Done, the output report is \"%s\"" % REPORT_OUTPUT) + logger.info("Done, the output report is \"%s\"" % REPORT_OUTPUT) |