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.

Files changed (39) hide show
  1. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/PKG-INFO +54 -12
  2. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/PKG-INFO +54 -12
  3. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/README.md +53 -11
  4. kea2_python-0.0.1b3/kea2/assets/fastbot_configs/widget.block.py +38 -0
  5. kea2_python-0.0.1b3/kea2/assets/monkeyq.jar +0 -0
  6. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/keaUtils.py +80 -31
  7. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/logWatcher.py +11 -8
  8. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/pyproject.toml +1 -1
  9. kea2_python-0.0.1b2/kea2/assets/fastbot_configs/widget.block.py +0 -18
  10. kea2_python-0.0.1b2/kea2/assets/monkeyq.jar +0 -0
  11. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/SOURCES.txt +0 -0
  12. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/dependency_links.txt +0 -0
  13. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/entry_points.txt +0 -0
  14. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/requires.txt +0 -0
  15. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/Kea2_python.egg-info/top_level.txt +0 -0
  16. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/LICENSE +0 -0
  17. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/__init__.py +0 -0
  18. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/absDriver.py +0 -0
  19. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/adbUtils.py +0 -0
  20. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot-thirdpart.jar +0 -0
  21. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/abl.strings +0 -0
  22. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/awl.strings +0 -0
  23. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.config +0 -0
  24. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.fuzzing.strings +0 -0
  25. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.schema.strings +0 -0
  26. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.strings +0 -0
  27. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_configs/max.tree.pruning +0 -0
  28. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
  29. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
  30. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/x86/libfastbot_native.so +0 -0
  31. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/fastbot_libs/x86_64/libfastbot_native.so +0 -0
  32. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/framework.jar +0 -0
  33. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/quicktest.py +0 -0
  34. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/assets/u2.jar +0 -0
  35. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/cli.py +0 -0
  36. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/kea_launcher.py +0 -0
  37. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/u2Driver.py +0 -0
  38. {kea2_python-0.0.1b2 → kea2_python-0.0.1b3}/kea2/utils.py +0 -0
  39. {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.1b2
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. The library is currently built on top of [Fastbot](https://github.com/bytedance/Fastbot_Android) and [uiautomator2](https://github.com/openatx/uiautomator2), and targeting [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) 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 widgets
178
+ ### Example 2: blacklisting specific UI elements
179
179
 
180
- We support blacklisting specific widgets so that Fastbot can avoid interacting with these widgets during fuzzing. We support (1) `Global Block List` (always taking effective), and (2) `Conditional Block List` (only taking effective when some conditions are met).
180
+ We support blacklisting specific elements so that Fastbot can avoid interacting with these
181
+ elements during fuzzing.
181
182
 
182
- The list of blocked widgets are specified in Kea2's config file `configs/widget.block.py` (generated when running `kea2 init`).
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
- #### Global Block List
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
- def global_block_widgets(d: "Device"):
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
- #### Conditional Block List
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, default: current time stamp | |
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.1b2
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. The library is currently built on top of [Fastbot](https://github.com/bytedance/Fastbot_Android) and [uiautomator2](https://github.com/openatx/uiautomator2), and targeting [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) 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 widgets
178
+ ### Example 2: blacklisting specific UI elements
179
179
 
180
- We support blacklisting specific widgets so that Fastbot can avoid interacting with these widgets during fuzzing. We support (1) `Global Block List` (always taking effective), and (2) `Conditional Block List` (only taking effective when some conditions are met).
180
+ We support blacklisting specific elements so that Fastbot can avoid interacting with these
181
+ elements during fuzzing.
181
182
 
182
- The list of blocked widgets are specified in Kea2's config file `configs/widget.block.py` (generated when running `kea2 init`).
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
- #### Global Block List
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
- def global_block_widgets(d: "Device"):
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
- #### Conditional Block List
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, default: current time stamp | |
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. The library is currently built on top of [Fastbot](https://github.com/bytedance/Fastbot_Android) and [uiautomator2](https://github.com/openatx/uiautomator2), and targeting [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) 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 widgets
166
+ ### Example 2: blacklisting specific UI elements
167
167
 
168
- We support blacklisting specific widgets so that Fastbot can avoid interacting with these widgets during fuzzing. We support (1) `Global Block List` (always taking effective), and (2) `Conditional Block List` (only taking effective when some conditions are met).
168
+ We support blacklisting specific elements so that Fastbot can avoid interacting with these
169
+ elements during fuzzing.
169
170
 
170
- The list of blocked widgets are specified in Kea2's config file `configs/widget.block.py` (generated when running `kea2 init`).
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
- #### Global Block List
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
- def global_block_widgets(d: "Device"):
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
- #### Conditional Block List
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, default: current time stamp | |
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 []
@@ -305,7 +305,8 @@ class KeaTestRunner(TextTestRunner):
305
305
  resultclass: JsonResult
306
306
  allProperties: PropertyStore
307
307
  options: Options = None
308
- _block_widgets_funcs = None
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
- block_widgets: List[str] = self._getBlockedWidgets()
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
- if self._block_widgets_funcs is None:
584
- self._block_widgets_funcs = list()
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
- file_block_widgets := root_dir / "configs" / "widget.block.py"
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.startswith("block_") or func_name == "global_block_widgets":
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
- if func_name.startswith("block_"):
607
- logger.warning(f"No precondition in block widget function: {func_name}. Default globally active.")
608
- setattr(func, PRECONDITIONS_MARKER, (lambda d: True, ))
609
- self._block_widgets_funcs.append(func)
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
- blocked_widgets = list()
615
- for func in self._blockWidgetFuncs:
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([precond(script_driver) for precond in preconds]):
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 not isinstance(_widgets, list):
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
- blocked_widgets.append(w._getXPath(w.selector))
657
+ xpath = w._getXPath(w.selector)
658
+ blocked_set.add(xpath) # 集合去重
626
659
  elif isinstance(w, u2.xpath.XPathSelector):
627
- def getXPathRepr(w):
628
- return w._parent.xpath
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"error when getting blocked widgets: {e}")
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
- statistic_match = PATTERN_STATISTIC.search(buffer)
50
- if statistic_match:
51
- statistic_body = statistic_match.group(1).strip()
52
- if statistic_body:
53
- print(
54
- "[INFO] Fastbot exit:\n" +
55
- statistic_body
56
- , flush=True)
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,6 +1,6 @@
1
1
  [project]
2
2
  name = "Kea2-python"
3
- version = "0.0.1b2"
3
+ version = "0.0.1b3"
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,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