diff --git a/haf/bench.py b/haf/bench.py index bc915ff..db18f7c 100644 --- a/haf/bench.py +++ b/haf/bench.py @@ -1,6 +1,6 @@ # encoding='utf-8' from haf.common.database import SQLConfig -from haf.case import HttpApiCase, AppCase +from haf.case import HttpApiCase, AppCase, WebCase class BaseBench(object): @@ -66,5 +66,34 @@ def update_case(self, case: AppCase): def get_case(self, key: str): return self.cases.get(key, None) + def get_db(self, key: str): + return self.dbs.get(key, None) + + +class WebBench(BaseBench): + def __init__(self): + super().__init__() + self.name = None + self._init_all() + + def _init_all(self): + self.cases = {} + self.dbs = {} + + def add_case(self, case: WebCase): + key = f"{case.ids.id}.{case.ids.subid}.{case.ids.name}" + self.cases.update({key: case}) + + def add_db(self, db: SQLConfig): + key_db = str(db.id) + self.dbs.update({key_db: db}) + + def update_case(self, case: WebCase): + key = f"{case.ids.id}.{case.ids.subid}.{case.ids.name}" + self.cases.update({key: case}) + + def get_case(self, key: str): + return self.cases.get(key, None) + def get_db(self, key: str): return self.dbs.get(key, None) \ No newline at end of file diff --git a/haf/case.py b/haf/case.py index d36d85b..66607e1 100644 --- a/haf/case.py +++ b/haf/case.py @@ -5,6 +5,7 @@ from haf.apphelper import Stage, AppIds, DesiredCaps from haf.config import * from haf.common.log import Log +from haf.webhelper import * logger = Log.getLogger(__name__) @@ -224,3 +225,71 @@ def deserialize(self): "sleep": self.time_sleep, "wait_activity": self.wait_activity } + + +class WebCase(BaseCase): + def __init__(self): + super().__init__() + self.mark = CASE_MARK_WEB + self.type = CASE_TYPE_WEBUI + self.message_type = MESSAGE_TYPE_CASE + self.log_key = "" + self._init_all() + + def _init_all(self): + self.ids = WebIds() + self.run = CASE_RUN + self.dependent = [] + self.bench_name = "" + self.stages = {} + self.log_key = "" + self.wait_activity = "" + self.desired_caps = WebDesiredCaps() + self.error = None + self.sqlinfo = SqlInfo() + self.time_sleep = 5 + self.pngs = {} + + def constructor(self, *args, **kwargs): + ''' + :param args: + :param kwargs: + :return: + ''' + args_init = {} + if len(args) > 0 and isinstance(args[0], dict): + args_init = args[0] + else: + args_init = kwargs + self.ids.constructor(args_init) + self.time_sleep = args_init.get("wait_time") or 5 + self.run = CASE_RUN if args_init.get("run") is True else CASE_SKIP + self.dependent = [x for x in str(args_init.get("dependent")).split(";") if args_init.get("dependent") is not None] + self.desired_caps.constructor(args_init.get("desired_caps")) + self.stages = {} + self.wait_activity = args_init.get("wait_activity", None) + for s in args_init.get("stage"): + stage = WebStage() + stage.constructor(s) + self.stages[stage.id] = stage + + def bind_bench(self, bench_name): + self.bench_name = bench_name + self.generate_log_key() + + def generate_log_key(self): + self.log_key = self.key = f"{self.bench_name}$%{self.ids.id}.{self.ids.subid}.{self.ids.name}$%" + + def deserialize(self): + return { + "ids": self.ids.deserialize(), + "run": self.run, + "dependent": self.dependent, + "bench_name": self.bench_name, + "stage": [stage.deserialize() for stage in self.stages.values()], + "type": self.type, + "desired_caps": self.desired_caps.deserialize(), + "pngs": self.pngs, + "sleep": self.time_sleep, + "wait_activity": self.wait_activity + } diff --git a/haf/config.py b/haf/config.py index ec923ef..dac6431 100644 --- a/haf/config.py +++ b/haf/config.py @@ -86,11 +86,30 @@ OPERATION_APP_OTHER: "other" } +OPERATION_WEB_CLICK = 80 +OPERATION_WEB_SENDKEYS = 81 +OPERATION_WEB_SWIPE = 82 +OPERATION_WEB_OTHER = 83 + +OPERATION_WEB_GROUP = { + "click": OPERATION_WEB_CLICK, + "swipe": OPERATION_WEB_SWIPE, + "send_keys": OPERATION_WEB_SENDKEYS, + "other": OPERATION_WEB_OTHER +} + +OPERATION_WEB_ANTI_GROUP = { + OPERATION_WEB_CLICK: "click", + OPERATION_WEB_SWIPE: "swipe", + OPERATION_WEB_SENDKEYS: "send_keys", + OPERATION_WEB_OTHER: "other" +} + LOG_PATH_DEFAULT = "D:\workspace\mine\python\haf\data" MAIN_VERSION = 2 SUB_VERSION = 6 -FIX_VERSION = 1 +FIX_VERSION = 2 VERSION_TYPE = "haf" PLATFORM_VERSION = f"{VERSION_TYPE}-{MAIN_VERSION}.{SUB_VERSION}.{FIX_VERSION}" diff --git a/haf/ext/jinjia2report/report.py b/haf/ext/jinjia2report/report.py index 25688f8..6a0b99e 100644 --- a/haf/ext/jinjia2report/report.py +++ b/haf/ext/jinjia2report/report.py @@ -28,7 +28,7 @@ def get_template_customer(path_: str) -> None: def get_template(key: str) -> None: if key == "base" or key == "online": template = "base.html" - elif key == "online-app" or key == "base_app": + elif key in ["online-app", "base_app", "online-web", "base_web"]: template = "base_app.html" elif key == "base_email": template = "base_email.html" diff --git a/haf/loader.py b/haf/loader.py index 53d1f71..0639995 100644 --- a/haf/loader.py +++ b/haf/loader.py @@ -4,7 +4,7 @@ from haf.bench import HttpApiBench from haf.busclient import BusClient from haf.common.database import SQLConfig -from haf.case import HttpApiCase, PyCase, AppCase +from haf.case import HttpApiCase, PyCase, AppCase, WebCase from haf.common.exception import FailLoaderException from haf.common.log import Log from haf.config import * @@ -70,8 +70,10 @@ def run(self): input["host_port"] = inputs.get("config")[0].get("host_port") if "api_name" in input.keys(): case = HttpApiCase() - elif "stage" in input.keys(): + elif input.get("type") == "app": case = AppCase() + elif input.get("type") == "web": + case = WebCase() else: case = PyCase(module_name, module_path) try: diff --git a/haf/recorder.py b/haf/recorder.py index 1de8d78..66de11b 100644 --- a/haf/recorder.py +++ b/haf/recorder.py @@ -4,11 +4,11 @@ from multiprocessing import Process from haf.busclient import BusClient -from haf.case import HttpApiCase, BaseCase, PyCase +from haf.case import HttpApiCase, BaseCase, PyCase, WebCase, AppCase from haf.common.database import SQLConfig from haf.common.exception import FailRecorderException from haf.common.log import Log -from haf.result import HttpApiResult, EndResult, Detail, Summary, AppResult +from haf.result import HttpApiResult, EndResult, Detail, Summary, AppResult, WebResult from haf.config import * from haf.utils import Utils from haf.ext.jinjia2report.report import Jinja2Report @@ -62,8 +62,8 @@ def run(self): while True: if not self.results_handler.empty() : result = self.results_handler.get() - if isinstance(result, HttpApiResult) or isinstance(result, AppResult): - if isinstance(result.case, HttpApiCase) or isinstance(result.case, BaseCase) or isinstance(result.case, PyCase): + if isinstance(result, (HttpApiResult, AppResult, WebResult)): + if isinstance(result.case, (HttpApiCase, BaseCase, PyCase, WebCase, AppCase)): logger.info(f"{self.recorder_key} recorder--{result.case.bench_name}.{result.case.ids.id}.{result.case.ids.subid}.{result.case.ids.name} is {result.result}") else: logger.info(f"{self.recorder_key} recorder ! wrong result!") diff --git a/haf/result.py b/haf/result.py index edc64af..c0eaa17 100644 --- a/haf/result.py +++ b/haf/result.py @@ -102,6 +102,46 @@ def deserialize(self): } +class WebResult(BaseResult): + def __init__(self): + super().__init__() + self.message_type = MESSAGE_TYPE_RESULT + self._init_all() + + def _init_all(self): + self.case = None + self.run_error = None + self.result = False + self.begin_time = None + self.end_time = None + self.log_dir = "" + self.runner = "" + self.pngs = {} + + def on_case_begin(self): + self.begin_time = Utils.get_datetime_now() + + def on_case_end(self): + self.end_time = Utils.get_datetime_now() + self.duration = Utils.get_date_result(self.begin_time, self.end_time) + + def bind_runner(self, runner:int=0): + self.runner = runner + + def deserialize(self): + return { + "case_name": f"{self.case.ids.id}.{self.case.ids.subid}.{self.case.ids.name}", + "run_error": self.run_error, + "result": RESULT_GROUP.get(str(self.result)), + "begin_time": self.begin_time, + "end_time": self.end_time, + "case": self.case.deserialize(), + "log_dir": self.log_dir, + "runner": self.runner, + "pngs": self.pngs + } + + class Detail(object): def __init__(self, suite_name): self.suite_name = suite_name diff --git a/haf/runner.py b/haf/runner.py index f7e115f..5acb966 100644 --- a/haf/runner.py +++ b/haf/runner.py @@ -6,17 +6,18 @@ from haf.apihelper import Request, Response from haf.apphelper import Stage, BasePage, save_screen_shot from haf.asserthelper import AssertHelper -from haf.bench import HttpApiBench, BaseBench, AppBench +from haf.bench import HttpApiBench, BaseBench, AppBench, WebBench from haf.busclient import BusClient -from haf.case import HttpApiCase, BaseCase, PyCase, AppCase +from haf.case import HttpApiCase, BaseCase, PyCase, AppCase, WebCase from haf.common.database import SQLConfig from haf.common.exception import FailRunnerException from haf.common.log import Log from haf.config import * from haf.mark import locker -from haf.result import HttpApiResult, AppResult +from haf.result import HttpApiResult, AppResult, WebResult from haf.suite import HttpApiSuite, AppSuite from haf.utils import Utils +from haf.webhelper import * import traceback import asyncio @@ -115,16 +116,16 @@ def run(self): if len(cases)>0 and (len(cases)>=3 or flag): results = loop.run_until_complete(self.run_cases(cases)) for result in results: - if isinstance(result, HttpApiResult) or isinstance(result, AppResult): + if isinstance(result, (HttpApiResult, AppResult, WebResult)): self.put_result("result", result) cases = [] - elif isinstance(case, (AppCase, PyCase)): + elif isinstance(case, (AppCase, PyCase, WebCase)): cases.append(case) time.sleep(0.01) if len(cases)>0 and (len(cases)>=1 or flag): results = loop.run_until_complete(self.run_cases(cases)) for result in results: - if isinstance(result, HttpApiResult) or isinstance(result, AppResult): + if isinstance(result, (HttpApiResult, AppResult, WebResult)): self.put_result("result", result) cases = [] if flag: @@ -149,6 +150,8 @@ async def run_case(self, local_case): result = AppResult() elif isinstance(local_case, PyCase): result = HttpApiResult() + elif isinstance(local_case, WebCase): + result = WebResult() try: try: self.key = local_case.log_key @@ -161,6 +164,8 @@ async def run_case(self, local_case): runner = PyRunner(self.bench) elif local_case.type == CASE_TYPE_APP: runner = AppRunner(self.bench, self.log_dir) + elif local_case.type == CASE_TYPE_WEBUI: + runner = WebRunner(self.bench, self.log_dir) result = await runner.run(local_case) @@ -432,7 +437,7 @@ async def run(self, case: AppCase): png_dir = f"{self.log_dir}" png_name = f"{case.bench_name}.{case.ids.id}.{case.ids.subid}.{case.ids.name}.{key}" png_before = save_screen_shot(driver, png_dir, f"{png_name}-before") - self.run_stage(case, page, case.stages.get(key), result) + self.run_stage(case, page, case.stages.get(key, Stage()), result) png_after = save_screen_shot(driver, png_dir, f"{png_name}-after") case.pngs[key] = {"before": f"./png/{png_name}-before.png", "after": f"./png/{png_name}-after.png"} result.case = case @@ -461,3 +466,116 @@ def run_stage(self, case, page, stage: Stage=Stage(), result: AppResult=AppResul result.run_error = f"{stage.id} : {e}" if not stage.show_try: raise e + + +class WebRunner(BaseRunner): + ''' + WebRunner + ''' + def __init__(self, bench: WebBench, log_dir): + super().__init__(bench) + self.bench = bench + self.key = "" + self.log_dir = log_dir + + def wait_activity(self, activity, timeout, driver): + """Wait for an activity: block until target activity presents + or time out. + This is an Android-only method. + :Agrs: + - activity - target activity + - timeout - max wait time, in seconds + - interval - sleep interval between retries, in seconds + """ + try: + i = 0 + while i