infomankit 0.3.23__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 (143) hide show
  1. infoman/__init__.py +1 -0
  2. infoman/cli/README.md +378 -0
  3. infoman/cli/__init__.py +7 -0
  4. infoman/cli/commands/__init__.py +3 -0
  5. infoman/cli/commands/init.py +312 -0
  6. infoman/cli/scaffold.py +634 -0
  7. infoman/cli/templates/Makefile.template +132 -0
  8. infoman/cli/templates/app/__init__.py.template +3 -0
  9. infoman/cli/templates/app/app.py.template +4 -0
  10. infoman/cli/templates/app/models_base.py.template +18 -0
  11. infoman/cli/templates/app/models_entity_init.py.template +11 -0
  12. infoman/cli/templates/app/models_schemas_init.py.template +11 -0
  13. infoman/cli/templates/app/repository_init.py.template +11 -0
  14. infoman/cli/templates/app/routers_init.py.template +15 -0
  15. infoman/cli/templates/app/services_init.py.template +11 -0
  16. infoman/cli/templates/app/static_index.html.template +39 -0
  17. infoman/cli/templates/app/static_main.js.template +31 -0
  18. infoman/cli/templates/app/static_style.css.template +111 -0
  19. infoman/cli/templates/app/utils_init.py.template +11 -0
  20. infoman/cli/templates/config/.env.dev.template +43 -0
  21. infoman/cli/templates/config/.env.prod.template +43 -0
  22. infoman/cli/templates/config/README.md.template +28 -0
  23. infoman/cli/templates/docker/.dockerignore.template +60 -0
  24. infoman/cli/templates/docker/Dockerfile.template +47 -0
  25. infoman/cli/templates/docker/README.md.template +240 -0
  26. infoman/cli/templates/docker/docker-compose.yml.template +81 -0
  27. infoman/cli/templates/docker/mysql_custom.cnf.template +42 -0
  28. infoman/cli/templates/docker/mysql_init.sql.template +15 -0
  29. infoman/cli/templates/project/.env.example.template +1 -0
  30. infoman/cli/templates/project/.gitignore.template +60 -0
  31. infoman/cli/templates/project/Makefile.template +38 -0
  32. infoman/cli/templates/project/README.md.template +137 -0
  33. infoman/cli/templates/project/deploy.sh.template +97 -0
  34. infoman/cli/templates/project/main.py.template +10 -0
  35. infoman/cli/templates/project/manage.sh.template +97 -0
  36. infoman/cli/templates/project/pyproject.toml.template +47 -0
  37. infoman/cli/templates/project/service.sh.template +203 -0
  38. infoman/config/__init__.py +25 -0
  39. infoman/config/base.py +67 -0
  40. infoman/config/db_cache.py +237 -0
  41. infoman/config/db_relation.py +181 -0
  42. infoman/config/db_vector.py +39 -0
  43. infoman/config/jwt.py +16 -0
  44. infoman/config/llm.py +16 -0
  45. infoman/config/log.py +627 -0
  46. infoman/config/mq.py +26 -0
  47. infoman/config/settings.py +65 -0
  48. infoman/llm/__init__.py +0 -0
  49. infoman/llm/llm.py +297 -0
  50. infoman/logger/__init__.py +57 -0
  51. infoman/logger/context.py +191 -0
  52. infoman/logger/core.py +358 -0
  53. infoman/logger/filters.py +157 -0
  54. infoman/logger/formatters.py +138 -0
  55. infoman/logger/handlers.py +276 -0
  56. infoman/logger/metrics.py +160 -0
  57. infoman/performance/README.md +583 -0
  58. infoman/performance/__init__.py +19 -0
  59. infoman/performance/cli.py +215 -0
  60. infoman/performance/config.py +166 -0
  61. infoman/performance/reporter.py +519 -0
  62. infoman/performance/runner.py +303 -0
  63. infoman/performance/standards.py +222 -0
  64. infoman/service/__init__.py +8 -0
  65. infoman/service/app.py +67 -0
  66. infoman/service/core/__init__.py +0 -0
  67. infoman/service/core/auth.py +105 -0
  68. infoman/service/core/lifespan.py +132 -0
  69. infoman/service/core/monitor.py +57 -0
  70. infoman/service/core/response.py +37 -0
  71. infoman/service/exception/__init__.py +7 -0
  72. infoman/service/exception/error.py +274 -0
  73. infoman/service/exception/exception.py +25 -0
  74. infoman/service/exception/handler.py +238 -0
  75. infoman/service/infrastructure/__init__.py +8 -0
  76. infoman/service/infrastructure/base.py +212 -0
  77. infoman/service/infrastructure/db_cache/__init__.py +8 -0
  78. infoman/service/infrastructure/db_cache/manager.py +194 -0
  79. infoman/service/infrastructure/db_relation/__init__.py +41 -0
  80. infoman/service/infrastructure/db_relation/manager.py +300 -0
  81. infoman/service/infrastructure/db_relation/manager_pro.py +408 -0
  82. infoman/service/infrastructure/db_relation/mysql.py +52 -0
  83. infoman/service/infrastructure/db_relation/pgsql.py +54 -0
  84. infoman/service/infrastructure/db_relation/sqllite.py +25 -0
  85. infoman/service/infrastructure/db_vector/__init__.py +40 -0
  86. infoman/service/infrastructure/db_vector/manager.py +201 -0
  87. infoman/service/infrastructure/db_vector/qdrant.py +322 -0
  88. infoman/service/infrastructure/mq/__init__.py +15 -0
  89. infoman/service/infrastructure/mq/manager.py +178 -0
  90. infoman/service/infrastructure/mq/nats/__init__.py +0 -0
  91. infoman/service/infrastructure/mq/nats/nats_client.py +57 -0
  92. infoman/service/infrastructure/mq/nats/nats_event_router.py +25 -0
  93. infoman/service/launch.py +284 -0
  94. infoman/service/middleware/__init__.py +7 -0
  95. infoman/service/middleware/base.py +41 -0
  96. infoman/service/middleware/logging.py +51 -0
  97. infoman/service/middleware/rate_limit.py +301 -0
  98. infoman/service/middleware/request_id.py +21 -0
  99. infoman/service/middleware/white_list.py +24 -0
  100. infoman/service/models/__init__.py +8 -0
  101. infoman/service/models/base.py +441 -0
  102. infoman/service/models/type/embed.py +70 -0
  103. infoman/service/routers/__init__.py +18 -0
  104. infoman/service/routers/health_router.py +311 -0
  105. infoman/service/routers/monitor_router.py +44 -0
  106. infoman/service/utils/__init__.py +8 -0
  107. infoman/service/utils/cache/__init__.py +0 -0
  108. infoman/service/utils/cache/cache.py +192 -0
  109. infoman/service/utils/module_loader.py +10 -0
  110. infoman/service/utils/parse.py +10 -0
  111. infoman/service/utils/resolver/__init__.py +8 -0
  112. infoman/service/utils/resolver/base.py +47 -0
  113. infoman/service/utils/resolver/resp.py +102 -0
  114. infoman/service/vector/__init__.py +20 -0
  115. infoman/service/vector/base.py +56 -0
  116. infoman/service/vector/qdrant.py +125 -0
  117. infoman/service/vector/service.py +67 -0
  118. infoman/utils/__init__.py +2 -0
  119. infoman/utils/decorators/__init__.py +8 -0
  120. infoman/utils/decorators/cache.py +137 -0
  121. infoman/utils/decorators/retry.py +99 -0
  122. infoman/utils/decorators/safe_execute.py +99 -0
  123. infoman/utils/decorators/timing.py +99 -0
  124. infoman/utils/encryption/__init__.py +8 -0
  125. infoman/utils/encryption/aes.py +66 -0
  126. infoman/utils/encryption/ecc.py +108 -0
  127. infoman/utils/encryption/rsa.py +112 -0
  128. infoman/utils/file/__init__.py +0 -0
  129. infoman/utils/file/handler.py +22 -0
  130. infoman/utils/hash/__init__.py +0 -0
  131. infoman/utils/hash/hash.py +61 -0
  132. infoman/utils/http/__init__.py +8 -0
  133. infoman/utils/http/client.py +62 -0
  134. infoman/utils/http/info.py +94 -0
  135. infoman/utils/http/result.py +19 -0
  136. infoman/utils/notification/__init__.py +8 -0
  137. infoman/utils/notification/feishu.py +35 -0
  138. infoman/utils/text/__init__.py +8 -0
  139. infoman/utils/text/extractor.py +111 -0
  140. infomankit-0.3.23.dist-info/METADATA +632 -0
  141. infomankit-0.3.23.dist-info/RECORD +143 -0
  142. infomankit-0.3.23.dist-info/WHEEL +4 -0
  143. infomankit-0.3.23.dist-info/entry_points.txt +5 -0
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 性能测试命令行工具
4
+
5
+ 提供简单的 CLI 接口用于运行性能测试
6
+ """
7
+
8
+ import asyncio
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Optional
12
+
13
+ import click
14
+ from loguru import logger
15
+
16
+ from .config import TestConfig
17
+ from .runner import PerformanceTestRunner
18
+ from .reporter import HTMLReporter
19
+
20
+
21
+ @click.group()
22
+ @click.version_option()
23
+ def cli():
24
+ """Infomankit 性能测试工具"""
25
+ pass
26
+
27
+
28
+ @cli.command()
29
+ @click.option(
30
+ "-c",
31
+ "--config",
32
+ "config_file",
33
+ required=True,
34
+ type=click.Path(exists=True),
35
+ help="配置文件路径 (YAML)",
36
+ )
37
+ @click.option(
38
+ "-o",
39
+ "--output",
40
+ "output_file",
41
+ type=click.Path(),
42
+ help="报告输出路径 (覆盖配置文件中的设置)",
43
+ )
44
+ @click.option(
45
+ "-u",
46
+ "--users",
47
+ "concurrent_users",
48
+ type=int,
49
+ help="并发用户数 (覆盖配置文件中的设置)",
50
+ )
51
+ @click.option(
52
+ "-d",
53
+ "--duration",
54
+ type=int,
55
+ help="测试持续时间(秒) (覆盖配置文件中的设置)",
56
+ )
57
+ @click.option(
58
+ "-v", "--verbose", is_flag=True, help="显示详细日志"
59
+ )
60
+ def run(
61
+ config_file: str,
62
+ output_file: Optional[str],
63
+ concurrent_users: Optional[int],
64
+ duration: Optional[int],
65
+ verbose: bool,
66
+ ):
67
+ """运行性能测试"""
68
+
69
+ # 配置日志级别
70
+ if not verbose:
71
+ logger.remove()
72
+ logger.add(sys.stderr, level="INFO")
73
+
74
+ try:
75
+ # 加载配置
76
+ logger.info(f"加载配置: {config_file}")
77
+ config = TestConfig.from_yaml(config_file)
78
+
79
+ # 覆盖命令行参数
80
+ if concurrent_users:
81
+ config.concurrent_users = concurrent_users
82
+ logger.info(f"覆盖并发用户数: {concurrent_users}")
83
+
84
+ if duration:
85
+ config.duration = duration
86
+ logger.info(f"覆盖测试时长: {duration}秒")
87
+
88
+ if output_file:
89
+ config.report_output = output_file
90
+ logger.info(f"覆盖报告输出: {output_file}")
91
+
92
+ # 显示测试信息
93
+ logger.info("=" * 60)
94
+ logger.info(f"项目: {config.project_name}")
95
+ logger.info(f"目标: {config.base_url}")
96
+ logger.info(f"并发用户: {config.concurrent_users}")
97
+ logger.info(f"持续时间: {config.duration}秒")
98
+ logger.info(f"测试用例: {len(config.get_enabled_test_cases())}个")
99
+ logger.info("=" * 60)
100
+
101
+ # 运行测试
102
+ asyncio.run(_run_test(config))
103
+
104
+ except FileNotFoundError as e:
105
+ logger.error(f"配置文件不存在: {e}")
106
+ sys.exit(1)
107
+ except Exception as e:
108
+ logger.error(f"测试失败: {e}")
109
+ if verbose:
110
+ raise
111
+ sys.exit(1)
112
+
113
+
114
+ async def _run_test(config: TestConfig):
115
+ """执行测试"""
116
+ # 运行测试
117
+ runner = PerformanceTestRunner(config)
118
+ results = await runner.run()
119
+
120
+ # 显示简要结果
121
+ logger.info("\n" + "=" * 60)
122
+ logger.info("测试结果汇总")
123
+ logger.info("=" * 60)
124
+
125
+ for name, result in results.items():
126
+ logger.info(f"\n📊 {name}")
127
+ logger.info(f" 总请求: {result.total_requests}")
128
+ logger.info(f" 成功率: {result.success_rate:.2f}%")
129
+ logger.info(f" 平均响应: {result.avg_response_time:.2f}ms")
130
+ logger.info(f" P95: {result.p95_response_time:.2f}ms")
131
+ logger.info(f" 吞吐量: {result.throughput:.2f} req/s")
132
+ logger.info(f" 评级: {result.overall_level}")
133
+
134
+ # 生成报告
135
+ logger.info("\n" + "=" * 60)
136
+ logger.info("生成报告...")
137
+ reporter = HTMLReporter(config)
138
+ report_path = reporter.generate(results)
139
+ logger.success(f"✅ 报告已生成: {report_path}")
140
+ logger.info("=" * 60)
141
+
142
+
143
+ @cli.command()
144
+ @click.argument("output", type=click.Path())
145
+ def init(output: str):
146
+ """生成示例配置文件"""
147
+ config = TestConfig(
148
+ project_name="My API",
149
+ base_url="http://localhost:8000",
150
+ concurrent_users=10,
151
+ duration=60,
152
+ )
153
+
154
+ # 添加示例测试用例
155
+ from .config import APITestCase
156
+
157
+ config.add_test_case(
158
+ APITestCase(
159
+ name="健康检查",
160
+ url="/api/health",
161
+ method="GET",
162
+ interface_type="fast",
163
+ description="API 健康检查",
164
+ )
165
+ )
166
+
167
+ config.add_test_case(
168
+ APITestCase(
169
+ name="用户列表",
170
+ url="/api/v1/users",
171
+ method="GET",
172
+ interface_type="normal",
173
+ params={"page": 1, "page_size": 20},
174
+ description="用户列表查询",
175
+ )
176
+ )
177
+
178
+ # 保存配置
179
+ config.to_yaml(output)
180
+ logger.success(f"✅ 配置文件已生成: {output}")
181
+ logger.info("请编辑配置文件后运行测试:")
182
+ logger.info(f" infoman perf run -c {output}")
183
+
184
+
185
+ @cli.command()
186
+ def standards():
187
+ """显示性能标准"""
188
+ from .standards import PerformanceStandards
189
+
190
+ logger.info("=" * 60)
191
+ logger.info("性能标准")
192
+ logger.info("=" * 60)
193
+
194
+ for interface_type, threshold in PerformanceStandards.STANDARDS.items():
195
+ logger.info(f"\n{interface_type.upper()} 接口:")
196
+ logger.info(f" 优秀 (Excellent): < {threshold.excellent}ms")
197
+ logger.info(f" 良好 (Good): < {threshold.good}ms")
198
+ logger.info(f" 可接受 (Acceptable): < {threshold.acceptable}ms")
199
+ logger.info(f" 较差 (Poor): < {threshold.poor}ms")
200
+ logger.info(f" 严重 (Critical): >= {threshold.poor}ms")
201
+
202
+ logger.info("\n" + "=" * 60)
203
+ logger.info("成功率标准")
204
+ logger.info("=" * 60)
205
+ for level, rate in PerformanceStandards.SUCCESS_RATE_STANDARDS.items():
206
+ logger.info(f" {level:12}: >= {rate}%")
207
+
208
+
209
+ def main():
210
+ """主函数"""
211
+ cli()
212
+
213
+
214
+ if __name__ == "__main__":
215
+ main()
@@ -0,0 +1,166 @@
1
+ """
2
+ 性能测试配置
3
+
4
+ 定义测试配置和测试用例
5
+ """
6
+
7
+ from typing import Dict, Any, List, Optional, Literal
8
+ from pydantic import BaseModel, Field
9
+ import yaml
10
+ from pathlib import Path
11
+
12
+
13
+ class APITestCase(BaseModel):
14
+ """单个 API 测试用例"""
15
+
16
+ name: str = Field(..., description="测试用例名称")
17
+ url: str = Field(..., description="API URL (相对路径或绝对路径)")
18
+ method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = Field(
19
+ default="GET",
20
+ description="HTTP 方法"
21
+ )
22
+ headers: Dict[str, str] = Field(
23
+ default_factory=dict,
24
+ description="请求头"
25
+ )
26
+ params: Dict[str, Any] = Field(
27
+ default_factory=dict,
28
+ description="URL 参数 (GET)"
29
+ )
30
+ json: Optional[Dict[str, Any]] = Field(
31
+ default=None,
32
+ description="JSON 请求体 (POST/PUT/PATCH)"
33
+ )
34
+ data: Optional[Dict[str, Any]] = Field(
35
+ default=None,
36
+ description="表单数据"
37
+ )
38
+ interface_type: Literal["fast", "normal", "complex", "heavy"] = Field(
39
+ default="normal",
40
+ description="接口类型 (用于性能标准评估)"
41
+ )
42
+ timeout: int = Field(
43
+ default=30,
44
+ description="请求超时时间 (秒)"
45
+ )
46
+ description: str = Field(
47
+ default="",
48
+ description="测试描述"
49
+ )
50
+ enabled: bool = Field(
51
+ default=True,
52
+ description="是否启用此测试"
53
+ )
54
+
55
+
56
+ class TestConfig(BaseModel):
57
+ """性能测试配置"""
58
+
59
+ # 基础配置
60
+ project_name: str = Field(default="Infomankit", description="项目名称")
61
+ base_url: str = Field(default="http://localhost:8000", description="基础 URL")
62
+
63
+ # 并发配置
64
+ concurrent_users: int = Field(default=10, description="并发用户数")
65
+ duration: int = Field(default=60, description="测试持续时间 (秒)")
66
+ spawn_rate: int = Field(default=1, description="每秒启动用户数")
67
+
68
+ # 全局请求头
69
+ global_headers: Dict[str, str] = Field(
70
+ default_factory=lambda: {
71
+ "User-Agent": "Infomankit-Performance-Test/1.0",
72
+ "Accept": "application/json",
73
+ },
74
+ description="全局请求头"
75
+ )
76
+
77
+ # 认证配置
78
+ auth_type: Optional[Literal["basic", "bearer", "custom"]] = Field(
79
+ default=None,
80
+ description="认证类型"
81
+ )
82
+ auth_token: Optional[str] = Field(default=None, description="Bearer Token")
83
+ auth_username: Optional[str] = Field(default=None, description="Basic Auth 用户名")
84
+ auth_password: Optional[str] = Field(default=None, description="Basic Auth 密码")
85
+
86
+ # 测试用例
87
+ test_cases: List[APITestCase] = Field(
88
+ default_factory=list,
89
+ description="API 测试用例列表"
90
+ )
91
+
92
+ # 报告配置
93
+ report_title: str = Field(default="性能测试报告", description="报告标题")
94
+ report_output: str = Field(
95
+ default="performance-report.html",
96
+ description="报告输出路径"
97
+ )
98
+
99
+ # 高级配置
100
+ think_time_min: int = Field(default=1, description="最小思考时间 (秒)")
101
+ think_time_max: int = Field(default=3, description="最大思考时间 (秒)")
102
+
103
+ stop_on_error: bool = Field(
104
+ default=False,
105
+ description="遇到错误时停止测试"
106
+ )
107
+
108
+ class Config:
109
+ json_schema_extra = {
110
+ "example": {
111
+ "project_name": "Infomankit API",
112
+ "base_url": "http://localhost:8000",
113
+ "concurrent_users": 50,
114
+ "duration": 120,
115
+ "auth_type": "bearer",
116
+ "auth_token": "your-token-here",
117
+ "test_cases": [
118
+ {
119
+ "name": "健康检查",
120
+ "url": "/api/health",
121
+ "method": "GET",
122
+ "interface_type": "fast",
123
+ },
124
+ {
125
+ "name": "用户列表",
126
+ "url": "/api/v1/users",
127
+ "method": "GET",
128
+ "interface_type": "normal",
129
+ "params": {"page": 1, "page_size": 20},
130
+ },
131
+ ]
132
+ }
133
+ }
134
+
135
+ @classmethod
136
+ def from_yaml(cls, filepath: str) -> "TestConfig":
137
+ """从 YAML 文件加载配置"""
138
+ path = Path(filepath)
139
+ if not path.exists():
140
+ raise FileNotFoundError(f"配置文件不存在: {filepath}")
141
+
142
+ with open(path, "r", encoding="utf-8") as f:
143
+ data = yaml.safe_load(f)
144
+
145
+ return cls(**data)
146
+
147
+ def to_yaml(self, filepath: str):
148
+ """保存配置到 YAML 文件"""
149
+ path = Path(filepath)
150
+ path.parent.mkdir(parents=True, exist_ok=True)
151
+
152
+ with open(path, "w", encoding="utf-8") as f:
153
+ yaml.dump(
154
+ self.model_dump(exclude_none=True),
155
+ f,
156
+ allow_unicode=True,
157
+ sort_keys=False,
158
+ )
159
+
160
+ def add_test_case(self, test_case: APITestCase):
161
+ """添加测试用例"""
162
+ self.test_cases.append(test_case)
163
+
164
+ def get_enabled_test_cases(self) -> List[APITestCase]:
165
+ """获取启用的测试用例"""
166
+ return [tc for tc in self.test_cases if tc.enabled]