def _init_phase(): Printer.phase("INIT") session_logger.log_session_start_time() Printer.step("Launcher started working!") Version.info() Version.python_check()
def _testing_phase(self): Printer.phase("TESTING") session_logger.log_total_test_start_time() Printer.step("Starting tests.") self.test_manager.run_tests(self.test_set, self.test_list) session_logger.log_total_test_end_time()
def _flakiness_check_phase(self): if GlobalConfig.SHOULD_RERUN_FAILED_TESTS: Printer.phase("FLAKINESS CHECK") session_logger.log_total_rerun_start_time() Printer.step("Re-running failed tests.") self.test_manager.rerun_failed_tests() session_logger.log_total_rerun_end_time()
def _apk_installation_phase(self): Printer.phase("APK INSTALLATION") session_logger.log_total_apk_install_start_time() Printer.step("Installing .*apk on devices included in test session.") apk = self.apk_manager.get_existing_apk(self.test_set) self.apk_manager.install_apk_on_devices(apk) session_logger.log_total_apk_install_end_time()
def launch_all_avd_sequentially(self): for device in self.device_store.get_devices(): if isinstance( device, SessionVirtualDevice) and device.status == "not-launched": session_logger.log_device_launch_start_time(device.adb_name) device.launch() self._wait_for_adb_statuses_change_to("device", (device, )) self._wait_for_property_statuses(self.device_store.get_devices())
def _device_launch_phase(self): Printer.phase("DEVICE LAUNCH") session_logger.log_total_device_launch_start_time() if GlobalConfig.SHOULD_USE_ONLY_DEVICES_SPAWNED_IN_SESSION: if GlobalConfig.SHOULD_LAUNCH_AVD_SEQUENTIALLY: Printer.step("Launching AVD - sequentially.") self.device_manager.launch_all_avd_sequentially() else: Printer.step("Launching AVD - all at once.") self.device_manager.launch_all_avd_at_once() else: Printer.step("Using currently launched devices.") session_logger.log_total_device_launch_end_time()
def _device_preparation_phase(self): Printer.phase("DEVICE PREPARATION") if GlobalConfig.SHOULD_USE_ONLY_DEVICES_SPAWNED_IN_SESSION: Printer.step("Killing currently launched AVD.") session_logger.log_total_device_creation_start_time() self.device_manager.add_models_representing_outside_session_virtual_devices( ) if self.device_manager.is_any_avd_visible(): self.device_manager.kill_all_avd() self.device_manager.clear_models_representing_outside_session_virtual_devices( ) if self.avd_set.avd_list: Printer.step( "Creating models for devices specified in AVD set.") self.device_manager.add_models_based_on_avd_schema( self.avd_set, self.avd_schemas) if GlobalConfig.SHOULD_RECREATE_EXISTING_AVD: Printer.step( "Creating all requested AVD from scratch. Recreating existing ones." ) self.device_manager.create_all_avd_and_recreate_existing() else: Printer.step( "Creating all requested AVD from scratch. Reusing existing ones." ) self.device_manager.create_all_avd_and_reuse_existing() session_logger.log_total_device_creation_end_time() else: Printer.step( "Creating models for currently visible Android Devices and AVD." ) self.device_manager.add_models_representing_outside_session_devices( ) self.device_manager.add_models_representing_outside_session_virtual_devices( ) if not self.device_manager.is_any_avd_visible(): quit() if GlobalConfig.IGNORED_DEVICE_LIST: Printer.step("Checking device ignore list") self.device_manager.clear_models_with_android_ids_in_ignore_list()
def _apk_preparation_phase(self): Printer.phase("APK PREPARATION") session_logger.log_total_apk_build_start_time() Printer.step("Preparing .*apk for test.") if GlobalConfig.SHOULD_BUILD_NEW_APK: apk = self.apk_manager.build_apk(self.test_set) else: apk = self.apk_manager.get_existing_apk(self.test_set) if apk is None: apk = self.apk_manager.build_apk(self.test_set) self.apk_manager.display_picked_apk_info() Printer.step("Scanning .*apk for helpful data.") self.apk_manager.set_instrumentation_runner_according_to(apk) session_logger.log_total_apk_build_end_time()
def create_all_avd_and_recreate_existing(self): created_avd_list = re.findall("Name: (.+)", self.avdmanager_controller.list_avd()) for device in self.device_store.get_devices(): if isinstance(device, SessionVirtualDevice): session_logger.log_device_creation_start_time(device.adb_name) start_time = int(round(time.time() * 1000)) if device.avd_schema.avd_name in created_avd_list: Printer.system_message( self.TAG, "AVD with name " + Color.GREEN + device.avd_schema.avd_name + Color.BLUE + " already exists and will be re-created.") device.delete() device.create() else: device.create() if device.avd_schema.create_avd_hardware_config_filepath != "": Printer.system_message( self.TAG, "'config.ini' file was specified in AVD schema of device " + Color.GREEN + device.adb_name + Color.BLUE + " in location " + Color.GREEN + device.avd_schema.create_avd_hardware_config_filepath + Color.BLUE + ". Applying...") device.apply_config_ini() end_time = int(round(time.time() * 1000)) session_logger.log_device_creation_end_time(device.adb_name) creation_time = (end_time - start_time) / 1000 reasonable_time = 25 if creation_time > reasonable_time and "--force" not in device.avd_schema.create_avd_additional_options: Printer.system_message( self.TAG, "AVD creation took: " + Color.GREEN + str(creation_time) + " sec" + Color.RED + " (Attention! Creation process could ran faster. Try adding " + "'--force' to your AVD schema in 'create_avd_additional_options' field.)" ) else: Printer.system_message( self.TAG, "AVD creation took: " + Color.GREEN + str(creation_time) + Color.BLUE + " sec")
def build_apk(self, test_set): Printer.system_message( self.TAG, "Building application and test .*apk from scratch.") session_logger.log_app_apk_build_start_time() self.gradle_controller.build_application_apk(test_set) session_logger.log_app_apk_build_end_time() session_logger.log_test_apk_build_start_time() self.gradle_controller.build_test_apk(test_set) session_logger.log_test_apk_build_end_time() return self.get_existing_apk(test_set)
def _finalization_phase(self): Printer.phase("FINALIZATION") Printer.step("Displaying saved files during test session.") session_logger.dump_saved_files_history() Printer.step("Session summary.") session_logger.log_session_end_time() session_logger.save_session_summary() session_logger.dump_session_summary() LogGenerator.generate_logs(self.test_set) if self.device_manager is not None and self.device_manager.is_any_avd_visible() \ and GlobalConfig.SHOULD_USE_ONLY_DEVICES_SPAWNED_IN_SESSION: Printer.step("Killing AVD spawned for test session.") self.device_manager.kill_all_avd() self.device_manager.clear_models_based_on_avd_schema()
def get_existing_apk(self, test_set): apk_candidate = self.apk_store.usable_apk_candidate if apk_candidate is None: apk_candidate = self.apk_store.provide_apk(test_set) if apk_candidate is None: message = "No .apk* candidates for test session were found. Check your config. Launcher will quit." raise LauncherFlowInterruptedException(self.TAG, message) session_logger.log_app_apk(apk_candidate.apk_name) session_logger.log_test_apk(apk_candidate.test_apk_name) session_logger.log_apk_version_code(apk_candidate.apk_version) if session_logger.session_log.apk_summary.apk_build_time is None: session_logger.session_log.apk_summary.apk_build_time = 0 if session_logger.session_log.apk_summary.test_apk_build_time is None: session_logger.session_log.apk_summary.test_apk_build_time = 0 return apk_candidate
def _run_tests(self, devices, test_cmd_templates, is_rerunning=False): device_commands_dict = self._prepare_device_control_cmds(devices) threads_finished = False logcat_threads_num = len(devices) recording_threads_num = len( devices) if GlobalConfig.SHOULD_RECORD_TESTS else 0 test_threads_num = len(test_cmd_templates) logcat_threads = list() test_threads = list() test_log_saving_threads = list() logcat_saving_threads = list() test_recording_saving_threads = list() try: while not threads_finished: if len(logcat_threads) != logcat_threads_num: for device in devices: logcat_thread = TestLogCatMonitorThread( device, device_commands_dict.get(device), GlobalConfig.SHOULD_RECORD_TESTS) logcat_threads.append(logcat_thread) logcat_thread.start() if len(test_recording_saving_threads) != recording_threads_num: for device in devices: test_recording_saving_thread = TestRecordingSavingThread( device) test_recording_saving_threads.append( test_recording_saving_thread) test_recording_saving_thread.start() if len(test_threads) != test_threads_num and all( t.logcat_process is not None for t in logcat_threads): for device in devices: if not any(t.device.adb_name == device.adb_name and t.is_alive() for t in test_threads) \ and len(test_cmd_templates) > 0: launch_cmd_template = test_cmd_templates.pop(0) launch_cmd = launch_cmd_template.replace( self.DEVICE_NAME_PLACEHOLDER, device.adb_name) instance = "packages" if not is_rerunning else "tests" Printer.system_message( self.TAG, str(len(test_cmd_templates)) + " {} to run left...".format(instance)) self.adb_package_manager_controller.clear_package_cache( device.adb_name, GlobalConfig.APP_PACKAGE) test_thread = TestThread(launch_cmd, device) test_threads.append(test_thread) test_thread.start() for test_thread in test_threads: if len(test_thread.logs) > 0: current_test_logs = copy.deepcopy(test_thread.logs) self.test_store.store_test_status(current_test_logs) for test_log in current_test_logs: contain_count = self.test_store.test_contain_count( test_log.test_name) if contain_count > 1: test_log.rerun_count += contain_count - 1 if is_rerunning: session_logger.update_flaky_candidate(test_log) else: if test_log.test_status == "success": session_logger.increment_passed_tests() if test_log.test_status == "failure": session_logger.increment_failed_tests() test_log_saving_thread = TestSummarySavingThread( test_thread.device, current_test_logs) test_log_saving_threads.append(test_log_saving_thread) test_log_saving_thread.start() test_thread.logs.clear() for logcat_thread in logcat_threads: if len(logcat_thread.logs) > 0: current_logcats = copy.deepcopy(logcat_thread.logs) self.test_store.store_test_logcat(current_logcats) for test_logcat in current_logcats: contain_count = self.test_store.test_logcat_contain_count( test_logcat.test_name) if contain_count > 1: test_logcat.rerun_count += contain_count - 1 logcat_saving_thread = TestLogcatSavingThread( logcat_thread.device, current_logcats) logcat_saving_threads.append(logcat_saving_thread) logcat_saving_thread.start() logcat_thread.logs.clear() if len(logcat_thread.recordings) > 0: device = logcat_thread.device current_recordings = copy.deepcopy( logcat_thread.recordings) for recording_saving_thread in test_recording_saving_threads: if recording_saving_thread.device.adb_name == device.adb_name: pull_cmd_list = list() clear_cmd_list = list() for recording_name in current_recordings: recording_dir = FileUtils.add_ending_slash( FileUtils.clean_path( GlobalConfig. DEVICE_VIDEO_STORAGE_DIR) ) + recording_name pull_cmd_list.append( self._prepare_pull_recording_cmd( device, recording_dir)) clear_cmd_list.append( self._prepare_remove_recording_cmd( device, recording_dir)) recording_saving_thread.add_recordings( current_recordings) recording_saving_thread.add_pull_recording_cmds( pull_cmd_list) recording_saving_thread.add_clear_recordings_cmd( clear_cmd_list) logcat_thread.recordings.clear() if len(test_threads) == test_threads_num \ and all(not t.is_alive() for t in test_threads) \ and all(t.is_finished() for t in test_log_saving_threads) \ and all(t.is_finished() for t in logcat_saving_threads): for test_thread in test_threads: test_thread.kill_processes() test_thread.join() for logcat_thread in logcat_threads: logcat_thread.kill_processes() logcat_thread.join() for test_log_saving_thread in test_log_saving_threads: test_log_saving_thread.join() for logcat_saving_thread in logcat_saving_threads: logcat_saving_thread.join() test_threads.clear() logcat_threads.clear() test_log_saving_threads.clear() logcat_saving_threads.clear() if len(test_recording_saving_threads) > 0 and len( logcat_threads) == 0: if all( len(t.recordings) == 0 for t in test_recording_saving_threads): for recording_thread in test_recording_saving_threads: recording_thread.kill_processes() recording_thread.join() test_recording_saving_threads.clear() threads_finished = len(logcat_threads) == 0 and len( test_threads) == 0 and len( test_log_saving_threads) == 0 and len( logcat_saving_threads) == 0 and len( test_recording_saving_threads) == 0 and len( test_cmd_templates) == 0 except Exception as e: message = "Error has occurred during test session: \n" + str(e) raise LauncherFlowInterruptedException(self.TAG, message) finally: if len(test_threads) > 0: for test_thread in test_threads: test_thread.kill_processes() test_thread.join() if len(logcat_threads) > 0: for logcat_thread in logcat_threads: logcat_thread.kill_processes() logcat_thread.join() if len(test_log_saving_threads) > 0: for test_log_saving_thread in test_log_saving_threads: test_log_saving_thread.join() if len(logcat_saving_threads) > 0: for logcat_saving_thread in logcat_saving_threads: logcat_saving_thread.join() if len(test_recording_saving_threads) > 0: for recording_thread in test_recording_saving_threads: recording_thread.kill_processes() recording_thread.join() test_threads.clear() logcat_threads.clear() test_log_saving_threads.clear() logcat_saving_threads.clear() test_recording_saving_threads.clear()
def _install_apk(self, apk): aapt_cmd_assembler = self.aapt_controller.aapt_command_assembler app_apk_log_note = "appApkThread" test_apk_log_note = "testApkThread" for device in self.device_store.get_devices(): if device.status != "device": message = (".*apk won't be installed on device with name " + device.adb_name + " because it's ADB " + "status is set to " + device.status + " instead of 'device'.") raise LauncherFlowInterruptedException(self.TAG, message) apk_install_threads = dict() for device in self.device_store.get_devices(): app_dump_badging_cmd = aapt_cmd_assembler.assemble_dump_badging_cmd( self.aapt_controller.aapt_bin, apk.apk_path) app_apk_thread = ApkInstallThread(app_dump_badging_cmd, device, apk.apk_name, apk.apk_path) app_apk_thread.note = app_apk_log_note test_dump_badging_cmd = aapt_cmd_assembler.assemble_dump_badging_cmd( self.aapt_controller.aapt_bin, apk.test_apk_path) test_apk_thread = ApkInstallThread(test_dump_badging_cmd, device, apk.test_apk_name, apk.test_apk_path) test_apk_thread.note = test_apk_log_note thread_list = list() thread_list.append(app_apk_thread) thread_list.append(test_apk_thread) apk_install_threads.update({device: thread_list}) all_devices_have_apk_installed = False while not all_devices_have_apk_installed: for device in self.device_store.get_devices(): device_threads = apk_install_threads[device] for thread in device_threads: if any(thread.is_alive() for thread in device_threads): break if not thread.is_finished: thread.start() if thread.note == app_apk_log_note: session_logger.log_app_apk_install_start_time_on_device( device.adb_name) if thread.note == test_apk_log_note: session_logger.log_test_apk_install_start_time_on_device( device.adb_name) all_threads_has_finished = True for device in self.device_store.get_devices(): device_threads = apk_install_threads[device] for thread in device_threads: if thread.is_finished: if thread.note == app_apk_log_note: session_logger.log_app_apk_install_end_time_on_device( device.adb_name) if thread.note == test_apk_log_note: session_logger.log_test_apk_install_end_time_on_device( device.adb_name) else: all_threads_has_finished = False if not all_threads_has_finished: break all_devices_have_apk_installed = all_threads_has_finished
def _wait_for_property_statuses(self, monitored_devices): Printer.system_message( self.TAG, "Waiting for 'dev.bootcomplete', 'sys.boot_completed', 'init.svc.bootanim', " "properties of devices (" + " ".join("'" + device.adb_name + "'" for device in monitored_devices) + ").") device_statuses = dict() for device in monitored_devices: device_statuses.update({device.adb_name: None}) start_time = last_scan_ended = time.time() * 1000 while True: current_time = time.time() * 1000 if current_time - last_scan_ended >= GlobalConfig.ADB_SCAN_INTERVAL or start_time == last_scan_ended: Printer.system_message(self.TAG, "Scanning...") for device in self.device_store.get_devices(): if device in monitored_devices: dev_boot = (self.adb_shell_controller.get_property( device.adb_name, "dev.bootcomplete")).strip() sys_boot = (self.adb_shell_controller.get_property( device.adb_name, "sys.boot_completed")).strip() boot_anim = (self.adb_shell_controller.get_property( device.adb_name, "init.svc.bootanim")).strip() boot_finished = dev_boot == "1" and sys_boot == "1" and boot_anim == "stopped" device_statuses.update({ device.adb_name: { "dev.bootcomplete": dev_boot, "sys.boot_completed": sys_boot, "init.svc.bootanim": boot_anim, "boot_finished": boot_finished } }) if boot_finished: session_logger.log_device_launch_end_time( device.adb_name) Printer.system_message(self.TAG, " * Current wait status:") for device_name, status_dict in device_statuses.items(): bcplte = str( status_dict["dev.bootcomplete"] if status_dict["dev.bootcomplete"] != "" else "0") bcplted = str( status_dict["sys.boot_completed"] if status_dict["sys.boot_completed"] != "" else "0") banim = str(status_dict["init.svc.bootanim"]) launched_status = "launched" if status_dict[ "boot_finished"] else "not-launched" Printer.system_message( self.TAG, " " + device_name + " properties: " + "('dev.bootcomplete' : " + bcplte + ", " + "'sys.boot_completed' : " + bcplted + ", " + "'init.svc.bootanim' : " + banim + ") - " + Color.GREEN + launched_status + Color.BLUE) if all(status_dict["boot_finished"] for status_dict in device_statuses.values()): break last_scan_ended = time.time() * 1000 if current_time - start_time >= GlobalConfig.AVD_SYSTEM_BOOT_TIMEOUT: message = "Devices took longer than seconds to launch (Property launch). Timeout quit." message = message.format( str(GlobalConfig.AVD_SYSTEM_BOOT_TIMEOUT)) raise LauncherFlowInterruptedException(self.TAG, message) Printer.system_message(self.TAG, "Property launch finished with success!")
def run_tests(self, test_set, test_list): devices = self.device_store.get_devices() test_packages = self.test_store.get_packages(test_set, test_list) launch_variant_string = "TESTS SPLIT INTO SHARDS" if test_set.shard else "EACH TEST ON EACH DEVICE" Printer.system_message( self.TAG, "According to test set settings, tests will be run with following variant: " + Color.GREEN + launch_variant_string + Color.BLUE + ".") device_commands_dict = self._prepare_device_control_cmds(devices) test_cmd_templates = self._prepare_launch_test_cmds_for_run( test_packages, devices, test_set.shard) threads_finished = False logcat_threads_num = len(devices) recording_threads_num = len( devices) if GlobalConfig.SHOULD_RECORD_TESTS else 0 test_threads_num = len(test_cmd_templates) logcat_threads = list() test_threads = list() test_log_saving_threads = list() logcat_saving_threads = list() test_recording_saving_threads = list() try: while not threads_finished: if len(logcat_threads) != logcat_threads_num: for device in devices: logcat_thread = TestLogCatMonitorThread( device, device_commands_dict.get(device), GlobalConfig.SHOULD_RECORD_TESTS) logcat_threads.append(logcat_thread) logcat_thread.start() if len(test_recording_saving_threads) != recording_threads_num: for device in devices: test_recording_saving_thread = TestRecordingSavingThread( device) test_recording_saving_threads.append( test_recording_saving_thread) test_recording_saving_thread.start() if len(test_threads) != test_threads_num and all( t.logcat_process is not None for t in logcat_threads): for device in devices: if not any(t.device.adb_name == device.adb_name and t.is_alive() for t in test_threads) \ and len(test_cmd_templates) > 0: launch_cmd_template = test_cmd_templates.pop(0) launch_cmd = launch_cmd_template.replace( self.DEVICE_NAME_PLACEHOLDER, device.adb_name) Printer.system_message( self.TAG, str(len(test_cmd_templates)) + " packages to run left...") self.adb_package_manager_controller.clear_package_cache( device.adb_name, GlobalConfig.APP_PACKAGE) test_thread = TestThread(launch_cmd, device) test_threads.append(test_thread) test_thread.start() for test_thread in test_threads: if len(test_thread.logs) > 0: current_test_logs = copy.deepcopy(test_thread.logs) for log in current_test_logs: if log.test_status == "success": session_logger.increment_passed_tests() if log.test_status == "failure": session_logger.increment_failed_tests() test_log_saving_thread = TestSummarySavingThread( test_thread.device, current_test_logs) test_log_saving_threads.append(test_log_saving_thread) test_log_saving_thread.start() test_thread.logs.clear() for logcat_thread in logcat_threads: if len(logcat_thread.logs) > 0: current_logcats = copy.deepcopy(logcat_thread.logs) logcat_saving_thread = TestLogcatSavingThread( logcat_thread.device, current_logcats) logcat_saving_threads.append(logcat_saving_thread) logcat_saving_thread.start() logcat_thread.logs.clear() if len(logcat_thread.recordings) > 0: device = logcat_thread.device current_recordings = copy.deepcopy( logcat_thread.recordings) for recording_saving_thread in test_recording_saving_threads: if recording_saving_thread.device.adb_name == device.adb_name: pull_cmd_list = list() clear_cmd_list = list() for recording_name in current_recordings: recording_dir = FileUtils.add_ending_slash( FileUtils.clean_path( GlobalConfig. DEVICE_VIDEO_STORAGE_DIR) ) + recording_name pull_cmd_list.append( self._prepare_pull_recording_cmd( device, recording_dir)) clear_cmd_list.append( self._prepare_remove_recording_cmd( device, recording_dir)) recording_saving_thread.add_recordings( current_recordings) recording_saving_thread.add_pull_recording_cmds( pull_cmd_list) recording_saving_thread.add_clear_recordings_cmd( clear_cmd_list) logcat_thread.recordings.clear() if len(test_threads) == test_threads_num \ and all(not t.is_alive() for t in test_threads) \ and all(t.is_finished() for t in test_log_saving_threads) \ and all(t.is_finished() for t in logcat_saving_threads): for test_thread in test_threads: test_thread.kill_processes() test_thread.join() for logcat_thread in logcat_threads: logcat_thread.kill_processes() logcat_thread.join() for test_log_saving_thread in test_log_saving_threads: test_log_saving_thread.join() for logcat_saving_thread in logcat_saving_threads: logcat_saving_thread.join() test_threads.clear() logcat_threads.clear() test_log_saving_threads.clear() logcat_saving_threads.clear() if len(test_recording_saving_threads) > 0 and len( logcat_threads) == 0: if all( len(t.recordings) == 0 for t in test_recording_saving_threads): for recording_thread in test_recording_saving_threads: recording_thread.kill_processes() recording_thread.join() test_recording_saving_threads.clear() threads_finished = len(logcat_threads) == 0 and len( test_threads) == 0 and len( test_log_saving_threads) == 0 and len( logcat_saving_threads) == 0 and len( test_recording_saving_threads) == 0 and len( test_cmd_templates) == 0 except Exception as e: message = "Error has occurred during test session: \n" + str(e) raise LauncherFlowInterruptedException(self.TAG, message) finally: if len(test_threads) > 0: for test_thread in test_threads: test_thread.kill_processes() test_thread.join() if len(logcat_threads) > 0: for logcat_thread in logcat_threads: logcat_thread.kill_processes() logcat_thread.join() if len(test_log_saving_threads) > 0: for test_log_saving_thread in test_log_saving_threads: test_log_saving_thread.join() if len(logcat_saving_threads) > 0: for logcat_saving_thread in logcat_saving_threads: logcat_saving_thread.join() if len(test_recording_saving_threads) > 0: for recording_thread in test_recording_saving_threads: recording_thread.kill_processes() recording_thread.join() test_threads.clear() logcat_threads.clear() test_log_saving_threads.clear() logcat_saving_threads.clear() test_recording_saving_threads.clear()