예제 #1
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)
예제 #2
0
    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))
예제 #3
0
    def _execute(self, symbol_search_string: str):
        logging.info('Start verifying symbols with substring %s are loaded', symbol_search_string)
        functions_dataview = DataViewPanel(self.find_control("Group", "FunctionsDataView"))

        logging.info('Filtering symbols')
        functions_dataview.filter.set_focus()
        functions_dataview.filter.set_edit_text('')
        send_keys(symbol_search_string)
        logging.info('Verifying at least one symbol with substring %s has been loaded',
                     symbol_search_string)
        self.expect_true(functions_dataview.get_row_count() > 1, "Found expected symbol(s)")
예제 #4
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.')
예제 #5
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.')
예제 #6
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.')
예제 #7
0
    def _execute(self, process_filter):
        if flags.FLAGS.enable_ui_beta:
            filter_edit = self.find_control('Edit', 'FilterProcesses')
            process_list = self.find_control('Table', 'ProcessList')
        else:
            process_data_view = DataViewPanel(self.find_control('Group', 'ProcessesDataView'))
            filter_edit = process_data_view.filter
            process_list = process_data_view.table

        logging.info('Waiting for process list to be populated')
        wait_for_condition(lambda: process_list.item_count() > 0, 30)
        logging.info('Setting filter text for process list')
        if process_filter:
            filter_edit.set_focus()
            filter_edit.set_edit_text('')
            send_keys(process_filter)
        # Wait for the process to show up - it may still be starting
        wait_for_condition(lambda: process_list.item_count() > 0, 30)

        if flags.FLAGS.enable_ui_beta:
            logging.info('Process selected, continuing to main window...')
            process_list.children(control_type='DataItem')[0].double_click_input()
            wait_for_main_window(self.suite.application)
            window = self.suite.top_window(True)
            self.expect_eq(window.class_name(), "OrbitMainWindow", 'Main window is visible')
        else:
            process_list.children(control_type='TreeItem')[0].click_input()
예제 #8
0
    def _execute(self, preset_name: str):
        _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 'No' in status_text:
            app_menu = self.suite.top_window().descendants(
                control_type="MenuBar")[1]
            app_menu.item_by_path("File->Open Preset...").click_input()
            dialog = self.suite.top_window().child_window(
                title_re="Select a file*")
            dialog.FileNameEdit.type_keys(preset_name)
            dialog.FileNameEdit.type_keys('{DOWN}{ENTER}')

            message_box = self.suite.top_window().child_window(
                title_re="Preset loading failed*")
            self.expect_true(message_box is not None, 'Message box found.')
            message_box.Ok.click()
        else:
            presets_panel.get_item_at(preset_row,
                                      0).click_input(button='right')
            self.find_context_menu_item('Load Preset').click_input()
            logging.info('Loaded preset: %s', preset_name)

            if 'Partially' in status_text:
                message_box = self.suite.top_window().child_window(
                    title_re="Preset only partially loaded*")
                self.expect_true(message_box is not None, 'Message box found.')
                message_box.Ok.click()
예제 #9
0
    def _execute(self, symbol_search_string: str, expect_loaded: bool = True):
        logging.info(
            'Start verifying symbols with substring %s are {}loaded'.format(
                "" if expect_loaded else "not "), symbol_search_string)
        functions_dataview = DataViewPanel(
            self.find_control("Group", "FunctionsDataView"))

        logging.info('Filtering symbols')
        functions_dataview.filter.set_focus()
        functions_dataview.filter.set_edit_text('')
        send_keys(symbol_search_string)
        if expect_loaded:
            logging.info(
                'Verifying at least one symbol with substring %s has been loaded',
                symbol_search_string)
            self.expect_true(functions_dataview.get_row_count() > 1,
                             "Found expected symbol(s)")
        else:
            logging.info(
                'Verifying no symbols with substring %s has been loaded',
                symbol_search_string)
            self.expect_true(functions_dataview.get_row_count() == 0,
                             "Found no symbols")
예제 #10
0
    def _execute(self):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        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)
        functions_dataview.filter.set_focus()
        functions_dataview.filter.set_edit_text('')
        functions_dataview.get_item_at(0, 0).click_input('left')
        # Hit Ctrl+a to select all functions.
        send_keys('^a')
        functions_dataview.get_item_at(0, 0).click_input('right')
        self.find_context_menu_item('Unhook').click_input()
예제 #11
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_52', 1, True)
        issue_frame_token_preset_row = presets_panel.find_first_item_row(
            'ggp_issue_frame_token_in_hello_ggp_1_52', 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')
예제 #12
0
    def _execute(self, function_search_string):
        _show_symbols_and_functions_tabs(self.suite.top_window())

        logging.info('Hooking functions 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() > 0)
        
        for i in range(functions_dataview.get_row_count()):
            functions_dataview.get_item_at(i, 0).click_input('right')
            self.find_context_menu_item('Hook').click_input()
            wait_for_condition(lambda: '✓' in functions_dataview.get_item_at(i, 0).texts()[0])
예제 #13
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
예제 #14
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()
예제 #15
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)
예제 #16
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))