Kea2-python 1.0.6b0__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.

Potentially problematic release.


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

Files changed (52) hide show
  1. kea2/__init__.py +3 -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 +320 -0
  24. kea2/fastbotManager.py +267 -0
  25. kea2/fastbotx/ActivityTimes.py +52 -0
  26. kea2/fastbotx/ReuseEntry.py +74 -0
  27. kea2/fastbotx/ReuseModel.py +63 -0
  28. kea2/fastbotx/__init__.py +7 -0
  29. kea2/fbm_parser.py +871 -0
  30. kea2/fs_lock.py +131 -0
  31. kea2/kea2_api.py +166 -0
  32. kea2/keaUtils.py +1112 -0
  33. kea2/kea_launcher.py +319 -0
  34. kea2/logWatcher.py +92 -0
  35. kea2/mixin.py +22 -0
  36. kea2/report/__init__.py +0 -0
  37. kea2/report/bug_report_generator.py +793 -0
  38. kea2/report/mixin.py +482 -0
  39. kea2/report/report_merger.py +797 -0
  40. kea2/report/templates/bug_report_template.html +3876 -0
  41. kea2/report/templates/merged_bug_report_template.html +3333 -0
  42. kea2/report/utils.py +10 -0
  43. kea2/resultSyncer.py +65 -0
  44. kea2/u2Driver.py +610 -0
  45. kea2/utils.py +184 -0
  46. kea2/version_manager.py +102 -0
  47. kea2_python-1.0.6b0.dist-info/METADATA +447 -0
  48. kea2_python-1.0.6b0.dist-info/RECORD +52 -0
  49. kea2_python-1.0.6b0.dist-info/WHEEL +5 -0
  50. kea2_python-1.0.6b0.dist-info/entry_points.txt +2 -0
  51. kea2_python-1.0.6b0.dist-info/licenses/LICENSE +16 -0
  52. kea2_python-1.0.6b0.dist-info/top_level.txt +1 -0
kea2/kea_launcher.py ADDED
@@ -0,0 +1,319 @@
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
+ # FBM sync options
146
+ parser.add_argument(
147
+ "--download-fbm",
148
+ dest="download_fbm",
149
+ action="store_true",
150
+ required=False,
151
+ help="When set, pull device FBM(s) at start, merge with PC FBM and push merged back to device",
152
+ )
153
+
154
+ parser.add_argument(
155
+ "--upload-fbm",
156
+ dest="upload_fbm",
157
+ action="store_true",
158
+ required=False,
159
+ help="When set, after run finishes pull device FBM(s) and merge into PC storage",
160
+ )
161
+
162
+ parser.add_argument(
163
+ "--act-whitelist-file",
164
+ dest="act_whitelist_file",
165
+ required=False,
166
+ type=str,
167
+ help="Activity WhiteList File. Only the activities listed in the file can be explored during testing.",
168
+ )
169
+
170
+ parser.add_argument(
171
+ "--act-blacklist-file",
172
+ dest="act_blacklist_file",
173
+ required=False,
174
+ type=str,
175
+ help="Activity BlackList File. The activities listed in the file will be avoided during testing.",
176
+ )
177
+
178
+ parser.add_argument(
179
+ "--restart-app-period",
180
+ dest="restart_app_period",
181
+ type=int,
182
+ required=False,
183
+ default=0,
184
+ help="The period (in the numbers of monkey events) to restart the app under test. 0 means no restart.",
185
+ )
186
+
187
+ parser.add_argument(
188
+ "extra",
189
+ nargs=argparse.REMAINDER,
190
+ help="Extra args (e.g. propertytest & --). See docs (https://github.com/ecnusse/Kea2/blob/main/docs/manual_en.md) for details.",
191
+ )
192
+
193
+
194
+ def extra_args_info_logger(args):
195
+ if args.agent == "native":
196
+ print("[Warning] Property not availble in native agent.", flush=True)
197
+ if args.unittest_args:
198
+ print("Captured unittest args:", args.unittest_args, flush=True)
199
+ if args.propertytest_args:
200
+ print("Captured propertytest args:", args.propertytest_args, flush=True)
201
+ if args.extra:
202
+ print("Captured extra args (Will be appended to fastbot launcher):", args.extra, flush=True)
203
+
204
+
205
+ def driver_info_logger(args):
206
+ print("[INFO] Driver Settings:", flush=True)
207
+ if args.serial:
208
+ print(" serial:", args.serial, flush=True)
209
+ if args.transport_id:
210
+ print(" transport_id:", args.transport_id, flush=True)
211
+ if args.package_names:
212
+ print(" package_names:", args.package_names, flush=True)
213
+ if args.agent:
214
+ print(" agent:", args.agent, flush=True)
215
+ if args.running_minutes:
216
+ print(" running_minutes:", args.running_minutes, flush=True)
217
+ if args.throttle_ms:
218
+ print(" throttle_ms:", args.throttle_ms, flush=True)
219
+ if args.log_stamp:
220
+ print(" log_stamp:", args.log_stamp, flush=True)
221
+ if args.take_screenshots:
222
+ print(" take_screenshots:", args.take_screenshots, flush=True)
223
+ if args.pre_failure_screenshots:
224
+ print(" pre_failure_screenshots:", args.pre_failure_screenshots, flush=True)
225
+ if args.post_failure_screenshots:
226
+ print(" post_failure_screenshots:", args.post_failure_screenshots, flush=True)
227
+ if args.max_step:
228
+ print(" max_step:", args.max_step, flush=True)
229
+ if args.restart_app_period > 0:
230
+ print(" restart_app_period:", args.restart_app_period, flush=True)
231
+
232
+
233
+ def parse_args(argv: List):
234
+ parser = argparse.ArgumentParser(description="Kea2")
235
+ subparsers = parser.add_subparsers(dest="command", required=True)
236
+
237
+ _set_runner_parser(subparsers)
238
+ args = parser.parse_args(argv)
239
+ return args
240
+
241
+
242
+ def _sanitize_args(args):
243
+ args.mode = None
244
+ args.propertytest_args = None
245
+ if args.agent == "u2" and not args.driver_name:
246
+ if args.extra == []:
247
+ args.driver_name = "d"
248
+ else:
249
+ raise ValueError("--driver-name should be specified when customizing script in --agent u2")
250
+
251
+ extra_args = {
252
+ "unittest": [],
253
+ "propertytest": [],
254
+ "extra": []
255
+ }
256
+
257
+ for i in range(len(args.extra)):
258
+ if args.extra[i] == "unittest":
259
+ current = "unittest"
260
+ elif args.extra[i] == "propertytest":
261
+ current = "propertytest"
262
+ elif args.extra[i] == "--":
263
+ current = "extra"
264
+ else:
265
+ extra_args[current].append(args.extra[i])
266
+ setattr(args, "unittest_args", [])
267
+ setattr(args, "propertytest_args", [])
268
+ args.unittest_args = extra_args["unittest"]
269
+ args.propertytest_args = extra_args["propertytest"]
270
+ args.extra = extra_args["extra"]
271
+
272
+
273
+ def run(args=None):
274
+ if args is None:
275
+ args = parse_args(sys.argv[1:])
276
+ _sanitize_args(args)
277
+ driver_info_logger(args)
278
+ extra_args_info_logger(args)
279
+
280
+ from kea2 import KeaTestRunner, Options, HybridTestRunner
281
+ from kea2.u2Driver import U2Driver
282
+ options = Options(
283
+ agent=args.agent,
284
+ driverName=args.driver_name,
285
+ Driver=U2Driver,
286
+ packageNames=args.package_names,
287
+ serial=args.serial,
288
+ transport_id=args.transport_id,
289
+ running_mins=args.running_minutes,
290
+ maxStep=args.max_step,
291
+ throttle=args.throttle_ms,
292
+ output_dir=args.output_dir,
293
+ log_stamp=args.log_stamp,
294
+ profile_period=args.profile_period,
295
+ take_screenshots=args.take_screenshots,
296
+ pre_failure_screenshots=args.pre_failure_screenshots,
297
+ post_failure_screenshots=args.post_failure_screenshots,
298
+ device_output_root=args.device_output_root,
299
+ act_whitelist_file=args.act_whitelist_file,
300
+ act_blacklist_file=args.act_blacklist_file,
301
+ restart_app_period=args.restart_app_period,
302
+ propertytest_args=args.propertytest_args,
303
+ unittest_args=args.unittest_args,
304
+ extra_args=args.extra,
305
+ upload_fbm=getattr(args, 'upload_fbm', False),
306
+ download_fbm=getattr(args, 'download_fbm', False),
307
+ )
308
+
309
+
310
+ is_hybrid_test = True if options.unittest_args else False
311
+ if is_hybrid_test:
312
+ HybridTestRunner.setOptions(options)
313
+ testRunner = HybridTestRunner
314
+ argv = ["python3 -m unittest"] + options.unittest_args
315
+ if not is_hybrid_test or options.agent == "u2":
316
+ KeaTestRunner.setOptions(options)
317
+ testRunner = KeaTestRunner
318
+ argv = ["python3 -m unittest"] + options.propertytest_args
319
+ unittest.main(module=None, argv=argv, testRunner=testRunner)
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
@@ -0,0 +1,22 @@
1
+ from unittest import TextTestResult, TestCase
2
+
3
+
4
+ class BetterConsoleLogExtensionMixin:
5
+ def __init__(self, stream, descriptions, verbosity):
6
+ super().__init__(stream, descriptions, verbosity)
7
+ self.showAll = True
8
+
9
+ def getDescription(self: "TextTestResult", test: "TestCase"):
10
+ doc_first_line = test.shortDescription()
11
+ if self.descriptions and doc_first_line:
12
+ doc_first_line = "# " + doc_first_line
13
+ return '\n'.join((str(test), doc_first_line))
14
+ else:
15
+ return str(test)
16
+
17
+ def startTest(self: "TextTestResult", test):
18
+ if self.showAll:
19
+ self.stream.write("[INFO] Start executing property: ")
20
+ self.stream.writeln(self.getDescription(test))
21
+ self.stream.flush()
22
+ self._newline = True
File without changes