Kea2-python 0.0.1b2__tar.gz → 0.0.1b3__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.
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/PKG-INFO +54 -12
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/PKG-INFO +54 -12
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/README.md +53 -11
- kea2_python-0.0.1b3/kea2/assets/fastbot_configs/widget.block.py +38 -0
- kea2_python-0.0.1b3/kea2/assets/monkeyq.jar +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/keaUtils.py +80 -31
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/logWatcher.py +11 -8
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/pyproject.toml +1 -1
- kea2_python-0.0.1b2/kea2/assets/fastbot_configs/widget.block.py +0 -18
- kea2_python-0.0.1b2/kea2/assets/monkeyq.jar +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/SOURCES.txt +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/dependency_links.txt +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/entry_points.txt +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/requires.txt +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/top_level.txt +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/LICENSE +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/__init__.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/absDriver.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/adbUtils.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot-thirdpart.jar +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/abl.strings +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/awl.strings +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.config +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.fuzzing.strings +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.schema.strings +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.strings +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.tree.pruning +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/x86/libfastbot_native.so +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/x86_64/libfastbot_native.so +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/framework.jar +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/quicktest.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/u2.jar +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/cli.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/kea_launcher.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/u2Driver.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/utils.py +0 -0
- {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Kea2-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1b3
|
|
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
|
<img src="https://github.com/user-attachments/assets/58f68b00-cc9c-4620-9e2e-66c43cf7caae" style="border-radius: 14px; width: 20%; height: 20%;"/>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
|
-
Kea2 is an easy-to-use Python library for supporting, customizing and improving automated UI testing for mobile apps.
|
|
23
|
+
Kea2 is an easy-to-use Python library for supporting, customizing and improving automated UI testing for mobile apps. Kea2's novelty is able to fuse the scripts (usually written by human) with automated UI testing tools, thus allowing many interesting and powerful features. Kea2 is currently built on top of [Fastbot](https://github.com/bytedance/Fastbot_Android) and [uiautomator2](https://github.com/openatx/uiautomator2) and targets [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) apps.
|
|
24
24
|
|
|
25
25
|
### Kea2 has three important features:
|
|
26
26
|
- **Feature 1**(查找稳定性问题): coming with the full capability of [Fastbot](https://github.com/bytedance/Fastbot_Android) for stress testing and finding *stability problems* (i.e., *crashing bugs*);
|
|
@@ -49,7 +49,7 @@ Kea2, released as a Python library, currently works with:
|
|
|
49
49
|
- [uiautomator2](https://github.com/openatx/uiautomator2) as the UI test driver;
|
|
50
50
|
- [Fastbot](https://github.com/bytedance/Fastbot_Android) as the backend automated UI testing tool.
|
|
51
51
|
|
|
52
|
-
In the future, Kea2 will be extended to support
|
|
52
|
+
**Roadmap**: In the future, Kea2 will be extended to support
|
|
53
53
|
- [pytest](https://docs.pytest.org/en/stable/)
|
|
54
54
|
- [Appium](https://github.com/appium/appium), [Hypium]() (for HarmonyOS)
|
|
55
55
|
- other automated UI testing tools (not limited to Fastbot)
|
|
@@ -175,20 +175,31 @@ You can find the full example in script `quicktest.py`, and run this script with
|
|
|
175
175
|
kea2 run -s "emulator-5554" -p it.feio.android.omninotes.alpha --agent u2 --running-minutes 10 --throttle 200 --driver-name d unittest discover -p quicktest.py
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
### Example 2: blacklisting specific UI
|
|
178
|
+
### Example 2: blacklisting specific UI elements
|
|
179
179
|
|
|
180
|
-
We support blacklisting specific
|
|
180
|
+
We support blacklisting specific elements so that Fastbot can avoid interacting with these
|
|
181
|
+
elements during fuzzing.
|
|
181
182
|
|
|
182
|
-
|
|
183
|
-
The widgets needed to be blocked can be flexibly specified by u2 selector (e.g., `text`, `description`) or `xpath`, etc.
|
|
183
|
+
We support two granularity levels for UI blocking:
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
- Widget Blocking: Block individual UI widgets.
|
|
186
|
+
|
|
187
|
+
- Tree Blocking : Block a UI widget trees by specifying its root node.
|
|
188
|
+
It can block the root node and all its descendants.
|
|
189
|
+
|
|
190
|
+
We support (1) `Global Block List` (always taking effective), and (2) `Conditional Block List` (only taking effective when some conditions are met).
|
|
191
|
+
|
|
192
|
+
The list of blocked elements are specified in Kea2's config file `configs/widget.block.py` (generated when running `kea2 init`).
|
|
193
|
+
The elements needed to be blocked can be flexibly specified by u2 selector (e.g., `text`, `description`) or `xpath`, etc.
|
|
194
|
+
|
|
195
|
+
#### Widget Blocking
|
|
196
|
+
##### Global Block List
|
|
186
197
|
We can define the function `global_block_widgets` to specify which UI widgets should be blocked globally. The blocking always takes effect.
|
|
187
198
|
|
|
188
199
|
```python
|
|
189
200
|
# file: configs/widget.block.py
|
|
190
201
|
|
|
191
|
-
|
|
202
|
+
def global_block_widgets(d: "Device"):
|
|
192
203
|
"""
|
|
193
204
|
global block list.
|
|
194
205
|
return the widgets which should be blocked globally
|
|
@@ -197,8 +208,8 @@ We can define the function `global_block_widgets` to specify which UI widgets sh
|
|
|
197
208
|
d.xpath(".//node[@text='widget to block']"),
|
|
198
209
|
d(description="widgets to block")]
|
|
199
210
|
```
|
|
200
|
-
|
|
201
|
-
We can define any reserved function whose name starts with "block_" and decorate such function by `@precondition` to allow conditional block list.
|
|
211
|
+
##### Conditional Block List
|
|
212
|
+
We can define any reserved function whose name starts with "block_" (but not requiring "block_tree_" prefix) and decorate such function by `@precondition` to allow conditional block list.
|
|
202
213
|
In this case, the blocking only takes effect when the precondition is satisfied.
|
|
203
214
|
```python
|
|
204
215
|
# file: configs/widget.block.py
|
|
@@ -212,6 +223,37 @@ def block_sth(d: "Device"):
|
|
|
212
223
|
d(description="widgets to block")]
|
|
213
224
|
```
|
|
214
225
|
|
|
226
|
+
#### Tree Blocking
|
|
227
|
+
##### Global Block List
|
|
228
|
+
We can define the function `global_block_tree` to specify which UI widget trees should be blocked globally. The blocking always takes effect.
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
# file: configs/widget.block.py
|
|
232
|
+
|
|
233
|
+
def global_block_tree(d: "Device"):
|
|
234
|
+
"""
|
|
235
|
+
Specify UI widget trees to be blocked globally during testing.
|
|
236
|
+
Returns a list of root nodes whose entire subtrees will be blocked from exploration.
|
|
237
|
+
This function is only available in 'u2 agent' mode.
|
|
238
|
+
"""
|
|
239
|
+
return [d(text="trees to block"), d.xpath(".//node[@text='tree to block']")]
|
|
240
|
+
```
|
|
241
|
+
##### Conditional Block List
|
|
242
|
+
We can define any reserved function whose name starts with "block_tree_" and decorate such function by `@precondition` to allow conditional block list.
|
|
243
|
+
In this case, the blocking only takes effect when the precondition is satisfied.
|
|
244
|
+
```python
|
|
245
|
+
# file: configs/widget.block.py
|
|
246
|
+
|
|
247
|
+
# Example of conditional tree blocking with precondition
|
|
248
|
+
|
|
249
|
+
@precondition(lambda d: d(text="In the home page").exists)
|
|
250
|
+
def block_tree_sth(d: "Device"):
|
|
251
|
+
# Note: Function name must start with "block_tree_"
|
|
252
|
+
return [d(text="trees to block"),
|
|
253
|
+
d.xpath(".//node[@text='tree to block']"),
|
|
254
|
+
d(description="trees to block")]
|
|
255
|
+
```
|
|
256
|
+
|
|
215
257
|
## Feature 3(支持断言机制): Supporting auto-assertions by scripts.
|
|
216
258
|
|
|
217
259
|
Kea2 supports auto-assertions when running Fastbot for finding *logic bugs* (i.e., *non-crashing bugs*). To achieve this, you can add assertions in the scripts. When an assertion fails during automated UI testing, we find a likely functional bug. This idea is inspired by [property-based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing) inheritted from [Kea](https://github.com/ecnusse/Kea).
|
|
@@ -339,7 +381,7 @@ kea2 run -s "emulator-5554" -p it.feio.android.omninotes.alpha --agent u2 --runn
|
|
|
339
381
|
| --max-step | The maxium number of monkey events to send (only available in `--agent u2`) | `inf` |
|
|
340
382
|
| --throttle | The delay time (ms) between two monkey events | `200` |
|
|
341
383
|
| --driver-name | The name of driver used in the script. If `--driver-name d` is specified, you should use `d` to interact with a device, e..g, `self.d(..).click()`. |
|
|
342
|
-
| --log-stamp | the stamp for log file and result file
|
|
384
|
+
| --log-stamp | the stamp for log file and result file. (e.g. `--log-stamp 123` then `fastbot_123.log` and `result_123.json` will be generated.) default: current time stamp | |
|
|
343
385
|
| unittest | Specify to load which scripts. This sub-command `unittest` is fully compatible with unittest. See `python3 -m unittest -h` for more options of unittest. This option is only available in `--agent u2`.
|
|
344
386
|
|
|
345
387
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: Kea2-python
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1b3
|
|
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
|
<img src="https://github.com/user-attachments/assets/58f68b00-cc9c-4620-9e2e-66c43cf7caae" style="border-radius: 14px; width: 20%; height: 20%;"/>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
|
-
Kea2 is an easy-to-use Python library for supporting, customizing and improving automated UI testing for mobile apps.
|
|
23
|
+
Kea2 is an easy-to-use Python library for supporting, customizing and improving automated UI testing for mobile apps. Kea2's novelty is able to fuse the scripts (usually written by human) with automated UI testing tools, thus allowing many interesting and powerful features. Kea2 is currently built on top of [Fastbot](https://github.com/bytedance/Fastbot_Android) and [uiautomator2](https://github.com/openatx/uiautomator2) and targets [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) apps.
|
|
24
24
|
|
|
25
25
|
### Kea2 has three important features:
|
|
26
26
|
- **Feature 1**(查找稳定性问题): coming with the full capability of [Fastbot](https://github.com/bytedance/Fastbot_Android) for stress testing and finding *stability problems* (i.e., *crashing bugs*);
|
|
@@ -49,7 +49,7 @@ Kea2, released as a Python library, currently works with:
|
|
|
49
49
|
- [uiautomator2](https://github.com/openatx/uiautomator2) as the UI test driver;
|
|
50
50
|
- [Fastbot](https://github.com/bytedance/Fastbot_Android) as the backend automated UI testing tool.
|
|
51
51
|
|
|
52
|
-
In the future, Kea2 will be extended to support
|
|
52
|
+
**Roadmap**: In the future, Kea2 will be extended to support
|
|
53
53
|
- [pytest](https://docs.pytest.org/en/stable/)
|
|
54
54
|
- [Appium](https://github.com/appium/appium), [Hypium]() (for HarmonyOS)
|
|
55
55
|
- other automated UI testing tools (not limited to Fastbot)
|
|
@@ -175,20 +175,31 @@ You can find the full example in script `quicktest.py`, and run this script with
|
|
|
175
175
|
kea2 run -s "emulator-5554" -p it.feio.android.omninotes.alpha --agent u2 --running-minutes 10 --throttle 200 --driver-name d unittest discover -p quicktest.py
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
### Example 2: blacklisting specific UI
|
|
178
|
+
### Example 2: blacklisting specific UI elements
|
|
179
179
|
|
|
180
|
-
We support blacklisting specific
|
|
180
|
+
We support blacklisting specific elements so that Fastbot can avoid interacting with these
|
|
181
|
+
elements during fuzzing.
|
|
181
182
|
|
|
182
|
-
|
|
183
|
-
The widgets needed to be blocked can be flexibly specified by u2 selector (e.g., `text`, `description`) or `xpath`, etc.
|
|
183
|
+
We support two granularity levels for UI blocking:
|
|
184
184
|
|
|
185
|
-
|
|
185
|
+
- Widget Blocking: Block individual UI widgets.
|
|
186
|
+
|
|
187
|
+
- Tree Blocking : Block a UI widget trees by specifying its root node.
|
|
188
|
+
It can block the root node and all its descendants.
|
|
189
|
+
|
|
190
|
+
We support (1) `Global Block List` (always taking effective), and (2) `Conditional Block List` (only taking effective when some conditions are met).
|
|
191
|
+
|
|
192
|
+
The list of blocked elements are specified in Kea2's config file `configs/widget.block.py` (generated when running `kea2 init`).
|
|
193
|
+
The elements needed to be blocked can be flexibly specified by u2 selector (e.g., `text`, `description`) or `xpath`, etc.
|
|
194
|
+
|
|
195
|
+
#### Widget Blocking
|
|
196
|
+
##### Global Block List
|
|
186
197
|
We can define the function `global_block_widgets` to specify which UI widgets should be blocked globally. The blocking always takes effect.
|
|
187
198
|
|
|
188
199
|
```python
|
|
189
200
|
# file: configs/widget.block.py
|
|
190
201
|
|
|
191
|
-
|
|
202
|
+
def global_block_widgets(d: "Device"):
|
|
192
203
|
"""
|
|
193
204
|
global block list.
|
|
194
205
|
return the widgets which should be blocked globally
|
|
@@ -197,8 +208,8 @@ We can define the function `global_block_widgets` to specify which UI widgets sh
|
|
|
197
208
|
d.xpath(".//node[@text='widget to block']"),
|
|
198
209
|
d(description="widgets to block")]
|
|
199
210
|
```
|
|
200
|
-
|
|
201
|
-
We can define any reserved function whose name starts with "block_" and decorate such function by `@precondition` to allow conditional block list.
|
|
211
|
+
##### Conditional Block List
|
|
212
|
+
We can define any reserved function whose name starts with "block_" (but not requiring "block_tree_" prefix) and decorate such function by `@precondition` to allow conditional block list.
|
|
202
213
|
In this case, the blocking only takes effect when the precondition is satisfied.
|
|
203
214
|
```python
|
|
204
215
|
# file: configs/widget.block.py
|
|
@@ -212,6 +223,37 @@ def block_sth(d: "Device"):
|
|
|
212
223
|
d(description="widgets to block")]
|
|
213
224
|
```
|
|
214
225
|
|
|
226
|
+
#### Tree Blocking
|
|
227
|
+
##### Global Block List
|
|
228
|
+
We can define the function `global_block_tree` to specify which UI widget trees should be blocked globally. The blocking always takes effect.
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
# file: configs/widget.block.py
|
|
232
|
+
|
|
233
|
+
def global_block_tree(d: "Device"):
|
|
234
|
+
"""
|
|
235
|
+
Specify UI widget trees to be blocked globally during testing.
|
|
236
|
+
Returns a list of root nodes whose entire subtrees will be blocked from exploration.
|
|
237
|
+
This function is only available in 'u2 agent' mode.
|
|
238
|
+
"""
|
|
239
|
+
return [d(text="trees to block"), d.xpath(".//node[@text='tree to block']")]
|
|
240
|
+
```
|
|
241
|
+
##### Conditional Block List
|
|
242
|
+
We can define any reserved function whose name starts with "block_tree_" and decorate such function by `@precondition` to allow conditional block list.
|
|
243
|
+
In this case, the blocking only takes effect when the precondition is satisfied.
|
|
244
|
+
```python
|
|
245
|
+
# file: configs/widget.block.py
|
|
246
|
+
|
|
247
|
+
# Example of conditional tree blocking with precondition
|
|
248
|
+
|
|
249
|
+
@precondition(lambda d: d(text="In the home page").exists)
|
|
250
|
+
def block_tree_sth(d: "Device"):
|
|
251
|
+
# Note: Function name must start with "block_tree_"
|
|
252
|
+
return [d(text="trees to block"),
|
|
253
|
+
d.xpath(".//node[@text='tree to block']"),
|
|
254
|
+
d(description="trees to block")]
|
|
255
|
+
```
|
|
256
|
+
|
|
215
257
|
## Feature 3(支持断言机制): Supporting auto-assertions by scripts.
|
|
216
258
|
|
|
217
259
|
Kea2 supports auto-assertions when running Fastbot for finding *logic bugs* (i.e., *non-crashing bugs*). To achieve this, you can add assertions in the scripts. When an assertion fails during automated UI testing, we find a likely functional bug. This idea is inspired by [property-based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing) inheritted from [Kea](https://github.com/ecnusse/Kea).
|
|
@@ -339,7 +381,7 @@ kea2 run -s "emulator-5554" -p it.feio.android.omninotes.alpha --agent u2 --runn
|
|
|
339
381
|
| --max-step | The maxium number of monkey events to send (only available in `--agent u2`) | `inf` |
|
|
340
382
|
| --throttle | The delay time (ms) between two monkey events | `200` |
|
|
341
383
|
| --driver-name | The name of driver used in the script. If `--driver-name d` is specified, you should use `d` to interact with a device, e..g, `self.d(..).click()`. |
|
|
342
|
-
| --log-stamp | the stamp for log file and result file
|
|
384
|
+
| --log-stamp | the stamp for log file and result file. (e.g. `--log-stamp 123` then `fastbot_123.log` and `result_123.json` will be generated.) default: current time stamp | |
|
|
343
385
|
| unittest | Specify to load which scripts. This sub-command `unittest` is fully compatible with unittest. See `python3 -m unittest -h` for more options of unittest. This option is only available in `--agent u2`.
|
|
344
386
|
|
|
345
387
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<img src="https://github.com/user-attachments/assets/58f68b00-cc9c-4620-9e2e-66c43cf7caae" style="border-radius: 14px; width: 20%; height: 20%;"/>
|
|
9
9
|
</div>
|
|
10
10
|
|
|
11
|
-
Kea2 is an easy-to-use Python library for supporting, customizing and improving automated UI testing for mobile apps.
|
|
11
|
+
Kea2 is an easy-to-use Python library for supporting, customizing and improving automated UI testing for mobile apps. Kea2's novelty is able to fuse the scripts (usually written by human) with automated UI testing tools, thus allowing many interesting and powerful features. Kea2 is currently built on top of [Fastbot](https://github.com/bytedance/Fastbot_Android) and [uiautomator2](https://github.com/openatx/uiautomator2) and targets [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) apps.
|
|
12
12
|
|
|
13
13
|
### Kea2 has three important features:
|
|
14
14
|
- **Feature 1**(查找稳定性问题): coming with the full capability of [Fastbot](https://github.com/bytedance/Fastbot_Android) for stress testing and finding *stability problems* (i.e., *crashing bugs*);
|
|
@@ -37,7 +37,7 @@ Kea2, released as a Python library, currently works with:
|
|
|
37
37
|
- [uiautomator2](https://github.com/openatx/uiautomator2) as the UI test driver;
|
|
38
38
|
- [Fastbot](https://github.com/bytedance/Fastbot_Android) as the backend automated UI testing tool.
|
|
39
39
|
|
|
40
|
-
In the future, Kea2 will be extended to support
|
|
40
|
+
**Roadmap**: In the future, Kea2 will be extended to support
|
|
41
41
|
- [pytest](https://docs.pytest.org/en/stable/)
|
|
42
42
|
- [Appium](https://github.com/appium/appium), [Hypium]() (for HarmonyOS)
|
|
43
43
|
- other automated UI testing tools (not limited to Fastbot)
|
|
@@ -163,20 +163,31 @@ You can find the full example in script `quicktest.py`, and run this script with
|
|
|
163
163
|
kea2 run -s "emulator-5554" -p it.feio.android.omninotes.alpha --agent u2 --running-minutes 10 --throttle 200 --driver-name d unittest discover -p quicktest.py
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
### Example 2: blacklisting specific UI
|
|
166
|
+
### Example 2: blacklisting specific UI elements
|
|
167
167
|
|
|
168
|
-
We support blacklisting specific
|
|
168
|
+
We support blacklisting specific elements so that Fastbot can avoid interacting with these
|
|
169
|
+
elements during fuzzing.
|
|
169
170
|
|
|
170
|
-
|
|
171
|
-
The widgets needed to be blocked can be flexibly specified by u2 selector (e.g., `text`, `description`) or `xpath`, etc.
|
|
171
|
+
We support two granularity levels for UI blocking:
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
- Widget Blocking: Block individual UI widgets.
|
|
174
|
+
|
|
175
|
+
- Tree Blocking : Block a UI widget trees by specifying its root node.
|
|
176
|
+
It can block the root node and all its descendants.
|
|
177
|
+
|
|
178
|
+
We support (1) `Global Block List` (always taking effective), and (2) `Conditional Block List` (only taking effective when some conditions are met).
|
|
179
|
+
|
|
180
|
+
The list of blocked elements are specified in Kea2's config file `configs/widget.block.py` (generated when running `kea2 init`).
|
|
181
|
+
The elements needed to be blocked can be flexibly specified by u2 selector (e.g., `text`, `description`) or `xpath`, etc.
|
|
182
|
+
|
|
183
|
+
#### Widget Blocking
|
|
184
|
+
##### Global Block List
|
|
174
185
|
We can define the function `global_block_widgets` to specify which UI widgets should be blocked globally. The blocking always takes effect.
|
|
175
186
|
|
|
176
187
|
```python
|
|
177
188
|
# file: configs/widget.block.py
|
|
178
189
|
|
|
179
|
-
|
|
190
|
+
def global_block_widgets(d: "Device"):
|
|
180
191
|
"""
|
|
181
192
|
global block list.
|
|
182
193
|
return the widgets which should be blocked globally
|
|
@@ -185,8 +196,8 @@ We can define the function `global_block_widgets` to specify which UI widgets sh
|
|
|
185
196
|
d.xpath(".//node[@text='widget to block']"),
|
|
186
197
|
d(description="widgets to block")]
|
|
187
198
|
```
|
|
188
|
-
|
|
189
|
-
We can define any reserved function whose name starts with "block_" and decorate such function by `@precondition` to allow conditional block list.
|
|
199
|
+
##### Conditional Block List
|
|
200
|
+
We can define any reserved function whose name starts with "block_" (but not requiring "block_tree_" prefix) and decorate such function by `@precondition` to allow conditional block list.
|
|
190
201
|
In this case, the blocking only takes effect when the precondition is satisfied.
|
|
191
202
|
```python
|
|
192
203
|
# file: configs/widget.block.py
|
|
@@ -200,6 +211,37 @@ def block_sth(d: "Device"):
|
|
|
200
211
|
d(description="widgets to block")]
|
|
201
212
|
```
|
|
202
213
|
|
|
214
|
+
#### Tree Blocking
|
|
215
|
+
##### Global Block List
|
|
216
|
+
We can define the function `global_block_tree` to specify which UI widget trees should be blocked globally. The blocking always takes effect.
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
# file: configs/widget.block.py
|
|
220
|
+
|
|
221
|
+
def global_block_tree(d: "Device"):
|
|
222
|
+
"""
|
|
223
|
+
Specify UI widget trees to be blocked globally during testing.
|
|
224
|
+
Returns a list of root nodes whose entire subtrees will be blocked from exploration.
|
|
225
|
+
This function is only available in 'u2 agent' mode.
|
|
226
|
+
"""
|
|
227
|
+
return [d(text="trees to block"), d.xpath(".//node[@text='tree to block']")]
|
|
228
|
+
```
|
|
229
|
+
##### Conditional Block List
|
|
230
|
+
We can define any reserved function whose name starts with "block_tree_" and decorate such function by `@precondition` to allow conditional block list.
|
|
231
|
+
In this case, the blocking only takes effect when the precondition is satisfied.
|
|
232
|
+
```python
|
|
233
|
+
# file: configs/widget.block.py
|
|
234
|
+
|
|
235
|
+
# Example of conditional tree blocking with precondition
|
|
236
|
+
|
|
237
|
+
@precondition(lambda d: d(text="In the home page").exists)
|
|
238
|
+
def block_tree_sth(d: "Device"):
|
|
239
|
+
# Note: Function name must start with "block_tree_"
|
|
240
|
+
return [d(text="trees to block"),
|
|
241
|
+
d.xpath(".//node[@text='tree to block']"),
|
|
242
|
+
d(description="trees to block")]
|
|
243
|
+
```
|
|
244
|
+
|
|
203
245
|
## Feature 3(支持断言机制): Supporting auto-assertions by scripts.
|
|
204
246
|
|
|
205
247
|
Kea2 supports auto-assertions when running Fastbot for finding *logic bugs* (i.e., *non-crashing bugs*). To achieve this, you can add assertions in the scripts. When an assertion fails during automated UI testing, we find a likely functional bug. This idea is inspired by [property-based testing](https://en.wikipedia.org/wiki/Software_testing#Property_testing) inheritted from [Kea](https://github.com/ecnusse/Kea).
|
|
@@ -327,7 +369,7 @@ kea2 run -s "emulator-5554" -p it.feio.android.omninotes.alpha --agent u2 --runn
|
|
|
327
369
|
| --max-step | The maxium number of monkey events to send (only available in `--agent u2`) | `inf` |
|
|
328
370
|
| --throttle | The delay time (ms) between two monkey events | `200` |
|
|
329
371
|
| --driver-name | The name of driver used in the script. If `--driver-name d` is specified, you should use `d` to interact with a device, e..g, `self.d(..).click()`. |
|
|
330
|
-
| --log-stamp | the stamp for log file and result file
|
|
372
|
+
| --log-stamp | the stamp for log file and result file. (e.g. `--log-stamp 123` then `fastbot_123.log` and `result_123.json` will be generated.) default: current time stamp | |
|
|
331
373
|
| unittest | Specify to load which scripts. This sub-command `unittest` is fully compatible with unittest. See `python3 -m unittest -h` for more options of unittest. This option is only available in `--agent u2`.
|
|
332
374
|
|
|
333
375
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from kea2.utils import Device
|
|
2
|
+
from kea2.keaUtils import precondition
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def global_block_widgets(d: "Device"):
|
|
6
|
+
"""
|
|
7
|
+
Specify UI widgets to be blocked globally during testing.
|
|
8
|
+
Returns a list of widgets that should be blocked from exploration.
|
|
9
|
+
This function is only available in 'u2 agent' mode.
|
|
10
|
+
"""
|
|
11
|
+
# return [d(text="widgets to block"), d.xpath(".//node[@text='widget to block']")]
|
|
12
|
+
return []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Example of conditional blocking with precondition
|
|
16
|
+
# @precondition(lambda d: d(text="In the home page").exists)
|
|
17
|
+
@precondition(lambda d: False)
|
|
18
|
+
def block_sth(d: "Device"):
|
|
19
|
+
# Note: Function name must start with "block_"
|
|
20
|
+
return []
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def global_block_tree(d: "Device"):
|
|
24
|
+
"""
|
|
25
|
+
Specify UI widget trees to be blocked globally during testing.
|
|
26
|
+
Returns a list of root nodes whose entire subtrees will be blocked from exploration.
|
|
27
|
+
This function is only available in 'u2 agent' mode.
|
|
28
|
+
"""
|
|
29
|
+
# return [d(text="trees to block"), d.xpath(".//node[@text='tree to block']")]
|
|
30
|
+
return []
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# Example of conditional tree blocking with precondition
|
|
34
|
+
# @precondition(lambda d: d(text="In the home page").exists)
|
|
35
|
+
@precondition(lambda d: False)
|
|
36
|
+
def block_tree_sth(d: "Device"):
|
|
37
|
+
# Note: Function name must start with "block_tree_"
|
|
38
|
+
return []
|
|
Binary file
|
|
@@ -305,7 +305,8 @@ class KeaTestRunner(TextTestRunner):
|
|
|
305
305
|
resultclass: JsonResult
|
|
306
306
|
allProperties: PropertyStore
|
|
307
307
|
options: Options = None
|
|
308
|
-
|
|
308
|
+
_block_funcs: Dict[Literal["widgets", "trees"], List[Callable]] = None
|
|
309
|
+
# _block_trees_funcs = None
|
|
309
310
|
|
|
310
311
|
@classmethod
|
|
311
312
|
def setOptions(cls, options: Options):
|
|
@@ -433,7 +434,6 @@ class KeaTestRunner(TextTestRunner):
|
|
|
433
434
|
|
|
434
435
|
print(f"Finish sending monkey events.", flush=True)
|
|
435
436
|
log_watcher.close()
|
|
436
|
-
self.tearDown()
|
|
437
437
|
|
|
438
438
|
# Source code from unittest Runner
|
|
439
439
|
# process the result
|
|
@@ -475,15 +475,19 @@ class KeaTestRunner(TextTestRunner):
|
|
|
475
475
|
"""
|
|
476
476
|
send a step monkey request to the server and get the xml string.
|
|
477
477
|
"""
|
|
478
|
-
|
|
478
|
+
block_dict = self._getBlockedWidgets()
|
|
479
|
+
block_widgets: List[str] = block_dict['widgets']
|
|
480
|
+
block_trees: List[str] = block_dict['trees']
|
|
479
481
|
URL = f"http://localhost:{self.scriptDriver.lport}/stepMonkey"
|
|
480
482
|
logger.debug(f"Sending request: {URL}")
|
|
481
483
|
logger.debug(f"Blocking widgets: {block_widgets}")
|
|
484
|
+
logger.debug(f"Blocking trees: {block_trees}")
|
|
482
485
|
r = requests.post(
|
|
483
486
|
url=URL,
|
|
484
487
|
json={
|
|
485
488
|
"steps_count": self.stepsCount,
|
|
486
|
-
"block_widgets": block_widgets
|
|
489
|
+
"block_widgets": block_widgets,
|
|
490
|
+
"block_trees": block_trees
|
|
487
491
|
}
|
|
488
492
|
)
|
|
489
493
|
|
|
@@ -577,17 +581,24 @@ class KeaTestRunner(TextTestRunner):
|
|
|
577
581
|
# save it into allProperties for PBT
|
|
578
582
|
self.allProperties[testMethodName] = t
|
|
579
583
|
print(f"[INFO] Load property: {getFullPropName(t)}", flush=True)
|
|
580
|
-
|
|
584
|
+
|
|
581
585
|
@property
|
|
582
586
|
def _blockWidgetFuncs(self):
|
|
583
|
-
|
|
584
|
-
|
|
587
|
+
"""
|
|
588
|
+
load and process blocking functions from widget.block.py configuration file.
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
dict: A dictionary containing two lists:
|
|
592
|
+
- 'widgets': List of functions that block individual widgets
|
|
593
|
+
- 'trees': List of functions that block widget trees
|
|
594
|
+
"""
|
|
595
|
+
if self._block_funcs is None:
|
|
596
|
+
self._block_funcs = {"widgets": list(), "trees": list()}
|
|
585
597
|
root_dir = getProjectRoot()
|
|
586
598
|
if root_dir is None or not os.path.exists(
|
|
587
|
-
|
|
599
|
+
file_block_widgets := root_dir / "configs" / "widget.block.py"
|
|
588
600
|
):
|
|
589
601
|
print(f"[WARNING] widget.block.py not find", flush=True)
|
|
590
|
-
|
|
591
602
|
|
|
592
603
|
def __get_block_widgets_module():
|
|
593
604
|
import importlib.util
|
|
@@ -601,43 +612,81 @@ class KeaTestRunner(TextTestRunner):
|
|
|
601
612
|
|
|
602
613
|
import inspect
|
|
603
614
|
for func_name, func in inspect.getmembers(mod, inspect.isfunction):
|
|
604
|
-
if func_name
|
|
615
|
+
if func_name == "global_block_widgets":
|
|
616
|
+
self._block_funcs["widgets"].append(func)
|
|
617
|
+
setattr(func, PRECONDITIONS_MARKER, (lambda d: True,))
|
|
618
|
+
continue
|
|
619
|
+
if func_name == "global_block_tree":
|
|
620
|
+
self._block_funcs["trees"].append(func)
|
|
621
|
+
setattr(func, PRECONDITIONS_MARKER, (lambda d: True,))
|
|
622
|
+
continue
|
|
623
|
+
if func_name.startswith("block_") and not func_name.startswith("block_tree_"):
|
|
624
|
+
if getattr(func, PRECONDITIONS_MARKER, None) is None:
|
|
625
|
+
logger.warning(f"No precondition in block widget function: {func_name}. Default globally active.")
|
|
626
|
+
setattr(func, PRECONDITIONS_MARKER, (lambda d: True,))
|
|
627
|
+
self._block_funcs["widgets"].append(func)
|
|
628
|
+
continue
|
|
629
|
+
if func_name.startswith("block_tree_"):
|
|
605
630
|
if getattr(func, PRECONDITIONS_MARKER, None) is None:
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
631
|
+
logger.warning(f"No precondition in block tree function: {func_name}. Default globally active.")
|
|
632
|
+
setattr(func, PRECONDITIONS_MARKER, (lambda d: True,))
|
|
633
|
+
self._block_funcs["trees"].append(func)
|
|
634
|
+
|
|
635
|
+
return self._block_funcs
|
|
610
636
|
|
|
611
|
-
return self._block_widgets_funcs
|
|
612
637
|
|
|
613
638
|
def _getBlockedWidgets(self):
|
|
614
|
-
|
|
615
|
-
|
|
639
|
+
"""
|
|
640
|
+
Executes all blocking functions to get lists of widgets and trees to be blocked during testing.
|
|
641
|
+
|
|
642
|
+
Returns:
|
|
643
|
+
dict: A dictionary containing:
|
|
644
|
+
- 'widgets': List of XPath strings for individual widgets to block
|
|
645
|
+
- 'trees': List of XPath strings for widget trees to block
|
|
646
|
+
"""
|
|
647
|
+
def _get_xpath_widgets(func):
|
|
648
|
+
blocked_set = set()
|
|
616
649
|
try:
|
|
617
650
|
script_driver = self.options.Driver.getScriptDriver()
|
|
618
|
-
preconds = getattr(func, PRECONDITIONS_MARKER)
|
|
619
|
-
if all(
|
|
651
|
+
preconds = getattr(func, PRECONDITIONS_MARKER, [])
|
|
652
|
+
if all(precond(script_driver) for precond in preconds):
|
|
620
653
|
_widgets = func(self.options.Driver.getStaticChecker())
|
|
621
|
-
if
|
|
622
|
-
_widgets = [_widgets]
|
|
654
|
+
_widgets = _widgets if isinstance(_widgets, list) else [_widgets]
|
|
623
655
|
for w in _widgets:
|
|
624
656
|
if isinstance(w, StaticU2UiObject):
|
|
625
|
-
|
|
657
|
+
xpath = w._getXPath(w.selector)
|
|
658
|
+
blocked_set.add(xpath) # 集合去重
|
|
626
659
|
elif isinstance(w, u2.xpath.XPathSelector):
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
blocked_widgets.append(getXPathRepr(w))
|
|
660
|
+
xpath = w._parent.xpath
|
|
661
|
+
blocked_set.add(xpath)
|
|
630
662
|
else:
|
|
631
663
|
logger.warning(f"{w} Not supported")
|
|
632
|
-
# blocked_widgets.extend([
|
|
633
|
-
# w._getXPath(w.selector) for w in _widgets
|
|
634
|
-
# ])
|
|
635
664
|
except Exception as e:
|
|
636
|
-
logger.error(f"
|
|
637
|
-
import traceback
|
|
665
|
+
logger.error(f"Error processing blocked widgets: {e}")
|
|
638
666
|
traceback.print_exc()
|
|
667
|
+
return blocked_set
|
|
668
|
+
|
|
669
|
+
res = {
|
|
670
|
+
"widgets": set(),
|
|
671
|
+
"trees": set()
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
for func in self._blockWidgetFuncs["widgets"]:
|
|
676
|
+
widgets = _get_xpath_widgets(func)
|
|
677
|
+
res["widgets"].update(widgets)
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
for func in self._blockWidgetFuncs["trees"]:
|
|
681
|
+
trees = _get_xpath_widgets(func)
|
|
682
|
+
res["trees"].update(trees)
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
res["widgets"] = list(res["widgets"] - res["trees"])
|
|
686
|
+
res["trees"] = list(res["trees"])
|
|
687
|
+
|
|
688
|
+
return res
|
|
639
689
|
|
|
640
|
-
return blocked_widgets
|
|
641
690
|
|
|
642
691
|
def __del__(self):
|
|
643
692
|
"""tearDown method. Cleanup the env.
|
|
@@ -46,17 +46,19 @@ class LogWatcher:
|
|
|
46
46
|
exception_body +
|
|
47
47
|
"\nSee fastbot.log for details."
|
|
48
48
|
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
if self.end_flag:
|
|
50
|
+
statistic_match = PATTERN_STATISTIC.search(buffer)
|
|
51
|
+
if statistic_match:
|
|
52
|
+
statistic_body = statistic_match.group(1).strip()
|
|
53
|
+
if statistic_body:
|
|
54
|
+
print(
|
|
55
|
+
"[INFO] Fastbot exit:\n" +
|
|
56
|
+
statistic_body
|
|
57
|
+
, flush=True)
|
|
57
58
|
|
|
58
59
|
def __init__(self, log_file):
|
|
59
60
|
self.log_file = log_file
|
|
61
|
+
self.end_flag = False
|
|
60
62
|
|
|
61
63
|
threading.excepthook = thread_excepthook
|
|
62
64
|
t = threading.Thread(target=self.watcher, daemon=True)
|
|
@@ -64,6 +66,7 @@ class LogWatcher:
|
|
|
64
66
|
|
|
65
67
|
def close(self):
|
|
66
68
|
time.sleep(0.2) # wait for the written logfile close
|
|
69
|
+
self.end_flag = True
|
|
67
70
|
self.read_log()
|
|
68
71
|
|
|
69
72
|
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from kea2.utils import Device
|
|
2
|
-
from kea2.keaUtils import precondition
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def global_block_widgets(d: "Device"):
|
|
6
|
-
"""
|
|
7
|
-
global block widgets.
|
|
8
|
-
return the widgets you want to block globally
|
|
9
|
-
only available in mode `u2 agent`
|
|
10
|
-
"""
|
|
11
|
-
return []
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# conditional block list
|
|
15
|
-
@precondition(lambda d: d(text="In the home page").exists)
|
|
16
|
-
def block_sth(d: "Device"):
|
|
17
|
-
# Important: function shold starts with "block_"
|
|
18
|
-
return [d(text="widgets to block"), d.xpath(".//node[@text='widget to block']")]
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so
RENAMED
|
File without changes
|
|
File without changes
|
{kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/x86/libfastbot_native.so
RENAMED
|
File without changes
|
{kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/x86_64/libfastbot_native.so
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|