blob: f1203f3274ec570c6ff9ea590261a363438a1488 [file] [log] [blame]
#!/usr/bin/env python
import argparse
import datetime
import logging
import os
import pexpect
import shlex
import shutil
import subprocess
import sys
import time
import result_parser
sys.path.insert(0, "../../lib/")
import py_test_lib # nopep8
OUTPUT = "%s/output" % os.getcwd()
RESULT_FILE = "%s/result.txt" % OUTPUT
TRADEFED_STDOUT = "%s/tradefed-stdout.txt" % OUTPUT
TRADEFED_LOGCAT = "%s/tradefed-logcat.txt" % OUTPUT
TEST_PARAMS = ""
parser = argparse.ArgumentParser()
parser.add_argument(
"-t", dest="TEST_PARAMS", required=True, help="tradefed shell test parameters"
)
parser.add_argument(
"-p", dest="TEST_PATH", required=True, help="path to tradefed package top directory"
)
parser.add_argument(
"-r",
dest="RESULTS_FORMAT",
required=False,
default=result_parser.TradefedResultParser.AGGREGATED,
choices=[
result_parser.TradefedResultParser.AGGREGATED,
result_parser.TradefedResultParser.ATOMIC,
],
help="The format of the saved results. 'aggregated' means number of \
passed and failed tests are recorded for each module. 'atomic' means \
each test result is recorded separately",
)
# The total number of failed test cases to be printed for this job
# Print too much failures would cause the lava job timed out
# Default to not print any failures
parser.add_argument(
"-f",
dest="FAILURES_PRINTED",
type=int,
required=False,
default=0,
help="Speciy the number of failed test cases to be\
printed, 0 means not print any failures.",
)
args = parser.parse_args()
# TEST_PARAMS = args.TEST_PARAMS
if os.path.exists(OUTPUT):
suffix = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
shutil.move(OUTPUT, "%s_%s" % (OUTPUT, suffix))
os.makedirs(OUTPUT)
# Setup logger.
# There might be an issue in lava/local dispatcher, most likely problem of
# pexpect. It prints the messages from print() last, not by sequence.
# Use logging and subprocess.call() to work around this.
logger = logging.getLogger("Tradefed")
logger.setLevel(logging.DEBUG)
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(name)s: %(levelname)s: %(message)s")
ch.setFormatter(formatter)
logger.addHandler(ch)
tradefed_stdout = open(TRADEFED_STDOUT, "w")
tradefed_logcat_out = open(TRADEFED_LOGCAT, "w")
tradefed_logcat = subprocess.Popen(["adb", "logcat"], stdout=tradefed_logcat_out)
logger.info("Test params: %s" % args.TEST_PARAMS)
logger.info("Starting tradefed shell test...")
command = None
prompt = None
if args.TEST_PATH == "android-cts":
command = "android-cts/tools/cts-tradefed"
prompt = "cts-tf >"
if args.TEST_PATH == "android-vts":
os.environ["VTS_ROOT"] = os.getcwd()
command = "android-vts/tools/vts-tradefed"
prompt = "vts-tf >"
if command is None:
logger.error("Not supported path: %s" % args.TEST_PATH)
sys.exit(1)
vts_monitor_enabled = False
if command == "android-vts/tools/vts-tradefed" and os.path.exists(
"android-vts/testcases/vts/script/monitor-runner-output.py"
):
vts_monitor_enabled = True
vts_run_details = open("{}/vts_run_details.txt".format(OUTPUT), "w")
monitor_cmd = "android-vts/testcases/vts/script/monitor-runner-output.py -m"
monitor_vts_output = subprocess.Popen(
shlex.split(monitor_cmd), stderr=subprocess.STDOUT, stdout=vts_run_details
)
child = pexpect.spawn(command, logfile=tradefed_stdout, searchwindowsize=1024)
try:
child.expect(prompt, timeout=60)
child.sendline(args.TEST_PARAMS)
except pexpect.TIMEOUT:
result = "lunch-tf-shell fail"
py_test_lib.add_result(RESULT_FILE, result)
fail_to_complete = False
while child.isalive():
subprocess.call("echo")
subprocess.call(["echo", "--- line break ---"])
logger.info("Checking adb connectivity...")
adb_command = "adb shell echo OK"
adb_check = subprocess.Popen(shlex.split(adb_command))
if adb_check.wait() != 0:
logger.debug(
"adb connection lost! maybe device is rebooting. Lets check again in 5 minute"
)
time.sleep(300)
adb_check = subprocess.Popen(shlex.split(adb_command))
if adb_check.wait() != 0:
logger.debug(
"adb connection lost! Trying to dump logs of all invocations..."
)
child.sendline("d l")
time.sleep(30)
subprocess.call(
[
"sh",
"-c",
". ../../lib/sh-test-lib && . ../../lib/android-test-lib && adb_debug_info",
]
)
logger.debug('"adb devices" output')
subprocess.call(["adb", "devices"])
logger.error(
"adb connection lost!! Will wait for 5 minutes and terminating tradefed shell test as adb connection is lost!"
)
time.sleep(300)
child.terminate(force=True)
result = "check-adb-connectivity fail"
py_test_lib.add_result(RESULT_FILE, result)
break
else:
logger.info("adb device is alive")
time.sleep(300)
# Check if all tests finished every minute.
m = child.expect(
[
"ResultReporter: Full Result:",
"ConsoleReporter:.*Test run failed to complete.",
pexpect.TIMEOUT,
],
searchwindowsize=1024,
timeout=60,
)
# Once all tests finshed, exit from tf shell to throw EOF, which sets child.isalive() to false.
if m == 0:
try:
child.expect(prompt, searchwindowsize=1024, timeout=60)
logger.debug('Sending "exit" command to TF shell...')
child.sendline("exit")
child.expect(pexpect.EOF, timeout=60)
logger.debug("Child process ended properly.")
except pexpect.TIMEOUT as e:
print(e)
logger.debug("Unsuccessful clean exit, force killing child process...")
child.terminate(force=True)
break
# Mark test run as fail when a module or the whole run failed to complete.
elif m == 1:
fail_to_complete = True
# CTS not finished yet, continue to wait.
elif m == 2:
# Flush pexpect input buffer.
child.expect([".+", pexpect.TIMEOUT, pexpect.EOF], timeout=1)
logger.info("Printing tradefed recent output...")
subprocess.call(["tail", TRADEFED_STDOUT])
if fail_to_complete:
py_test_lib.add_result(RESULT_FILE, "tradefed-test-run fail")
else:
py_test_lib.add_result(RESULT_FILE, "tradefed-test-run pass")
logger.info("Tradefed test finished")
tradefed_logcat.kill()
tradefed_logcat_out.close()
tradefed_stdout.close()
if vts_monitor_enabled:
monitor_vts_output.kill()
vts_run_details.close()
# Locate and parse test result.
result_dir = "%s/results" % args.TEST_PATH
parser = result_parser.TradefedResultParser(RESULT_FILE)
parser.logger = logger
parser.results_format = args.RESULTS_FORMAT
parser.failures_to_print = args.FAILURES_PRINTED
success = parser.parse_recursively(result_dir)
sys.exit(0 if success else 1)