コード例 #1
0
def check_needed_commands_available() -> None:
    if not os.path.exists(settings.ANDROID_HOME):
        cause = f"Declared ANDROID_HOME points to a missing directory: {settings.ANDROID_HOME}"
        logger.log_progress(cause)
        raise Exception(cause)

    if not is_command_available(adb.adb_cmd_prefix):
        cause = f"Command \'adb\' was not found in the path {adb.adb_cmd_prefix}"
        logger.log_progress(cause)
        raise Exception(cause)

    avd_manager_path = f"{settings.ANDROID_HOME}tools/bin/avdmanager"
    if os.path.exists(avd_manager_path):
        features.provide('avd_manager_path', avd_manager_path)
    else:
        cause = f"Command \'avdmanager\' was not found in the path {avd_manager_path}"
        logger.log_progress(cause)
        raise Exception(cause)

    if not is_command_available("ant"):
        cause = "Command 'ant' needed but not found."
        logger.log_progress(cause)
        raise Exception(cause)

    if not is_command_available("java"):
        cause = "Command 'java' needed but not found."
        logger.log_progress(cause)
        raise Exception(cause)

    if not is_command_available("javac"):
        cause = "Command 'javac' needed but not found."
        logger.log_progress(cause)
        raise Exception(cause)

    if args.coverage == "ella" and not is_command_available("socat"):
        cause = "Command 'socat' needed for ELLA coverage but not found."
        logger.log_progress(cause)
        raise Exception(cause)

    output, errors, result_code = run_cmd("java -version")
    first_line = errors.split('\n')[0].strip()
    version = first_line.split(' ')[2]
    if not version[1:-1].startswith("1.8"):
        cause = f"Found java with version {version}, but 1.8 is needed."
        logger.log_progress(cause)
        raise Exception(cause)

    output, errors, result_code = run_cmd("javac -version")
    version = errors.split(' ')[1].strip()
    if not version.startswith("1.8"):
        cause = f"Found javac with version {version}, but 1.8 is needed."
        logger.log_progress(cause)
        raise Exception(cause)
コード例 #2
0
    def prepare_app_for_instrumentation(self) -> Tuple[str, str]:
        # copy sources to instrumented subjects folder
        app_name = os.path.basename(self.app_path)
        instrumented_source_path = self.instrumented_subjects_path + app_name
        os.system(f"rm -rf {instrumented_source_path}")
        os.system(f"mkdir -p {self.instrumented_subjects_path}")
        os.system(f"cp -Lr {self.app_path} {instrumented_source_path}")

        # get AndroidManifest path
        manifest_path = self.get_manifest_path(instrumented_source_path)

        # get package name
        package_name = self.get_package_name(manifest_path)

        # copy emma source
        source_root = self.get_source_root(manifest_path, package_name)
        os.system(f"cp -r {self.emma_instrument_path} {source_root}")

        # modify emma source
        emma_instrument_dest_path: str = f"{source_root}EmmaInstrument"
        for target in os.listdir(emma_instrument_dest_path):
            if target.endswith(".java"):
                self.alter_emma_file(f"{emma_instrument_dest_path}/{target}",
                                     package_name)

        # get & alter based on main activity based on "android.intent.action.MAIN"
        main_activity = self.get_main_activity(manifest_path)
        if main_activity.startswith("."):
            main_activity = package_name + main_activity
        elif not main_activity.startswith(package_name):
            main_activity = package_name + "." + main_activity

        features.provide('main_activity', main_activity)

        # update main activity in InstrumentedActivity.java
        self.alter_InstrumentedActivity(
            f"{emma_instrument_dest_path}/InstrumentedActivity.java",
            main_activity)

        # update AndroidManifest.xml
        self.alter_AndroidManifest(manifest_path, package_name)

        self.alter_MainActivity(manifest_path, main_activity)

        # update project
        os.chdir(instrumented_source_path)
        # TODO: replace for a command that doesn't depend on old android-sdk-linux
        os.system(
            f"{settings.WORKING_DIR}monkey/android-sdk-linux/tools/android update project --path . "
            f"--target {settings.ANDROID_TARGET} --subprojects{logger.redirect_string()}"
        )

        return instrumented_source_path, package_name
コード例 #3
0
    def instrument(self) -> None:
        self.app_path: str = RequiredFeature('app_path').request()
        self.result_dir: str = RequiredFeature('result_dir').request()
        self.instrumented_subjects_path: str = RequiredFeature('instrumented_subjects_path').request()
        self.emma_instrument_path: str = RequiredFeature('emma_instrument_path').request()

        # first, check if we should assume apps are already instrumented
        assume_subjects_instrumented = RequiredFeature('assume_subjects_instrumented').request()
        if assume_subjects_instrumented:
            features.provide('instrumented_app_path', self.app_path)

            output, errors, result_code = run_cmd(f"aapt dump badging {self.app_path} | grep package:\\ name")
            package_name = output.split("package: name=\'")[1].split("\'")[0]
            features.provide('package_name', package_name)

            self.prepare_files_for_coverage()
            return

        logger.log_progress(f"\nInstrumenting app: {os.path.basename(self.app_path)}")

        # copy sources and instrument application
        instrumented_app_path, package_name = self.prepare_app_for_instrumentation()

        features.provide('package_name', package_name)
        features.provide('instrumented_app_path', instrumented_app_path)

        self.instrument_gradle_file(instrumented_app_path, package_name)

        result_code = os.system(f"./gradlew assembleDebug 2>&1 >{self.result_dir}/build.log")
        if result_code != 0:
            raise Exception("Unable run assembleDebug")

        os.chdir(settings.WORKING_DIR)

        self.prepare_files_for_coverage()
コード例 #4
0
def run(strategy_name: str, app_paths: List[str]) -> None:
    compress = RequiredFeature('compress').request()
    continue_on_subject_failure = RequiredFeature(
        'continue_on_subject_failure').request()

    for i in range(0, len(app_paths)):
        features.provide('app_path', app_paths[i])

        success = run_one_app(strategy_name)
        if not success and not continue_on_subject_failure:
            break

        if compress:
            compress_results(strategy_name)
コード例 #5
0
def prepare_result_dir(app_name: str, repetition: int,
                       strategy_with_runner_name: str) -> str:
    repetition_folder = str(repetition)
    algorithm_folder = strategy_with_runner_name

    # check if the user wants to overwrite repetition_folder because it's evaluating scripts
    evaluate_scripts_repetition_number = RequiredFeature(
        'evaluate_scripts_repetition_number').request()
    if evaluate_scripts_repetition_number is not None:
        repetition_folder = str(evaluate_scripts_repetition_number)

    evaluate_scripts_algorithm_name = RequiredFeature(
        'evaluate_scripts_algorithm_name').request()
    if evaluate_scripts_algorithm_name is not None:
        algorithm_folder = str(evaluate_scripts_algorithm_name)

    # build result_dir path
    result_dir = f"{settings.WORKING_DIR}results/{algorithm_folder}/{app_name}/{repetition_folder}"

    skip_subject_if_logbook_in_results = RequiredFeature(
        'skip_subject_if_logbook_in_results').request()
    if skip_subject_if_logbook_in_results:
        if os.path.exists(f"{result_dir}/logbook.pickle"):
            raise Exception(
                f"Skipping run for {algorithm_folder}/{app_name}/{repetition_folder} since there is "
                f"already a results folder with a valid logbook file inside it."
            )

    # clean and create result_dir
    os.system(f"rm -rf {result_dir}/*{logger.redirect_string()}")
    result_code = os.system(f"mkdir -p {result_dir}")
    if result_code != 0: raise Exception("Unable to create result dir")

    os.system(f"mkdir -p {result_dir}/intermediate")
    os.system(f"mkdir -p {result_dir}/coverage")
    os.system(f"mkdir -p {result_dir}/crashes")

    features.provide('result_dir', result_dir)
    adb.adb_logs_dir = result_dir

    return result_dir
コード例 #6
0
    def __init__(self) -> None:
        self.device_manager = RequiredFeature('device_manager').request()
        self.strategy = RequiredFeature('strategy').request()
        self.test_suite_evaluator = RequiredFeature('test_suite_evaluator').request()
        self.test_runner = RequiredFeature('test_runner').request()
        self.population_generator = RequiredFeature('population_generator').request()
        self.toolbox = RequiredFeature('toolbox').request()
        self.result_dir = RequiredFeature('result_dir').request()

        self.budget_manager = RequiredFeature('budget_manager').request()

        self.test_runner.register_crossover_operator(self.toolbox)
        self.test_runner.register_mutation_operator(self.toolbox)
        self.test_suite_evaluator.register_selection_operator(self.toolbox)

        self.apk_preparer = ApkPreparer()
        features.provide('apk_preparer', self.apk_preparer)

        self.history = RequiredFeature('history').request()
        self.toolbox.decorate("mate", self.history.decorator)
        self.toolbox.decorate("mutate", self.history.decorator)
コード例 #7
0
    def provide_compiled_package_name(self, build_gradle_path, package_name) -> None:
        """
        This method takes care of parsing the "debug" build type config, in search of applicationIdSuffix properties
        that might change the package name once installed in the emulator.

        If the application has an ETG config file, it will use that instead.

        :param build_gradle_path:
        :param package_name:
        :return:
        """
        etg_config_path = "etg.config"
        if os.path.isfile(etg_config_path):
            etg_config = ETGConfig(etg_config_path)
            features.provide('compiled_package_name', etg_config.compiled_package_name())
            return

        suffix_found = False

        in_stream = open(build_gradle_path)
        for index, line in enumerate(in_stream):

            if line.find("applicationIdSuffix = \"") != -1:
                suffix: str = line.split("applicationIdSuffix = \"")[1]
                suffix = suffix.strip("\"\n")
                suffix_found = True
                features.provide('compiled_package_name', f"{package_name}{suffix}")
                break

        in_stream.close()

        if not suffix_found:
            # assume same compiled package name as the one declard in AndroidManifest.xml file
            features.provide('compiled_package_name', package_name)
コード例 #8
0
def get_subject_paths(arguments: argparse.Namespace) -> List[str]:
    features.provide('assume_subjects_instrumented',
                     arguments.assume_subjects_instrumented)

    subject_path = arguments.subject_path
    if subject_path is not None:
        absolute_path = os.path.abspath(subject_path)
        absolute_path = absolute_path.rstrip('/')
        features.provide('subjects_path', [absolute_path])
        return [absolute_path]
    else:
        subjects_path = arguments.subjects_path.rstrip('/') + '/'
        features.provide('subjects_path', subjects_path)

        app_paths = []

        if arguments.assume_subjects_instrumented:
            output, errors, result_code = run_cmd(
                f"find -L {subjects_path} -name \"*.apk\"")
            for line in output.strip().split('\n'):
                app_paths.append(
                    line.rstrip('/'))  # remove trailing forward slash
        else:
            output, errors, result_code = run_cmd(
                f"ls -1 \"{subjects_path}\"*")
            for relative_path in output.strip().split('\n'):
                # convert relative path to absolute path
                absolute_path = os.path.abspath(relative_path)
                absolute_path = absolute_path.rstrip('/')

                if os.path.isdir(absolute_path):
                    app_paths.append(absolute_path)
                elif os.path.isfile(absolute_path):
                    if absolute_path.endswith(".apk"):
                        if "hydrate" not in relative_path:  # hydrate app doesn't compile yet, so don't bother
                            app_paths.append(
                                absolute_path)  # remove trailing forward slash
                    else:
                        logger.log_progress(
                            f"Ignoring non-APK file {absolute_path} in subjects path"
                        )
                else:
                    # special file (e.g., socket)
                    logger.log_progress(
                        f"Ignoring special file {absolute_path} in subjects path"
                    )
                    continue

        if arguments.randomize_subjects:
            random.shuffle(app_paths)

        if arguments.limit_subjects_number != -1:
            app_paths = app_paths[0:arguments.limit_subjects_number]

        # return list(filter(lambda p: 'com.zhiliaoapp.musically' in p, app_paths))
        return app_paths
コード例 #9
0
ファイル: apk_analyser.py プロジェクト: FlyingPumba/evolutiz
    def get_apk_path(self) -> None:
        self.apk_path = None
        if self.instrumented_app_path.endswith(".apk"):
            self.apk_path = self.instrumented_app_path
        else:
            # now find its name
            output, errors, result_code = run_cmd(
                f"find -L {self.instrumented_app_path} -name \"*.apk\" | grep -v androidTest | grep -v unaligned"
            )
            apk_paths = []
            for file_path in output.split("\n"):
                if file_path != "":
                    apk_paths.append(file_path)

            if len(apk_paths) == 0:
                raise Exception(
                    f"No APKs found inside folder {self.instrumented_app_path} after build."
                )

            if len(apk_paths) > 1:
                # try to filter APKs based on ETG.config file (might not be present)
                etg_config_path = f"{self.instrumented_app_path}/etg.config"
                if os.path.isfile(etg_config_path):
                    etg_config = ETGConfig(etg_config_path)

                    # try to filter by build type
                    build_type = etg_config.build_type()
                    apk_paths = list(
                        filter(lambda path: f"/{build_type}/" in path,
                               apk_paths))

                    # try to filter by product flavors
                    product_flavors = etg_config.product_flavors()
                    if len(product_flavors) > 0:
                        product_flavors_combined = ''
                        for index, flavor in enumerate(product_flavors):
                            if index == 0:
                                product_flavors_combined += flavor.lower()
                            else:
                                product_flavors_combined += flavor.capitalize()

                        apk_paths = list(
                            filter(
                                lambda path: f"/{product_flavors_combined}/" in
                                path, apk_paths))

                        if len(apk_paths) == 0:
                            raise Exception(
                                f"Evolutiz was unable to determine which APK inside folder "
                                f"{self.instrumented_app_path} should it use, since neither of them satisfy the "
                                f"combined product flavor provided: {product_flavors_combined} in the ETG config "
                                f"file")
                else:
                    # TODO: provide more info about ETG config files
                    raise Exception(
                        f"There are several APKs found inside folder {self.instrumented_app_path} after "
                        f"build. Evolutiz was unable to determine which one should it use. "
                        f"You can help it by providing an ETG config file at the root of the app's folder."
                    )

            self.apk_path = apk_paths[0]

        features.provide('apk_path', self.apk_path)
        assert self.apk_path is not None
コード例 #10
0
    def instrument(self) -> None:
        self.app_path: str = RequiredFeature('app_path').request()
        self.result_dir: str = RequiredFeature('result_dir').request()
        self.instrumented_subjects_path: str = RequiredFeature(
            'instrumented_subjects_path').request()

        if not self.app_path.endswith(".apk"):
            cause = "ELLA instrumentation only works with APKs.\n" \
                    f"Provided app path was: {self.app_path}"
            logger.log_progress(cause)
            raise Exception(cause)

        apk_filename = os.path.basename(self.app_path)
        logger.log_progress(f"\nInstrumenting app: {apk_filename}")

        # delete any previous content in ELLA's output folder
        run_cmd(f"rm -rf {self.ella_original_output_folder_path}/*")

        # delete any previous content generated by ELLA in /tmp folder
        run_cmd(f"rm /tmp/ella* /tmp/inputclasses*")

        # prepare the ella-customized jars
        output, errors, result_code = run_cmd(
            f"python gen-ella-wrappers.py",
            cwd=self.ella_original_folder_path,
            timeout=120)
        if result_code != 0:
            raise Exception("Unable generate ELLA wrappers")

        output, errors, result_code = run_cmd(
            f"ant clean build", cwd=self.ella_original_folder_path)
        if result_code != 0:
            raise Exception("Unable compile ELLA JARs")

        # perform the instrumentation of the APK
        output, errors, result_code = run_cmd(
            f"./ella.sh i {self.app_path}",
            cwd=self.ella_original_folder_path,
            timeout=120)
        if result_code != 0:
            raise Exception(
                f"Unable instrument {self.app_path} APK using ELLA")

        os.chdir(settings.WORKING_DIR)

        # find instrumented APK in ELLA's output folder
        output, errors, result_code = run_cmd(
            f"find {self.get_current_apk_output_folder()} -type f -name \"instrumented.apk\""
        )
        instrumented_app_path = output.rstrip('\n')
        features.provide('instrumented_app_path', instrumented_app_path)

        # get package and Main activity name directly from the original APK
        output, errors, result_code = run_cmd(
            f"aapt dump badging {self.app_path} | grep package:\\ name")
        package_name = output.split("package: name=\'")[1].split("\'")[0]
        features.provide('package_name', package_name)
        features.provide('compiled_package_name', package_name)

        output, errors, result_code = run_cmd(
            f"aapt dump badging {self.app_path} | grep launchable-activity | cut -d' ' -f2 | cut -d\"'\" -f 2"
        )
        main_activity_name = output.rstrip('\n')
        features.provide('main_activity', main_activity_name)
コード例 #11
0
 def register_app_instrumentator(self):
     features.provide('app_instrumentator', JacocoAppInstrumentator)
コード例 #12
0
 def register_minimum_api(self) -> None:
     self.minimum_api = 19
     features.provide('minimum_api', self.minimum_api)
コード例 #13
0
    def prepare_files_for_coverage(self):
        instrumented_app_path = RequiredFeature('instrumented_app_path').request()
        self.jacoco_coverage_class_files_path = f"{settings.WORKING_DIR}{instrumented_app_path}/classes"
        features.provide('jacoco_coverage_class_files_path', self.jacoco_coverage_class_files_path)

        etg_config_path = f"{instrumented_app_path}/etg.config"
        if not os.path.isfile(etg_config_path):
            raise Exception("Unable to find ETG config for JaCoCo coverage fetcher")

        etg_config = ETGConfig(etg_config_path)

        package_name_path = '/'.join(etg_config.package_name().split('.'))

        app_folder_path = etg_config.get_application_folder_path()

        # do we have a .jar
        output, errors, result_code = run_cmd(f"find {app_folder_path} -name \"*.jar\" -type f | grep app_classes")
        app_classes_jar_path = output.strip("\n")
        if app_classes_jar_path != "":
            # unzip this jar so it is taken into account in next find command
            unzip_folder = f"{os.path.dirname(app_classes_jar_path)}/unzipped"
            run_cmd(f"rm -r {unzip_folder}")
            run_cmd(f"unzip {app_classes_jar_path} -d {unzip_folder}")

        # find out all .class files
        output, errors, result_code = run_cmd(f"find {app_folder_path} -name \"*.class\" -type f")
        class_files = output.split("\n")

        # figure out build variant
        build_variant = "debug"
        build_variant_path = build_variant
        product_flavors = etg_config.product_flavors()
        if len(product_flavors) > 0:
            product_flavors_combined = ""
            product_flavors_combined_path = ""
            for i, flavor in enumerate(product_flavors):
                if i == 0:
                    product_flavors_combined += flavor.lower()
                else:
                    product_flavors_combined += flavor.capitalize()

                product_flavors_combined_path += "/"
                product_flavors_combined_path += flavor.lower()

            build_variant = product_flavors_combined + etg_config.build_type().capitalize()
            build_variant_path = product_flavors_combined_path + "/" + etg_config.build_type() + "/"

            if package_name_path.endswith(product_flavors_combined):
                package_name_path = package_name_path.split("/" + product_flavors_combined)[0]

        filtered_class_files = []
        for class_file in class_files:
            if (build_variant in class_file or build_variant_path in class_file) \
                    and not "AndroidTest" in class_file \
                    and not "androidTest" in class_file \
                    and not "UnitTest" in class_file \
                    and not "R$" in class_file \
                    and not "R.class" in class_file \
                    and not "BuildConfig.class" in class_file \
                    and not "/EmmaInstrument/" in class_file \
                    and not "/jacoco_instrumented_classes/" in class_file \
                    and not "/jacoco/" in class_file \
                    and not "/transforms/" in class_file \
                    and not "/kapt3/" in class_file:
                filtered_class_files.append(class_file)

        run_cmd(f"mkdir -p {self.jacoco_coverage_class_files_path}")

        # Proceed to find the root folder where package name start for each class file. For example:
        # 'subjects/com.a42crash.iarcuschin.a42crash/app/build/tmp/kotlin-classes/debug/com/a42crash/iarcuschin/a42crash/MainActivity.class'
        # -> We should copy from the /debug/ folder onwards
        # 'subjects/com.a42crash.iarcuschin.a42crash/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/a42crash/iarcuschin/a42crash/MainActivity_ViewBinding.class'
        # -> We should copy from the /classes/ folder onwards

        class_folders = []
        for class_file in filtered_class_files:
            should_inspect = True
            for folder in class_folders:
                if class_file.startswith(folder):
                    should_inspect = False
                    break
            if not should_inspect:
                # we already have the folder for this class file
                continue

            aux = Path(class_file).parent
            class_file_folder = str(aux.absolute())
            while not class_file_folder.endswith("subjects"):
                if class_file_folder.endswith(package_name_path):
                    class_folder = class_file_folder.split(package_name_path)[0]

                    if not class_folder in class_folders:
                        class_folders.append(class_folder)

                    break
                else:
                    aux = aux.parent
                    class_file_folder = str(aux.absolute())

                    if "/" == class_file_folder:
                        break

        # copy class folders with their directory structure
        run_cmd(f"mkdir -p {self.jacoco_coverage_class_files_path}/{package_name_path}")
        for class_folder in class_folders:
            run_cmd("rsync -a --prune-empty-dirs --exclude=\"*EmmaInstrument*/\" " +
                    "--exclude=\"*AndroidTest*/\" --exclude=\"*UnitTest*/\" --exclude=\"*kapt3*/\" " +
                    "--exclude=\"*jacoco_instrumented_classes*/\" --exclude=\"R\\$*.class\" " +
                    "--exclude=\"*jacoco*/\" --exclude=\"*androidTest*/\" --exclude=\"*transforms*/\" " +
                    "--exclude=\"BuildConfig.class\" --exclude=\"R.class\" --include=\"*.class\" " +
                    "--include=\"*/\" --exclude=\"*\" " +
                    f"{class_folder}/{package_name_path}/ {self.jacoco_coverage_class_files_path}/{package_name_path}")
コード例 #14
0
def provide_features() -> None:
    # define subjects
    features.provide('instrumented_subjects_path',
                     args.instrumented_subjects_path)
    features.provide('continue_on_subject_failure',
                     args.continue_on_subject_failure)
    features.provide('continue_on_repetition_failure',
                     args.continue_on_repetition_failure)

    # define budget and repetitions
    features.provide('repetitions', args.repetitions)
    features.provide('repetitions_offset', args.repetitions_offset)
    features.provide(
        'budget_manager',
        BudgetManager(time_budget=args.time_budget,
                      evaluations_budget=args.evaluations_budget))

    # define devices configuration
    features.provide('emulators_number', args.emulators_number)
    features.provide('real_devices_number', args.real_devices_number)
    features.provide('avd_series', args.avd_series)
    features.provide('avd_manager', AvdManager())
    features.provide('strategy', possible_strategies[args.strategy])
    features.provide('test_suite_evaluator',
                     possible_test_suite_evaluators[args.evaluator])

    # define test runner
    test_runner = possible_test_runners[args.test_runner]
    features.provide('test_runner', test_runner)
    test_runner.register_minimum_api()

    # define coverage fetcher app instrumentator
    coverage_fetcher = possible_coverage_fetchers[args.coverage]
    features.provide('coverage_fetcher', coverage_fetcher)
    coverage_fetcher.register_app_instrumentator()

    features.provide('emma_instrument_path', args.emma_instrument_path)

    # define individual and population generators
    features.provide('individual_generator',
                     possible_individual_generators[args.individual_generator])
    features.provide('population_generator', PopulationGenerator)

    # define extras
    features.provide('verbose_level', args.verbose)
    features.provide('write_logbook', args.write_logbook)
    features.provide('write_history', args.write_history)
    features.provide('write_hall_of_fame', args.write_hall_of_fame)
    features.provide('compress', args.compress)

    # singletons
    toolbox = Toolbox()
    toolbox.register("selectBest", tools.selBest)
    features.provide('toolbox', toolbox)
    features.provide('device_manager', DeviceManager())

    features.provide('evaluate_scripts_folder_path',
                     args.evaluate_scripts_folder_path)
    features.provide('evaluate_scripts_repetition_number',
                     args.evaluate_scripts_repetition_number)
    features.provide('evaluate_scripts_algorithm_name',
                     args.evaluate_scripts_algorithm_name)

    features.provide('skip_subject_if_logbook_in_results',
                     args.skip_subject_if_logbook_in_results)
コード例 #15
0
    def instrument(self) -> None:
        self.app_path: str = RequiredFeature('app_path').request()
        self.result_dir: str = RequiredFeature('result_dir').request()
        self.instrumented_subjects_path: str = RequiredFeature(
            'instrumented_subjects_path').request()
        self.emma_instrument_path: str = RequiredFeature(
            'emma_instrument_path').request()

        # first, check if we should assume apps are already instrumented
        assume_subjects_instrumented = RequiredFeature(
            'assume_subjects_instrumented').request()
        if assume_subjects_instrumented:
            features.provide('instrumented_app_path', self.app_path)

            # copy emma generated file
            result_code = os.system(
                f"cp bin/coverage.em {self.result_dir}/{logger.redirect_string()}"
            )
            if result_code != 0:
                raise Exception("Unable to copy coverage.em file")

            output, errors, result_code = run_cmd(
                f"aapt dump badging {self.app_path} | grep package:\\ name")
            package_name = output.split("package: name=\'")[1].split("\'")[0]
            features.provide('package_name', package_name)
            features.provide('compiled_package_name', package_name)
            return

        logger.log_progress(
            f"\nInstrumenting app: {os.path.basename(self.app_path)}")

        # copy sources and instrument application
        instrumented_app_path, package_name = self.prepare_app_for_instrumentation(
        )

        # compile with emma data
        result_code = os.system(
            f"ant clean emma debug 2>&1 >{self.result_dir}/build.log")
        if result_code != 0:
            raise Exception("Unable run ant clean emma debug")

        # copy emma generated file
        result_code = os.system(
            f"cp bin/coverage.em {self.result_dir}/{logger.redirect_string()}")
        if result_code != 0:
            raise Exception("Unable to copy coverage.em file")

        os.chdir(settings.WORKING_DIR)

        features.provide('package_name', package_name)
        features.provide('instrumented_app_path', instrumented_app_path)

        # assume same compiled package name as the one declard in AndroidManifest.xml file
        features.provide('compiled_package_name', package_name)
コード例 #16
0
 def register_app_instrumentator(self):
     features.provide('app_instrumentator', EllaAppInstrumentator())
コード例 #17
0
def run_one_app(strategy_with_runner_name: str) -> bool:
    app_path = RequiredFeature('app_path').request()
    repetitions = RequiredFeature('repetitions').request()
    repetitions_offset = RequiredFeature('repetitions_offset').request()
    budget_manager = RequiredFeature('budget_manager').request()
    test_suite_evaluator = RequiredFeature('test_suite_evaluator').request()
    verbose_level = RequiredFeature('verbose_level').request()

    continue_on_repetition_failure = RequiredFeature(
        'continue_on_repetition_failure').request()

    app_name = os.path.basename(app_path)

    try:
        there_was_a_failed_repetition = False
        for repetition in range(repetitions_offset, repetitions):
            try:
                os.chdir(settings.WORKING_DIR)

                logbook = tools.Logbook()
                logbook.header = ['gen']
                features.provide('logbook', logbook)

                history = tools.History()
                features.provide('history', history)

                hall_of_fame = test_suite_evaluator.new_hall_of_fame()
                features.provide('hall_of_fame', hall_of_fame)

                result_dir = prepare_result_dir(app_name, repetition,
                                                strategy_with_runner_name)

                get_emulators_running(result_dir)

                test_generator = Evolutiz()

                budget_manager.start_budget()

                logger.log_progress(
                    f"\n-----> Starting repetition: {str(repetition)} for app: {app_name}, "
                    f"initial timestamp is: {str(budget_manager.start_time)}")
                test_generator.run()

                logger.log_progress(f"\nEvolutiz finished for app: {app_name}")

                time_budget_used = budget_manager.get_time_budget_used()
                if time_budget_used is not None:
                    logger.log_progress(
                        f"\nTime budget used: {time_budget_used:.2f} seconds\n"
                    )

                evaluations_budget_used = budget_manager.get_evaluations_budget_used(
                )
                if evaluations_budget_used is not None:
                    logger.log_progress(
                        f"\nEvaluations budget used: {evaluations_budget_used:d}\n"
                    )

                # wait for all MultipleQueueConsumerThread to terminate
                wait_for_working_threas_to_finish()
            except Exception as e:
                logger.log_progress(
                    f"\nThere was an error running repetition {repetition} on app: {app_name}"
                )
                if verbose_level > 0:
                    logger.log_progress(f"\n{str(e)}")
                if verbose_level > 1:
                    logger.log_progress(f"\n{traceback.format_exc()}")
                traceback.print_exc()

                there_was_a_failed_repetition = True
                if not continue_on_repetition_failure:
                    # there was a problem during current repetition, halt further executions of this subject
                    raise e
                # otherwise, keep running the remaining repetitions

        return not there_was_a_failed_repetition
    except Exception as e:
        logger.log_progress(
            f"\nThere was an error running evolutiz on app: {app_name}")
        if verbose_level > 0:
            logger.log_progress(f"\n{str(e)}")
        if verbose_level > 1:
            logger.log_progress(f"\n{traceback.format_exc()}")
        traceback.print_exc()
        return False