def py_base_ex03(): sys.path.append(os.getenv('PYPATH')) from utils import Constants from utils import LogManager from utils import SysUtils try: logger = LogManager.build_logger(Constants.LOG_FILE_PATH) logger.info('import external modules test.') utils = SysUtils().get_instance() utils.run_sys_cmd('python --version') finally: LogManager.clear_log_handles()
class MonkeyTest(object): ''' Monkey test for APP, and collect APP and profile logs. Pre-condition: login into APP before monkey test (by manual). ''' # -------------------------------------------------------------- # Init # -------------------------------------------------------------- def __init__(self, test_pkg_name, run_mins): ''' Constructor ''' self.__test_pkg_name = test_pkg_name self.__run_mins = int(run_mins) cur_time = SysUtils.get_current_date_and_time() self.__log_root_path = os.path.join(os.getcwd(), 'monkeyreports') self.__log_dir_path_for_win = os.path.join(self.__log_root_path, cur_time) self.__log_dir_path_for_shell = '/data/local/tmp/monkey_test_logs' self.__exec_log_path = os.path.join(self.__log_dir_path_for_win, 'run_log.log') self.__device_props_file_path = os.path.join( self.__log_dir_path_for_win, 'device_props.log') self.__app_dump_file_path = os.path.join(self.__log_dir_path_for_win, 'app_info.log') self.__monkey_log_path_for_shell = '%s/%s' % ( self.__log_dir_path_for_shell, 'monkey_log.log') self.__logcat_log_path_for_shell = '%s/%s' % ( self.__log_dir_path_for_shell, 'logcat_full_log.log') self.__logcat_exception_file_name = 'logcat_exception.log' self.__logcat_exception_path_for_shell = '%s/%s' % ( self.__log_dir_path_for_shell, self.__logcat_exception_file_name) self.__logcat_anr_file_name = 'logcat_anr.log' self.__logcat_anr_path_for_shell = '%s/%s' % ( self.__log_dir_path_for_shell, self.__logcat_anr_file_name) SysUtils.create_dir(self.__log_dir_path_for_win) self.__logger = LogManager.build_logger(self.__exec_log_path) self.__sysutils = SysUtils() self.__adbutils = AdbUtils() self.__monitor = MonkeyMonitor() self.__profile_monitor = ProfileMonitor( Constants.ITEST_COLLECT_INTERVAL) self.__chart_parser = ChartParser(self.__log_dir_path_for_win) self.__report = MonkeyReport(self.__log_dir_path_for_win, self.__logcat_exception_file_name, self.__logcat_anr_file_name) # -------------------------------------------------------------- # Monkey and logcat processes # -------------------------------------------------------------- def __build_monkey_cmd(self): monkey_cmd = 'adb shell "monkey --throttle 500 -p %s' % self.__test_pkg_name monkey_launch_params = '-c android.intent.category.MONKEY -c android.intent.category.LAUNCHER -c ' + \ 'android.intent.category.DEFAULT --monitor-native-crashes --kill-process-after-error' monkey_ignore = '' if Constants.IS_MONKEY_CRASH_IGNORE: monkey_ignore = '--ignore-crashes --ignore-timeouts --ignore-security-exceptions --ignore-native-crashes' # monkey_actions_pct = '--pct-touch 65 --pct-motion 20 --pct-trackball 5 --pct-nav 0 ' + \ # '--pct-majornav 5 --pct-syskeys 5 --pct-appswitch 0 --pct-flip 0 --pct-anyevent 0' monkey_actions_pct = self.__build_monkey_action_cmd() monkey_format = '-v -v -v %s > %s"' % ( Constants.MONKEY_TOTAL_RUN_TIMES, self.__monkey_log_path_for_shell) return ' '.join((monkey_cmd, monkey_launch_params, monkey_ignore, monkey_actions_pct, monkey_format)) def __build_monkey_action_cmd(self): options = [] options.append('--pct-touch ' + Constants.PCT_TOUCH) options.append('--pct-motion ' + Constants.PCT_MOTION) options.append('--pct-trackball ' + Constants.PCT_TRACKBALL) options.append('--pct-nav ' + Constants.PCT_NAV) options.append('--pct-majornav ' + Constants.PCT_MAJORNAV) options.append('--pct-syskeys ' + Constants.PCT_SYSKEYS) options.append('--pct-appswitch ' + Constants.PCT_APPSWITCH) options.append('--pct-anyevent ' + Constants.PCT_ANYEVENT) return ' '.join(options) def __run_monkey_subprocess(self): cmd = self.__build_monkey_cmd() self.__logger.info('Run monkey command: ' + cmd) return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) def __run_logcat_subprocess(self): cmd = 'adb logcat -c && adb logcat -f %s -v threadtime *:%s' % ( self.__logcat_log_path_for_shell, Constants.LOGCAT_LOG_LEVEL) return subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # -------------------------------------------------------------- # Adb and Shell utils # -------------------------------------------------------------- def __create_log_dir_for_shell(self, dir_path): self.__check_adb_action(self.__adbutils.create_dir_on_shell(dir_path)) def __clear_log_dir_for_shell(self): self.__check_adb_action( self.__adbutils.remove_files_on_shell( self.__log_dir_path_for_shell)) def __check_adb_action(self, lines): for line in lines: if 'busy' in line: self.__logger.error(line) raise Exception('Monkey test exit because of device busy!') def __filter_shell_logcat_exception(self): cmd = 'adb shell \"cat %s | grep \'at com.jd.b2b\' -C 20 > %s"' % ( self.__logcat_log_path_for_shell, self.__logcat_exception_path_for_shell) if not self.__sysutils.run_sys_cmd(cmd): self.__logger.warning('Filter exception for logcat failed!') def __filter_shell_logcat_anr(self): cmd = 'adb shell \"cat %s | grep \'E ANRManager: ANR\' -C 20 > %s"' % ( self.__logcat_log_path_for_shell, self.__logcat_anr_path_for_shell) if not self.__sysutils.run_sys_cmd(cmd): self.__logger.warning('Filter anr for logcat failed!') def __pull_all_testing_logs(self): shell_log_files = (self.__logcat_log_path_for_shell, self.__monkey_log_path_for_shell, self.__logcat_exception_path_for_shell, self.__logcat_anr_path_for_shell) for shell_f in shell_log_files: cmd_pull_log_files = 'adb pull %s %s' % ( shell_f, self.__log_dir_path_for_win) if not self.__sysutils.run_sys_cmd(cmd_pull_log_files): self.__logger.warning('Pull logcat file failed: ' + shell_f) if not self.__adbutils.dump_tombstone_files( self.__log_dir_path_for_win): self.__logger.warning('Pull tombstone file failed!') self.__pull_latest_anr_files() def __pull_latest_anr_files(self): ''' Get anr files in 24 hours. ''' cmd = 'adb shell "find /data/anr/ -name *.txt -mtime -1 2>/dev/null"' anr_files = self.__sysutils.run_sys_cmd_and_ret_lines(cmd) if len(anr_files) == 0: return save_path = os.path.join(self.__log_dir_path_for_win, 'anr') self.__sysutils.create_dir(save_path) for f in anr_files: f = f.strip('\r\n') if len(f) == 0: continue cmd = 'adb pull %s %s' % (f, save_path) if not self.__sysutils.run_sys_cmd(cmd): self.__logger.warning('Pull anr file failed: ' + f) # -------------------------------------------------------------- # Create report and archive # -------------------------------------------------------------- def __create_monkey_test_report(self): title_dict = {} title_dict['TEST PACKAGE'] = self.__test_pkg_name title_dict['RUN TIME (minutes)'] = str(self.__run_mins) self.__report.create_monkey_test_report(title_dict) def __create_archive_report_file(self): time.sleep(1) root_dir = r'D:\JDTestLogs' # temp local save path target_file = os.path.join( root_dir, 'monkey_' + os.path.basename(self.__log_dir_path_for_win) + '.7z') cmd = r'"C:\Program Files\7-Zip\7z" a -t7z %s %s' % ( target_file, self.__log_dir_path_for_win) self.__logger.debug('Create archive report file: ' + target_file) if not self.__sysutils.run_sys_cmd(cmd): self.__logger.warning('Create archive report file failed!') # -------------------------------------------------------------- # Monkey Test Main # -------------------------------------------------------------- def __is_profile_test_ok(self): return Constants.IS_PROFILE_TEST and int( self.__adbutils.get_android_version()[0]) < 7 def __test_setup_main(self): if not self.__adbutils.is_devices_connected(): raise Exception('No devices connected!') # shell env setup self.__adbutils.clear_anr_dir() self.__adbutils.clear_tombstone_dir() self.__clear_log_dir_for_shell() self.__create_log_dir_for_shell(self.__log_dir_path_for_shell) # win env setup self.__adbutils.dump_device_props(self.__device_props_file_path) self.__adbutils.dump_app_info(Constants.PKG_NAME_ZGB, self.__app_dump_file_path) if self.__is_profile_test_ok(): self.__profile_monitor.start_monitor() def __test_main(self): self.__logger.info('Start logcat process.') logcat_p = self.__run_logcat_subprocess() self.__logger.info('Start monkey main process.') monkey_p = self.__run_monkey_subprocess() self.__logger.info('Start monkey monitor process.') monkey_monitor_t = threading.Thread( target=self.__monitor.process_monkey_monitor_main, args=(self.__run_mins, )) threads = [] threads.append(monkey_monitor_t) if self.__is_profile_test_ok(): self.__logger.info('Start APP profile monitor process.') profile_monitor_t = threading.Thread( target=self.__profile_monitor.running_monitor, args=(self.__run_mins, False, Constants.WAIT_TIME_IN_LOOP)) threads.append(profile_monitor_t) for t in threads: t.start() for t in threads: t.join() monkey_p.kill() logcat_p.kill() def __test_clearup_main(self): # the adb connection maybe disconnect when running the monkey if self.__adbutils.is_devices_connected(): self.__profile_monitor.stop_monitor() self.__adbutils.stop_app(self.__test_pkg_name) self.__filter_shell_logcat_exception() self.__filter_shell_logcat_anr() self.__pull_all_testing_logs() self.__create_monkey_test_report() if self.__is_profile_test_ok(): time.sleep(1) self.__profile_monitor.pull_itest_logfiles( self.__log_dir_path_for_win) self.__chart_parser.build_all_profile_charts() else: self.__logger.error('Device disconnect!') LogManager.clear_log_handles() if Constants.IS_CREATE_ARCHIVE: self.__create_archive_report_file() def mokeytest_main(self): self.__test_setup_main() self.__test_main() self.__test_clearup_main()
class ProfileMonitor(object): ''' Android app profile monitor by iTest. Pre-conditions: APP under test is added into iTest, and set data collect interval configs (by manual), prefer 3s. ''' __itest_pkg_name = 'iflytek.testTech.propertytool' __itest_boot_act = 'iflytek.testTech.propertytool.activity.BootActivity' __log_root_dir_path = '/sdcard/AndroidPropertyTool4' __hand_log_dir = 'handTest' __hand_log_dir_path = __log_root_dir_path + '/' + __hand_log_dir def __init__(self, itest_collect_interval): ''' Constructor ''' self.__is_stopped = True self.__logger = LogManager.get_logger() self.__sys_utils = SysUtils() self.__adb_utils = AdbUtils() # note: this value should be greater than interval config in iTest self.__wait_time_between_check = itest_collect_interval + 1 # -------------------------------------------------------------- # Start Monitor # -------------------------------------------------------------- def start_monitor(self): self.__clear_itest_logs() self.__launch_itest() time.sleep(2) self.__click_itest_monitor_btn() time.sleep(1) if not self.__is_itest_logfile_created(): raise Exception('start iTest monitor failed!') self.__is_stopped = False def __clear_itest_logs(self): cmd = 'adb shell "cd %s;rm -rf %s*"' \ % (self.__log_root_dir_path, self.__hand_log_dir) if not self.__sys_utils.run_sys_cmd(cmd): raise Exception('clear iTest log files failed!') def __launch_itest(self): cmd = 'adb shell am start ' + self.__itest_pkg_name + '/' + self.__itest_boot_act self.__sys_utils.run_sys_cmd(cmd) for i in range(0, 3): if self.__adb_utils.is_package_on_top(self.__itest_pkg_name): return time.sleep(1) raise Exception('launch iTest app failed!') def __is_itest_logfile_created(self): cmd = 'adb shell "cd %s;ls|grep %s"' \ % (self.__log_root_dir_path, self.__hand_log_dir) return len(self.__sys_utils.run_sys_cmd_and_ret_content(cmd)) != 0 def __click_itest_monitor_btn(self): cmd = 'adb shell input tap 800 1880' return self.__sys_utils.run_sys_cmd(cmd) # -------------------------------------------------------------- # Running Monitor # -------------------------------------------------------------- def running_monitor(self, run_mins, is_end_with_stop=True, interval=15): run_secs = run_mins * 60 start = time.perf_counter() while 1: time.sleep(interval) if not self.__is_itest_running(): self.__logger.error('iTest process is NOT running!') return if time.perf_counter() - start >= run_secs and self.__is_itest_running(): if is_end_with_stop: self.stop_monitor() self.__is_stopped = True return def __is_itest_process_running(self): cmd = 'adb shell "ps | grep %s"' % self.__itest_pkg_name if len(self.__sys_utils.run_sys_cmd_and_ret_content(cmd)) == 0: return False return True def __is_cpu_logfile_updated(self): before_record_time = self.__get_cpu_logfile_record_time() self.__logger.info('before time: ' + before_record_time) time.sleep(self.__wait_time_between_check) after_record_time = self.__get_cpu_logfile_record_time() self.__logger.info('after time: ' + after_record_time) return before_record_time != after_record_time def __get_cpu_logfile_record_time(self): file_name = 'cpuSystem.txt' cmd = 'adb shell "cd %s;tail -n 1 %s"' \ % (self.__hand_log_dir_path, file_name) last_line = self.__sys_utils.run_sys_cmd_and_ret_content(cmd) return last_line.split()[0] # record time def __is_itest_running(self): if self.__is_itest_process_running() and self.__is_cpu_logfile_updated(): return True return False # -------------------------------------------------------------- # Stop Monitor and pull logs # -------------------------------------------------------------- def stop_monitor(self): if self.__is_stopped: return self.__launch_itest() time.sleep(2) # wait to fix action failed self.__click_itest_monitor_btn() time.sleep(1) self.__force_stop_itest() self.__is_stopped = True def __force_stop_itest(self): cmd = 'adb shell am force-stop ' + self.__itest_pkg_name self.__sys_utils.run_sys_cmd(cmd) def __clear_local_itest_logs(self, dir_path): SysUtils.delete_files_in_dir(dir_path) def pull_itest_logfiles(self, local_save_path): if len(local_save_path) == 0: self.__logger.warn('skip dump iTest logs!') return self.__clear_local_itest_logs(os.path.join(local_save_path, self.__hand_log_dir)) cmd = 'adb pull %s %s' % (self.__hand_log_dir_path, local_save_path) if not self.__sys_utils.run_sys_cmd(cmd): self.__logger.error('dump iTest logs failed!')