def install(self, device: Device) -> bool: adb.get_root_permissions(device) # remount partitions output, errors, result_code = adb.adb_command(device, "remount", retry=5) if result_code != 0: raise Exception(f"Unable to remount partitions on device: {device.name} - {errors} - {output}") # make /mnt/sdcard writable output, errors, result_code = adb.shell_command(device, "mount -o rw,remount /") if result_code != 0: raise Exception(f"Unable to remount root partition on device: {device.name}") # push adb.push(device, self.test_runner_jar_path, f"/system/framework/{self.test_runner_name}.jar") output, errors, result_code = adb.shell_command( device, f"chmod 777 /system/framework/{self.test_runner_name}.jar" ) if result_code != 0: raise Exception(f"Unable to install test runner on device: {device.name}") adb.push(device, self.test_runner_executable_path, f"/system/bin/{self.test_runner_name}") output, errors, result_code = adb.shell_command(device, f"chmod 777 /system/bin/{self.test_runner_name}") if result_code != 0: raise Exception(f"Unable to install test runner on device: {device.name}") return True
def get_suite_coverage(self, scripts: List[str], device: Device, generation: int, individual_index: int) -> CoverageResult: self.verbose_level = RequiredFeature('verbose_level').request() compiled_package_name: str = RequiredFeature( 'compiled_package_name').request() unique_crashes: Set[str] = set() scripts_crash_status: Dict[str, bool] = {} accumulated_output = "" accumulated_errors = "" # stop target app in the device (just in case) adb.shell_command(device, f"am force-stop {compiled_package_name}") coverage_folder_local_path = self.prepare_coverage_folder( generation, individual_index) # upload the test scripts to device adb.push_all(device, scripts, "/mnt/sdcard") # run scripts for test_case_index, script_path in enumerate(scripts): self.generate_test_coverage(device, coverage_folder_local_path, accumulated_output, accumulated_errors, script_path, generation, individual_index, test_case_index, unique_crashes, scripts_crash_status) # collect coverage data coverage = self.get_coverage(device, coverage_folder_local_path, accumulated_output, accumulated_errors) return coverage, unique_crashes, scripts_crash_status
def clean_coverage_files_in_device(self, device: Device) -> None: compiled_package_name: str = RequiredFeature('compiled_package_name').request() application_files = f"/data/data/{compiled_package_name}/files" coverage_ec_device_path = f"{application_files}/coverage.ec" adb.shell_command(device, f"rm -f {coverage_ec_device_path}") adb.shell_command(device, f"rm -f {self.coverage_ec_device_backup_path}")
def generate_test_coverage( self, device: Device, coverage_folder_local_path: str, accumulated_output: str, accumulated_errors: str, script_path: str, generation: int, individual_index: int, test_case_index: int, unique_crashes: Set[str], scripts_crash_status: Dict[str, bool] ) -> bool: compiled_package_name: str = RequiredFeature('compiled_package_name').request() result_dir: str = RequiredFeature('result_dir').request() # clear app's data and state output, errors, result_code = adb.shell_command(device, f"pm clear {compiled_package_name}") accumulated_output += output accumulated_errors += errors if result_code != 0: adb.log_evaluation_result(device, result_dir, script_path, False) if self.verbose_level > 0: logger.log_progress(f"\n{accumulated_output}\n{accumulated_errors}") raise Exception(f"Unable to clear package for script_path {script_path} in device: {device.name}") output, errors, result_code = adb.shell_command( device, f"am instrument {compiled_package_name}/{compiled_package_name}.EmmaInstrument.EmmaInstrumentation" ) accumulated_output += output accumulated_errors += errors if result_code != 0: adb.log_evaluation_result(device, result_dir, script_path, False) if self.verbose_level > 0: logger.log_progress(f"\n{accumulated_output}\n{accumulated_errors}") raise Exception(f"Unable to instrument for script_path {script_path} in device: {device.name}") script_name = script_path.split("/")[-1] test_runner = RequiredFeature('test_runner').request() test_runner.run(device, compiled_package_name, script_name) return self.dump_script_coverage( device, coverage_folder_local_path, accumulated_output, accumulated_errors, script_path, generation, individual_index, test_case_index, unique_crashes, scripts_crash_status)
def upload_string_xml(self, device: Device) -> None: string_xml_path = f"{self.decoded_dir}/res/values/strings.xml" if settings.ENABLE_STRING_SEEDING is False or os.path.exists( string_xml_path) is False: # if not exist, upload dummy strings.xml string_xml_path = f"{settings.WORKING_DIR}resources/dummy_strings.xml" adb.shell_command(device, f" rm /mnt/sdcard/{self.package_name}_strings.xml") adb.push(device, string_xml_path, f"/mnt/sdcard/{self.package_name}_strings.xml")
def clean_sdcard(self) -> None: adb.get_root_permissions(self) adb.adb_command(self, "remount", timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) adb.shell_command(self, "mount -o rw,remount /", timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) adb.shell_command(self, "rm -rf /mnt/sdcard/*", timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT)
def get_suite_coverage( self, scripts: List[str], device: Device, generation: int, individual_index: int ) -> CoverageResult: self.verbose_level = RequiredFeature('verbose_level').request() compiled_package_name: str = RequiredFeature('compiled_package_name').request() result_dir: str = RequiredFeature('result_dir').request() unique_crashes: Set[str] = set() scripts_crash_status: Dict[str, bool] = {} accumulated_output = "" accumulated_errors = "" self.clean_coverage_files_in_device(device) coverage_folder_local_path = self.prepare_coverage_folder(generation, individual_index) # copy coverage.em file to local folder coverage_em_local_path = f"{coverage_folder_local_path}/coverage.em" os.system(f"cp {result_dir}/coverage.em {coverage_em_local_path}{logger.redirect_string()}") adb.shell_command(device, f"am force-stop {compiled_package_name}") adb.push_all(device, scripts, "/mnt/sdcard") # run scripts there_is_coverage = False for test_case_index, script_path in enumerate(scripts): there_is_coverage = self.generate_test_coverage( device, coverage_folder_local_path, accumulated_output, accumulated_errors, script_path, generation, individual_index, test_case_index, unique_crashes, scripts_crash_status) # collect coverage data coverage = 0 if there_is_coverage: coverage = self.get_coverage(device, coverage_folder_local_path, accumulated_output, accumulated_errors) return coverage, unique_crashes, scripts_crash_status
def handle(device: Device, script_path: str, generation: int, individual_index: int, test_case_index: int, unique_crashes: Set[str]) -> bool: result_dir = RequiredFeature('result_dir').request() device_bugreport_path = "/mnt/sdcard/bugreport.crash" individual_suffix = f"{str(generation)}.{str(individual_index)}.{str(test_case_index)}" local_bugreport_path = f"{result_dir}/crashes/bugreport.{individual_suffix}" # save the crash report output, errors, result_code = adb.pull(device, device_bugreport_path, local_bugreport_path) if result_code != 0: return False # get content with open(local_bugreport_path) as bug_report_file: content = bug_report_file.read().split('\n') # delete remote file adb.shell_command(device, f"rm {device_bugreport_path}") # should not caused by android itself if content[0].startswith("// CRASH: com.android."): os.system(f"rm {local_bugreport_path}") # caught a crash, but it was Android related return True # drop first line content = content[1:] # filter duplicate crashes content_str = "".join(content) if content_str in unique_crashes: os.system(f"rm {local_bugreport_path}") # caught a crash, but it wasn't a new one return True unique_crashes.add(content_str) # save the script, indicating its ith gen if script_path != "": os.system( f"cp {script_path} {result_dir}/crashes/script.{individual_suffix}" ) return True
def send_command(self, device: Device, package_name: str, command: str) -> str: """ :param command: to send through the socket and be run by the runner. :return: the response of the runner as a string. """ # ensure there is only one return character at the end of the command command = command.rstrip("\n") + "\n" # set up evolutiz runner in emulator adb.adb_command(device, f"forward tcp:{self.port} tcp:{self.port}") adb.shell_command( device, f"evolutiz -p {package_name} -c android.intent.category.LAUNCHER --port {self.port} &", discard_output=True) # wait for evolutiz runner to be ready output = "" tries = 0 while "Using EvolutizSourceNetwork" not in output: if tries >= 6: raise Exception( f"Unable to connect to Evolutiz test runner for command: {command}." ) tries += 1 output, errors, result_code = adb.adb_command( device, f"logcat -s Evolutiz -d | tail -n 1") time.sleep(0.5) # send command and collect result with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((self.host, self.port)) s.sendall(command.encode('utf-8')) data = self.receive_data(s) s.close() # need to manually kill evolutiz after working adb.pkill(device, "evolutiz") if data is None: raise Exception(f"Unable to parse result of command {command}.") else: return data.rstrip("\n")
def run(self, device: Device, package_name: str, script_name: str) -> None: assert device.api_level() >= self.minimum_api verbose_level = RequiredFeature('verbose_level').request() start_time = time.time() self.prepare_device_for_run(device) evolutiz_cmd = f"evolutiz -p {package_name} -v -v -v --throttle 200 --ignore-crashes " \ f"--ignore-security-exceptions --ignore-timeouts --bugreport -f /mnt/sdcard/{script_name} 1" output, errors, result_code = adb.shell_command( device, evolutiz_cmd, timeout=settings.TEST_CASE_EVAL_TIMEOUT) if verbose_level > 1: print(f"Test case running finished with output:\n{output}") if "Exception" in errors: device_stacktrace = errors.split("** Error: ")[1] raise Exception( f"An error occurred when running test case: {device_stacktrace}" ) # need to manually kill evolutiz when timeout adb.pkill(device, "evolutiz") self.clean_device_after_run(device) if verbose_level > 0: logger.log_progress( f'\nEvolutiz test run took: {time.time() - start_time:.2f} seconds' )
def run(self, device: Device, package_name: str, script_name: str) -> None: verbose_level = RequiredFeature('verbose_level').request() start_time = time.time() self.prepare_device_for_run(device) string_seeding_flag = "" if self.use_motifgene: string_seeding_flag = f"--string-seeding /mnt/sdcard/{package_name}_strings.xml" motifcore_cmd = f"motifcore -p {package_name} --ignore-crashes --ignore-security-exceptions --ignore-timeouts" \ f" --bugreport {string_seeding_flag} -f /mnt/sdcard/{script_name} 1" output, errors, result_code = adb.shell_command( device, motifcore_cmd, timeout=settings.TEST_CASE_EVAL_TIMEOUT) if verbose_level > 1: print(f"Test case running finished with output:\n{output}") if "Exception" in errors: device_stacktrace = errors.split("** Error: ")[1] raise Exception( f"An error occurred when running test case: {device_stacktrace}" ) # need to manually kill motifcore when timeout adb.pkill(device, "motifcore") self.clean_device_after_run(device) if verbose_level > 0: logger.log_progress( f'\nMotifcore test run took: {time.time() - start_time:.2f} seconds' )
def instrument_device(self, device: Device) -> bool: package_name = RequiredFeature('compiled_package_name').request() instrumentation_cmd = f"am instrument {package_name}/{package_name}.EmmaInstrument.EmmaInstrumentation" output, errors, result_code = adb.shell_command( device, instrumentation_cmd) if result_code != 0: raise Exception(f"Unable to instrument {package_name}") return True
def check_booted(self) -> None: if self.state >= State.booted: # don't change the state of devices when it is higher or equal than booted return try: output, errors, result_code = adb.shell_command( self, "getprop init.svc.bootanim") if output.strip() == "stopped" and "error" not in errors.strip(): self.state = State.booted except TimeoutExpired as e: return
def generate(self, device: Device, package_name: str, destination_file_name: str) -> TestCase: verbose_level = RequiredFeature('verbose_level').request() start_time = time.time() self.prepare_device_for_run(device) evolutiz_events = random.randint(settings.SEQUENCE_LENGTH_MIN, settings.SEQUENCE_LENGTH_MAX) string_seeding_flag = "" # String seeding is NOT supported yet # if self.use_motifgene: # string_seeding_flag = f"--string-seeding /mnt/sdcard/{package_name}_strings.xml" evolutiz_cmd = f"evolutiz -p {package_name} --ignore-crashes --ignore-security-exceptions --ignore-timeouts" \ f" --bugreport {string_seeding_flag} -o {self.evolutiz_script_path_in_devices}" \ f" --throttle {self.throttle} -v {str(evolutiz_events)}" output, errors, result_code = adb.shell_command( device, evolutiz_cmd, timeout=settings.TEST_CASE_EVAL_TIMEOUT) if verbose_level > 1: print(f"Test case generation finished with output:\n{output}") if "Exception" in errors: if "** Error: " in errors: device_stacktrace = errors.split("** Error: ")[1] raise Exception( f"An error occurred when generating test case: {device_stacktrace}" ) else: raise Exception( f"An error occurred when generating test case: {errors}") # need to manually kill evolutiz when timeout adb.pkill(device, "evolutiz") time.sleep(5) test_case: TestCase = self.retrieve_generated_test( device, destination_file_name) self.clean_device_after_run(device) if verbose_level > 0: logger.log_progress( f'\nEvolutiz test generation took: {time.time() - start_time:.2f} seconds ' f'for {evolutiz_events:d} events') return test_case
def install_on_device(self, device: Device) -> None: package_name: str = RequiredFeature('compiled_package_name').request() apk_path: str = RequiredFeature('apk_path').request() successful = False for i in range(3): try: self.apk_analyser.upload_string_xml(device) adb.shell_command(device, "rm /mnt/sdcard/bugreport.crash") adb.uninstall(device, package_name) adb.install(device, package_name, apk_path) successful = self.app_instrumentator.instrument_device(device) if successful: break except Exception as e: logger.log_progress( f"\nThere was an error installing apk on device: {str(e)}") time.sleep(5) if not successful: raise Exception(f"Unable to setup device: {device.name}")
def generate_test_coverage(self, device: Device, coverage_folder_local_path: str, accumulated_output: str, accumulated_errors: str, script_path: str, generation: int, individual_index: int, test_case_index: int, unique_crashes: Set[str], scripts_crash_status: Dict[str, bool]) -> bool: compiled_package_name: str = RequiredFeature( 'compiled_package_name').request() result_dir: str = RequiredFeature('result_dir').request() # clear app's data and state output, errors, result_code = adb.shell_command( device, f"pm clear {compiled_package_name}") accumulated_output += str(output) accumulated_errors += str(errors) if result_code != 0: adb.log_evaluation_result(device, result_dir, script_path, False) if self.verbose_level > 0: logger.log_progress( f"\n{accumulated_output}\n{accumulated_errors}") raise Exception( f"Unable to clear package for script_path {script_path} in device: {device.name}" ) # copy the covids file to the coverage_folder_local_path ella_coverage_ids_file_path = f"{self.get_current_apk_output_folder(device)}/covids" output, errors, result_code = run_cmd( f"cp {ella_coverage_ids_file_path} {coverage_folder_local_path}/") if result_code != 0: raise Exception( f"Unable to copy the coverage ids file for test script, path is: {ella_coverage_ids_file_path}" ) # Run test case using the requested test runner. # Internally, the test runner will take care of calling the methods AppInstrumentator#setup_for_test_run and # AppInstrumentator#teardown_after_test_run, which will start and stop the ELLA server correspondingly. script_name = script_path.split("/")[-1] test_runner = RequiredFeature('test_runner').request() test_runner.run(device, compiled_package_name, script_name) return self.dump_script_coverage(device, coverage_folder_local_path, accumulated_output, accumulated_errors, script_path, generation, individual_index, test_case_index, unique_crashes, scripts_crash_status)
def check_ready(self) -> None: if self.state >= State.ready_idle: # don't change the state of devices when it is higher or equal than ready_idle return try: output, errors, result_code = adb.shell_command( self, "pm list packages") if "Error: Could not access the Package Manager" not in output.strip( ) and errors.strip() == "": # this device is ready to receive commands, but first we have to check if it needs to be set up if not self.needs_setup: self.state = State.ready_idle else: time.sleep(15) device_setup_thread = DeviceSetupThread(self) device_setup_thread.run() except TimeoutExpired as e: return
def get_sequence(self, device: Device, generation: int, individual_index: int, test_case_index: int) -> TestCase: package_name: str = RequiredFeature('compiled_package_name').request() test_runner: TestRunner = RequiredFeature('test_runner').request() # clear data before generating new test case output, errors, result_code = adb.shell_command( device, f"pm clear {package_name}", timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT, retry=2) if result_code != 0: raise Exception( f"Failed to clear package {package_name} in device: {device.name}.\n{output}\n{errors}" ) script_path = self.get_path_for_test_case(generation, individual_index, test_case_index) test_case_content = test_runner.generate(device, package_name, script_path) return test_case_content
def start_ella(self, device: Device) -> None: self.prepare_ella_folder_for_device(device) run_cmd(f"find {self.get_device_ella_output_folder_path(device)} -type f -name \"coverage.dat.*\" | " f"xargs -I {{}} rm {{}}") # start ELLA server output, errors, result_code = run_cmd(f"./ella.sh s", cwd=self.get_device_ella_folder_path(device)) if result_code != 0: raise Exception("Unable to start ELLA server") # start the TCP relay service on the device output, errors, result_code = adb.shell_command( device, f"am startservice -n {self.tcp_relay_android_package_name}/.RelayService -a start " f"--ei pA {self.ella_original_port} --ei pB {self.get_device_tcp_relay_port(device)}") if result_code != 0: raise Exception("Unable to start the TCP relay service") # forward the TCP relay port from the emulator to the local PC device.forward_port(self.get_device_tcp_relay_port(device), self.get_device_tcp_relay_port(device)) # forward, locally, the TCP relay port to the ELLA server port run_cmd(f"socat TCP:localhost:{self.get_device_ella_port(device)} TCP:localhost:{self.get_device_tcp_relay_port(device)} &", discard_output=True)
def shutdown(self) -> None: Device.shutdown(self) adb.shell_command(self, "reboot -p")
def dump_script_coverage( self, device: Device, coverage_folder_local_path: str, accumulated_output: str, accumulated_errors: str, script_path: str, generation: int, individual_index: int, test_case_index: int, unique_crashes: Set[str], scripts_crash_status: Dict[str, bool] ) -> bool: compiled_package_name: str = RequiredFeature('compiled_package_name').request() package_name: str = RequiredFeature('package_name').request() result_dir: str = RequiredFeature('result_dir').request() application_files = f"/data/data/{compiled_package_name}/files" coverage_ec_device_path = f"{application_files}/coverage.ec" if crash_handler.handle(device, script_path, generation, individual_index, test_case_index, unique_crashes): scripts_crash_status[script_path] = True return False else: # no crash, can broadcast scripts_crash_status[script_path] = False # don't check result_code of the following command, since it can fail if this is the first time running emma # for this test suite and there is no coverage.ec file in /mnt/sdcard folder. adb.sudo_shell_command( device, f"cp -p {self.coverage_ec_device_backup_path} {coverage_ec_device_path}" ) broadcast = f"am broadcast -a evolutiz.emma.COLLECT_COVERAGE " \ f"-n {compiled_package_name}/{package_name}.EmmaInstrument.CollectCoverageReceiver" output, errors, result_code = adb.shell_command(device, broadcast, timeout=60) accumulated_output += output accumulated_errors += errors if "Exception" in errors: adb.log_evaluation_result(device, result_dir, script_path, False) if self.verbose_level > 0: logger.log_progress(f"\n{accumulated_output}\n{accumulated_errors}") raise Exception(f"Unable to broadcast coverage gathering for " f"script_path {script_path} in device: {device.name}") if not adb.exists_file(device, coverage_ec_device_path): adb.log_evaluation_result(device, result_dir, script_path, False) if self.verbose_level > 0: logger.log_progress(f"\n{accumulated_output}\n{accumulated_errors}") raise Exception(f"Coverage broadcast was sent for script_path {script_path} " f"in device: {device.name} but there is not file: {coverage_ec_device_path}") adb.log_evaluation_result(device, result_dir, script_path, True) # save coverage.ec file to /mnt/sdcard before clearing app (files are deleted) cp_command = f"cp -p {coverage_ec_device_path} {self.coverage_ec_device_backup_path}" output, errors, result_code = adb.sudo_shell_command(device, cp_command) accumulated_output += output accumulated_errors += errors if result_code != 0: adb.log_evaluation_result(device, result_dir, script_path, False) if self.verbose_level > 0: logger.log_progress(f"\n{accumulated_output}\n{accumulated_errors}") raise Exception(f"Unable to retrieve coverage.ec file after coverage broadcast for " f"script_path {script_path} in device: {device.name}") return True
def mutate_test_case(self, device: Device, test_case: EvolutizTestCase) -> EvolutizTestCase: """Implements a cut point mutation function for test cases. """ # Copy actions from original test case up until a cut point package_name = RequiredFeature('compiled_package_name').request() cut_point = random.randint(1, len(test_case)) # TODO: or is it random.randint(1, len(test_case)-1) mutated_test_case = test_case[:cut_point-1] adb.shell_command(device, f"pm clear {package_name}") self.evolutiz_connector.send_command(device, package_name, f"performview launch-app") # re-execute said actions for widget_action_result in mutated_test_case: success = widget_action_result.widget_action.execute(device, self.evolutiz_connector) if not success: raise Exception("Unable to re-execute test case in mutation operator") # from there onwards, execute random actions until we've reached max number of events or we have left the app while len(mutated_test_case) < settings.SEQUENCE_LENGTH_MAX: widget_action_result = WidgetAction.random(device, self.evolutiz_connector) mutated_test_case.append(widget_action_result) if widget_action_result.is_outbound(): break return mutated_test_case # # def mutate_test_suite(self, device, package_name, individual): # """Implements the mutation operator of test suites as described in [ArcuriF13]_. # # The mutation operator for test suites works both at test suite and test case levels: When a test suite T is # mutated, each of its test cases is mutated with probability 1/|T|. Then, with probability σ = 0.1, a new test # case is added to the test suite. If it is added, then a second test case is added with probability σ^2 , and so # on until the ith test case is not added (which happens with probability 1 − σ^i ). Test cases are added only if # the limit N has not been reached. # # When a test case is chosen to be mutated, we apply a number of mutations at random in between 1 and m, for some # constant m (which is a parameter that needs to be tuned). For each of these mutations on a test case (which are # applied sequentially), we apply three different operations with probability 1/3 in order: remove, change and # insert. # # When removing statements out of a test case of length l, each statement is removed with probability 1/l. # Removing a statement might invalidate dependencies within the test case, which we attempt to repair; if this # repair fails, then dependent statements are also deleted. When applying the change mutation, each statement is # changed with probability 1/l. A change means it is replaced with a different statement that retains the validity # of the test case; e.g., a different method call with the same return type. When inserting statements, we first # insert a new statement with probability σ' = 0.5 at a random position. If it is added, then a second statement # is added with probability σ'^2 , and so on until the ith statement is not inserted. If after applying these # mutation operators a test case t has no statement left (i.e., all have been removed), then t is removed from T. # # .. [ArcuriF13] A. Arcuri and G. Fraser, “Parameter tuning or default values? An empirical investigation in # search-based software engineering,” Empirical Software Engineering, vol. 18, no. 3, pp. 594–623, Jun. 2013. # # :param device: the device where the test suite will be mutated. # :param package_name: the package name of the application being tested. # :param individual: the test suite. # :return: mutated test suite. # """ # result_dir: str = RequiredFeature('result_dir').request() # # # mutate test cases # test_suite_size = settings.SUITE_SIZE # test_case_mutation_pb = 1/float(test_suite_size) # # for i in range(len(individual)): # if random.random() < test_case_mutation_pb: # mutated_test_case = self.mutate_test_case(device, package_name, individual[i]) # if len(mutated_test_case) > 0: # individual[i] = mutated_test_case # else: # del individual[i] # # # add test cases # sigma = float(0.1) # test_case_addition_pb = sigma # # pb = random.random() # while pb < test_case_mutation_pb and len(individual) < test_suite_size: # # ts = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S") # local_dst_filename = f"{result_dir}/intermediate/offspring.{ts}" # test_content = self.generate(device, package_name, local_dst_filename) # individual.append(test_content) # # test_case_addition_pb = test_case_addition_pb * sigma # pb = random.random() # # return individual, # # def mutate_test_case(self, device, package_name: str, test_case): # # assert device.api_level() >= self.minimum_api # # result_dir: str = RequiredFeature('result_dir').request() # # # write individual to local file # ts = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S") # local_src_filename: str = f"{result_dir}/intermediate/offspring.{ts}" # self.write_test_case_to_file(test_case, local_src_filename) # # # push individual to device # remote_src_filename: str = f"/mnt/sdcard/offspring.{ts}" # output, errors, result_code = adb.push(device, local_src_filename, remote_src_filename, # timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) # # # call evolutiz test runner # remote_dst_filename = f"/mnt/sdcard/offspring.out.{ts}" # evolutiz_cmd = f"evolutiz -p {package_name} -v -v -v --throttle 200 --dry --mutate" \ # f" -f {remote_src_filename} -o {remote_dst_filename} 1" # # adb.sudo_shell_command(device, evolutiz_cmd, timeout=settings.TEST_CASE_EVAL_TIMEOUT) # adb.pkill(device, "evolutiz") # # # fetch mutated individual # local_dst_filename = f"{result_dir}/intermediate/offspring.out.{ts}" # output, errors, result_code = adb.pull(device, remote_dst_filename, local_dst_filename, # timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) # # # get content from local file # mutated_test_case = self.get_test_case_content_from_file(local_dst_filename) # # return mutated_test_case
def run_monkey_one_app(app_path, device): folder_name = os.path.basename(app_path) try: result_dir = "../../results/" + folder_name os.chdir(app_path) os.system("rm " + result_dir + "/*" + logger.redirect_string()) apk_path, package_name = instrument_apk(folder_name, app_path, result_dir) os.system(adb.adb_cmd_prefix + " -s " + device + " install " + apk_path + " 2>&1 >" + result_dir + "/install.log") logger.log_progress("\nPreparing device: " + device + " sdcard") adb.sudo_shell_command(device, "mount -o rw,remount rootfs /", timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) adb.sudo_shell_command(device, "chmod 777 /mnt/sdcard", timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) adb.sudo_shell_command(device, "mount -o rw,remount /system", timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) for repetition in range(0, REPETITIONS): logger.log_progress("\nStarting repetition: " + str(repetition) + " for app: " + folder_name) files_repetition_suffix = "." + str(repetition) # clear package data from previous runs adb.shell_command(device, "pm clear " + package_name, timeout=settings.ADB_REGULAR_COMMAND_TIMEOUT) # clear logcat os.system(adb.adb_cmd_prefix + " -s " + device + " logcat -c") # run logcat logcat_file = open( result_dir + "/monkey.logcat" + files_repetition_suffix, 'w') sub.Popen(adb.adb_cmd_prefix + " -s " + device + " logcat", stdout=logcat_file, stderr=logcat_file, shell=True) # start dumping intermediate coverage # monkey_finished_event = multiprocessing.Event() # p = multiprocessing.Process(target=startIntermediateCoverage, args=(device, result_dir, monkey_finished_event)) # p.start() # start running monkey with timeout EXPERIMENT_TIME logger.log_progress("\nStarting monkey for app: " + folder_name + " in device: " + device + " at: " + datetime.today().strftime("%H:%M:%S")) monkey_cmd = timeout_cmd + adb.adb_cmd_prefix + " -s " + device + " shell monkey -p " + package_name + " -v --throttle 200 --ignore-crashes --ignore-native-crashes --ignore-timeouts --ignore-security-exceptions 1000000 2>&1 >" + result_dir + "/monkey.log" + files_repetition_suffix os.system(monkey_cmd) adb.pkill(device, "monkey") logger.log_progress("\nMonkey finished for app: " + folder_name) # monkey_finished_event.set() # p.join() # collect final coverage collectCoverage(device, package_name, result_dir, suffix=files_repetition_suffix) return (True, device) except Exception as e: logger.log_progress("\nThere was an error running monkey on app: " + folder_name) traceback.print_exc() return (False, device)