def main(argv): # simple command line parameter support. only [-f ini_file] [-h] support # usage = "usage: %prog [options]" # # parser = argparse.ArgumentParser() # parser.add_argument("echo") # args = parser.parse_args() # print args.echo # parser = OptionParser(usage) # parser.add_option("-f", "--file", dest="scptfilename", \ # help="specify script file to run", metavar="FILE") # parser.add_option("-r", "--reference", \ # help="list fw usage keywords and examples") # (options, args) = parser.parse_args() # if len(args)==0: # parser.print_help() # return # print options # scptfilename=options.scptfilename # print scptfilename deviceIds = Shell().getShellCmdOutput(r"adb devices") # deviceIdList = filter(lambda x: len(x) > 0, devices.split('\n')) # .split('\t',1)[0] deviceId = None connected_RE = re.compile("^\S+\t*device$") for line in deviceIds.split('\n'): # if deviceIdList[i].strip() == 'List of devices attached': # print 'list start' # deviceIdList = deviceIdList[i+1:] # break if connected_RE.match(line): deviceId = line.split('\t', 1)[0] if deviceId is None: print "device/emulator not found. Please check the USB connection or start the emulator and try again." return # print("Got device %s." % deviceId) idev = iDevice(deviceId) try_count = 0 tv = None while tv is None: if try_count == 0: vtext = raw_input("please enter the view text you are looking for:") else: vtext = raw_input('Sorry, The view was not found. Please check the text in the screen' ' and try again [Q|q to exit]:') if vtext.lower() == 'q': return idev.vc.dump() tv = idev.vc.findViewWithText(vtext) try_count += 1 print "The view's id is:", tv.getId() # print "target view's tag is:", tv.getTag() idev.vc.findViewsWithSameId(tv, [tv])
def getDeviceIdList(): devices = Shell().getShellCmdOutput(r"adb devices") # |awk -F'\t' '{print $1}' print devices deviceIdList = [] # filter(lambda x: len(x) > 0, devices.split('\n')) # .split('\t',1)[0] connected_RE = re.compile("^\S+\t*device$") for line in devices.split('\n'): # if deviceIdList[i].strip() == 'List of devices attached': # print 'list start' # deviceIdList = deviceIdList[i+1:] # break if connected_RE.match(line): deviceIdList.append(line.split('\t', 1)[0]) if len(deviceIdList) > 0: printLog('List of devices attached: \n' + str(deviceIdList)) return deviceIdList
def __getDeviceInfo(deviceId, propName): cmd = "adb -s " + deviceId + " shell getprop | awk -F':' '/" + propName + "/ { print $2 }'|tr -d '[] '" # add alarm to detect timeout shell = Shell() counter = 0 while counter < 2: try: with time_limit(FETCH_DEVICEINFO_TIMEOUT): output = shell.getShellCmdOutput(cmd).splitlines() if len(output) > 0: return output[0].strip() else: return 'UNKNOWN' except TimeoutException: printLog("Timed out! Failed to retrieve device info.", logging.ERROR) # todo: reboot device or emulator output = shell.getShellCmdOutput('adb reboot') time.sleep(20) counter += 1
def __init__(self): # device = TestDevicePool().getDevice() # if device is None: # print("NO IDLE DEVICE AVAILABLE. TERMINATE.") # assert False # # self.threadName='<'+self.device.model+'_'+self.device.deviceId+'> ' # print("Got device %s." % device.deviceId) devices = Shell().getShellCmdOutput(r"adb devices") # deviceIdList = filter(lambda x: len(x) > 0, devices.split('\n')) # .split('\t',1)[0] deviceIdList = [] # filter(lambda x: len(x) > 0, devices.split('\n')) # .split('\t',1)[0] connected_RE = re.compile("^\S+\t*device$") for line in devices.split("\n"): # if deviceIdList[i].strip() == 'List of devices attached': # print 'list start' # deviceIdList = deviceIdList[i+1:] # break if connected_RE.match(line): deviceIdList.append(line.split("\t", 1)[0]) if len(deviceIdList) > 0: print ("List of devices:") for j in range(len(deviceIdList)): print ("%d: %s\n" % (j, deviceIdList[j])) try: # connect device self.adbc, self.serial_no = ViewClient.connectToDeviceOrExit(verbose=DEBUG, serialno=deviceIdList[0]) print "device %s connected." % self.serial_no self.devices = self.adbc.getDevices() for device in self.devices: print device.serialno except: traceback.print_exc() raise RuntimeError("cannot connect to device.") else: raise RuntimeError("cannot find device.")
def __init__(self, suite=DEFAULT_TEST_SUITE, buildnum=0): """ constructor. """ self.test_buildnum = buildnum """ the build number to verify """ self.test_suite = suite """ the suite to test""" self.Pass = 0 """ Passed testcase number""" self.Fail = 0 """ failed testcase number """ self.Total = 0 """ total testcase number """ self.ALTList = [] """ activity launch time list """ self.exception_map_list = [{}, {}] """ app exception map list: one keeps formulated exceptions and the other keeps raw exceptions """ self.start_time = None """ test start time""" self.end_time = None """ test finish time""" self.shell = Shell() """ Shell object """ # do environment validation if not path.isdir(TC_DIR): print ("Required directory %s does not exist. please check and run again." % TC_DIR) return if not path.isdir(TS_DIR): print ("Required directory %s does not exist. please check and run again." % TS_DIR) return if not path.isdir(SNAPSHOT_DIR): mkdir(SNAPSHOT_DIR) # remove old log file if path.isfile(TESTER_DEBUG_LOG_FILE): if Tester.DEBUG == logging.DEBUG: print ("Removing old log file...") remove(TESTER_DEBUG_LOG_FILE) # truncate_file(TESTER_DEBUG_LOG_FILE) # create new log file # Oct 21: need to assign a different logger id each time, otherwise it will use the existing one # which will be closed at the end of run() self.logHandler = createLogger(Tester.DEBUG) """ log file handler """ # get device, by default get the connected Genymotion device self.device = None self.device = TestDevicePool().getDevice() # make='Genymotion') """ test device """ if self.device is None: raise EnvironmentError("[Tester] NO DEVICE OR MORE THAN ONE DEVICE FOUND. QUIT.") if Tester.DEBUG == logging.DEBUG: printLog("[Tester] FOUND DEVICE.", logging.DEBUG) if Tester.GET_BUILD: if not self.getBuild(): raise EnvironmentError("[Tester] Get build failed.") # build testcase pool self.testPool = TestCasePool.fromSuite(self.test_suite) """ testcase pool for current test run """ if len(self.testPool) == 0: raise EnvironmentError("[Tester] NO TESTCASE IN THE TEST SUITE. QUIT.")
class Tester: """ The Tester class plays a tester role -- It manages test build, testcase, test devices, and test results. It uses AppTestRunner to execute testcases. """ EXCEPTION_AGGREGATION_MODE = 0 """ 0: use thread/class as key, 1: use exception as key""" GET_BUILD = True """ used to control if tester gets the build file before test starts, or use the installed build in test""" DEBUG = logging.NOTSET """ control log verbosity""" def __init__(self, suite=DEFAULT_TEST_SUITE, buildnum=0): """ constructor. """ self.test_buildnum = buildnum """ the build number to verify """ self.test_suite = suite """ the suite to test""" self.Pass = 0 """ Passed testcase number""" self.Fail = 0 """ failed testcase number """ self.Total = 0 """ total testcase number """ self.ALTList = [] """ activity launch time list """ self.exception_map_list = [{}, {}] """ app exception map list: one keeps formulated exceptions and the other keeps raw exceptions """ self.start_time = None """ test start time""" self.end_time = None """ test finish time""" self.shell = Shell() """ Shell object """ # do environment validation if not path.isdir(TC_DIR): print ("Required directory %s does not exist. please check and run again." % TC_DIR) return if not path.isdir(TS_DIR): print ("Required directory %s does not exist. please check and run again." % TS_DIR) return if not path.isdir(SNAPSHOT_DIR): mkdir(SNAPSHOT_DIR) # remove old log file if path.isfile(TESTER_DEBUG_LOG_FILE): if Tester.DEBUG == logging.DEBUG: print ("Removing old log file...") remove(TESTER_DEBUG_LOG_FILE) # truncate_file(TESTER_DEBUG_LOG_FILE) # create new log file # Oct 21: need to assign a different logger id each time, otherwise it will use the existing one # which will be closed at the end of run() self.logHandler = createLogger(Tester.DEBUG) """ log file handler """ # get device, by default get the connected Genymotion device self.device = None self.device = TestDevicePool().getDevice() # make='Genymotion') """ test device """ if self.device is None: raise EnvironmentError("[Tester] NO DEVICE OR MORE THAN ONE DEVICE FOUND. QUIT.") if Tester.DEBUG == logging.DEBUG: printLog("[Tester] FOUND DEVICE.", logging.DEBUG) if Tester.GET_BUILD: if not self.getBuild(): raise EnvironmentError("[Tester] Get build failed.") # build testcase pool self.testPool = TestCasePool.fromSuite(self.test_suite) """ testcase pool for current test run """ if len(self.testPool) == 0: raise EnvironmentError("[Tester] NO TESTCASE IN THE TEST SUITE. QUIT.") def __del__(self): if self.device: del self.device del self.ALTList self.logHandler.close() logging.shutdown() def __reset(self): """ reset counters and remove result file and temp files Note: execution log file is not removed at the beginning of each run, but during the init. """ self.Pass = 0 self.Fail = 0 self.Total = 0 self.ALTList = [] self.start_time = None self.end_time = None # remove old result file if path.isfile(self.test_suite + ".txt"): print "Removing old result file %s ..." % (self.test_suite + ".txt") remove(self.test_suite + ".txt") if path.isfile(APPLOG_FILE): print "Removing old app log file %s ..." % APPLOG_FILE remove(APPLOG_FILE) if path.isfile(ADBLOG_FILE): print "Removing old ADB log file %s ..." % ADBLOG_FILE remove(ADBLOG_FILE) # remove temp png files self.shell.runShellCmd(r"rm *.png") self.shell.runShellCmd(r"rm %s/*.png" % SNAPSHOT_DIR) # reset test pool status for tc in self.testPool: tc.result = TestStatus.NotRun tc.crash = False def getBuild(self): """ get the specified build file to current directory this is an abstract method. subclasses should implement it. """ raise NotImplementedError("Please implement getBuild()!") def generateTestReport(self): """ generate test report content this is an abstract method. subclasses should implement it. """ raise NotImplementedError("Please implement generateTestReport()!") def scanExceptionInAppLog(self, file_path): """ scan the app log for exceptions, and parse them into lists of exception, class and line numbers this is an abstract method. subclasses should implement it. @param file_path: file path (string) @return: two maps: one keeps formulated exceptions and the other keeps raw exceptions @rtype list """ raise NotImplementedError("Please implement scanExceptionInAppLog()!") @staticmethod def __convertTime(rawtime): """ split the minute part from second part, and convert to launch time in seconds. the input raw time may contain seconds and milliseconds, e.g. 1s12ms (2014-07-22) @param rawtime: raw time string @return: the processed time string """ # printLog('[getTime] raw time: %s'% rawtime) # remove the trailing '\n' and 'ms' rawtime = rawtime.split("m")[0] # rawtime=rawtime[0:(len(rawtime)-2)] # printLog('[getTime] stripped raw time: %s'% rawtime) if not rawtime.isdigit(): sec, ms = rawtime.split("s") rawtime = str(int(sec) * 1000 + int(ms)) # printLog('[getTime] converted time: %s(ms)' % rawtime) return rawtime @staticmethod def getLaunchTime(fname): """ scan logcat file and retrieve activity launch time data 2015-09-01: refactored to remove the dependency to external shell script @param fname: the logcat filename @return: a list of activities and their launch time """ if not os.path.isfile(fname): return "" ALTList = [] LT_RE = re.compile("^I/ActivityManager\(\s*\d+\): Displayed {}/(\S+): \+(\S+)\s*$".format(APP_PKG_NAME)) try: with open(ADBLOG_FILE, "r") as fd: lines = filter(lambda x: not x.startswith("\n") and APP_PKG_NAME in x, fd.readlines()) for line in lines: # printLog('[getLaunchTime] current line: %s'% line) if LT_RE.match(line): activity, ltime = LT_RE.search(line).groups() ltime = Tester.__convertTime(ltime.rstrip("\n")) # Oct 23: changed method to get activity name and time # use ':' to split columns in get_ALT.sh and '+' to split # activity name and launch time ALTList.append((activity, ltime)) except Exception, e: printLog( "[getLaunchTime] Caught exception while writing launch time data to file: %s" % e.message, logging.ERROR ) finally: