From 90270552c639088c2d6f46f02a9cdaa8711f2755 Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Tue, 7 Jan 2025 16:43:25 +0800 Subject: [PATCH 1/9] feat(property files):add load property files from a directory if input a directory after -f or in the config.yml --- kea/start.py | 8 +++++--- kea/utils.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/kea/start.py b/kea/start.py index 8bab310..44f2271 100644 --- a/kea/start.py +++ b/kea/start.py @@ -1,4 +1,5 @@ import argparse +import os import warnings from dataclasses import dataclass @@ -9,7 +10,7 @@ from .input_manager import DEFAULT_POLICY, DEFAULT_TIMEOUT from .kea import Kea -from .utils import get_yml_config, sanitize_args +from .utils import get_yml_config, sanitize_args, load_properties_from_dir from .droidbot import DroidBot from .utils import DEFAULT_POLICY, DEFAULT_EVENT_INTERVAL, DEFAULT_TIMEOUT, DEFAULT_EVENT_COUNT @@ -86,9 +87,10 @@ def parse_args(): # load the args from the config file `config.yml` if options.load_config: options = load_ymal_args(options) + options.property_files = load_properties_from_dir(options.property_files) # sanitize these args - sanitize_args(options) + sanitize_args(options) return options @@ -190,7 +192,7 @@ def main(): generate_utg=options.generate_utg, is_package=options.is_package ) - + # load the pdl driver for Android/HarmonyOS driver = load_pdl_driver(settings) Kea.set_pdl_driver(driver) diff --git a/kea/utils.py b/kea/utils.py index 31074c6..7550162 100644 --- a/kea/utils.py +++ b/kea/utils.py @@ -1,4 +1,5 @@ import json +import logging import os import re import functools @@ -313,6 +314,23 @@ def sanitize_args(options): else: options.is_package = False +def load_properties_from_dir(property_files): + new_property_files = [] + for property_file in property_files: + if os.path.isdir(property_file): + print(f"load all the property files under: {property_file} ") + try: + for entry in os.listdir(property_file): + full_path = os.path.join(property_file, entry) + if os.path.isfile(full_path): + new_property_files.append(full_path) + except Exception as e: + print(e) + else: + new_property_files.append(property_file) + return new_property_files + + def identify_device_serial(options): """ automatically identify the device serial From 550d2ba948c9633c32049ad9b094268d91454ba6 Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Tue, 7 Jan 2025 19:08:56 +0800 Subject: [PATCH 2/9] perf(log):add current event count log for helping user find uiobject missing bug through logger --- kea/device.py | 1 + 1 file changed, 1 insertion(+) diff --git a/kea/device.py b/kea/device.py index 8c58d7f..6f1b8bd 100644 --- a/kea/device.py +++ b/kea/device.py @@ -868,6 +868,7 @@ def save_screenshot_for_report(self, event_name=None, event=None, current_state= """ self.cur_event_count += 1 + self.logger.debug("current event count: %s" % self.cur_event_count) if current_state is None: self.current_state = self.get_current_state() else: From 03e516a67c07d43582a013c268c5d31dd46e943b Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Thu, 9 Jan 2025 20:11:21 +0800 Subject: [PATCH 3/9] feat(logger):save log to a file --- kea/device.py | 8 ++++---- kea/droidbot.py | 6 ++++-- kea/input_manager.py | 14 +++++++++----- kea/input_policy.py | 13 ++++++++++--- kea/utils.py | 8 ++++++++ 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/kea/device.py b/kea/device.py index 6f1b8bd..c4a69ac 100644 --- a/kea/device.py +++ b/kea/device.py @@ -17,7 +17,7 @@ from .adapter.process_monitor import ProcessMonitor from .adapter.telnet import TelnetConsole from .adapter.user_input_monitor import UserInputMonitor - +from .utils import save_log from .app import App from .intent import Intent @@ -27,7 +27,6 @@ DEFAULT_NUM = '1234567890' DEFAULT_CONTENT = 'Hello world!' - class Device(object): """ this class describes a connected device @@ -56,6 +55,8 @@ def __init__( """ self.logger = logging.getLogger(self.__class__.__name__) + self.output_dir = output_dir + save_log(self.logger, self.output_dir) self.app_package_name = app_package_name if device_serial is None: from .utils import get_available_devices @@ -72,7 +73,6 @@ def __init__( self.serial = device_serial self.is_emulator = is_emulator self.cv_mode = cv_mode - self.output_dir = output_dir if output_dir is not None: if not os.path.isdir(output_dir): os.makedirs(output_dir) @@ -868,7 +868,7 @@ def save_screenshot_for_report(self, event_name=None, event=None, current_state= """ self.cur_event_count += 1 - self.logger.debug("current event count: %s" % self.cur_event_count) + self.logger.info("Total event count: %s" % self.cur_event_count) if current_state is None: self.current_state = self.get_current_state() else: diff --git a/kea/droidbot.py b/kea/droidbot.py index e5d8f33..cc746dc 100644 --- a/kea/droidbot.py +++ b/kea/droidbot.py @@ -168,7 +168,8 @@ def init_droidbot(self, is_harmonyos): replay_output=self.replay_output, kea=self.kea, number_of_events_that_restart_app=self.number_of_events_that_restart_app, - generate_utg=self.generate_utg + generate_utg=self.generate_utg, + output_dir=self.output_dir ) # self.send_documents() # initializer for HarmonyOS system @@ -203,7 +204,8 @@ def init_droidbot(self, is_harmonyos): profiling_method=self.profiling_method, master=self.master, replay_output=self.replay_output, - kea=self.kea) + kea=self.kea, + output_dir=self.output_dir) @staticmethod def get_instance(): diff --git a/kea/input_manager.py b/kea/input_manager.py index 05295f2..5065fee 100644 --- a/kea/input_manager.py +++ b/kea/input_manager.py @@ -3,7 +3,7 @@ import time from .similarity import Similarity - +from .utils import save_log from .input_event import EventLog from .input_policy import ( GuidedPolicy, @@ -46,7 +46,8 @@ def __init__( replay_output=None, kea=None, number_of_events_that_restart_app=100, - generate_utg=False + generate_utg=False, + output_dir=None ): """ manage input event sent to the target device @@ -56,6 +57,8 @@ def __init__( :return: """ self.logger = logging.getLogger('InputEventManager') + self.output_dir = output_dir + save_log(self.logger, self.output_dir) self.enabled = True self.device = device self.app = app @@ -81,12 +84,13 @@ def get_input_policy(self, device, app, master): device, app, self.kea, - self.generate_utg + self.generate_utg, + self.output_dir ) elif self.policy_name == POLICY_RANDOM: - input_policy = RandomPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_reinstall_app=True, allow_to_generate_utg = self.generate_utg) + input_policy = RandomPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_reinstall_app=True, allow_to_generate_utg = self.generate_utg, output_dir=self.output_dir) elif self.policy_name == POLICY_LLM: - input_policy = LLMPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_restart_app_data_after_100_events=True, allow_to_generate_utg = self.generate_utg) + input_policy = LLMPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_restart_app_data_after_100_events=True, allow_to_generate_utg = self.generate_utg, output_dir=self.output_dir) else: self.logger.warning( "No valid input policy specified. Using policy \"none\"." diff --git a/kea/input_policy.py b/kea/input_policy.py index 7fbf74e..41b4a59 100644 --- a/kea/input_policy.py +++ b/kea/input_policy.py @@ -5,7 +5,7 @@ import copy import re import time -from .utils import Time, generate_report +from .utils import Time, generate_report, save_log from abc import abstractmethod from .input_event import ( KEY_RotateDeviceToPortraitEvent, @@ -377,12 +377,15 @@ def __init__( number_of_events_that_restart_app=100, clear_and_reinstall_app=False, allow_to_generate_utg=False, + output_dir=None ): super(RandomPolicy, self).__init__(device, app, kea, allow_to_generate_utg) self.restart_app_after_check_property = restart_app_after_check_property self.number_of_events_that_restart_app = number_of_events_that_restart_app self.clear_and_reinstall_app = clear_and_reinstall_app self.logger = logging.getLogger(self.__class__.__name__) + self.output_dir=output_dir + save_log(self.logger, self.output_dir) self.last_rotate_events = KEY_RotateDeviceToPortraitEvent def generate_event(self): @@ -472,10 +475,11 @@ class GuidedPolicy(KeaInputPolicy): generate events around the main path """ - def __init__(self, device, app, kea=None, allow_to_generate_utg=False): + def __init__(self, device, app, kea=None, allow_to_generate_utg=False,output_dir=None): super(GuidedPolicy, self).__init__(device, app, kea, allow_to_generate_utg) self.logger = logging.getLogger(self.__class__.__name__) - + self.output_dir = output_dir + save_log(self.logger,self.output_dir) if len(self.kea.all_mainPaths): self.logger.info("Found %d mainPaths" % len(self.kea.all_mainPaths)) else: @@ -734,9 +738,12 @@ def __init__( number_of_events_that_restart_app=100, clear_and_restart_app_data_after_100_events=False, allow_to_generate_utg=False, + output_dir=None ): super(LLMPolicy, self).__init__(device, app, kea) self.logger = logging.getLogger(self.__class__.__name__) + self.output_dir = output_dir + save_log(self.logger,self.output_dir) self.__action_history = [] self.__all_action_history = set() self.__activity_history = set() diff --git a/kea/utils.py b/kea/utils.py index 7550162..ff88242 100644 --- a/kea/utils.py +++ b/kea/utils.py @@ -330,6 +330,14 @@ def load_properties_from_dir(property_files): new_property_files.append(property_file) return new_property_files +def save_log(logger, output_dir): + # output logging into a txt file + log_dir = os.path.join(output_dir, "records.log") + file_handler = logging.FileHandler(log_dir) + file_handler.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + file_handler.setFormatter(formatter) + logger.addHandler(file_handler) def identify_device_serial(options): """ From afdb6ac5126715161ef9d009d7c960d91a265d03 Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Thu, 9 Jan 2025 20:16:59 +0800 Subject: [PATCH 4/9] perf(is package):do not reinstall the app when use the installed package --- kea/droidbot.py | 6 ++++-- kea/input_manager.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/kea/droidbot.py b/kea/droidbot.py index cc746dc..85ad982 100644 --- a/kea/droidbot.py +++ b/kea/droidbot.py @@ -169,7 +169,8 @@ def init_droidbot(self, is_harmonyos): kea=self.kea, number_of_events_that_restart_app=self.number_of_events_that_restart_app, generate_utg=self.generate_utg, - output_dir=self.output_dir + output_dir=self.output_dir, + is_package=self.is_package ) # self.send_documents() # initializer for HarmonyOS system @@ -205,7 +206,8 @@ def init_droidbot(self, is_harmonyos): master=self.master, replay_output=self.replay_output, kea=self.kea, - output_dir=self.output_dir) + output_dir=self.output_dir, + is_package=self.is_package) @staticmethod def get_instance(): diff --git a/kea/input_manager.py b/kea/input_manager.py index 5065fee..4ef045c 100644 --- a/kea/input_manager.py +++ b/kea/input_manager.py @@ -47,7 +47,8 @@ def __init__( kea=None, number_of_events_that_restart_app=100, generate_utg=False, - output_dir=None + output_dir=None, + is_package=None ): """ manage input event sent to the target device @@ -75,6 +76,7 @@ def __init__( self.generate_utg = generate_utg self.policy = self.get_input_policy(device, app, master) self.sim_calculator = Similarity(DEFAULT_UI_TARPIT_NUM) + self.is_package = is_package def get_input_policy(self, device, app, master): if self.policy_name == POLICY_NONE: @@ -88,7 +90,7 @@ def get_input_policy(self, device, app, master): self.output_dir ) elif self.policy_name == POLICY_RANDOM: - input_policy = RandomPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_reinstall_app=True, allow_to_generate_utg = self.generate_utg, output_dir=self.output_dir) + input_policy = RandomPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_reinstall_app=not self.is_package, allow_to_generate_utg = self.generate_utg, output_dir=self.output_dir) elif self.policy_name == POLICY_LLM: input_policy = LLMPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_restart_app_data_after_100_events=True, allow_to_generate_utg = self.generate_utg, output_dir=self.output_dir) else: From a36e0c8066d034e25ff22a499137a1f1af101885 Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Thu, 9 Jan 2025 21:34:58 +0800 Subject: [PATCH 5/9] fix(is_package):fix the bug of the function do not reinstall the app when use the installed package --- kea/input_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kea/input_manager.py b/kea/input_manager.py index 4ef045c..ac9bac2 100644 --- a/kea/input_manager.py +++ b/kea/input_manager.py @@ -48,7 +48,7 @@ def __init__( number_of_events_that_restart_app=100, generate_utg=False, output_dir=None, - is_package=None + is_package=False, ): """ manage input event sent to the target device @@ -74,9 +74,9 @@ def __init__( self.profiling_method = profiling_method self.number_of_events_that_restart_app = number_of_events_that_restart_app self.generate_utg = generate_utg - self.policy = self.get_input_policy(device, app, master) self.sim_calculator = Similarity(DEFAULT_UI_TARPIT_NUM) self.is_package = is_package + self.policy = self.get_input_policy(device, app, master) def get_input_policy(self, device, app, master): if self.policy_name == POLICY_NONE: From 51502e5b922f3fd66e3519603f3f22b733815df2 Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Thu, 9 Jan 2025 21:36:43 +0800 Subject: [PATCH 6/9] feat(disable rotate option):add an option to diable rotate event --- kea/droidbot.py | 8 ++++++-- kea/input_manager.py | 5 ++++- kea/input_policy.py | 11 ++++++++--- kea/start.py | 10 +++++++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/kea/droidbot.py b/kea/droidbot.py index 85ad982..799585c 100644 --- a/kea/droidbot.py +++ b/kea/droidbot.py @@ -55,6 +55,7 @@ def __init__( is_harmonyos=False, is_package=False, generate_utg=False, + disable_rotate=False, settings:"Setting"=None ): """ @@ -123,6 +124,7 @@ def __init__( self.run_initial_rules_after_every_mutation = run_initial_rules_after_every_mutation self.is_package = is_package self.generate_utg = generate_utg + self.disable_rotate = disable_rotate self.settings = settings try: self.init_droidbot(is_harmonyos) @@ -170,7 +172,8 @@ def init_droidbot(self, is_harmonyos): number_of_events_that_restart_app=self.number_of_events_that_restart_app, generate_utg=self.generate_utg, output_dir=self.output_dir, - is_package=self.is_package + is_package=self.is_package, + disable_rotate=self.disable_rotate ) # self.send_documents() # initializer for HarmonyOS system @@ -207,7 +210,8 @@ def init_droidbot(self, is_harmonyos): replay_output=self.replay_output, kea=self.kea, output_dir=self.output_dir, - is_package=self.is_package) + is_package=self.is_package, + disable_rotate=self.disable_rotate) @staticmethod def get_instance(): diff --git a/kea/input_manager.py b/kea/input_manager.py index ac9bac2..6d4ec2c 100644 --- a/kea/input_manager.py +++ b/kea/input_manager.py @@ -49,6 +49,7 @@ def __init__( generate_utg=False, output_dir=None, is_package=False, + disable_rotate=False ): """ manage input event sent to the target device @@ -75,6 +76,7 @@ def __init__( self.number_of_events_that_restart_app = number_of_events_that_restart_app self.generate_utg = generate_utg self.sim_calculator = Similarity(DEFAULT_UI_TARPIT_NUM) + self.disable_rotate=disable_rotate self.is_package = is_package self.policy = self.get_input_policy(device, app, master) @@ -87,10 +89,11 @@ def get_input_policy(self, device, app, master): app, self.kea, self.generate_utg, + self.disable_rotate, self.output_dir ) elif self.policy_name == POLICY_RANDOM: - input_policy = RandomPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_reinstall_app=not self.is_package, allow_to_generate_utg = self.generate_utg, output_dir=self.output_dir) + input_policy = RandomPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_reinstall_app= not self.is_package, allow_to_generate_utg = self.generate_utg,disable_rotate=self.disable_rotate,output_dir=self.output_dir) elif self.policy_name == POLICY_LLM: input_policy = LLMPolicy(device, app, kea=self.kea, number_of_events_that_restart_app = self.number_of_events_that_restart_app, clear_and_restart_app_data_after_100_events=True, allow_to_generate_utg = self.generate_utg, output_dir=self.output_dir) else: diff --git a/kea/input_policy.py b/kea/input_policy.py index 41b4a59..20b76c0 100644 --- a/kea/input_policy.py +++ b/kea/input_policy.py @@ -377,6 +377,7 @@ def __init__( number_of_events_that_restart_app=100, clear_and_reinstall_app=False, allow_to_generate_utg=False, + disable_rotate=False, output_dir=None ): super(RandomPolicy, self).__init__(device, app, kea, allow_to_generate_utg) @@ -386,6 +387,7 @@ def __init__( self.logger = logging.getLogger(self.__class__.__name__) self.output_dir=output_dir save_log(self.logger, self.output_dir) + self.disable_rotate=disable_rotate self.last_rotate_events = KEY_RotateDeviceToPortraitEvent def generate_event(self): @@ -452,7 +454,8 @@ def generate_random_event_based_on_current_state(self): possible_events = current_state.get_possible_input() possible_events.append(KeyEvent(name="BACK")) - possible_events.append(RotateDevice()) + if not self.disable_rotate: + possible_events.append(RotateDevice()) self._event_trace += EVENT_FLAG_EXPLORE @@ -475,11 +478,12 @@ class GuidedPolicy(KeaInputPolicy): generate events around the main path """ - def __init__(self, device, app, kea=None, allow_to_generate_utg=False,output_dir=None): + def __init__(self, device, app, kea=None, allow_to_generate_utg=False,disable_rotate=False,output_dir=None): super(GuidedPolicy, self).__init__(device, app, kea, allow_to_generate_utg) self.logger = logging.getLogger(self.__class__.__name__) self.output_dir = output_dir save_log(self.logger,self.output_dir) + self.disable_rotate = disable_rotate if len(self.kea.all_mainPaths): self.logger.info("Found %d mainPaths" % len(self.kea.all_mainPaths)) else: @@ -708,7 +712,8 @@ def generate_random_event_based_on_current_state(self): # if self.random_input: # random.shuffle(possible_events) possible_events.append(KeyEvent(name="BACK")) - possible_events.append(RotateDevice()) + if not self.disable_rotate: + possible_events.append(RotateDevice()) self._event_trace += EVENT_FLAG_EXPLORE diff --git a/kea/start.py b/kea/start.py index 44f2271..a2ef119 100644 --- a/kea/start.py +++ b/kea/start.py @@ -46,6 +46,7 @@ class Setting: is_harmonyos:bool=False generate_utg:bool=False is_package:bool=False + disable_rotate:bool=False def parse_args(): """Parse, load and sanitize the args from the command line and the config file `config.yml`. @@ -82,6 +83,8 @@ def parse_args(): help="load the args from config.yml, and the args in the command line will be ignored.") parser.add_argument("-utg", action="store_true", dest="generate_utg", default=False, help="Generate UI transition graph") + parser.add_argument("-disable_rotate", action="store_true", dest="disable_rotate", default=False, + help="Disable rotate event in the testing") options = parser.parse_args() # load the args from the config file `config.yml` @@ -91,7 +94,6 @@ def parse_args(): # sanitize these args sanitize_args(options) - return options def load_ymal_args(opts): @@ -164,7 +166,8 @@ def start_kea(kea:"Kea", settings:"Setting" = None): is_harmonyos=settings.is_harmonyos, is_package=settings.is_package, settings=settings, - generate_utg=settings.generate_utg + generate_utg=settings.generate_utg, + disable_rotate=settings.disable_rotate ) kea._pdl_driver.set_droidbot(droidbot) @@ -190,7 +193,8 @@ def main(): grant_perm=options.grant_perm, is_emulator=options.is_emulator, generate_utg=options.generate_utg, - is_package=options.is_package + is_package=options.is_package, + disable_rotate=options.disable_rotate ) # load the pdl driver for Android/HarmonyOS From 201bc889d79fdb2a85ab93a7d28e01259204265d Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Thu, 9 Jan 2025 21:45:15 +0800 Subject: [PATCH 7/9] feat(disable rotate):add disable_rotate option in the yaml --- kea/start.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kea/start.py b/kea/start.py index a2ef119..e0327a6 100644 --- a/kea/start.py +++ b/kea/start.py @@ -120,6 +120,8 @@ def load_ymal_args(opts): opts.property_files = value elif key.lower() == "keep_app" and value: opts.keep_app = value + elif key.lower() == "disable_rotate" and value: + opts.disable_rotate = value return opts From 54251b13237dd8baee96a63a290005ef070732a3 Mon Sep 17 00:00:00 2001 From: XiangchenShen Date: Sun, 12 Jan 2025 18:47:28 +0800 Subject: [PATCH 8/9] feat(wechat): add swipe event for finder in wechat --- kea/device_state.py | 16 +++++++++++++++- kea/input_event.py | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/kea/device_state.py b/kea/device_state.py index e0dda28..4506112 100644 --- a/kea/device_state.py +++ b/kea/device_state.py @@ -10,7 +10,7 @@ from .device import Device from .utils import md5, deprecated -from .input_event import SearchEvent, SetTextAndSearchEvent, TouchEvent, LongTouchEvent, ScrollEvent, SetTextEvent, KeyEvent, UIEvent +from .input_event import SearchEvent, SetTextAndSearchEvent, TouchEvent, LongTouchEvent, ScrollEvent, SetTextEvent, KeyEvent, UIEvent, SwipeEvent class DeviceState(object): @@ -600,6 +600,20 @@ def get_possible_input(self): # For old Android navigation bars # possible_events.append(KeyEvent(name="MENU")) + for view_id in enabled_view_ids: + if self.__safe_dict_get(self.views[view_id], 'package') == 'com.tencent.mm' and self.__safe_dict_get(self.views[view_id], 'resource_id') == "com.tencent.mm:id/media_container": + bounds = self.__safe_dict_get(self.views[view_id], 'bounds') + x0 = bounds[0][0] + y0 = bounds[0][1] + x1 = bounds[1][0] + y1 = bounds[1][1] + swipe_x = (x0 + x1) / 2.0 + swipe_y0 = y0 + 3.0 * (y1 - y0) / 4.0 + swipe_y1 = y0 + (y1- y0) / 4.0 + possible_events.append(SwipeEvent(start_x=swipe_x, start_y=swipe_y0, end_x=swipe_x, end_y=swipe_y1, duration = 500)) + possible_events.append(SwipeEvent(start_x=swipe_x, start_y=swipe_y1, end_x=swipe_x, end_y=swipe_y0, duration = 500)) + + self.possible_events = possible_events return [] + possible_events diff --git a/kea/input_event.py b/kea/input_event.py index 0c98379..195afc5 100644 --- a/kea/input_event.py +++ b/kea/input_event.py @@ -789,7 +789,7 @@ def get_views(self): return views def get_event_name(self): - return self.get_event_str() + return "Swipe" class ScrollEvent(UIEvent): """ From 3410faa1b6c0c15cd8ed87efb652fd528b6f6c19 Mon Sep 17 00:00:00 2001 From: ShenXiangchen Date: Mon, 13 Jan 2025 16:26:22 +0800 Subject: [PATCH 9/9] feat(bug report): add detailed property checking statistics bug report --- kea/input_policy.py | 44 ++++++++++++++++++---------------- kea/kea.py | 2 +- kea/resources/style/style.html | 24 ++++++++++++++++++- kea/utils.py | 35 +++++++++++++++++++++++---- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/kea/input_policy.py b/kea/input_policy.py index 20b76c0..0dc7145 100644 --- a/kea/input_policy.py +++ b/kea/input_policy.py @@ -1,11 +1,10 @@ -from dataclasses import dataclass import os import logging import random import copy import re import time -from .utils import Time, generate_report, save_log +from .utils import Time, generate_report, save_log, RULE_STATE from abc import abstractmethod from .input_event import ( KEY_RotateDeviceToPortraitEvent, @@ -57,14 +56,6 @@ POLICY_NONE = "none" POLICY_LLM = "llm" - -@dataclass -class RULE_STATE: - PRECONDITION_SATISFIED = "#satisfy pre" - PROPERTY_CHECKED = "#check property" - POSTCONDITION_VIOLATED = "#postcondition is violated" - - class InputInterruptedException(Exception): pass @@ -89,6 +80,7 @@ def __init__(self, device: "Device", app: "App", allow_to_generate_utg=False): self.allow_to_generate_utg = allow_to_generate_utg self.triggered_bug_information = [] self.time_needed_to_satisfy_precondition = [] + self.statistics_of_rules = {} self._num_restarts = 0 self._num_steps_outside = 0 @@ -148,6 +140,7 @@ def start(self, input_manager: "InputManager"): self.time_needed_to_satisfy_precondition, self.device.cur_event_count, self.time_recoder.get_time_duration(), + self.statistics_of_rules ) except KeyboardInterrupt: @@ -262,12 +255,12 @@ def __init__(self, device, app, kea: "Kea" = None, allow_to_generate_utg=False): # self.to_state = None # retrive all the rules from the provided properties - self.statistics_of_rules = {} for rule in self.kea.all_rules: - self.statistics_of_rules[str(rule)] = { + self.statistics_of_rules[str(rule.function.__name__)] = { RULE_STATE.PRECONDITION_SATISFIED: 0, RULE_STATE.PROPERTY_CHECKED: 0, RULE_STATE.POSTCONDITION_VIOLATED: 0, + RULE_STATE.UI_OBJECT_NOT_FOUND: 0 } def run_initializer(self): @@ -298,16 +291,12 @@ def check_rule_whose_precondition_are_satisfied(self): return candidate_rules_list = list(rules_ready_to_be_checked.keys()) - for candidate_rule in candidate_rules_list: - self.statistics_of_rules[str(candidate_rule)][ - RULE_STATE.PRECONDITION_SATISFIED - ] += 1 # randomly select a rule to check rule_to_check = random.choice(candidate_rules_list) if rule_to_check is not None: self.logger.info(f"-------Check Property : {rule_to_check}------") - self.statistics_of_rules[str(rule_to_check)][ + self.statistics_of_rules[str(rule_to_check.function.__name__)][ RULE_STATE.PROPERTY_CHECKED ] += 1 precondition_page_index = self.device.cur_event_count @@ -323,7 +312,7 @@ def check_rule_whose_precondition_are_satisfied(self): "-------time from start : %s-----------" % str(self.time_recoder.get_time_duration()) ) - self.statistics_of_rules[str(rule_to_check)][ + self.statistics_of_rules[str(rule_to_check.function.__name__)][ RULE_STATE.POSTCONDITION_VIOLATED ] += 1 postcondition_page__index = self.device.cur_event_count @@ -347,6 +336,9 @@ def check_rule_whose_precondition_are_satisfied(self): self.logger.error( f"-------Execution failed: UiObjectNotFound during exectution. Property:{rule_to_check}-----------" ) + self.statistics_of_rules[str(rule_to_check.function.__name__)][ + RULE_STATE.UI_OBJECT_NOT_FOUND + ] += 1 elif result == CHECK_RESULT.PRECON_NOT_SATISFIED: self.logger.info("-------Precondition not satisfied-----------") else: @@ -419,6 +411,10 @@ def generate_event(self): return KillAndRestartAppEvent(app=self.app) rules_to_check = self.kea.get_rules_whose_preconditions_are_satisfied() + for rule_to_check in rules_to_check: + self.statistics_of_rules[str(rule_to_check.function.__name__)][ + RULE_STATE.PRECONDITION_SATISFIED + ] += 1 if len(rules_to_check) > 0: t = self.time_recoder.get_time_duration() @@ -579,9 +575,11 @@ def mutate_the_main_path(self): self.logger.info( "reach the end of the main path that could satisfy the precondition" ) - rules_to_check = ( - self.kea.get_rules_whose_preconditions_are_satisfied() - ) + rules_to_check = self.kea.get_rules_whose_preconditions_are_satisfied() + for rule_to_check in rules_to_check: + self.statistics_of_rules[str(rule_to_check.function.__name__)][ + RULE_STATE.PRECONDITION_SATISFIED + ] += 1 if len(rules_to_check) > 0: t = self.time_recoder.get_time_duration() self.time_needed_to_satisfy_precondition.append(t) @@ -861,6 +859,10 @@ def generate_llm_event(self): ) return ReInstallAppEvent(self.app) rules_to_check = self.kea.get_rules_whose_preconditions_are_satisfied() + for rule_to_check in rules_to_check: + self.statistics_of_rules[str(rule_to_check.function.__name__)][ + RULE_STATE.PRECONDITION_SATISFIED + ] += 1 if len(rules_to_check) > 0: t = self.time_recoder.get_time_duration() diff --git a/kea/kea.py b/kea/kea.py index bf34079..258dc27 100644 --- a/kea/kea.py +++ b/kea/kea.py @@ -344,7 +344,7 @@ def get_rules_whose_preconditions_are_satisfied(self) -> Dict["Rule", "KeaTest"] def single_thread_precondition_checker(self): """ - check precondition with sigle-thread + check precondition with single-thread """ rules_passed_precondition: Dict["Rule", "KeaTest"] = dict() diff --git a/kea/resources/style/style.html b/kea/resources/style/style.html index 89dbc39..521aa39 100644 --- a/kea/resources/style/style.html +++ b/kea/resources/style/style.html @@ -112,7 +112,7 @@

Runtime Statistics

-

Property Checking Statistics

+

Comprehensive Statistics

Num
@@ -130,6 +130,7 @@

Property Violations

+ @@ -141,6 +142,27 @@

Property Violations

Index Property Name Page of Precondition Pages of Interaction Scenario
+ +
+ +

Property Checking Statistics

+
+ + + + + + + + + + + + + + +
IndexProperty NamePrecondition Satisfied TimesPrecondition Checked TimesPostcondition Violated TimesUi Object Not Found Times
property statisticproperty statisticproperty statisticproperty statistic
+
\ No newline at end of file diff --git a/kea/utils.py b/kea/utils.py index ff88242..729d309 100644 --- a/kea/utils.py +++ b/kea/utils.py @@ -8,7 +8,7 @@ import warnings import pkg_resources # TODO: warning pkg_resources has been depreciated import yaml - +from dataclasses import dataclass # logcat regex, which will match the log message generated by `adb logcat -v threadtime` LOGCAT_THREADTIME_RE = re.compile( '^(?P\S+)\s+(?P