Kea2-python 1.1.0b1__py3-none-any.whl

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.
Files changed (49) hide show
  1. kea2/__init__.py +8 -0
  2. kea2/absDriver.py +56 -0
  3. kea2/adbUtils.py +554 -0
  4. kea2/assets/config_version.json +16 -0
  5. kea2/assets/fastbot-thirdpart.jar +0 -0
  6. kea2/assets/fastbot_configs/abl.strings +2 -0
  7. kea2/assets/fastbot_configs/awl.strings +3 -0
  8. kea2/assets/fastbot_configs/max.config +7 -0
  9. kea2/assets/fastbot_configs/max.fuzzing.strings +699 -0
  10. kea2/assets/fastbot_configs/max.schema.strings +1 -0
  11. kea2/assets/fastbot_configs/max.strings +3 -0
  12. kea2/assets/fastbot_configs/max.tree.pruning +27 -0
  13. kea2/assets/fastbot_configs/teardown.py +18 -0
  14. kea2/assets/fastbot_configs/widget.block.py +38 -0
  15. kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
  16. kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
  17. kea2/assets/fastbot_libs/x86/libfastbot_native.so +0 -0
  18. kea2/assets/fastbot_libs/x86_64/libfastbot_native.so +0 -0
  19. kea2/assets/framework.jar +0 -0
  20. kea2/assets/kea2-thirdpart.jar +0 -0
  21. kea2/assets/monkeyq.jar +0 -0
  22. kea2/assets/quicktest.py +126 -0
  23. kea2/cli.py +216 -0
  24. kea2/fastbotManager.py +269 -0
  25. kea2/kea2_api.py +166 -0
  26. kea2/keaUtils.py +926 -0
  27. kea2/kea_launcher.py +299 -0
  28. kea2/logWatcher.py +92 -0
  29. kea2/mixin.py +0 -0
  30. kea2/report/__init__.py +0 -0
  31. kea2/report/bug_report_generator.py +879 -0
  32. kea2/report/mixin.py +496 -0
  33. kea2/report/report_merger.py +1066 -0
  34. kea2/report/templates/bug_report_template.html +4028 -0
  35. kea2/report/templates/merged_bug_report_template.html +3602 -0
  36. kea2/report/utils.py +10 -0
  37. kea2/result.py +257 -0
  38. kea2/resultSyncer.py +65 -0
  39. kea2/state.py +22 -0
  40. kea2/typedefs.py +32 -0
  41. kea2/u2Driver.py +612 -0
  42. kea2/utils.py +192 -0
  43. kea2/version_manager.py +102 -0
  44. kea2_python-1.1.0b1.dist-info/METADATA +447 -0
  45. kea2_python-1.1.0b1.dist-info/RECORD +49 -0
  46. kea2_python-1.1.0b1.dist-info/WHEEL +5 -0
  47. kea2_python-1.1.0b1.dist-info/entry_points.txt +2 -0
  48. kea2_python-1.1.0b1.dist-info/licenses/LICENSE +16 -0
  49. kea2_python-1.1.0b1.dist-info/top_level.txt +1 -0
kea2/kea_launcher.py ADDED
@@ -0,0 +1,299 @@
1
+ import sys
2
+ import argparse
3
+ import unittest
4
+ from typing import List
5
+
6
+
7
+ def _set_runner_parser(subparsers: "argparse._SubParsersAction[argparse.ArgumentParser]"):
8
+ parser = subparsers.add_parser("run", help="run kea2")
9
+ parser.add_argument(
10
+ "-s",
11
+ "--serial",
12
+ dest="serial",
13
+ required=False,
14
+ default=None,
15
+ type=str,
16
+ help="The serial of your device. Can be found with `adb devices`",
17
+ )
18
+
19
+ parser.add_argument(
20
+ "-t",
21
+ "--transport-id",
22
+ dest="transport_id",
23
+ required=False,
24
+ default=None,
25
+ type=str,
26
+ help="transport-id of your device, can be found with `adb devices -l`",
27
+ )
28
+
29
+ parser.add_argument(
30
+ "-p",
31
+ "--packages",
32
+ dest="package_names",
33
+ nargs="+",
34
+ type=str,
35
+ required=True,
36
+ help="Specify the target app package name(s) to test (e.g., com.example.app). *Supports multiple packages: `-p pkg1 pkg2 pkg3`*",
37
+ )
38
+
39
+ parser.add_argument(
40
+ "-o",
41
+ "--output-dir",
42
+ dest="output_dir",
43
+ type=str,
44
+ required=False,
45
+ default="output",
46
+ help="The ouput directory for logs and results"
47
+ )
48
+
49
+ parser.add_argument(
50
+ "--agent",
51
+ dest="agent",
52
+ type=str,
53
+ default="u2",
54
+ choices=["native", "u2"],
55
+ help="By default, `u2` is used and supports all the three important features of Kea2. If you hope to run the orignal Fastbot, please use `native`.",
56
+ )
57
+
58
+ parser.add_argument(
59
+ "--running-minutes",
60
+ dest="running_minutes",
61
+ type=int,
62
+ required=False,
63
+ default=10,
64
+ help="The time (in minutes) to run Kea2",
65
+ )
66
+
67
+ parser.add_argument(
68
+ "--max-step",
69
+ dest="max_step",
70
+ type=int,
71
+ required=False,
72
+ help="The maxium number of monkey events to send (only available in `--agent u2`)",
73
+ )
74
+
75
+ parser.add_argument(
76
+ "--throttle",
77
+ dest="throttle_ms",
78
+ type=int,
79
+ required=False,
80
+ help="The delay time (in milliseconds) between two monkey events",
81
+ )
82
+
83
+ parser.add_argument(
84
+ "--driver-name",
85
+ dest="driver_name",
86
+ type=str,
87
+ required=False,
88
+ help="The name of driver used in the kea2's scripts. If `--driver-name d` is specified, you should use `d` to interact with a device, e..g, `self.d(..).click()`. ",
89
+ )
90
+
91
+ parser.add_argument(
92
+ "--log-stamp",
93
+ dest="log_stamp",
94
+ type=str,
95
+ required=False,
96
+ help="the stamp for log file and result file. (e.g., if `--log-stamp 123` is specified, the log files will be named as `fastbot_123.log` and `result_123.json`.)",
97
+ )
98
+
99
+ parser.add_argument(
100
+ "--profile-period",
101
+ dest="profile_period",
102
+ type=int,
103
+ required=False,
104
+ default=25,
105
+ help="The period (in the numbers of monkey events) to profile coverage and collect UI screenshots. Specifically, the UI screenshots are stored on the SDcard of the mobile device, and thus you need to set an appropriate value according to the available device storage.",
106
+ )
107
+
108
+
109
+ parser.add_argument(
110
+ "--take-screenshots",
111
+ dest="take_screenshots",
112
+ required=False,
113
+ action="store_true",
114
+ default=False,
115
+ help="Take the UI screenshot at every Monkey event. The screenshots will be automatically pulled from the mobile device to your host machine periodically",
116
+ )
117
+
118
+ parser.add_argument(
119
+ "--pre-failure-screenshots",
120
+ dest="pre_failure_screenshots",
121
+ type=int,
122
+ required=False,
123
+ default=0,
124
+ help="Dump n screenshots before failure. 0 means take screenshots for every step.",
125
+ )
126
+
127
+ parser.add_argument(
128
+ "--post-failure-screenshots",
129
+ dest="post_failure_screenshots",
130
+ type=int,
131
+ required=False,
132
+ default=0,
133
+ help="Dump n screenshots after failure. Should be smaller than --pre-failure-screenshots.",
134
+ )
135
+
136
+ parser.add_argument(
137
+ "--device-output-root",
138
+ dest="device_output_root",
139
+ type=str,
140
+ required=False,
141
+ default="/sdcard",
142
+ help="The root of device output dir. Kea2 will temporarily save the screenshots and result log into `<device-output-root>/output_*********/`. Make sure the root dir can be access.",
143
+ )
144
+
145
+ parser.add_argument(
146
+ "--act-whitelist-file",
147
+ dest="act_whitelist_file",
148
+ required=False,
149
+ type=str,
150
+ help="Activity WhiteList File. Only the activities listed in the file can be explored during testing.",
151
+ )
152
+
153
+ parser.add_argument(
154
+ "--act-blacklist-file",
155
+ dest="act_blacklist_file",
156
+ required=False,
157
+ type=str,
158
+ help="Activity BlackList File. The activities listed in the file will be avoided during testing.",
159
+ )
160
+
161
+ parser.add_argument(
162
+ "--restart-app-period",
163
+ dest="restart_app_period",
164
+ type=int,
165
+ required=False,
166
+ default=0,
167
+ help="The period (in the numbers of monkey events) to restart the app under test. 0 means no restart.",
168
+ )
169
+
170
+ parser.add_argument(
171
+ "extra",
172
+ nargs=argparse.REMAINDER,
173
+ help="Extra args (e.g. propertytest & --). See docs (https://github.com/ecnusse/Kea2/blob/main/docs/manual_en.md) for details.",
174
+ )
175
+
176
+
177
+ def extra_args_info_logger(args):
178
+ if args.agent == "native":
179
+ print("[Warning] Property not availble in native agent.", flush=True)
180
+ if args.unittest_args:
181
+ print("Captured unittest args:", args.unittest_args, flush=True)
182
+ if args.propertytest_args:
183
+ print("Captured propertytest args:", args.propertytest_args, flush=True)
184
+ if args.extra:
185
+ print("Captured extra args (Will be appended to fastbot launcher):", args.extra, flush=True)
186
+
187
+
188
+ def driver_info_logger(args):
189
+ print("[INFO] Driver Settings:", flush=True)
190
+ if args.serial:
191
+ print(" serial:", args.serial, flush=True)
192
+ if args.transport_id:
193
+ print(" transport_id:", args.transport_id, flush=True)
194
+ if args.package_names:
195
+ print(" package_names:", args.package_names, flush=True)
196
+ if args.agent:
197
+ print(" agent:", args.agent, flush=True)
198
+ if args.running_minutes:
199
+ print(" running_minutes:", args.running_minutes, flush=True)
200
+ if args.throttle_ms:
201
+ print(" throttle_ms:", args.throttle_ms, flush=True)
202
+ if args.log_stamp:
203
+ print(" log_stamp:", args.log_stamp, flush=True)
204
+ if args.take_screenshots:
205
+ print(" take_screenshots:", args.take_screenshots, flush=True)
206
+ if args.pre_failure_screenshots:
207
+ print(" pre_failure_screenshots:", args.pre_failure_screenshots, flush=True)
208
+ if args.post_failure_screenshots:
209
+ print(" post_failure_screenshots:", args.post_failure_screenshots, flush=True)
210
+ if args.max_step:
211
+ print(" max_step:", args.max_step, flush=True)
212
+ if args.restart_app_period > 0:
213
+ print(" restart_app_period:", args.restart_app_period, flush=True)
214
+
215
+
216
+ def parse_args(argv: List):
217
+ parser = argparse.ArgumentParser(description="Kea2")
218
+ subparsers = parser.add_subparsers(dest="command", required=True)
219
+
220
+ _set_runner_parser(subparsers)
221
+ args = parser.parse_args(argv)
222
+ return args
223
+
224
+
225
+ def _sanitize_args(args):
226
+ args.mode = None
227
+ args.propertytest_args = None
228
+ if args.agent == "u2" and not args.driver_name:
229
+ if args.extra == []:
230
+ args.driver_name = "d"
231
+ else:
232
+ raise ValueError("--driver-name should be specified when customizing script in --agent u2")
233
+
234
+ extra_args = {
235
+ "unittest": [],
236
+ "propertytest": [],
237
+ "extra": []
238
+ }
239
+
240
+ for i in range(len(args.extra)):
241
+ if args.extra[i] == "unittest":
242
+ current = "unittest"
243
+ elif args.extra[i] == "propertytest":
244
+ current = "propertytest"
245
+ elif args.extra[i] == "--":
246
+ current = "extra"
247
+ else:
248
+ extra_args[current].append(args.extra[i])
249
+ setattr(args, "unittest_args", [])
250
+ setattr(args, "propertytest_args", [])
251
+ args.unittest_args = extra_args["unittest"]
252
+ args.propertytest_args = extra_args["propertytest"]
253
+ args.extra = extra_args["extra"]
254
+
255
+
256
+ def run(args=None):
257
+ if args is None:
258
+ args = parse_args(sys.argv[1:])
259
+ _sanitize_args(args)
260
+ driver_info_logger(args)
261
+ extra_args_info_logger(args)
262
+
263
+ from kea2 import KeaTestRunner, HybridTestRunner, Options, keaTestLoader
264
+ from kea2.u2Driver import U2Driver
265
+ options = Options(
266
+ agent=args.agent,
267
+ driverName=args.driver_name,
268
+ Driver=U2Driver,
269
+ packageNames=args.package_names,
270
+ serial=args.serial,
271
+ transport_id=args.transport_id,
272
+ running_mins=args.running_minutes,
273
+ maxStep=args.max_step,
274
+ throttle=args.throttle_ms,
275
+ output_dir=args.output_dir,
276
+ log_stamp=args.log_stamp,
277
+ profile_period=args.profile_period,
278
+ take_screenshots=args.take_screenshots,
279
+ pre_failure_screenshots=args.pre_failure_screenshots,
280
+ post_failure_screenshots=args.post_failure_screenshots,
281
+ device_output_root=args.device_output_root,
282
+ act_whitelist_file=args.act_whitelist_file,
283
+ act_blacklist_file=args.act_blacklist_file,
284
+ restart_app_period=args.restart_app_period,
285
+ propertytest_args=args.propertytest_args,
286
+ unittest_args=args.unittest_args,
287
+ extra_args=args.extra,
288
+ )
289
+
290
+ is_hybrid_test = True if options.unittest_args else False
291
+ if is_hybrid_test:
292
+ HybridTestRunner.setOptions(options)
293
+ testRunner = HybridTestRunner
294
+ argv = ["python3 -m unittest"] + options.unittest_args
295
+ if not is_hybrid_test or options.agent == "u2":
296
+ KeaTestRunner.setOptions(options)
297
+ testRunner = KeaTestRunner
298
+ argv = ["python3 -m unittest"] + options.propertytest_args
299
+ unittest.main(module=None, argv=argv, testRunner=testRunner, testLoader=keaTestLoader)
kea2/logWatcher.py ADDED
@@ -0,0 +1,92 @@
1
+ import re
2
+ import os
3
+ import threading
4
+ import time
5
+
6
+ from typing import IO
7
+ from .utils import getLogger
8
+
9
+
10
+ logger = getLogger(__name__)
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
+ class LogWatcher:
22
+
23
+ def watcher(self, poll_interval=3):
24
+ self.last_pos = 0
25
+
26
+ with open(self.log_file, "r", encoding="utf-8") as fp:
27
+ while not self.end_flag:
28
+ self.read_log(fp)
29
+ time.sleep(poll_interval)
30
+
31
+ time.sleep(0.2)
32
+ self.read_log(fp)
33
+
34
+ def read_log(self, f: IO):
35
+ f.seek(self.last_pos)
36
+ buffer = f.read()
37
+ self.last_pos = f.tell()
38
+
39
+ self.parse_log(buffer)
40
+
41
+ def parse_log(self, content):
42
+ exception_match = PATTERN_EXCEPTION.search(content)
43
+ if exception_match:
44
+ exception_body = exception_match.group(1).strip()
45
+ if exception_body:
46
+ raise RuntimeError(
47
+ "[Error] Fatal Execption while running fastbot:\n" +
48
+ exception_body +
49
+ f"\nSee {self.log_file} for details."
50
+ )
51
+
52
+ statistic_match = PATTERN_STATISTIC.search(content)
53
+ if statistic_match and not self.statistic_printed:
54
+ statistic_body = statistic_match.group(1).strip()
55
+ if statistic_body:
56
+ self.statistic_printed = True
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
+ self.statistic_printed = False
67
+
68
+ threading.excepthook = thread_excepthook
69
+ self.t = threading.Thread(target=self.watcher, daemon=True)
70
+ self.t.start()
71
+
72
+ def close(self):
73
+ logger.info("Close: LogWatcher")
74
+ self.end_flag = True
75
+ if self.t:
76
+ self.t.join()
77
+
78
+ if not self.statistic_printed:
79
+ self._parse_whole_log()
80
+
81
+ def _parse_whole_log(self):
82
+ logger.warning(
83
+ "LogWatcher closed without reading the statistics, parsing the whole log now."
84
+ )
85
+ with open(self.log_file, "r", encoding="utf-8") as fp:
86
+ content = fp.read()
87
+ self.parse_log(content)
88
+
89
+
90
+ if __name__ == "__main__":
91
+ # LogWatcher()
92
+ pass
kea2/mixin.py ADDED
File without changes
File without changes