Exemple #1
0
    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)
Exemple #5
0
    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")
Exemple #6
0
    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
Exemple #9
0
    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")
Exemple #10
0
    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'
            )
Exemple #11
0
    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
Exemple #13
0
    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
Exemple #14
0
    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
Exemple #15
0
    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)
Exemple #17
0
    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
Exemple #19
0
    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)
Exemple #20
0
    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
Exemple #22
0
    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
Exemple #23
0
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)