def heavily_discourage_exploration(action: UIAction, node: UITreeNode): if node.is_terminal(): return SMALL_PENALTY elif not node.get_children(): return SMALL_PENALTY elif action == UIAction.LEFT_CLICK: return LARGE_REWARD return SMALL_PENALTY
def encourage_success(action: UIAction, node: UITreeNode): if node.is_terminal(): return LARGE_REWARD elif not node.get_children(): return SMALL_PENALTY elif action == UIAction.LEFT_CLICK: return MEDIUM_REWARD return NO_REWARD
def visit_dfs(action: UIAction, node: UITreeNode, driver: Driver): if len(visited_urls) > max_urls_to_visit: return self.__stats.record(Driver.STAT_ELEMENTS_ENCOUNTERED, str(node)) visited_nodes.add(node.get_id()) if not deep or action == UIAction.NAVIGATE: child_tags = node.get_element().find_elements_by_xpath("./*") for child_tag in child_tags: node.add_transition(child_tag) for act, child in node.get_transition_tuples(): if child.get_id() not in visited_nodes: visit_dfs(act, child, driver) else: @timeout_decorator.timeout(10, timeout_exception=StopIteration) def visit_new_page(): sub_driver = Driver() sub_driver.open(driver.__driver.current_url) if action == UIAction.LEFT_CLICK: sub_driver.__left_click(node) self.__stats.record(Driver.STAT_ELEMENTS_LEFT_CLICKED, str(node)) elif action == UIAction.INPUT: sub_driver.__input(node) self.__stats.record(Driver.STAT_ELEMENTS_INPUTTED, str(node)) else: self.__stats.record(Driver.STAT_ELEMENTS_NAVIGATED, str(node)) sub_html_tag = sub_driver.__driver.find_elements_by_tag_name("html")[0] if sub_driver.__driver.current_url not in visited_urls and len(visited_urls) < max_urls_to_visit: self.__stats.record(Driver.STAT_URLS_VISITED, sub_driver.__driver.current_url) visited_urls.add(sub_driver.__driver.current_url) sub_child_tags = sub_html_tag.find_elements_by_xpath("./*") for sub_child_tag in sub_child_tags: node.add_transition(sub_child_tag) for sub_act, sub_child in node.get_transition_tuples(): if sub_child.get_id() not in visited_nodes: visit_dfs(sub_act, sub_child, sub_driver) del sub_driver def on_fail(e): self.__stats.record(Driver.STAT_CRASH_DETECTED, { "on_action": action.name, "element": str(node), "error": str(e), }) try_again_on_fail(visit_new_page, 5, 5, on_fail)
def __get_likely_transition_tuple_from_history(self, from_node: UITreeNode) -> Tuple[Optional[UIAction], Optional[UITreeNode]]: if len(self.__history[from_node.get_hash()].keys()) == 0: return None, None max_transitions = 0 max_action = None max_to_node = None for to_node_hash in self.__history[from_node.get_hash()]: num_transitions, action, to_node = self.__history[from_node.get_hash()][to_node_hash] if num_transitions > max_transitions: max_transitions = num_transitions max_action = action max_to_node = to_node return max_action, max_to_node
def __input(self, node: UITreeNode): node_in_dom = self.__find_node_in_dom(node) value = generate_input(node.get_element(), self.__input_values) if node_in_dom: if inline_try(lambda: ActionChains(self.__driver).send_keys(value).perform()): self.__stats.record(Driver.STAT_CRASH_DETECTED, { "on_action": "INPUT", "element": str(node_in_dom) })
def __find_node_in_dom(self, node: UITreeNode) -> Optional[UITreeNode]: """ Finds a node in the current DOM, in case the passed-in node has had its window displaced. :param node: The node to find. :return: The same node in the current window or None. """ shallow_tree = self.__visit(deep=False) _, node_in_dom = shallow_tree.find_node_by_hash(node.get_hash()) return node_in_dom
def __get_transition_from_history(self, from_node: UITreeNode, to_node: UITreeNode) -> Tuple[int, Optional[UIAction]]: if to_node.get_hash() not in self.__history[from_node.get_hash()]: return 0, None return self.__history[from_node.get_hash()][to_node.get_hash()][:2]
def __record_transition_in_history(self, from_node: UITreeNode, to_node: UITreeNode, action: UIAction): if to_node.get_hash() not in self.__history[from_node.get_hash()]: self.__history[from_node.get_hash()][to_node.get_hash()] = [1, action, to_node] else: self.__history[from_node.get_hash()][to_node.get_hash()][0] += 1
def penalize_repeat_visits(action: UIAction, node: UITreeNode): if node.get_visits(): return LARGE_PENALTY return encourage_exploration(action, node)
def reward_repeat_visits(action: UIAction, node: UITreeNode): if node.get_visits(): return LARGE_REWARD return encourage_exploration(action, node)