Kea2-python 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Kea2-python might be problematic. Click here for more details.

Files changed (44) hide show
  1. {kea2_python-0.2.0 → kea2_python-0.2.2}/Kea2_python.egg-info/PKG-INFO +2 -2
  2. {kea2_python-0.2.0 → kea2_python-0.2.2}/PKG-INFO +2 -2
  3. {kea2_python-0.2.0 → kea2_python-0.2.2}/README.md +1 -1
  4. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/adbUtils.py +13 -5
  5. kea2_python-0.2.2/kea2/assets/monkeyq.jar +0 -0
  6. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/bug_report_generator.py +1 -1
  7. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/fastbotManager.py +37 -21
  8. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/keaUtils.py +16 -11
  9. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/kea_launcher.py +19 -1
  10. kea2_python-0.2.2/kea2/logWatcher.py +79 -0
  11. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/templates/bug_report_template.html +6 -2
  12. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/u2Driver.py +3 -2
  13. {kea2_python-0.2.0 → kea2_python-0.2.2}/pyproject.toml +1 -1
  14. {kea2_python-0.2.0 → kea2_python-0.2.2}/tests/test_u2Selector.py +9 -3
  15. kea2_python-0.2.0/kea2/assets/monkeyq.jar +0 -0
  16. kea2_python-0.2.0/kea2/logWatcher.py +0 -82
  17. {kea2_python-0.2.0 → kea2_python-0.2.2}/Kea2_python.egg-info/SOURCES.txt +0 -0
  18. {kea2_python-0.2.0 → kea2_python-0.2.2}/Kea2_python.egg-info/dependency_links.txt +0 -0
  19. {kea2_python-0.2.0 → kea2_python-0.2.2}/Kea2_python.egg-info/entry_points.txt +0 -0
  20. {kea2_python-0.2.0 → kea2_python-0.2.2}/Kea2_python.egg-info/requires.txt +0 -0
  21. {kea2_python-0.2.0 → kea2_python-0.2.2}/Kea2_python.egg-info/top_level.txt +0 -0
  22. {kea2_python-0.2.0 → kea2_python-0.2.2}/LICENSE +0 -0
  23. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/__init__.py +0 -0
  24. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/absDriver.py +0 -0
  25. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot-thirdpart.jar +0 -0
  26. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/abl.strings +0 -0
  27. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/awl.strings +0 -0
  28. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/max.config +0 -0
  29. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/max.fuzzing.strings +0 -0
  30. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/max.schema.strings +0 -0
  31. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/max.strings +0 -0
  32. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/max.tree.pruning +0 -0
  33. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_configs/widget.block.py +0 -0
  34. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
  35. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
  36. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_libs/x86/libfastbot_native.so +0 -0
  37. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/fastbot_libs/x86_64/libfastbot_native.so +0 -0
  38. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/framework.jar +0 -0
  39. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/kea2-thirdpart.jar +0 -0
  40. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/assets/quicktest.py +0 -0
  41. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/cli.py +0 -0
  42. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/resultSyncer.py +0 -0
  43. {kea2_python-0.2.0 → kea2_python-0.2.2}/kea2/utils.py +0 -0
  44. {kea2_python-0.2.0 → kea2_python-0.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Kea2-python
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A python library for supporting and customizing automated UI testing for mobile apps
5
5
  Author-email: Xixian Liang <xixian@stu.ecnu.edu.cn>
6
6
  Requires-Python: >=3.8
@@ -20,7 +20,7 @@ Dynamic: license-file
20
20
 
21
21
 
22
22
  <div>
23
- <img src="https://github.com/user-attachments/assets/aa5839fc-4542-46f6-918b-c9f891356c84" style="border-radius: 14px; width: 20%; height: 20%;"/>
23
+ <img src="https://github.com/user-attachments/assets/36ec9f2f-a3d8-482a-9a61-4785f3278991" style="border-radius: 14px; width: 20%; height: 20%;"/>
24
24
  </div>
25
25
 
26
26
  ### Github repo link
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Kea2-python
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A python library for supporting and customizing automated UI testing for mobile apps
5
5
  Author-email: Xixian Liang <xixian@stu.ecnu.edu.cn>
6
6
  Requires-Python: >=3.8
@@ -20,7 +20,7 @@ Dynamic: license-file
20
20
 
21
21
 
22
22
  <div>
23
- <img src="https://github.com/user-attachments/assets/aa5839fc-4542-46f6-918b-c9f891356c84" style="border-radius: 14px; width: 20%; height: 20%;"/>
23
+ <img src="https://github.com/user-attachments/assets/36ec9f2f-a3d8-482a-9a61-4785f3278991" style="border-radius: 14px; width: 20%; height: 20%;"/>
24
24
  </div>
25
25
 
26
26
  ### Github repo link
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
  <div>
9
- <img src="https://github.com/user-attachments/assets/aa5839fc-4542-46f6-918b-c9f891356c84" style="border-radius: 14px; width: 20%; height: 20%;"/>
9
+ <img src="https://github.com/user-attachments/assets/36ec9f2f-a3d8-482a-9a61-4785f3278991" style="border-radius: 14px; width: 20%; height: 20%;"/>
10
10
  </div>
11
11
 
12
12
  ### Github repo link
@@ -6,7 +6,6 @@ from typing import List, Optional, Set, Tuple
6
6
  from kea2.utils import getLogger
7
7
  from adbutils import AdbDevice, adb
8
8
  from typing import IO, TYPE_CHECKING, Generator, Optional, List, Union
9
- from adbutils import AdbConnection
10
9
 
11
10
  logger = getLogger(__name__)
12
11
 
@@ -44,20 +43,29 @@ class ADBDevice(AdbDevice):
44
43
  super().__init__(client=adb, serial=ADBDevice.serial, transport_id=ADBDevice.transport_id)
45
44
 
46
45
  @property
47
- def stream_shell(self) -> "ADBStreamShell_V2":
46
+ def stream_shell(self) -> "StreamShell":
48
47
  if "shell_v2" in self.get_features():
49
48
  return ADBStreamShell_V2(session=self)
50
49
  logger.warning("Using ADBStreamShell_V1. All output will be printed to stdout.")
51
50
  return ADBStreamShell_V1(session=self)
52
51
 
52
+ def kill_proc(self, proc_name):
53
+ r = self.shell(f"ps -ef")
54
+ pids = [l for l in r.splitlines() if proc_name in l]
55
+ if pids:
56
+ logger.info(f"{proc_name} running, trying to kill it.")
57
+ pid = pids[0].split()[1]
58
+ self.shell(f"kill {pid}")
59
+
53
60
 
54
61
  class StreamShell:
55
62
  def __init__(self, session: "ADBDevice"):
56
63
  self.dev: ADBDevice = session
57
- self._thread = None
64
+ self._thread: threading.Thread = None
58
65
  self._exit_code = 255
59
66
  self.stdout = sys.stdout
60
67
  self.stderr = sys.stderr
68
+ self._finished = False
61
69
 
62
70
  def __call__(self, cmdargs: Union[List[str], str], stdout: IO = None,
63
71
  stderr: IO = None, timeout: Union[float, None] = None) -> "StreamShell":
@@ -107,7 +115,7 @@ class StreamShell:
107
115
  class ADBStreamShell_V1(StreamShell):
108
116
 
109
117
  def __call__(
110
- self, cmdargs: Union[List[str]], stdout: IO = None,
118
+ self, cmdargs: Union[List[str], str], stdout: IO = None,
111
119
  stderr: IO = None, timeout: Union[float, None] = None
112
120
  ) -> "StreamShell":
113
121
  return self.shell_v1(cmdargs, stdout, stderr, timeout)
@@ -168,7 +176,7 @@ class ADBStreamShell_V2(StreamShell):
168
176
  self._exit_code = 255
169
177
 
170
178
  def __call__(
171
- self, cmdargs: Union[List[str]], stdout: IO = None,
179
+ self, cmdargs: Union[List[str], str], stdout: IO = None,
172
180
  stderr: IO = None, timeout: Union[float, None] = None
173
181
  ) -> "StreamShell":
174
182
  return self.shell_v2(cmdargs, stdout, stderr, timeout)
@@ -94,7 +94,7 @@ class BugReportGenerator:
94
94
  with open(report_path, "w", encoding="utf-8") as f:
95
95
  f.write(html_content)
96
96
 
97
- logger.info(f"Bug report saved to: {report_path}")
97
+ logger.debug(f"Bug report saved to: {report_path}")
98
98
 
99
99
  except Exception as e:
100
100
  logger.error(f"Error generating bug report: {e}")
@@ -1,5 +1,5 @@
1
- import subprocess
2
- import threading
1
+ from retry import retry
2
+ from retry.api import retry_call
3
3
  from dataclasses import asdict
4
4
  import requests
5
5
  from time import sleep
@@ -70,6 +70,21 @@ class FastbotManager:
70
70
  "/data/local/tmp/x86_64/libfastbot_native.so",
71
71
  )
72
72
 
73
+ whitelist = self.options.act_whitelist_file
74
+ blacklist = self.options.act_blacklist_file
75
+ if bool(whitelist) ^ bool(blacklist):
76
+ if whitelist:
77
+ file_to_push = cur_dir.parent / 'configs' / 'awl.strings'
78
+ remote_path = whitelist
79
+ else:
80
+ file_to_push = cur_dir.parent / 'configs' / 'abl.strings'
81
+ remote_path = blacklist
82
+
83
+ self.dev.sync.push(
84
+ file_to_push,
85
+ remote_path
86
+ )
87
+
73
88
  t = self._startFastbotService()
74
89
  logger.info("Running Fastbot...")
75
90
 
@@ -80,25 +95,18 @@ class FastbotManager:
80
95
  """
81
96
  check if the script driver and proxy server are alive.
82
97
  """
98
+ def _check_alive_request():
99
+ _http_request(dev=self.dev, device_port=8090, method="GET", path="/ping")
83
100
 
84
- for _ in range(10):
85
- sleep(2)
86
- try:
87
- _http_request(
88
- dev=self.dev,
89
- device_port=8090,
90
- method="GET",
91
- path="/ping",
92
- )
93
- return
94
- except requests.ConnectionError:
95
- logger.info("waiting for connection.")
96
- pass
97
- raise RuntimeError("Failed to connect fastbot")
101
+ try:
102
+ retry_call(_check_alive_request, tries=10, delay=2)
103
+ except requests.ConnectionError:
104
+ raise RuntimeError("Failed to connect fastbot")
98
105
 
99
106
  def request(self, method: str, path: str, data: Dict=None, timeout: int=10) -> HTTPResponse:
100
107
  return _http_request(self.dev, 8090, method, path, data, timeout)
101
108
 
109
+ @retry(Exception, tries=2, delay=2)
102
110
  def init(self, options: "Options", stamp):
103
111
  post_data = {
104
112
  "takeScreenshots": options.take_screenshots,
@@ -117,6 +125,7 @@ class FastbotManager:
117
125
  self._device_output_dir = re.match(r"outputDir:(.+)", r.text).group(1)
118
126
  print(f"[INFO] Fastbot initiated. outputDir: {r.text}", flush=True)
119
127
 
128
+ @retry(Exception, tries=2, delay=2)
120
129
  def stepMonkey(self, monkeyStepInfo):
121
130
  r = self.request(
122
131
  method="POST",
@@ -125,6 +134,7 @@ class FastbotManager:
125
134
  )
126
135
  return r.json()["result"]
127
136
 
137
+ @retry(Exception, tries=2, delay=2)
128
138
  def stopMonkey(self):
129
139
  """
130
140
  send a stop monkey request to the server.
@@ -136,6 +146,7 @@ class FastbotManager:
136
146
 
137
147
  print(f"[Server INFO] {r.text}", flush=True)
138
148
 
149
+ @retry(Exception, tries=2, delay=2)
139
150
  def logScript(self, execution_info: Dict):
140
151
  r = self.request(
141
152
  method="POST",
@@ -171,6 +182,14 @@ class FastbotManager:
171
182
  if self.options.profile_period:
172
183
  shell_command += ["--profile-period", f"{self.options.profile_period}"]
173
184
 
185
+ whitelist = self.options.act_whitelist_file
186
+ blacklist = self.options.act_blacklist_file
187
+ if bool(whitelist) ^ bool(blacklist):
188
+ if whitelist:
189
+ shell_command += ["--act-whitelist-file", f"{whitelist}"]
190
+ else:
191
+ shell_command += ["--act-blacklist-file", f"{blacklist}"]
192
+
174
193
  shell_command += ["-v", "-v", "-v"]
175
194
 
176
195
  full_cmd = ["adb"] + (["-s", self.options.serial] if self.options.serial else []) + ["shell"] + shell_command
@@ -182,12 +201,7 @@ class FastbotManager:
182
201
  logger.info("Launching fastbot with shell command:\n{}".format(" ".join(full_cmd)))
183
202
  logger.info("Fastbot log will be saved to {}".format(outfile.name))
184
203
 
185
- # stream = self.dev.shell(shell_command, encoding="utf-8", stream=True, timeout=float("inf"))
186
- # process handler
187
204
  t = self.dev.stream_shell(shell_command, stdout=outfile, stderr=outfile)
188
- # proc = subprocess.Popen(full_cmd, stdout=outfile, stderr=outfile)
189
- # t = threading.Thread(target=self.close_on_exit, args=(proc, outfile), daemon=True)
190
- # t.start()
191
205
  return t
192
206
 
193
207
  def close_on_exit(self, proc: ADBStreamShell_V2, f: IO):
@@ -203,6 +217,8 @@ class FastbotManager:
203
217
  return self.thread.poll()
204
218
 
205
219
  def start(self):
220
+ # kill the fastbot process if runing.
221
+ self.dev.kill_proc("com.android.commands.monkey")
206
222
  self.thread = self._activateFastbot()
207
223
 
208
224
  def join(self):
@@ -9,14 +9,15 @@ import random
9
9
  import warnings
10
10
  from dataclasses import dataclass, asdict
11
11
  import requests
12
- from .absDriver import AbstractDriver
12
+ from kea2.absDriver import AbstractDriver
13
13
  from functools import wraps
14
- from .bug_report_generator import BugReportGenerator
15
- from .resultSyncer import ResultSyncer
16
- from .logWatcher import LogWatcher
17
- from .utils import TimeStamp, getProjectRoot, getLogger
18
- from .u2Driver import StaticU2UiObject
19
- from .fastbotManager import FastbotManager
14
+ from kea2.bug_report_generator import BugReportGenerator
15
+ from kea2.resultSyncer import ResultSyncer
16
+ from kea2.logWatcher import LogWatcher
17
+ from kea2.utils import TimeStamp, getProjectRoot, getLogger
18
+ from kea2.u2Driver import StaticU2UiObject
19
+ from kea2.fastbotManager import FastbotManager
20
+ from kea2.adbUtils import ADBDevice
20
21
  import uiautomator2 as u2
21
22
  import types
22
23
 
@@ -133,6 +134,10 @@ class Options:
133
134
  device_output_root: str = "/sdcard"
134
135
  # the debug mode
135
136
  debug: bool = False
137
+ # Activity WhiteList File
138
+ act_whitelist_file: str = None
139
+ # Activity BlackList File
140
+ act_blacklist_file: str = None
136
141
 
137
142
  def __setattr__(self, name, value):
138
143
  if value is None:
@@ -149,6 +154,7 @@ class Options:
149
154
  if self.transport_id:
150
155
  target_device["transport_id"] = self.transport_id
151
156
  self.Driver.setDevice(target_device)
157
+ ADBDevice.setDevice(self.serial, self.transport_id)
152
158
  global LOGFILE, RESFILE, STAMP
153
159
  if self.log_stamp:
154
160
  illegal_chars = ['/', '\\', ':', '*', '?', '"', '<', '>', '|', '\n', '\r', '\t', '\0']
@@ -170,12 +176,11 @@ class Options:
170
176
  if self.throttle < 0:
171
177
  raise ValueError("--throttle should be greater than or equal to 0")
172
178
 
173
- _check_package_installation(self.serial, self.packageNames)
179
+ _check_package_installation(self.packageNames)
174
180
 
175
181
 
176
- def _check_package_installation(serial, packageNames):
177
- from .adbUtils import get_packages
178
- installed_packages = get_packages(device=serial)
182
+ def _check_package_installation(packageNames):
183
+ installed_packages = set(ADBDevice().list_packages())
179
184
 
180
185
  for package in packageNames:
181
186
  if package not in installed_packages:
@@ -122,6 +122,22 @@ def _set_runner_parser(subparsers: "argparse._SubParsersAction[argparse.Argument
122
122
  help="Take screenshots for every step.",
123
123
  )
124
124
 
125
+ parser.add_argument(
126
+ "--act-whitelist-file",
127
+ dest="act_whitelist_file",
128
+ required=False,
129
+ type=str,
130
+ help="Add Activity Whitelist File.",
131
+ )
132
+
133
+ parser.add_argument(
134
+ "--act-blacklist-file",
135
+ dest="act_blacklist_file",
136
+ required=False,
137
+ type=str,
138
+ help="Add Activity Blacklist File.",
139
+ )
140
+
125
141
  parser.add_argument(
126
142
  "extra",
127
143
  nargs=argparse.REMAINDER,
@@ -195,7 +211,9 @@ def run(args=None):
195
211
  log_stamp=args.log_stamp,
196
212
  profile_period=args.profile_period,
197
213
  take_screenshots=args.take_screenshots,
198
- device_output_root=args.device_output_root
214
+ device_output_root=args.device_output_root,
215
+ act_whitelist_file = args.act_whitelist_file,
216
+ act_blacklist_file=args.act_blacklist_file
199
217
  )
200
218
 
201
219
  KeaTestRunner.setOptions(options)
@@ -0,0 +1,79 @@
1
+ import re
2
+ import os
3
+ import threading
4
+ import time
5
+ from typing import IO
6
+ from kea2.utils import getLogger
7
+
8
+
9
+ logger = getLogger(__name__)
10
+
11
+
12
+ PATTERN_EXCEPTION = re.compile(r"\[Fastbot\].+Internal\serror\n([\s\S]*)")
13
+ PATTERN_STATISTIC = re.compile(r".+Monkey\sis\sover!\n([\s\S]+)")
14
+
15
+
16
+ def thread_excepthook(args):
17
+ print(args.exc_value, flush=True)
18
+ os._exit(1)
19
+
20
+
21
+
22
+ class LogWatcher:
23
+
24
+ def watcher(self, poll_interval=3):
25
+ self.last_pos = 0
26
+
27
+ with open(self.log_file, "r", encoding="utf-8") as fp:
28
+ while not self.end_flag:
29
+ self.read_log(fp)
30
+ time.sleep(poll_interval)
31
+
32
+ time.sleep(0.2)
33
+ self.read_log(fp)
34
+
35
+ def read_log(self, f: IO):
36
+ f.seek(self.last_pos)
37
+ buffer = f.read()
38
+ self.last_pos = f.tell()
39
+
40
+ self.parse_log(buffer)
41
+
42
+ def parse_log(self, content):
43
+ exception_match = PATTERN_EXCEPTION.search(content)
44
+ if exception_match:
45
+ exception_body = exception_match.group(1).strip()
46
+ if exception_body:
47
+ raise RuntimeError(
48
+ "[Error] Fatal Execption while running fastbot:\n" +
49
+ exception_body +
50
+ "\nSee fastbot.log for details."
51
+ )
52
+
53
+ statistic_match = PATTERN_STATISTIC.search(content)
54
+ if statistic_match:
55
+ statistic_body = statistic_match.group(1).strip()
56
+ if statistic_body:
57
+ print(
58
+ "[INFO] Fastbot exit:\n" +
59
+ statistic_body
60
+ , flush=True)
61
+
62
+ def __init__(self, log_file):
63
+ logger.info(f"Watching log: {log_file}")
64
+ self.log_file = log_file
65
+ self.end_flag = False
66
+
67
+ threading.excepthook = thread_excepthook
68
+ self.t = threading.Thread(target=self.watcher, daemon=True)
69
+ self.t.start()
70
+
71
+ def close(self):
72
+ logger.info("Close: LogWatcher")
73
+ self.end_flag = True
74
+ if self.t:
75
+ self.t.join()
76
+
77
+
78
+ if __name__ == "__main__":
79
+ LogWatcher("/Users/atria/Desktop/coding/Kea2/output/res_2025062510_0420056539/fastbot_2025062510_0420056539.log")
@@ -696,6 +696,7 @@
696
696
  x: {
697
697
  type: 'linear',
698
698
  beginAtZero: true,
699
+ max: steps.length > 0 ? Math.max(...steps) : 10,
699
700
  grid: {
700
701
  display: false
701
702
  },
@@ -707,9 +708,12 @@
707
708
  }
708
709
  },
709
710
  ticks: {
710
- stepSize: Math.max(10, Math.ceil(Math.max(...steps) / 10)),
711
+ stepSize: steps.length > 0 ? Math.max(1, Math.ceil(Math.max(...steps) / 10)) : 1,
711
712
  callback: function(value) {
712
- return value;
713
+ if (Number.isInteger(value) && value <= (steps.length > 0 ? Math.max(...steps) : 10)) {
714
+ return value;
715
+ }
716
+ return null;
713
717
  }
714
718
  }
715
719
  },
@@ -285,13 +285,14 @@ class _HindenWidgetFilter:
285
285
 
286
286
 
287
287
  class U2StaticDevice(u2.Device):
288
- def __init__(self, script_driver):
288
+ def __init__(self, script_driver=None):
289
289
  self.xml: etree._Element = None
290
290
  self._script_driver = script_driver
291
291
 
292
292
  def __call__(self, **kwargs):
293
293
  ui = StaticU2UiObject(session=self, selector=u2.Selector(**kwargs))
294
- ui.jsonrpc = self._script_driver.jsonrpc
294
+ if self._script_driver:
295
+ ui.jsonrpc = self._script_driver.jsonrpc
295
296
  return ui
296
297
 
297
298
  @property
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "Kea2-python"
3
- version = "0.2.0"
3
+ version = "0.2.2"
4
4
  description = "A python library for supporting and customizing automated UI testing for mobile apps"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.8"
@@ -1,16 +1,22 @@
1
1
  import unittest
2
- from kea2.u2Driver import _HindenWidgetFilter, U2Driver
2
+ from kea2.u2Driver import U2StaticChecker, U2StaticDevice
3
3
  from lxml import etree
4
4
  from pathlib import Path
5
5
 
6
6
 
7
+
7
8
  XML_PATH = Path(__file__).parent / "hidden_widget_test.xml"
8
9
 
9
10
 
11
+ class U2StaticCheckerForTest(U2StaticChecker):
12
+ def __init__(self):
13
+ self.d = U2StaticDevice(script_driver=None)
14
+
15
+
10
16
  def get_static_checker():
11
17
  xml: etree._ElementTree = etree.parse(XML_PATH)
12
- d = U2Driver.getStaticChecker(xml)
13
- return d
18
+ d = U2StaticCheckerForTest()
19
+ return d.getInstance(xml)
14
20
 
15
21
 
16
22
  class TestHiddenWidget(unittest.TestCase):
Binary file
@@ -1,82 +0,0 @@
1
- import re
2
- import os
3
- import threading
4
- import time
5
- from .utils import getLogger
6
-
7
-
8
- logger = getLogger(__name__)
9
-
10
-
11
- PATTERN_EXCEPTION = re.compile(r"\[Fastbot\].+Internal\serror\n([\s\S]*)")
12
- PATTERN_STATISTIC = re.compile(r".+Monkey\sis\sover!\n([\s\S]+)")
13
-
14
-
15
- def thread_excepthook(args):
16
- print(args.exc_value, flush=True)
17
- os._exit(1)
18
-
19
-
20
-
21
- class LogWatcher:
22
-
23
- def watcher(self, poll_interval=0.5):
24
- self.buffer = ""
25
- self.last_pos = 0
26
-
27
- while not self.end_flag:
28
- self.read_log()
29
- time.sleep(poll_interval)
30
-
31
- time.sleep(0.2)
32
- self.read_log()
33
-
34
- def read_log(self):
35
- with open(self.log_file, 'r', encoding='utf-8') as f:
36
- f.seek(self.last_pos)
37
- new_data = f.read()
38
- self.last_pos = f.tell()
39
-
40
- if new_data:
41
- self.buffer += new_data
42
- self.parse_log()
43
-
44
- def parse_log(self):
45
- buffer = self.buffer
46
- exception_match = PATTERN_EXCEPTION.search(buffer)
47
- if exception_match:
48
- exception_body = exception_match.group(1).strip()
49
- if exception_body:
50
- raise RuntimeError(
51
- "[Error] Execption while running fastbot:\n" +
52
- exception_body +
53
- "\nSee fastbot.log for details."
54
- )
55
- if self.end_flag:
56
- statistic_match = PATTERN_STATISTIC.search(buffer)
57
- if statistic_match:
58
- statistic_body = statistic_match.group(1).strip()
59
- if statistic_body:
60
- print(
61
- "[INFO] Fastbot exit:\n" +
62
- statistic_body
63
- , flush=True)
64
-
65
- def __init__(self, log_file):
66
- logger.info(f"Watching log: {log_file}")
67
- self.log_file = log_file
68
- self.end_flag = False
69
-
70
- threading.excepthook = thread_excepthook
71
- self.t = threading.Thread(target=self.watcher, daemon=True)
72
- self.t.start()
73
-
74
- def close(self):
75
- logger.info("Close: LogWatcher")
76
- self.end_flag = True
77
- if self.t:
78
- self.t.join()
79
-
80
-
81
- if __name__ == "__main__":
82
- LogWatcher("fastbot.log")
File without changes
File without changes
File without changes
File without changes