rodski 5.7.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. rodski/LICENSE +21 -0
  2. rodski/README.md +56 -0
  3. rodski/__init__.py +2 -0
  4. rodski/api/__init__.py +0 -0
  5. rodski/api/rest_helper.py +116 -0
  6. rodski/cli_main.py +106 -0
  7. rodski/config/__init__.py +0 -0
  8. rodski/config/android_config.json +8 -0
  9. rodski/config/config.json +25 -0
  10. rodski/config/default_config.yaml +96 -0
  11. rodski/config/ios_config.json +7 -0
  12. rodski/config/llm_config.yaml +58 -0
  13. rodski/config/reviewer_config.yaml +31 -0
  14. rodski/config/vision_config.yaml +14 -0
  15. rodski/core/__init__.py +36 -0
  16. rodski/core/assertion/__init__.py +16 -0
  17. rodski/core/assertion/base_assertion.py +35 -0
  18. rodski/core/assertion/image_matcher.py +266 -0
  19. rodski/core/assertion/video_analyzer.py +271 -0
  20. rodski/core/browser_recycler.py +251 -0
  21. rodski/core/case_metadata.py +104 -0
  22. rodski/core/case_parser.py +159 -0
  23. rodski/core/condition_evaluator.py +92 -0
  24. rodski/core/config_manager.py +95 -0
  25. rodski/core/data_table_parser.py +93 -0
  26. rodski/core/diagnosis_engine.py +216 -0
  27. rodski/core/driver_factory.py +470 -0
  28. rodski/core/dynamic_executor.py +283 -0
  29. rodski/core/dynamic_steps.py +73 -0
  30. rodski/core/exceptions.py +408 -0
  31. rodski/core/execution_stats.py +81 -0
  32. rodski/core/global_value_parser.py +52 -0
  33. rodski/core/json_formatter.py +73 -0
  34. rodski/core/keyword_engine.py +2040 -0
  35. rodski/core/logger.py +81 -0
  36. rodski/core/loop_executor.py +202 -0
  37. rodski/core/metadata_writer.py +63 -0
  38. rodski/core/model_parser.py +306 -0
  39. rodski/core/parallel_executor.py +92 -0
  40. rodski/core/performance.py +48 -0
  41. rodski/core/profiler.py +85 -0
  42. rodski/core/recording/__init__.py +12 -0
  43. rodski/core/recording/recorder.py +142 -0
  44. rodski/core/recovery_engine.py +287 -0
  45. rodski/core/result_writer.py +227 -0
  46. rodski/core/runtime_context.py +20 -0
  47. rodski/core/runtime_control.py +115 -0
  48. rodski/core/ski_executor.py +652 -0
  49. rodski/core/statistics_collector.py +240 -0
  50. rodski/core/task_executor.py +122 -0
  51. rodski/core/test_case_explainer.py +1032 -0
  52. rodski/core/test_runner.py +269 -0
  53. rodski/core/xml_schema_validator.py +179 -0
  54. rodski/data/__init__.py +5 -0
  55. rodski/data/data_resolver.py +144 -0
  56. rodski/data/model_manager.py +90 -0
  57. rodski/drivers/__init__.py +39 -0
  58. rodski/drivers/android_driver.py +33 -0
  59. rodski/drivers/appium_driver.py +272 -0
  60. rodski/drivers/base_driver.py +356 -0
  61. rodski/drivers/desktop_driver.py +692 -0
  62. rodski/drivers/ios_driver.py +24 -0
  63. rodski/drivers/playwright_driver.py +629 -0
  64. rodski/drivers/pywinauto_driver.py +79 -0
  65. rodski/llm/__init__.py +10 -0
  66. rodski/llm/capabilities/__init__.py +23 -0
  67. rodski/llm/capabilities/base.py +14 -0
  68. rodski/llm/capabilities/screenshot_verifier.py +78 -0
  69. rodski/llm/capabilities/test_reviewer.py +131 -0
  70. rodski/llm/capabilities/vision_locator.py +62 -0
  71. rodski/llm/client.py +66 -0
  72. rodski/llm/config.py +134 -0
  73. rodski/llm/exceptions.py +21 -0
  74. rodski/llm/providers/__init__.py +17 -0
  75. rodski/llm/providers/base.py +38 -0
  76. rodski/llm/providers/claude.py +78 -0
  77. rodski/llm/providers/openai.py +73 -0
  78. rodski/reviewers/__init__.py +10 -0
  79. rodski/reviewers/cli.py +35 -0
  80. rodski/reviewers/llm_reviewer.py +149 -0
  81. rodski/rodski_cli/__init__.py +43 -0
  82. rodski/rodski_cli/config.py +50 -0
  83. rodski/rodski_cli/docs.py +126 -0
  84. rodski/rodski_cli/explain.py +129 -0
  85. rodski/rodski_cli/log.py +58 -0
  86. rodski/rodski_cli/model.py +57 -0
  87. rodski/rodski_cli/profile.py +57 -0
  88. rodski/rodski_cli/report.py +620 -0
  89. rodski/rodski_cli/run.py +229 -0
  90. rodski/rodski_cli/stats.py +305 -0
  91. rodski/schemas/case.xsd +128 -0
  92. rodski/schemas/data.xsd +56 -0
  93. rodski/schemas/globalvalue.xsd +48 -0
  94. rodski/schemas/model.xsd +177 -0
  95. rodski/schemas/result.xsd +104 -0
  96. rodski/ski_gui.py +6 -0
  97. rodski/ski_run.py +132 -0
  98. rodski/ui/__init__.py +0 -0
  99. rodski/utils/__init__.py +4 -0
  100. rodski/utils/helpers.py +29 -0
  101. rodski/vision/__init__.py +67 -0
  102. rodski/vision/ai_verifier.py +378 -0
  103. rodski/vision/bbox_locator.py +147 -0
  104. rodski/vision/cache.py +253 -0
  105. rodski/vision/coordinate_utils.py +315 -0
  106. rodski/vision/desktop_driver.py +258 -0
  107. rodski/vision/exceptions.py +267 -0
  108. rodski/vision/llm_analyzer.py +92 -0
  109. rodski/vision/locator.py +575 -0
  110. rodski/vision/matcher.py +136 -0
  111. rodski/vision/ocr_locator.py +333 -0
  112. rodski/vision/omni_client.py +220 -0
  113. rodski/vision/screen_recorder.py +210 -0
  114. rodski/vision/screenshot.py +148 -0
  115. rodski-5.7.1.dist-info/METADATA +101 -0
  116. rodski-5.7.1.dist-info/RECORD +119 -0
  117. rodski-5.7.1.dist-info/WHEEL +5 -0
  118. rodski-5.7.1.dist-info/entry_points.txt +2 -0
  119. rodski-5.7.1.dist-info/top_level.txt +1 -0
rodski/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lightning Strike Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
rodski/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # RodSki - 自动化测试框架
2
+
3
+ 基于关键字驱动的现代化自动化测试框架,Python 重写版本。
4
+
5
+ ## 特性
6
+
7
+ - 🎯 关键字驱动 - 简单易用的测试语法
8
+ - 🔧 模型驱动 - 模型与数据分离
9
+ - 🌐 多驱动支持 - Playwright (Web) + PyWinAuto (Desktop) + Appium (Mobile)
10
+ - 📊 XML 用例 - 结构化测试定义
11
+ - 🔌 RESTful API - 接口测试支持
12
+
13
+ ## 快速开始
14
+
15
+ 📖 **[5分钟快速入门指南](docs/user-guides/QUICKSTART.md)** - 新手必读!
16
+
17
+ ### 安装
18
+
19
+ ```bash
20
+ pip install -r requirements.txt
21
+ playwright install chromium
22
+ ```
23
+
24
+ ### CLI 运行
25
+
26
+ ```bash
27
+ python3 cli_main.py run examples/product/DEMO/demo_site/case/demo_case.xml
28
+ ```
29
+
30
+ ## 项目结构
31
+
32
+ ```
33
+ rodski/
34
+ ├── core/ # 核心引擎
35
+ ├── drivers/ # 驱动层
36
+ ├── api/ # API 测试
37
+ ├── config/ # 配置
38
+ ├── data/ # 测试数据
39
+ ├── examples/ # 示例用例
40
+ └── docs/ # 文档
41
+ ```
42
+
43
+ ## 开发
44
+
45
+ ### 环境要求
46
+
47
+ - Python 3.8+
48
+ - Playwright
49
+
50
+ ### 贡献
51
+
52
+ 欢迎提交 Issue 和 Pull Request!
53
+
54
+ ## 许可证
55
+
56
+ MIT License
rodski/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ """RodSki Test Framework"""
2
+ __version__ = "5.7.1"
rodski/api/__init__.py ADDED
File without changes
@@ -0,0 +1,116 @@
1
+ """RESTful API 测试辅助工具"""
2
+ import json
3
+ import logging
4
+ from typing import Any, Dict, List, Optional
5
+ from jsonschema import validate, ValidationError
6
+ import requests
7
+ from requests.adapters import HTTPAdapter
8
+ from urllib3.util.retry import Retry
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class RestHelper:
14
+ """REST API 测试辅助类"""
15
+
16
+ @staticmethod
17
+ def _get_session(max_retries: int = 3, pool_connections: int = 10, pool_maxsize: int = 10) -> requests.Session:
18
+ """获取配置了连接池和重试的 Session"""
19
+ session = requests.Session()
20
+ retry_strategy = Retry(
21
+ total=max_retries,
22
+ backoff_factor=0.3,
23
+ status_forcelist=[429, 500, 502, 503, 504],
24
+ )
25
+ adapter = HTTPAdapter(max_retries=retry_strategy, pool_connections=pool_connections, pool_maxsize=pool_maxsize)
26
+ session.mount("http://", adapter)
27
+ session.mount("https://", adapter)
28
+ return session
29
+
30
+ @staticmethod
31
+ def validate_json_schema(data: Dict, schema: Dict) -> bool:
32
+ """验证 JSON Schema"""
33
+ try:
34
+ validate(instance=data, schema=schema)
35
+ return True
36
+ except ValidationError:
37
+ return False
38
+
39
+ @staticmethod
40
+ def jsonpath_extract(data: Dict, path: str) -> Any:
41
+ """简单 JSONPath 提取(支持点号路径)"""
42
+ keys = path.strip('$.').split('.')
43
+ current = data
44
+ for key in keys:
45
+ if isinstance(current, dict):
46
+ current = current.get(key)
47
+ else:
48
+ return None
49
+ return current
50
+
51
+ @staticmethod
52
+ def send_request(
53
+ method: str,
54
+ url: str,
55
+ headers: Optional[Dict[str, str]] = None,
56
+ body: Any = None,
57
+ timeout: float = 30.0,
58
+ max_retries: int = 3,
59
+ use_session: bool = True,
60
+ cookies: Optional[Dict[str, str]] = None,
61
+ ) -> requests.Response:
62
+ """发送 HTTP 请求"""
63
+ method = method.upper()
64
+ kwargs: Dict[str, Any] = {"headers": headers, "timeout": timeout}
65
+ if body is not None:
66
+ kwargs["json"] = body
67
+ if cookies:
68
+ kwargs["cookies"] = cookies
69
+
70
+ try:
71
+ logger.debug(f"Sending {method} request to {url}")
72
+ if use_session:
73
+ session = RestHelper._get_session(max_retries=max_retries)
74
+ response = session.request(method, url, **kwargs)
75
+ else:
76
+ response = requests.request(method, url, **kwargs)
77
+ logger.debug(f"Response: {response.status_code} in {response.elapsed.total_seconds():.3f}s")
78
+ return response
79
+ except requests.exceptions.Timeout as e:
80
+ logger.error(f"Request timeout: {url}")
81
+ raise
82
+ except requests.exceptions.ConnectionError as e:
83
+ logger.error(f"Connection error: {url}")
84
+ raise
85
+ except requests.exceptions.RequestException as e:
86
+ logger.error(f"Request failed: {url} - {str(e)}")
87
+ raise
88
+
89
+ @staticmethod
90
+ def assert_response_time(response: requests.Response, max_ms: float) -> bool:
91
+ """断言响应时间(毫秒)"""
92
+ elapsed_ms = response.elapsed.total_seconds() * 1000
93
+ return elapsed_ms <= max_ms
94
+
95
+ @staticmethod
96
+ def extract_headers(response: requests.Response, header_name: str) -> Optional[str]:
97
+ """提取响应头"""
98
+ return response.headers.get(header_name)
99
+
100
+ @staticmethod
101
+ def compare_responses(
102
+ resp1: Dict,
103
+ resp2: Dict,
104
+ ignore_fields: Optional[List[str]] = None,
105
+ ) -> bool:
106
+ """比较两个响应(忽略指定字段)"""
107
+ ignore_fields = ignore_fields or []
108
+
109
+ def _strip(d: Any) -> Any:
110
+ if isinstance(d, dict):
111
+ return {k: _strip(v) for k, v in d.items() if k not in ignore_fields}
112
+ if isinstance(d, list):
113
+ return [_strip(i) for i in d]
114
+ return d
115
+
116
+ return _strip(resp1) == _strip(resp2)
rodski/cli_main.py ADDED
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python3
2
+ """RodSki CLI 入口"""
3
+ import sys
4
+ import argparse
5
+ import traceback
6
+ from .rodski_cli import run, model, config, log, report, profile, docs
7
+
8
+ from rodski import __version__ as VERSION
9
+
10
+
11
+ def format_error(e, verbose=False):
12
+ """格式化错误信息,提高可读性"""
13
+ error_type = type(e).__name__
14
+ error_msg = str(e)
15
+
16
+ # 常见错误的友好提示
17
+ hints = {
18
+ FileNotFoundError: "请检查文件路径是否正确",
19
+ PermissionError: "请检查文件权限或以管理员身份运行",
20
+ ConnectionError: "请检查网络连接或目标服务是否可用",
21
+ TimeoutError: "操作超时,请检查网络或增加超时时间",
22
+ KeyboardInterrupt: "用户中断执行",
23
+ ImportError: "缺少依赖包,请运行: pip install -r requirements.txt",
24
+ }
25
+
26
+ hint = hints.get(type(e), "")
27
+ lines = [f"错误 [{error_type}]: {error_msg}"]
28
+ if hint:
29
+ lines.append(f"提示: {hint}")
30
+ if verbose:
31
+ lines.append("")
32
+ lines.append("详细堆栈信息:")
33
+ lines.append(traceback.format_exc())
34
+ return "\n".join(lines)
35
+
36
+
37
+ def main():
38
+ parser = argparse.ArgumentParser(
39
+ prog="rodski",
40
+ description="RodSki - 关键字驱动测试框架",
41
+ formatter_class=argparse.RawDescriptionHelpFormatter,
42
+ epilog="示例:\n"
43
+ " ski run case/ 执行测试用例\n"
44
+ " ski run case/ --dry-run 验证用例但不执行\n"
45
+ " ski run case/ --verbose 详细输出模式\n"
46
+ " ski run case/ --step-by-step 单步执行模式\n"
47
+ " ski run case/ --pause-on-error 错误时暂停\n"
48
+ " ski run case/ --interactive 交互模式\n"
49
+ " ski config list 查看配置\n"
50
+ )
51
+ parser.add_argument("--version", action="version", version=f"RodSki {VERSION}")
52
+ parser.add_argument("--verbose", action="store_true", help="详细输出模式")
53
+
54
+ subparsers = parser.add_subparsers(dest="command", help="子命令")
55
+
56
+ # run 子命令
57
+ run.setup_parser(subparsers)
58
+
59
+ # model 子命令
60
+ model.setup_parser(subparsers)
61
+
62
+ # config 子命令
63
+ config.setup_parser(subparsers)
64
+
65
+ # log 子命令
66
+ log.setup_parser(subparsers)
67
+
68
+ # report 子命令
69
+ report.setup_parser(subparsers)
70
+
71
+ # profile 子命令
72
+ profile.setup_parser(subparsers)
73
+
74
+ # docs 子命令
75
+ docs.setup_parser(subparsers)
76
+
77
+ args = parser.parse_args()
78
+
79
+ if not args.command:
80
+ parser.print_help()
81
+ return 0
82
+
83
+ # 执行对应子命令
84
+ handlers = {
85
+ "run": run.handle,
86
+ "model": model.handle,
87
+ "config": config.handle,
88
+ "log": log.handle,
89
+ "report": report.handle,
90
+ "profile": profile.handle,
91
+ "docs": docs.handle
92
+ }
93
+
94
+ verbose = getattr(args, "verbose", False)
95
+
96
+ try:
97
+ return handlers[args.command](args)
98
+ except KeyboardInterrupt:
99
+ print("\n操作已被用户中断", file=sys.stderr)
100
+ return 130
101
+ except Exception as e:
102
+ print(format_error(e, verbose=verbose), file=sys.stderr)
103
+ return 1
104
+
105
+ if __name__ == "__main__":
106
+ sys.exit(main())
File without changes
@@ -0,0 +1,8 @@
1
+ {
2
+ "platformName": "Android",
3
+ "deviceName": "Android Emulator",
4
+ "automationName": "UiAutomator2",
5
+ "appPackage": "com.example.app",
6
+ "appActivity": ".MainActivity",
7
+ "serverUrl": "http://localhost:4723"
8
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "driver": "web",
3
+ "browser": "chromium",
4
+ "headless": false,
5
+ "timeout": 60,
6
+ "retry": 0,
7
+ "retry_delay": 1.0,
8
+ "retry_on_errors": [
9
+ "ElementNotFound",
10
+ "Timeout",
11
+ "StaleElement"
12
+ ],
13
+ "log_level": "INFO",
14
+ "log_dir": "logs",
15
+ "report_format": "html",
16
+ "auto_screenshot_on_failure": true,
17
+ "auto_screenshot_on_step": true,
18
+ "screenshot_dir": "screenshots",
19
+ "smart_wait_enabled": true,
20
+ "smart_wait_max_retries": 30,
21
+ "smart_wait_retry_interval": 0.3,
22
+ "smart_wait_log_retry": true,
23
+ "element_wait_timeout": 0.5,
24
+ "element_retry_interval": 0.1
25
+ }
@@ -0,0 +1,96 @@
1
+ # RodSki 默认配置 - Iteration-04 异常处理与智能恢复
2
+
3
+ execution:
4
+ # 最大重试次数(全局)
5
+ max_retries: 3
6
+ # 是否启用智能恢复
7
+ recovery_enabled: true
8
+ # 单次恢复最大尝试次数
9
+ recovery_max_attempts: 2
10
+ # 失败时自动截图
11
+ screenshot_on_failure: true
12
+ # 浏览器实例最大步数(超过后自动回收)
13
+ browser_restart_interval: 50
14
+ # 恢复动作之间等待秒数
15
+ recovery_wait_seconds: 1
16
+
17
+ verification:
18
+ # AI 视觉验证模型
19
+ model: claude
20
+ # AI 请求超时(秒)
21
+ timeout: 30
22
+ # 模型名称(空表示提供者默认值)
23
+ model_name: ""
24
+ # API 密钥环境变量名
25
+ api_key_env: ANTHROPIC_API_KEY
26
+ # 代理地址(空表示官方地址)
27
+ base_url: ""
28
+
29
+ diagnosis:
30
+ # 是否启用 AI 辅助诊断
31
+ ai_enabled: true
32
+ # 诊断超时(秒)
33
+ timeout: 30
34
+ # AI 视觉分析失败时是否回退到规则诊断
35
+ fallback_to_rules: true
36
+
37
+ recovery:
38
+ # 恢复动作注册表(可扩展自定义动作)
39
+ actions: {}
40
+ # custom_action: "my_module.custom_handler"
41
+
42
+ snapshot:
43
+ # 是否启用执行快照(断点续跑)
44
+ enabled: false
45
+ # 快照存放目录
46
+ snapshot_dir: "snapshots"
47
+ # 每次步骤执行后保存快照(可能导致性能下降)
48
+ save_on_every_step: false
49
+
50
+ result:
51
+ # 记录步骤执行时间
52
+ record_step_timing: true
53
+ # 捕获失败上下文(页面源码、控制台日志等)
54
+ capture_failure_context: true
55
+ # 在结果中嵌入诊断信息
56
+ embed_diagnosis: true
57
+
58
+ metadata:
59
+ # 从用例中提取元数据
60
+ extract_from_case: true
61
+ # 在 CLI 中显示元数据
62
+ show_in_cli: true
63
+
64
+ statistics:
65
+ # 结果目录
66
+ result_dir: "result"
67
+ # 不稳定用例阈值(失败率)
68
+ flaky_threshold: 0.3
69
+ # 显示最慢用例数量
70
+ top_slow_count: 10
71
+
72
+ execution:
73
+ # 最大重试次数(全局)
74
+ max_retries: 3
75
+ # 是否启用智能恢复
76
+ recovery_enabled: true
77
+ # 单次恢复最大尝试次数
78
+ recovery_max_attempts: 2
79
+ # 失败时自动截图
80
+ screenshot_on_failure: true
81
+ # 浏览器实例最大步数(超过后自动回收)
82
+ browser_restart_interval: 50
83
+ # 恢复动作之间等待秒数
84
+ recovery_wait_seconds: 1
85
+ # 允许条件执行
86
+ allow_conditions: true
87
+ # 允许循环执行
88
+ allow_loops: true
89
+ # 允许动态步骤注入
90
+ allow_dynamic_steps: true
91
+ # 循环最大迭代次数
92
+ loop_max_iterations: 1000
93
+ # 动态步骤配置
94
+ dynamic_step:
95
+ # 每个触发点最大动态步骤数
96
+ max_per_trigger: 10
@@ -0,0 +1,7 @@
1
+ {
2
+ "platformName": "iOS",
3
+ "deviceName": "iPhone 14",
4
+ "automationName": "XCUITest",
5
+ "bundleId": "com.example.app",
6
+ "serverUrl": "http://localhost:4723"
7
+ }
@@ -0,0 +1,58 @@
1
+ # RodSki LLM 统一配置
2
+ # 所有 LLM 相关配置集中在此文件
3
+
4
+ # 默认 provider
5
+ provider: claude
6
+
7
+ # Provider 配置
8
+ providers:
9
+ claude:
10
+ model: claude-opus-4-6
11
+ base_url: "http://code.casstime.ai" # 可选代理地址
12
+ api_key_env: ANTHROPIC_API_KEY
13
+ timeout: 10
14
+ max_tokens: 1024
15
+
16
+ openai:
17
+ model: gpt-5.4
18
+ base_url: "http://code.casstime.ai"
19
+ api_key_env: OPENAI_API_KEY
20
+ timeout: 10
21
+ max_tokens: 2000
22
+
23
+ # 能力配置
24
+ capabilities:
25
+ vision_locator:
26
+ provider: claude # 可覆盖默认 provider
27
+ screenshot_verifier:
28
+ provider: claude
29
+ test_reviewer:
30
+ provider: openai
31
+ temperature: 0.1
32
+ max_tokens: 2000
33
+ enable_vision: true
34
+ max_screenshots: 10
35
+ system_prompt: |
36
+ 你是一个专业的自动化测试结果审查员。
37
+ 你的任务是根据测试用例定义、执行日志和截图,判断测试是否真正成功。
38
+
39
+ 判断标准:
40
+ 1. 所有步骤是否按预期执行
41
+ 2. 截图中的界面状态是否符合预期
42
+ 3. 是否有异常、错误或警告
43
+ 4. 最终结果是否达到测试目标
44
+
45
+ 输出格式:
46
+ {
47
+ "verdict": "PASS|FAIL|SUSPICIOUS",
48
+ "confidence": 0.0-1.0,
49
+ "reason": "判断理由",
50
+ "issues": ["发现的问题列表"]
51
+ }
52
+
53
+ # OmniParser 配置
54
+ omniparser:
55
+ url: "http://14.103.175.167:7862/parse/"
56
+ box_threshold: 0.18
57
+ iou_threshold: 0.7
58
+ timeout: 5
@@ -0,0 +1,31 @@
1
+ # DEPRECATED: 配置已迁移到 llm_config.yaml。本文件仅作为向后兼容保留。
2
+ # LLM Reviewer 配置
3
+
4
+ # API 配置
5
+ api_base: "http://code.casstime.ai"
6
+ api_key: "sk-f3tf9sUywnTBNbkQesLsaEE5Abtz1vZX88Sqvqm5MG7cGg3w"
7
+ model: "gpt-5.4"
8
+ temperature: 0.1
9
+ max_tokens: 2000
10
+
11
+ # 审查配置
12
+ review:
13
+ enable_vision: true
14
+ max_screenshots: 10
15
+ system_prompt: |
16
+ 你是一个专业的自动化测试结果审查员。
17
+ 你的任务是根据测试用例定义、执行日志和截图,判断测试是否真正成功。
18
+
19
+ 判断标准:
20
+ 1. 所有步骤是否按预期执行
21
+ 2. 截图中的界面状态是否符合预期
22
+ 3. 是否有异常、错误或警告
23
+ 4. 最终结果是否达到测试目标
24
+
25
+ 输出格式:
26
+ {
27
+ "verdict": "PASS|FAIL|SUSPICIOUS",
28
+ "confidence": 0.0-1.0,
29
+ "reason": "判断理由",
30
+ "issues": ["发现的问题列表"]
31
+ }
@@ -0,0 +1,14 @@
1
+ # DEPRECATED: 配置已迁移到 llm_config.yaml。本文件仅作为向后兼容保留。
2
+ omniparser:
3
+ url: http://14.103.175.167:7862/parse/
4
+ box_threshold: 0.18
5
+ iou_threshold: 0.7
6
+ timeout: 5
7
+
8
+ llm:
9
+ provider: claude # claude / openai / qwen
10
+ model: claude-opus-4-6
11
+ base_url: "" # 留空使用默认,或填代理地址
12
+ api_key_env: ANTHROPIC_API_KEY # 环境变量名
13
+ timeout: 10
14
+ max_tokens: 1024
@@ -0,0 +1,36 @@
1
+ """Core package — lazy imports to avoid heavy optional dependencies at import time"""
2
+
3
+ __all__ = [
4
+ 'KeywordEngine',
5
+ 'TaskExecutor',
6
+ 'ConfigManager',
7
+ 'Logger',
8
+ 'RodskiXmlValidator',
9
+ 'XmlSchemaValidationError',
10
+ 'DriverFactory',
11
+ ]
12
+
13
+
14
+ def __getattr__(name):
15
+ if name == 'KeywordEngine':
16
+ from .keyword_engine import KeywordEngine
17
+ return KeywordEngine
18
+ if name == 'TaskExecutor':
19
+ from .task_executor import TaskExecutor
20
+ return TaskExecutor
21
+ if name == 'ConfigManager':
22
+ from .config_manager import ConfigManager
23
+ return ConfigManager
24
+ if name == 'Logger':
25
+ from .logger import Logger
26
+ return Logger
27
+ if name == 'RodskiXmlValidator':
28
+ from .xml_schema_validator import RodskiXmlValidator
29
+ return RodskiXmlValidator
30
+ if name == 'XmlSchemaValidationError':
31
+ from .exceptions import XmlSchemaValidationError
32
+ return XmlSchemaValidationError
33
+ if name == 'DriverFactory':
34
+ from .driver_factory import DriverFactory
35
+ return DriverFactory
36
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,16 @@
1
+ """视觉断言模块 — lazy imports to avoid requiring cv2 at import time."""
2
+
3
+ __all__ = ["BaseAssertion", "ImageMatcher", "VideoAnalyzer"]
4
+
5
+
6
+ def __getattr__(name):
7
+ if name == 'BaseAssertion':
8
+ from .base_assertion import BaseAssertion
9
+ return BaseAssertion
10
+ if name == 'ImageMatcher':
11
+ from .image_matcher import ImageMatcher
12
+ return ImageMatcher
13
+ if name == 'VideoAnalyzer':
14
+ from .video_analyzer import VideoAnalyzer
15
+ return VideoAnalyzer
16
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,35 @@
1
+ """断言基类 - 定义断言接口"""
2
+ from abc import ABC, abstractmethod
3
+ from typing import Dict, Any
4
+ from pathlib import Path
5
+
6
+
7
+ class BaseAssertion(ABC):
8
+ """视觉断言基类
9
+
10
+ 所有断言实现必须继承此类并实现 match 方法。
11
+ """
12
+
13
+ @abstractmethod
14
+ def match(self, *args, **kwargs) -> Dict[str, Any]:
15
+ """执行断言匹配
16
+
17
+ Returns:
18
+ 结构化结果字典,至少包含:
19
+ - matched: bool 是否匹配成功
20
+ - similarity: float 匹配度
21
+ - threshold: float 阈值
22
+ """
23
+ pass
24
+
25
+ @staticmethod
26
+ def resolve_reference_path(reference: str, module_dir: Path) -> Path:
27
+ """将相对路径解析为绝对路径
28
+
29
+ 预期图片路径相对于 `images/assert/` 目录。
30
+ """
31
+ images_dir = module_dir / "images" / "assert"
32
+ ref_path = Path(reference)
33
+ if ref_path.is_absolute():
34
+ return ref_path
35
+ return images_dir / reference