Пример #1
0
    def _execute(self, function_search_string):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        logging.info('Hooking function based on search "%s"', function_search_string)
        functions_dataview = DataViewPanel(self.find_control("Group", "FunctionsDataView"))

        logging.info('Waiting for function list to be populated...')
        wait_for_condition(lambda: functions_dataview.get_row_count() > 0, 100)

        logging.info('Filtering and hooking')
        functions_dataview.filter.set_focus()
        functions_dataview.filter.set_edit_text('')
        send_keys(function_search_string)
        wait_for_condition(lambda: functions_dataview.get_row_count() == 1)
        functions_dataview.get_item_at(0, 0).click_input('right')

        self.find_context_menu_item('Hook').click_input()
        wait_for_condition(lambda: '✓' in functions_dataview.get_item_at(0, 0).texts()[0])
Пример #2
0
    def _try_verify_functions_are_hooked(self):
        logging.info('Finding rows in the function list')
        functions_panel = DataViewPanel(self.find_control('Group', 'FunctionsDataViewD'))
        draw_frame_row = functions_panel.find_first_item_row('DrawFrame', 1)
        issue_frame_token_row = functions_panel.find_first_item_row('GgpIssueFrameToken', 1)

        if draw_frame_row is None:
            return False
        if issue_frame_token_row is None:
            return False

        logging.info('Verifying hook status of functions')
        self.expect_true('✓' in functions_panel.get_item_at(draw_frame_row, 0).texts()[0],
                         'DrawFrame is marked as hooked')
        self.expect_true('✓' in functions_panel.get_item_at(issue_frame_token_row, 0).texts()[0],
                         'GgpIssueFrameToken is marked as hooked')

        return True
Пример #3
0
    def _provoke_goto_source_action(self, function_search_string: str):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        logging.info('Start showing source code for function {}'.format(function_search_string))
        functions_dataview = DataViewPanel(self.find_control("Group", "FunctionsDataView"))

        logging.info('Waiting for function list to be populated...')
        wait_for_condition(lambda: functions_dataview.get_row_count() > 0, 100)

        logging.info('Filtering functions')
        functions_dataview.filter.set_focus()
        functions_dataview.filter.set_edit_text('')
        send_keys(function_search_string)
        wait_for_condition(lambda: functions_dataview.get_row_count() == 1)
        functions_dataview.get_item_at(0, 0).click_input('right')

        logging.info('Click on "Go to Source code"')
        self.find_context_menu_item('Go to Source code').click_input()
Пример #4
0
    def _execute(self,
                 function_search_string: str,
                 expect_hooked: bool = True):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        functions_dataview = DataViewPanel(
            self.find_control("Group", "FunctionsDataView"))
        functions_dataview.filter.set_focus()
        functions_dataview.filter.set_edit_text('')
        send_keys(function_search_string)
        row = functions_dataview.find_first_item_row(function_search_string, 1)
        if expect_hooked:
            self.expect_true(
                '✓' in functions_dataview.get_item_at(row, 0).texts()[0],
                'Function is marked as hooked.')
        else:
            self.expect_true(
                '✓' not in functions_dataview.get_item_at(row, 0).texts()[0],
                'Function is not marked as hooked.')
Пример #5
0
    def _load_presets(self):
        presets_panel = DataViewPanel(self.find_control('Group', 'PresetsDataView'))

        draw_frame_preset_row = presets_panel.find_first_item_row('draw_frame_in_hello_ggp_1_68', 1,
                                                                  True)
        issue_frame_token_preset_row = presets_panel.find_first_item_row(
            'ggp_issue_frame_token_in_hello_ggp_1_68', 1, True)

        self.expect_true(draw_frame_preset_row is not None, 'Found draw_frame preset')
        self.expect_true(issue_frame_token_preset_row is not None,
                         'Found ggp_issue_frame_token preset')

        presets_panel.get_item_at(draw_frame_preset_row, 0).click_input(button='right')
        self.find_context_menu_item('Load Preset').click_input()
        logging.info('Loaded Preset DrawFrame')

        presets_panel.get_item_at(issue_frame_token_preset_row, 0).click_input(button='right')
        self.find_context_menu_item('Load Preset').click_input()
        logging.info('Loaded Preset GgpIssueFrameToken')
Пример #6
0
    def _execute(self, module_search_string: str, expect_loaded: bool = True):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        logging.info('Start verifying module %s is %s.', module_search_string,
                     "loaded" if expect_loaded else "not loaded")
        modules_dataview = DataViewPanel(self.find_control("Group", "ModulesDataView"))
        wait_for_condition(lambda: modules_dataview.get_row_count() > 0, 100)
        modules_dataview.filter.set_focus()
        modules_dataview.filter.set_edit_text('')
        send_keys(module_search_string)
        wait_for_condition(lambda: modules_dataview.get_row_count() > 0)
        self.expect_true('*' in modules_dataview.get_item_at(0, 0).texts()[0], 'Module is loaded.')
Пример #7
0
    def _execute(self, preset_name: str, expected_status: PresetStatus):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        presets_panel = DataViewPanel(self.find_control('Group', 'PresetsDataView'))
        preset_row = presets_panel.find_first_item_row(preset_name, 1, True)
        self.expect_true(preset_row is not None, 'Found preset.')
        status_text = presets_panel.get_item_at(preset_row, 0).texts()[0]
        if expected_status is PresetStatus.LOADABLE:
            self.expect_true('Yes' in status_text, 'Preset is loadable.')
        if expected_status is PresetStatus.PARTIALLY_LOADABLE:
            self.expect_true('Partially' in status_text, 'Preset is partially loadable.')
        if expected_status is PresetStatus.NOT_LOADABLE:
            self.expect_true('No' in status_text, 'Preset is not loadable.')
Пример #8
0
    def _execute(self, module_search_string: str, expect_fail=False):
        """
        :param module_search_string: String to enter in the module filter field, the first entry in the list of
            remaining modules will be loaded
        :param expect_fail: If True, the test will succeed if loading symbols results in an error message
        """
        _show_symbols_and_functions_tabs(self.suite.top_window())

        logging.info('Start loading symbols for module %s',
                     module_search_string)
        modules_dataview = DataViewPanel(
            self.find_control("Group", "ModulesDataView"))

        logging.info('Waiting for module list to be populated...')
        wait_for_condition(lambda: modules_dataview.get_row_count() > 0, 100)

        logging.info('Filtering and loading')
        modules_dataview.filter.set_focus()
        modules_dataview.filter.set_edit_text('')
        send_keys(module_search_string)
        wait_for_condition(lambda: modules_dataview.get_row_count() == 1)
        modules_dataview.get_item_at(0, 0).click_input('right')

        self.find_context_menu_item('Load Symbols').click_input()

        logging.info('Waiting for * to indicate loaded modules')

        # The Loading column which should get filled with the "*" is the first column (0)
        if expect_fail:
            wait_for_condition(lambda: _find_and_close_error_dialog(
                self.suite.top_window()) is not None)
        else:
            wait_for_condition(
                lambda: modules_dataview.get_item_at(0, 0).texts()[0] == "*",
                100)

        VerifySymbolsLoaded(symbol_search_string=module_search_string,
                            expect_loaded=not expect_fail).execute(self.suite)
Пример #9
0
    def _execute(self, module_search_string: str):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        logging.info('Start loading symbols for module %s', module_search_string)
        modules_dataview = DataViewPanel(self.find_control("Group", "ModulesDataView"))

        logging.info('Waiting for module list to be populated...')
        wait_for_condition(lambda: modules_dataview.get_row_count() > 0, 100)

        logging.info('Filtering and loading')
        modules_dataview.filter.set_focus()
        modules_dataview.filter.set_edit_text('')
        send_keys(module_search_string)
        wait_for_condition(lambda: modules_dataview.get_row_count() == 1)
        modules_dataview.get_item_at(0, 0).click_input('right')

        self.find_context_menu_item('Load Symbols').click_input()

        logging.info('Waiting for * to indicate loaded modules')

        wait_for_condition(lambda: modules_dataview.get_item_at(0, 4).texts()[0] == "*", 100)

        functions_dataview = DataViewPanel(self.find_control("Group", "FunctionsDataView"))
        wait_for_condition(lambda: functions_dataview.get_row_count() > 0)
Пример #10
0
class LoadAllSymbolsAndVerifyCache(E2ETestCase):
    """
    Loads all symbol files at once and checks if all of them exist in the cache. In addition, this test measures the
    total duration of symbol loading (estimated), and can fail if the duration differs from the previous run by
    a limit defined by `expected_duration_difference`.
    """
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self._modules_dataview = None

    def _execute(self, expected_duration_difference_ratio: float = None):
        """
        :param expected_duration_difference_ratio: Expected difference as ratio relative to the previously stored value.
            If < 1.0, the current run must take *at most* expected_difference_ratio * previous_time.
            If >= 1.0, the current run must take *at least* expected_difference_ratio * previous_time.
            If None, this will only update the stored value.
            If no stored value is present from a previous run, the parameter will be treated as None, and cannot fail
            the test.
            Violating those conditions will result in test failure.
        """
        _show_symbols_and_functions_tabs(self.suite.top_window())
        self._modules_dataview = DataViewPanel(
            self.find_control("Group", "ModulesDataView"))
        self._load_all_modules()

        modules_loading_result = self._wait_for_loading_and_collect_errors()

        self._check_and_update_duration("load_all_modules_duration",
                                        modules_loading_result.time,
                                        expected_duration_difference_ratio)

        modules = self._gather_module_states()
        self._verify_all_modules_are_cached(modules)
        self._verify_all_errors_were_raised(modules,
                                            modules_loading_result.errors)
        logging.info(
            "Done. Loading time: {time:.2f}s, module errors: {errors}".format(
                time=modules_loading_result.time,
                errors=modules_loading_result.errors))

    def _load_all_modules(self):
        logging.info("Loading all modules")
        self._modules_dataview.get_item_at(0, 0).click_input()
        # Select all
        send_keys("^a")
        self._modules_dataview.get_item_at(0, 0).click_input('right')
        self.find_context_menu_item('Load Symbols').click_input()

    def _verify_all_modules_are_cached(self, modules: List[Module]):
        loaded_modules = [module for module in modules if module.is_loaded]
        module_set = set(loaded_modules)
        logging.info(
            'Verifying cache. Found {total} modules in total, {loaded} of which are loaded'
            .format(total=len(modules), loaded=len(loaded_modules)))

        cached_files = [file for file in os.listdir(CACHE_LOCATION)]
        cached_file_set = set(cached_files)

        for module in loaded_modules:
            expected_filename = module.path.replace("/", "_")
            self.expect_true(
                expected_filename in cached_file_set,
                'Module {expected} found in cache'.format(
                    expected=expected_filename))
            module_set.remove(module)
            cached_file_set.remove(expected_filename)

        self.expect_eq(
            0, len(module_set),
            'All successfully loaded modules are cached. Modules not found in cache: {}'
            .format([module.name for module in module_set]))

    def _verify_all_errors_were_raised(self, all_modules: List[Module],
                                       errors: List[str]):
        modules_not_loaded = set(
            [module.path for module in all_modules if not module.is_loaded])
        error_set = set(errors)
        for module in modules_not_loaded:
            self.expect_true(
                module in error_set,
                'Error has been raised for module {}'.format(module))
            error_set.remove(module)
        self.expect_eq(0, len(error_set),
                       'All errors raised resulted in non-loadable modules')

    def _wait_for_loading_and_collect_errors(self) -> ModulesLoadingResult:
        assume_loading_complete = 0
        num_assumptions_to_be_safe = 5
        error_modules = set()
        total_time = 0

        while assume_loading_complete < num_assumptions_to_be_safe:
            start_time = time.time()

            time.sleep(1)

            # Since there is no "loading completed" feedback, give orbit some time to update the status message or
            # show an error dialog. Then check if any of those is visible.
            # If not, try a few more times to make sure we didn't just accidentally query the UI while the status
            # message was being updated.
            error_module = _find_and_close_error_dialog(
                self.suite.top_window())
            status_message = self.find_control('StatusBar',
                                               recurse=False).texts()[0]
            if "Copying debug info file" not in status_message and "Loading symbols" not in status_message:
                status_message = None

            if error_module is not None:
                error_modules.add(error_module)

            if not error_module and not status_message:
                assume_loading_complete += 1
            else:
                total_time += time.time() - start_time
                assume_loading_complete = 0
        logging.info(
            "Assuming symbol loading has completed. Total time: {time:.2f} seconds"
            .format(time=total_time))
        return ModulesLoadingResult(total_time, error_modules)

    def _gather_module_states(self) -> List[Module]:
        result = []
        for i in range(0, self._modules_dataview.get_row_count()):
            is_loaded = self._modules_dataview.get_item_at(i,
                                                           0).texts()[0] == "*"
            name = self._modules_dataview.get_item_at(i, 1).texts()[0]
            path = self._modules_dataview.get_item_at(i, 2).texts()[0]
            result.append(Module(name, path, is_loaded))

        return result

    def _check_and_update_duration(self, storage_key: str,
                                   current_duration: float,
                                   expected_difference_ratio: float):
        """
        Compare the current duration with the previous run, and fail if it exceeds the defined bounds.
        :param storage_key: Unique key to store the duration within the test suite, used to persist the data across
            multiple tests (uses `self.suite.shared_data`)
        :param current_duration: The duration of the current run
        :param expected_difference_ratio: @see documentation of the same parameter in _execute
        """
        last_duration = self.suite.shared_data.get(storage_key, None)
        self.suite.shared_data[storage_key] = current_duration

        if expected_difference_ratio is not None and last_duration is not None:
            expected_duration = last_duration * expected_difference_ratio
            if expected_difference_ratio < 1.0:
                self.expect_true(
                    current_duration <= expected_duration,
                    "Expected symbol loading time to be at most {expected:.2f}s."
                    "Last run duration: {last:.2f}s, current run duration: {cur:.2f}s"
                    .format(expected=expected_duration,
                            last=last_duration,
                            cur=current_duration))
            else:
                self.expect_true(
                    current_duration >= expected_duration,
                    "Expected symbol loading time to be at least {expected:.2f}s."
                    "Last run duration: {last:.2f}s, current run duration: {cur:.2f}s"
                    .format(expected=expected_duration,
                            last=last_duration,
                            cur=current_duration))