Kea2-python 1.0.6b0__tar.gz → 1.1.0__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.
Files changed (65) hide show
  1. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/Kea2_python.egg-info/PKG-INFO +6 -2
  2. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/Kea2_python.egg-info/SOURCES.txt +3 -7
  3. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/PKG-INFO +6 -2
  4. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/README.md +5 -1
  5. kea2_python-1.1.0/kea2/__init__.py +8 -0
  6. kea2_python-1.1.0/kea2/assets/monkeyq.jar +0 -0
  7. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/quicktest.py +41 -22
  8. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/cli.py +10 -106
  9. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/fastbotManager.py +4 -4
  10. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/kea2_api.py +7 -3
  11. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/keaUtils.py +316 -478
  12. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/kea_launcher.py +4 -26
  13. kea2_python-1.1.0/kea2/report/__init__.py +0 -0
  14. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/report/bug_report_generator.py +151 -40
  15. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/report/mixin.py +28 -13
  16. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/report/report_merger.py +281 -12
  17. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/report/templates/bug_report_template.html +347 -107
  18. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/report/templates/merged_bug_report_template.html +545 -276
  19. kea2_python-1.1.0/kea2/result.py +259 -0
  20. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/resultSyncer.py +2 -1
  21. kea2_python-1.1.0/kea2/state.py +22 -0
  22. kea2_python-1.1.0/kea2/typedefs.py +32 -0
  23. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/u2Driver.py +5 -4
  24. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/utils.py +56 -1
  25. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/pyproject.toml +1 -1
  26. kea2_python-1.0.6b0/kea2/__init__.py +0 -3
  27. kea2_python-1.0.6b0/kea2/absDriver.py +0 -56
  28. kea2_python-1.0.6b0/kea2/assets/monkeyq.jar +0 -0
  29. kea2_python-1.0.6b0/kea2/fastbotx/ActivityTimes.py +0 -52
  30. kea2_python-1.0.6b0/kea2/fastbotx/ReuseEntry.py +0 -74
  31. kea2_python-1.0.6b0/kea2/fastbotx/ReuseModel.py +0 -63
  32. kea2_python-1.0.6b0/kea2/fastbotx/__init__.py +0 -7
  33. kea2_python-1.0.6b0/kea2/fbm_parser.py +0 -871
  34. kea2_python-1.0.6b0/kea2/fs_lock.py +0 -131
  35. kea2_python-1.0.6b0/kea2/mixin.py +0 -22
  36. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/Kea2_python.egg-info/dependency_links.txt +0 -0
  37. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/Kea2_python.egg-info/entry_points.txt +0 -0
  38. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/Kea2_python.egg-info/requires.txt +0 -0
  39. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/Kea2_python.egg-info/top_level.txt +0 -0
  40. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/LICENSE +0 -0
  41. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/adbUtils.py +0 -0
  42. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/config_version.json +0 -0
  43. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot-thirdpart.jar +0 -0
  44. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/abl.strings +0 -0
  45. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/awl.strings +0 -0
  46. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/max.config +0 -0
  47. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/max.fuzzing.strings +0 -0
  48. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/max.schema.strings +0 -0
  49. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/max.strings +0 -0
  50. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/max.tree.pruning +0 -0
  51. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/teardown.py +0 -0
  52. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_configs/widget.block.py +0 -0
  53. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
  54. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
  55. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_libs/x86/libfastbot_native.so +0 -0
  56. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/fastbot_libs/x86_64/libfastbot_native.so +0 -0
  57. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/framework.jar +0 -0
  58. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/assets/kea2-thirdpart.jar +0 -0
  59. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/logWatcher.py +0 -0
  60. /kea2_python-1.0.6b0/kea2/report/__init__.py → /kea2_python-1.1.0/kea2/mixin.py +0 -0
  61. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/report/utils.py +0 -0
  62. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/kea2/version_manager.py +0 -0
  63. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/setup.cfg +0 -0
  64. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/tests/test_u2Selector.py +0 -0
  65. {kea2_python-1.0.6b0 → kea2_python-1.1.0}/tests/test_xpath.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Kea2-python
3
- Version: 1.0.6b0
3
+ Version: 1.1.0
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
@@ -290,7 +290,7 @@ Some notes:
290
290
  3. You need to insert the following code template into your existing test cases: Here, you can add your own hook logic in the commented sections, including starting or stopping the appium session, cleaning up instances, etc. This depends on how you want to design the setup and teardown. Apart from that, you only need to configure the `option` parameter and `configs_path` parameter(where your directory `configs` located, btw, `configs`'s location dependon where you executed `kea2 init`), then pass it to the `run_kea2_testing` function.
291
291
 
292
292
  ```python
293
- from kea2 import Kea2Tester, Options, U2Driver
293
+ from kea2 import Kea2Tester, Options
294
294
 
295
295
  if os.environ.get('KEA2_HYBRID_MODE', '').lower() == 'true':
296
296
  '''
@@ -327,6 +327,10 @@ if os.environ.get('KEA2_HYBRID_MODE', '').lower() == 'true':
327
327
  Kea2 automatically generates a HTML test report after each testing session. You can find the report in `output/` under your working directory.
328
328
 
329
329
  You can also manually generate the test report by `kea2 report` (see `kea2 report -h` for details).
330
+ Use `-s/--sync` to sync data from device before generating the report, and `-p/--path` to point to one or more result directories.
331
+ For example:
332
+ `kea2 report -p output/res_YYYYMMDDHH_xxxxxx`
333
+ `kea2 report -s -p output/res_YYYYMMDDHH_xxxxxx`
330
334
 
331
335
  You can also merge the test report from multiple testing sessions by `kea2 merge` (see `kea2 merge -h` for details).
332
336
  The merged test report is quite useful if you would test your apps for multiple sessions.
@@ -8,18 +8,18 @@ Kea2_python.egg-info/entry_points.txt
8
8
  Kea2_python.egg-info/requires.txt
9
9
  Kea2_python.egg-info/top_level.txt
10
10
  kea2/__init__.py
11
- kea2/absDriver.py
12
11
  kea2/adbUtils.py
13
12
  kea2/cli.py
14
13
  kea2/fastbotManager.py
15
- kea2/fbm_parser.py
16
- kea2/fs_lock.py
17
14
  kea2/kea2_api.py
18
15
  kea2/keaUtils.py
19
16
  kea2/kea_launcher.py
20
17
  kea2/logWatcher.py
21
18
  kea2/mixin.py
19
+ kea2/result.py
22
20
  kea2/resultSyncer.py
21
+ kea2/state.py
22
+ kea2/typedefs.py
23
23
  kea2/u2Driver.py
24
24
  kea2/utils.py
25
25
  kea2/version_manager.py
@@ -42,10 +42,6 @@ kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so
42
42
  kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so
43
43
  kea2/assets/fastbot_libs/x86/libfastbot_native.so
44
44
  kea2/assets/fastbot_libs/x86_64/libfastbot_native.so
45
- kea2/fastbotx/ActivityTimes.py
46
- kea2/fastbotx/ReuseEntry.py
47
- kea2/fastbotx/ReuseModel.py
48
- kea2/fastbotx/__init__.py
49
45
  kea2/report/__init__.py
50
46
  kea2/report/bug_report_generator.py
51
47
  kea2/report/mixin.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Kea2-python
3
- Version: 1.0.6b0
3
+ Version: 1.1.0
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
@@ -290,7 +290,7 @@ Some notes:
290
290
  3. You need to insert the following code template into your existing test cases: Here, you can add your own hook logic in the commented sections, including starting or stopping the appium session, cleaning up instances, etc. This depends on how you want to design the setup and teardown. Apart from that, you only need to configure the `option` parameter and `configs_path` parameter(where your directory `configs` located, btw, `configs`'s location dependon where you executed `kea2 init`), then pass it to the `run_kea2_testing` function.
291
291
 
292
292
  ```python
293
- from kea2 import Kea2Tester, Options, U2Driver
293
+ from kea2 import Kea2Tester, Options
294
294
 
295
295
  if os.environ.get('KEA2_HYBRID_MODE', '').lower() == 'true':
296
296
  '''
@@ -327,6 +327,10 @@ if os.environ.get('KEA2_HYBRID_MODE', '').lower() == 'true':
327
327
  Kea2 automatically generates a HTML test report after each testing session. You can find the report in `output/` under your working directory.
328
328
 
329
329
  You can also manually generate the test report by `kea2 report` (see `kea2 report -h` for details).
330
+ Use `-s/--sync` to sync data from device before generating the report, and `-p/--path` to point to one or more result directories.
331
+ For example:
332
+ `kea2 report -p output/res_YYYYMMDDHH_xxxxxx`
333
+ `kea2 report -s -p output/res_YYYYMMDDHH_xxxxxx`
330
334
 
331
335
  You can also merge the test report from multiple testing sessions by `kea2 merge` (see `kea2 merge -h` for details).
332
336
  The merged test report is quite useful if you would test your apps for multiple sessions.
@@ -275,7 +275,7 @@ Some notes:
275
275
  3. You need to insert the following code template into your existing test cases: Here, you can add your own hook logic in the commented sections, including starting or stopping the appium session, cleaning up instances, etc. This depends on how you want to design the setup and teardown. Apart from that, you only need to configure the `option` parameter and `configs_path` parameter(where your directory `configs` located, btw, `configs`'s location dependon where you executed `kea2 init`), then pass it to the `run_kea2_testing` function.
276
276
 
277
277
  ```python
278
- from kea2 import Kea2Tester, Options, U2Driver
278
+ from kea2 import Kea2Tester, Options
279
279
 
280
280
  if os.environ.get('KEA2_HYBRID_MODE', '').lower() == 'true':
281
281
  '''
@@ -312,6 +312,10 @@ if os.environ.get('KEA2_HYBRID_MODE', '').lower() == 'true':
312
312
  Kea2 automatically generates a HTML test report after each testing session. You can find the report in `output/` under your working directory.
313
313
 
314
314
  You can also manually generate the test report by `kea2 report` (see `kea2 report -h` for details).
315
+ Use `-s/--sync` to sync data from device before generating the report, and `-p/--path` to point to one or more result directories.
316
+ For example:
317
+ `kea2 report -p output/res_YYYYMMDDHH_xxxxxx`
318
+ `kea2 report -s -p output/res_YYYYMMDDHH_xxxxxx`
315
319
 
316
320
  You can also merge the test report from multiple testing sessions by `kea2 merge` (see `kea2 merge -h` for details).
317
321
  The merged test report is quite useful if you would test your apps for multiple sessions.
@@ -0,0 +1,8 @@
1
+ from .keaUtils import KeaTestRunner, HybridTestRunner, keaTestLoader
2
+ from .keaUtils import Options
3
+ from .keaUtils import precondition, prob, max_tries, interruptable
4
+ from .keaUtils import kea2_breakpoint
5
+ from .state import state, invariant
6
+ from .kea2_api import Kea2Tester
7
+ from .u2Driver import U2Driver
8
+ from .state import state
@@ -2,39 +2,43 @@ import unittest
2
2
  import uiautomator2 as u2
3
3
 
4
4
  from time import sleep
5
- from kea2 import precondition, prob, KeaTestRunner, Options
6
- from kea2.u2Driver import U2Driver
5
+ from kea2 import precondition, prob, KeaTestRunner, Options, keaTestLoader, invariant
7
6
 
8
7
 
9
8
  class Omni_Notes_Sample(unittest.TestCase):
9
+ d: u2.Device
10
10
 
11
- def setUp(self):
12
- self.d = u2.connect()
13
-
14
- @prob(0.2)
11
+ @classmethod
12
+ def setUpClass(cls):
13
+ """Here you can setup the initialize setting for uiautomator2
14
+ """
15
+ print("Setting driver settings")
16
+ cls.d.settings["wait_timeout"] = 5.0
17
+ cls.d.settings["operation_delay"] = (0, 1.0)
18
+
19
+ @prob(0.5)
15
20
  @precondition(
16
21
  lambda self: self.d(description="Navigate up").exists
17
22
  )
18
- def test_goBack(self):
23
+ def navigate_up(self):
19
24
  print("Navigate back")
20
25
  self.d(description="Navigate up").click()
21
- sleep(0.5)
22
-
23
- @prob(0.2)
26
+
27
+ @prob(0.5)
24
28
  @precondition(
25
- lambda self: self.d(description="drawer closed").exists
29
+ lambda self: self.d(description="drawer closed").exists and
30
+ not self.d(text="Omni Notes Alpha").exists
26
31
  )
27
- def test_openDrawer(self):
32
+ def open_drawer(self):
28
33
  print("Open drawer")
29
34
  self.d(description="drawer closed").click()
30
- sleep(0.5)
31
35
 
32
- @prob(0.5) # The probability of executing the function when precondition is satisfied.
36
+ @prob(0.7) # The probability of executing the function when precondition is satisfied.
33
37
  @precondition(
34
38
  lambda self: self.d(text="Omni Notes Alpha").exists
35
39
  and self.d(text="Settings").exists
36
40
  )
37
- def test_goToPrivacy(self):
41
+ def go_to_privacy_settings(self):
38
42
  """
39
43
  The ability to jump out of the UI tarpits
40
44
 
@@ -45,14 +49,13 @@ class Omni_Notes_Sample(unittest.TestCase):
45
49
  """
46
50
  print("trying to click Settings")
47
51
  self.d(text="Settings").click()
48
- sleep(0.5)
49
52
  print("trying to click Privacy")
50
53
  self.d(text="Privacy").click()
51
54
 
52
55
  @precondition(
53
56
  lambda self: self.d(resourceId="it.feio.android.omninotes.alpha:id/search_src_text").exists
54
57
  )
55
- def test_rotation(self):
58
+ def rotation_should_not_close_the_search_input(self):
56
59
  """
57
60
  The ability to make assertion to find functional bug
58
61
 
@@ -65,11 +68,28 @@ class Omni_Notes_Sample(unittest.TestCase):
65
68
  """
66
69
  print("rotate the device")
67
70
  self.d.set_orientation("l")
68
- sleep(2)
69
71
  self.d.set_orientation("n")
70
- sleep(2)
71
- assert self.d(resourceId="it.feio.android.omninotes.alpha:id/search_src_text").exists()
72
+ assert self.d(resourceId="it.feio.android.omninotes.alpha:id/search_src_text").exists
72
73
 
74
+ @invariant
75
+ def search_button_and_search_input_box_should_not_exists_at_the_same_time(self):
76
+ """Search input box and search button should not exists at the same time
77
+ """
78
+ search_input_box_exists = self.d(resourceId="it.feio.android.omninotes.alpha:id/search_src_text").exists
79
+ serach_button_exists = self.d(resourceId="it.feio.android.omninotes.alpha:id/menu_search").exists
80
+ if search_input_box_exists or serach_button_exists:
81
+ assert search_input_box_exists ^ serach_button_exists
82
+
83
+ @precondition(lambda self: "camera" in self.d.app_current().get("package", ""))
84
+ def exit_camera(self):
85
+ """Exit camera app if it is launched
86
+ (fastbot can't exit camera app by itself, we use kea2 to exit it to aviod getting stuck in camera)
87
+ """
88
+ print("Exiting camera app")
89
+ pkg_camera = self.d.app_current().get("package", "")
90
+ print(f"Current package: {pkg_camera}")
91
+ if "camera" in pkg_camera:
92
+ self.d.app_stop(pkg_camera)
73
93
 
74
94
  URL = "https://github.com/federicoiosue/Omni-Notes/releases/download/6.2.0_alpha/OmniNotes-alphaRelease-6.2.0.apk"
75
95
  FALL_BACK_URL = "https://gitee.com/XixianLiang/Kea2/raw/main/omninotes.apk"
@@ -112,7 +132,6 @@ if __name__ == "__main__":
112
132
  KeaTestRunner.setOptions(
113
133
  Options(
114
134
  driverName="d",
115
- Driver=U2Driver,
116
135
  packageNames=[PACKAGE_NAME],
117
136
  # serial="emulator-5554", # specify the serial
118
137
  maxStep=50,
@@ -123,4 +142,4 @@ if __name__ == "__main__":
123
142
  agent="u2" # 'native' for running the vanilla Fastbot, 'u2' for running Kea2
124
143
  )
125
144
  )
126
- unittest.main(testRunner=KeaTestRunner)
145
+ unittest.main(testRunner=KeaTestRunner, testLoader=keaTestLoader)
@@ -58,6 +58,8 @@ def cmd_report(args):
58
58
  from .report.bug_report_generator import BugReportGenerator
59
59
  report_dirs = args.path
60
60
 
61
+ sync_data = args.sync
62
+
61
63
  for report_dir in report_dirs:
62
64
  report_dir = Path(report_dir).resolve()
63
65
 
@@ -66,7 +68,7 @@ def cmd_report(args):
66
68
  continue
67
69
 
68
70
  logger.debug(f"Generating test report from directory: {report_dir}")
69
- BugReportGenerator(report_dir).generate_report()
71
+ BugReportGenerator(report_dir, sync_data).generate_report()
70
72
 
71
73
 
72
74
  def cmd_merge(args):
@@ -103,90 +105,7 @@ def cmd_merge(args):
103
105
  print(f"📈 Merged {merge_summary.get('merged_directories', 0)} directories", flush=True)
104
106
 
105
107
  except Exception as e:
106
- logger.error(f"Error during merge operation: {e}")
107
-
108
-
109
- def cmd_mergefbm(args):
110
- """Merge all FBM files in the specified folder and its subfolders using sum mode"""
111
- from .fbm_parser import FBMMerger
112
- import glob
113
- import shutil
114
-
115
- try:
116
- # Validate input path
117
- input_path = Path(args.path).resolve()
118
- if not input_path.exists():
119
- logger.error(f"Input directory does not exist: {input_path}")
120
- return
121
- if not input_path.is_dir():
122
- logger.error(f"Input path is not a directory: {input_path}")
123
- return
124
-
125
- # Find all FBM files in the directory and its subdirectories
126
- fbm_files = glob.glob(str(input_path / "**" / "*.fbm"), recursive=True)
127
-
128
- if not fbm_files:
129
- logger.error(f"No FBM files found in {input_path} or its subdirectories")
130
- return
131
-
132
- logger.debug(f"Found {len(fbm_files)} FBM files to merge:")
133
- for fbm_file in fbm_files:
134
- logger.debug(f" - {fbm_file}")
135
-
136
- # Set default output file if not provided
137
- if not args.output:
138
- output_file = input_path / "merged.fbm"
139
- else:
140
- output_file = Path(args.output).resolve()
141
-
142
- # Initialize merger
143
- merger = FBMMerger()
144
-
145
- # Handle different cases
146
- if len(fbm_files) == 1:
147
- # Only one file, just copy it to output
148
- shutil.copyfile(fbm_files[0], output_file)
149
- logger.info(f"Only one FBM file found, copied to {output_file}")
150
- else:
151
- # Merge files iteratively: start with the first file and merge with each subsequent file
152
- # Create a temporary file for the intermediate merged result
153
- temp_output = input_path / f".tmp_merged.fbm"
154
-
155
- # Start with the first file as the initial merged result
156
- shutil.copyfile(fbm_files[0], temp_output)
157
-
158
- # Iterate through the remaining files and merge them one by one
159
- for i in range(1, len(fbm_files)):
160
- current_file = fbm_files[i]
161
- next_temp = input_path / f".tmp_merged_{i}.fbm"
162
-
163
- logger.debug(f"Merging {temp_output} and {current_file} into {next_temp}")
164
- success = merger.merge(str(temp_output), str(current_file), str(next_temp), merge_mode='sum')
165
-
166
- if not success:
167
- logger.error(f"Failed to merge {temp_output} and {current_file}")
168
- # Clean up temporary files
169
- for f in [temp_output, next_temp]:
170
- if f.exists() and f.name.startswith(".tmp_"):
171
- f.unlink()
172
- return
173
-
174
- # Remove the previous temporary file and update to the new one
175
- temp_output.unlink()
176
- temp_output = next_temp
177
-
178
- # Move the final merged file to the output location
179
- if temp_output != output_file:
180
- temp_output.replace(output_file)
181
-
182
- print(f"✅ All FBM files merged successfully!", flush=True)
183
- print(f"📊 Merged FBM file: {output_file}", flush=True)
184
- print(f"📈 Merged {len(fbm_files)} FBM files", flush=True)
185
-
186
- except Exception as e:
187
- logger.error(f"Error during FBM merge operation: {e}")
188
- import traceback
189
- logger.debug(traceback.format_exc())
108
+ logger.error(f"Error during merge operation: {e}")
190
109
 
191
110
 
192
111
  def cmd_run(args):
@@ -219,6 +138,12 @@ _commands = [
219
138
  nargs="+",
220
139
  required=True,
221
140
  help="Root directory path of the test results to generate report from"
141
+ ),
142
+ dict(
143
+ name=["sync_data"],
144
+ args=["-s", "--sync"],
145
+ action="store_true",
146
+ help="Sync data from device before generating report"
222
147
  )
223
148
  ]
224
149
  ),
@@ -243,27 +168,6 @@ _commands = [
243
168
  help="Output directory for merged report (optional)"
244
169
  )
245
170
  ]
246
- ),
247
- dict(
248
- action=cmd_mergefbm,
249
- command="mergefbm",
250
- help="merge all FBM files in the specified folder and its subfolders using sum mode",
251
- flags=[
252
- dict(
253
- name=["path"],
254
- args=["-p", "--path"],
255
- type=str,
256
- required=True,
257
- help="Path to the folder containing FBM files to merge"
258
- ),
259
- dict(
260
- name=["output"],
261
- args=["-o", "--output"],
262
- type=str,
263
- required=False,
264
- help="Output file path for merged FBM file (optional, default: merged.fbm in the input folder)"
265
- )
266
- ]
267
171
  )
268
172
  ]
269
173
 
@@ -16,7 +16,8 @@ from .adbUtils import ADBDevice, ADBStreamShell_V2
16
16
 
17
17
  from typing import IO, TYPE_CHECKING, Dict
18
18
  if TYPE_CHECKING:
19
- from .keaUtils import Options, PropertyExecutionInfo
19
+ from .keaUtils import Options
20
+ from .typedefs import PropertyExecutionInfo
20
21
 
21
22
 
22
23
  logger = getLogger(__name__)
@@ -114,6 +115,7 @@ class FastbotManager:
114
115
  data={
115
116
  "propName": execution_info.propName,
116
117
  "startStepsCount": execution_info.startStepsCount,
118
+ "kind": execution_info.kind,
117
119
  "state": execution_info.state,
118
120
  }
119
121
  )
@@ -235,7 +237,7 @@ class FastbotManager:
235
237
 
236
238
  outfile = open(self.log_file, "w", encoding="utf-8", buffering=1)
237
239
 
238
- logger.info("Options info: {}".format(asdict(self.options)))
240
+ logger.info("Options info: {}".format(self.options.to_dict()))
239
241
  logger.info("Launching fastbot with shell command:\n{}".format(" ".join(full_cmd)))
240
242
  logger.info("Fastbot log will be saved to {}".format(outfile.name))
241
243
 
@@ -263,5 +265,3 @@ class FastbotManager:
263
265
  self.thread.join()
264
266
 
265
267
 
266
-
267
-
@@ -106,11 +106,15 @@ class Kea2Tester:
106
106
 
107
107
  output_dir = self.options.output_dir
108
108
 
109
- from .keaUtils import STAMP, LOGFILE, RESFILE
109
+ from .utils import StampManager
110
110
 
111
111
  bug_report_path = output_dir / "bug_report.html"
112
- result_json_path = output_dir / RESFILE.name if hasattr(RESFILE, 'name') else output_dir / f"result_{STAMP}.json"
113
- log_file_path = output_dir / LOGFILE.name if hasattr(LOGFILE, 'name') else output_dir / f"fastbot_{STAMP}.log"
112
+ stamp_manager = StampManager()
113
+ stamp = stamp_manager.stamp or self.options.log_stamp
114
+ result_name = stamp_manager.result_file.name if stamp_manager.result_file else f"result_{stamp}.json"
115
+ log_name = stamp_manager.log_file.name if stamp_manager.log_file else f"fastbot_{stamp}.log"
116
+ result_json_path = output_dir / result_name
117
+ log_file_path = output_dir / log_name
114
118
 
115
119
  return {
116
120
  'executed': True,