def _display_emulator_binaries(self): emulator_binaries = dict() emulator_dir = clean_path( add_ending_slash(str(GlobalConfig.SDK_DIR)) + "emulator/") try: for the_file in list_files_in_dir(emulator_dir): file_path = os.path.join(emulator_dir, the_file) if os.path.isfile(file_path) and "emulator" in file_path: binary_name = re.findall("emulator\/(emulator*.+)", file_path) if binary_name: emulator_binaries[str(binary_name[0])] = file_path finally: if len(emulator_binaries) == 0: message = "Unable to find emulator binary files in direction '{}' of Android SDK." message = message.format(str(emulator_dir)) raise LauncherFlowInterruptedException(self.TAG, message) else: Printer.system_message( self.TAG, "Emulator related binary files found in Android SDK:") for path in emulator_binaries.values(): Printer.system_message( self.TAG, " * " + Color.GREEN + path + Color.BLUE) return emulator_binaries
def _init_phase(): Printer.phase("INIT") session_logger.log_session_start_time() Printer.step("Launcher started working!") Version.info() Version.python_check()
def _pre_test_clean_up_phase(self): Printer.phase("PRE-TESTING CLEAN UP") if GlobalConfig.SHOULD_RECORD_TESTS: Printer.step( "Preparing directory for recordings storage on test devices") self.clean_up_manager.prepare_device_directories()
def run(self): Printer.console_highlighted(self.TAG, "Executing shell command: ", self.launch_tests_cmd) with subprocess.Popen(self.launch_tests_cmd, shell=True, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True, encoding="utf-8", errors="ignore") as p: self.test_process = p is_using_post_api27_flow = None reading_stack_in_progress = False current_log = None stack = None for line in p.stdout: line_cleaned = line.encode("utf-8", "ignore").decode("utf-8") if self.TEST_NAME in line_cleaned and is_using_post_api27_flow is None: is_using_post_api27_flow = False elif self.TEST_PACKAGE in line_cleaned and is_using_post_api27_flow is None: is_using_post_api27_flow = True elif is_using_post_api27_flow is None: continue if is_using_post_api27_flow: current_log, stack, reading_stack_in_progress = self._post_api27_logging_flow( line_cleaned, current_log, stack, reading_stack_in_progress) else: current_log, stack, reading_stack_in_progress = self._pre_api27_logging_flow( line_cleaned, current_log, stack, reading_stack_in_progress)
def _wait_for_adb_statuses_change_to(self, status, monitored_devices): Printer.system_message( self.TAG, "Waiting until (" + " ".join("'" + device.adb_name + "'" for device in monitored_devices) + ") devices status will change to '" + status + "'.") timeout = GlobalConfig.AVD_ADB_BOOT_TIMEOUT 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...") self.device_store.update_model_statuses() Printer.system_message(self.TAG, " * Current wait status:") for device in monitored_devices: Printer.system_message( self.TAG, " " + device.adb_name + " " + Color.GREEN + "('" + device.status + "')") if all(device.status == status for device in monitored_devices): break last_scan_ended = time.time() * 1000 if current_time - start_time >= timeout: message = "Devices took longer than {} seconds to launch (ADB launch). Timeout quit." message = message.format(str(timeout)) raise LauncherFlowInterruptedException(self.TAG, message) Printer.system_message(self.TAG, "ADB wait finished with success!")
def display_picked_apk_info(self): self.apk_store.display_candidates() if self.apk_store.usable_apk_candidate is not None: Printer.system_message( self.TAG, "Picked .*apk with highest version code:\n" + Color.GREEN + str(self.apk_store.usable_apk_candidate) + Color.BLUE + ".")
def _find_latest_build_tools(self): build_tools = list_files_in_dir( clean_path(add_ending_slash(GlobalConfig.SDK_DIR) + "build-tools")) build_tools = [ build_tool for build_tool in build_tools if build_tool[0].isdigit() ] build_tools_folder_with_highest_ver = None Printer.system_message( self.TAG, "Available Android SDK Build-Tools versions: " + str(build_tools)) for build_tools_folder in build_tools: if build_tools_folder_with_highest_ver is None: build_tools_folder_with_highest_ver = build_tools_folder continue ver = int(re.sub("[^0-9]", "", build_tools_folder)) highest_ver = int( re.sub("[^0-9]", "", build_tools_folder_with_highest_ver)) if ver > highest_ver: build_tools_folder_with_highest_ver = build_tools_folder if build_tools_folder_with_highest_ver is None: message = "Android SDK Build-Tools not found. Launcher will quit." raise LauncherFlowInterruptedException(self.TAG, message) else: Printer.system_message( self.TAG, "Android SDK Build-Tools with latest version were selected: " + Color.GREEN + str(build_tools_folder_with_highest_ver) + Color.BLUE + ".") return build_tools_folder_with_highest_ver
def prepare_session_devices(self, avd_set, avd_schemas): avd_ports = PortManager.get_open_ports(avd_set) for avd in avd_set.avd_list: instances_of_schema = avd.instances for i in range(instances_of_schema): avd_schema = copy.deepcopy(avd_schemas[avd.avd_name]) avd_schema.avd_name = avd_schema.avd_name + "-" + str(i) port = avd_ports.pop(0) log_file = FileUtils.clean_path( GlobalConfig.OUTPUT_AVD_LOG_DIR + avd_schema.avd_name + ".txt") FileUtils.create_file(GlobalConfig.OUTPUT_AVD_LOG_DIR, avd_schema.avd_name, "txt") Printer.system_message( self.TAG, "Created file " + Color.GREEN + log_file + Color.BLUE + ".") session_device = SessionVirtualDevice( avd_schema, port, log_file, self.avdmanager_controller, self.emulator_controller, self.adb_controller, self.adb_package_manager_controller, self.adb_settings_controller) self.session_devices.append(session_device) Printer.system_message( self.TAG, "Android Virtual Device model was created according to schema " + Color.GREEN + avd_schema.avd_name + Color.BLUE + ". Instance number: " + str(i) + ". Assigned to port: " + str(port) + ".")
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 _load_launch_plan(launch_manifest, launch_plan_name): if launch_manifest.contains_plan(launch_plan_name): Printer.system_message(TAG, "Launch plan " + Color.GREEN + launch_plan_name + Color.BLUE + " was found in LaunchManifest.") return launch_manifest.get_plan(launch_plan_name) else: message = "Invalid launch plan with name '{}' does not exist in LaunchManifest!" message = message.format(launch_plan_name) raise LauncherFlowInterruptedException(TAG, message)
def _load_avd_set_name(): avd_set_name = ArgLoader.get_arg_loaded_by(ArgLoader.AVD_SET_PREFIX) if avd_set_name is None: Printer.system_message(TAG, "No AVD set selected. ""Currently available real devices will be used in test " "session.") else: Printer.system_message(TAG, "Selected avd set: " + Color.GREEN + avd_set_name + Color.BLUE + ".") return avd_set_name
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 _assert_bin_directory_exists(self): if os.path.isfile(self.adb_bin): Printer.system_message( self.TAG, "ADB binary file found at " + Color.GREEN + self.adb_bin + Color.BLUE + ".") else: message = "Unable to find ADB binary at '{}'." message = message.format(self.adb_bin) raise LauncherFlowInterruptedException(self.TAG, message)
def _load_launch_plan_name(): launch_plan_name = ArgLoader.get_arg_loaded_by(ArgLoader.LAUNCH_PLAN_PREFIX) if launch_plan_name is None: message = "No launch plan selected. Launcher will quit." raise LauncherFlowInterruptedException(TAG, message) else: Printer.system_message(TAG, "Selected launch plan: " + Color.GREEN + launch_plan_name + Color.BLUE + ".") return launch_plan_name
def _create_apk_dir_if_not_exists(self): if FileUtils.dir_exists(GlobalConfig.APK_DIR): Printer.system_message( self.TAG, "Directory " + Color.GREEN + GlobalConfig.APK_DIR + Color.BLUE + " was found.") else: Printer.system_message( self.TAG, "Directory " + Color.GREEN + GlobalConfig.APK_DIR + Color.BLUE + " not found. Creating...") FileUtils.create_dir(GlobalConfig.APK_DIR)
def _load_path_set_name(): path_set_name = ArgLoader.get_arg_loaded_by(ArgLoader.PATH_SET_PREFIX) if path_set_name is None: message = "No path set was selected. Launcher will quit." raise LauncherFlowInterruptedException(TAG, message) else: Printer.system_message( TAG, "Selected path set: " + Color.GREEN + path_set_name + Color.BLUE + ".") return path_set_name
def _load_path_set(path_manifest, path_set_name): if path_manifest.contains_set(path_set_name): Printer.system_message( TAG, "Path set " + Color.GREEN + path_set_name + Color.BLUE + " was found in PathManifest.") return path_manifest.get_set(path_set_name) else: message = "Invalid path set with name '{}' does not exist in PathManifest!" message = message.format(path_set_name) raise LauncherFlowInterruptedException(TAG, message)
def python_check(): if sys.version_info >= MIN_PYTHON_VER: Printer.system_message( "", "Minimum Python version requirement met! Your version: " + Color.GREEN + str(sys.version_info) + Color.BLUE + ".") else: message = ("Invalid Python version. Please use at least Python " + str(MIN_PYTHON_VER[0]) + "." + str(MIN_PYTHON_VER[1]) + ".") raise LauncherFlowInterruptedException("", message)
def _load_test_set_name(): test_set_name = ArgLoader.get_arg_loaded_by(ArgLoader.TEST_SET_PREFIX) if test_set_name is None: message = "No test set inserted. Launcher will quit." raise LauncherFlowInterruptedException(TAG, message) else: Printer.system_message( TAG, "Selected test set: " + Color.GREEN + test_set_name + Color.BLUE + ".") return test_set_name
def remove_device_from_session(self, device): if device in self.outside_session_virtual_devices: self.outside_session_virtual_devices.remove(device) elif device in self.outside_session_devices: self.outside_session_devices.remove(device) elif device in self.session_devices: self.session_devices.remove(device) Printer.system_message( self.TAG, "Device with name " + Color.GREEN + device.adb_name + Color.BLUE + " was removed from session.")
def print_test_summary(): Printer.system_message(TAG, "Test details:") Printer.system_message(TAG, " * Total number of test cases: " + Color.GREEN + str(session_log.test_summary.test_number) + Color.BLUE + ".") Printer.system_message(TAG, " * Tests passed: " + Color.GREEN + str(session_log.test_summary.test_passed) + Color.BLUE + ".") Printer.system_message(TAG, " * Tests failed: " + Color.GREEN + str(session_log.test_summary.test_failed) + Color.BLUE + ".") if session_log.test_summary.health_rate is not None: Printer.system_message(TAG, " * Health rate: " + Color.GREEN + "{0:.2f}%".format(session_log.test_summary.health_rate * 100) + Color.BLUE + ".")
def _load_launch_plan_manifest(): launch_manifest_dir = make_path_absolute(ArgLoader.get_manifest_dir(ArgLoader.LAUNCH_MANIFEST_DIR_KEY)) if launch_manifest_dir is None: message = ("LaunchManifest file directory was not found. Check if config_files_dir.json exists in root " "of project. Otherwise check if it's linking to existing file.") raise LauncherFlowInterruptedException(TAG, message) else: launch_manifest = LaunchManifest(launch_manifest_dir) Printer.system_message(TAG, "Created LaunchManifest from file: " + Color.GREEN + launch_manifest_dir + Color.BLUE + ".") return launch_manifest
def _load_avd_manifest(): avd_manifest_dir = make_path_absolute(ArgLoader.get_manifest_dir(ArgLoader.AVD_MANIFEST_DIR_KEY)) if avd_manifest_dir is None: message = ("AvdManifest file directory was not found. Check if config_files_dir.json exists in root of" + "project. Otherwise check if it's linking to existing file.") raise LauncherFlowInterruptedException(TAG, message) else: avd_manifest = AvdManifest(avd_manifest_dir) Printer.system_message(TAG, "Created AvdManifest from file: " + Color.GREEN + avd_manifest_dir + Color.BLUE + ".") return avd_manifest
def set_instrumentation_runner_according_to(self, apk): Printer.system_message( self.TAG, "Scanning test .*apk file for Instrumentation Runner data.") resources = self.aapt_controller.list_resources(apk.test_apk_path) target_package = "" instrumentation_runner_name = "" inside_instrumentation_section = False inside_manifest_section = False for line in resources.splitlines(): if "E: instrumentation" in line: inside_instrumentation_section = True continue if "E: manifest" in line: inside_manifest_section = True continue if inside_instrumentation_section and "E: " in line: inside_instrumentation_section = False if inside_manifest_section and "E: " in line: inside_manifest_section = False if inside_instrumentation_section: if "A: android:name" in line: regex_result = re.findall("=\"(.+?)\"", line) if regex_result: instrumentation_runner_name = str(regex_result[0]) if inside_manifest_section: if "A: package" in line: regex_result = re.findall("=\"(.+?)\"", line) if regex_result: target_package = str(regex_result[0]) if target_package == "": message = "Unable to find package of tested application in test .*apk file. Tests won't start without it." raise LauncherFlowInterruptedException(self.TAG, message) if instrumentation_runner_name == "": message = ( "Unable to find Instrumentation Runner name of tested application in test .*apk file." " Tests won't start without it.") raise LauncherFlowInterruptedException(self.TAG, message) GlobalConfig.INSTRUMENTATION_RUNNER = target_package + "/" + instrumentation_runner_name Printer.system_message( self.TAG, "Instrumentation Runner found: " + Color.GREEN + GlobalConfig.INSTRUMENTATION_RUNNER + Color.BLUE + ".")
def _load_avd_schema(avd_manifest, avd_set, avd_set_name): avd_schema_dict = avd_manifest.avd_schema_dict for avd in avd_set.avd_list: if avd_manifest.contains_schema(avd.avd_name): Printer.system_message(TAG, "AVD schema " + Color.GREEN + avd.avd_name + Color.BLUE + " was found in AvdManifest.") else: message = "Set '{}' requests usage of AVD schema with name '{}' which doesn't exists in AVD schema list." message = message.format(avd_set_name, avd.avd_name) raise LauncherFlowInterruptedException(TAG, message) return avd_schema_dict
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) test_cmd_templates = self._prepare_launch_test_cmds_for_run( test_packages, devices, test_set.shard) 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 + ".") self._run_tests(devices, test_cmd_templates)
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 _check_if_gradle_binary_was_found(self): self.project_root_found = GlobalConfig.PROJECT_ROOT_DIR != "" and os.path.isdir( GlobalConfig.PROJECT_ROOT_DIR) self.gradlew_found = os.path.isfile(self.gradle_bin) if self.project_root_found: Printer.system_message( self.TAG, "Project root dir " + Color.GREEN + GlobalConfig.PROJECT_ROOT_DIR + Color.BLUE + " was found! Building new .*apk is possible.") if self.gradlew_found: Printer.system_message( self.TAG, "gradlew binary found at " + Color.GREEN + str(self.gradle_bin) + Color.BLUE + ".")
def _load_test_set(test_manifest, test_set_name): if test_manifest.contains_set(test_set_name): Printer.system_message( TAG, "Test set " + Color.GREEN + test_set_name + Color.BLUE + " was found in TestManifest.") test_set = test_manifest.get_set(test_set_name) Printer.system_message(TAG, "Test set contains following package names: ") for package_name in test_set.set_package_names: Printer.system_message( TAG, " * " + Color.GREEN + package_name + Color.BLUE) found_all_packages = True errors = "" for package_name in test_set.set_package_names: if not test_manifest.contains_package(package_name): found_all_packages = False errors += "\n - Test package '" + package_name + "' was not found in TestManifest!" if found_all_packages: Printer.system_message( TAG, "All test packages from set " + Color.GREEN + test_set_name + Color.BLUE + " were found in TestManifest.") else: raise LauncherFlowInterruptedException(TAG, errors) else: message = "Test set '{}' not found in TestManifest. Launcher will quit." message = message.format(test_set_name) raise LauncherFlowInterruptedException(TAG, message) return test_set