stress-test-kit 0.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.
- stress_test_kit-0.1.0/LICENSE +21 -0
- stress_test_kit-0.1.0/PKG-INFO +92 -0
- stress_test_kit-0.1.0/README.md +56 -0
- stress_test_kit-0.1.0/setup.cfg +4 -0
- stress_test_kit-0.1.0/setup.py +46 -0
- stress_test_kit-0.1.0/stress_test_kit/__init__.py +5 -0
- stress_test_kit-0.1.0/stress_test_kit/__main__.py +5 -0
- stress_test_kit-0.1.0/stress_test_kit/cli.py +115 -0
- stress_test_kit-0.1.0/stress_test_kit/frontend/assets/index-CmHHqmG4.js +150 -0
- stress_test_kit-0.1.0/stress_test_kit/frontend/assets/index-iaKBrxqZ.css +1 -0
- stress_test_kit-0.1.0/stress_test_kit/frontend/index.html +13 -0
- stress_test_kit-0.1.0/stress_test_kit/load_machine.py +66 -0
- stress_test_kit-0.1.0/stress_test_kit/locustfile_generator.py +337 -0
- stress_test_kit-0.1.0/stress_test_kit/models.py +170 -0
- stress_test_kit-0.1.0/stress_test_kit/param_files.py +71 -0
- stress_test_kit-0.1.0/stress_test_kit/process_manager.py +354 -0
- stress_test_kit-0.1.0/stress_test_kit/sampler.py +447 -0
- stress_test_kit-0.1.0/stress_test_kit/server.py +1022 -0
- stress_test_kit-0.1.0/stress_test_kit.egg-info/PKG-INFO +92 -0
- stress_test_kit-0.1.0/stress_test_kit.egg-info/SOURCES.txt +22 -0
- stress_test_kit-0.1.0/stress_test_kit.egg-info/dependency_links.txt +1 -0
- stress_test_kit-0.1.0/stress_test_kit.egg-info/entry_points.txt +2 -0
- stress_test_kit-0.1.0/stress_test_kit.egg-info/requires.txt +10 -0
- stress_test_kit-0.1.0/stress_test_kit.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 gg.zhao
|
|
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.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stress-test-kit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: 本地压测工具,基于 Locust 和 FastAPI
|
|
5
|
+
Author: gg.zhao
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: fastapi>=0.100.0
|
|
18
|
+
Requires-Dist: uvicorn[standard]>=0.23.0
|
|
19
|
+
Requires-Dist: sqlalchemy>=2.0.0
|
|
20
|
+
Requires-Dist: locust>=2.15.0
|
|
21
|
+
Requires-Dist: psutil>=5.9.0
|
|
22
|
+
Requires-Dist: requests>=2.28.0
|
|
23
|
+
Requires-Dist: click>=8.1.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: python-multipart>=0.0.6
|
|
26
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: license
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
Dynamic: requires-dist
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
Dynamic: summary
|
|
36
|
+
|
|
37
|
+
# Stress Test Kit
|
|
38
|
+
|
|
39
|
+
一个基于 Locust 的本地压测工具,提供完整的 Web UI 和实时监控。
|
|
40
|
+
|
|
41
|
+
## 特性
|
|
42
|
+
|
|
43
|
+
- 📦 一键安装,开箱即用
|
|
44
|
+
- 🎯 完整的压测任务配置(请求头、请求体、参数化)
|
|
45
|
+
- 📊 实时资源监控(CPU、内存、请求曲线)
|
|
46
|
+
- 🔧 内置函数变量(时间戳、UUID、随机数)
|
|
47
|
+
- 💾 SQLite 本地存储,无需额外中间件
|
|
48
|
+
- 🧹 孤儿进程自动清理
|
|
49
|
+
|
|
50
|
+
## 快速开始
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# 安装
|
|
54
|
+
pip install stress-test-kit
|
|
55
|
+
|
|
56
|
+
# 启动(自动打开浏览器)
|
|
57
|
+
stress-test
|
|
58
|
+
|
|
59
|
+
# 自定义端口
|
|
60
|
+
stress-test --port 9000
|
|
61
|
+
|
|
62
|
+
# 指定数据目录
|
|
63
|
+
stress-test --data-dir ./my-tests
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 开发
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# 克隆项目
|
|
70
|
+
cd stress-test-kit
|
|
71
|
+
|
|
72
|
+
# 创建虚拟环境
|
|
73
|
+
python -m venv venv
|
|
74
|
+
.\venv\Scripts\Activate.ps1
|
|
75
|
+
|
|
76
|
+
# 安装开发依赖
|
|
77
|
+
pip install -e .
|
|
78
|
+
|
|
79
|
+
# 运行
|
|
80
|
+
python -m stress_test_kit
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 架构
|
|
84
|
+
|
|
85
|
+
- **后端**: FastAPI + SQLAlchemy + SQLite
|
|
86
|
+
- **压测引擎**: Locust
|
|
87
|
+
- **进程管理**: psutil
|
|
88
|
+
- **前端**: Vue 3 + Element Plus + ECharts
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
MIT
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Stress Test Kit
|
|
2
|
+
|
|
3
|
+
一个基于 Locust 的本地压测工具,提供完整的 Web UI 和实时监控。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 📦 一键安装,开箱即用
|
|
8
|
+
- 🎯 完整的压测任务配置(请求头、请求体、参数化)
|
|
9
|
+
- 📊 实时资源监控(CPU、内存、请求曲线)
|
|
10
|
+
- 🔧 内置函数变量(时间戳、UUID、随机数)
|
|
11
|
+
- 💾 SQLite 本地存储,无需额外中间件
|
|
12
|
+
- 🧹 孤儿进程自动清理
|
|
13
|
+
|
|
14
|
+
## 快速开始
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# 安装
|
|
18
|
+
pip install stress-test-kit
|
|
19
|
+
|
|
20
|
+
# 启动(自动打开浏览器)
|
|
21
|
+
stress-test
|
|
22
|
+
|
|
23
|
+
# 自定义端口
|
|
24
|
+
stress-test --port 9000
|
|
25
|
+
|
|
26
|
+
# 指定数据目录
|
|
27
|
+
stress-test --data-dir ./my-tests
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 开发
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# 克隆项目
|
|
34
|
+
cd stress-test-kit
|
|
35
|
+
|
|
36
|
+
# 创建虚拟环境
|
|
37
|
+
python -m venv venv
|
|
38
|
+
.\venv\Scripts\Activate.ps1
|
|
39
|
+
|
|
40
|
+
# 安装开发依赖
|
|
41
|
+
pip install -e .
|
|
42
|
+
|
|
43
|
+
# 运行
|
|
44
|
+
python -m stress_test_kit
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 架构
|
|
48
|
+
|
|
49
|
+
- **后端**: FastAPI + SQLAlchemy + SQLite
|
|
50
|
+
- **压测引擎**: Locust
|
|
51
|
+
- **进程管理**: psutil
|
|
52
|
+
- **前端**: Vue 3 + Element Plus + ECharts
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
MIT
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="stress-test-kit",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
author="gg.zhao",
|
|
10
|
+
description="本地压测工具,基于 Locust 和 FastAPI",
|
|
11
|
+
long_description=long_description,
|
|
12
|
+
long_description_content_type="text/markdown",
|
|
13
|
+
license="MIT",
|
|
14
|
+
packages=find_packages(),
|
|
15
|
+
include_package_data=True,
|
|
16
|
+
python_requires=">=3.9",
|
|
17
|
+
install_requires=[
|
|
18
|
+
"fastapi>=0.100.0",
|
|
19
|
+
"uvicorn[standard]>=0.23.0",
|
|
20
|
+
"sqlalchemy>=2.0.0",
|
|
21
|
+
"locust>=2.15.0",
|
|
22
|
+
"psutil>=5.9.0",
|
|
23
|
+
"requests>=2.28.0",
|
|
24
|
+
"click>=8.1.0",
|
|
25
|
+
"pydantic>=2.0.0",
|
|
26
|
+
"python-multipart>=0.0.6", # 文件上传支持
|
|
27
|
+
"aiofiles>=23.0.0", # 异步文件操作
|
|
28
|
+
],
|
|
29
|
+
entry_points={
|
|
30
|
+
"console_scripts": [
|
|
31
|
+
"stress-test=stress_test_kit.cli:main",
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
package_data={
|
|
35
|
+
"stress_test_kit": ["frontend/**/*"],
|
|
36
|
+
},
|
|
37
|
+
classifiers=[
|
|
38
|
+
"Programming Language :: Python :: 3",
|
|
39
|
+
"Programming Language :: Python :: 3.9",
|
|
40
|
+
"Programming Language :: Python :: 3.10",
|
|
41
|
+
"Programming Language :: Python :: 3.11",
|
|
42
|
+
"Programming Language :: Python :: 3.12",
|
|
43
|
+
"License :: OSI Approved :: MIT License",
|
|
44
|
+
"Operating System :: OS Independent",
|
|
45
|
+
],
|
|
46
|
+
)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""CLI 入口(类似 locust 命令)"""
|
|
2
|
+
import os
|
|
3
|
+
import click
|
|
4
|
+
import uvicorn
|
|
5
|
+
import webbrowser
|
|
6
|
+
import threading
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.command()
|
|
10
|
+
@click.option('--port', default=8765, help='Web服务端口(前后端同一端口,不推荐与 --backend-port/--frontend-port 同时使用)')
|
|
11
|
+
@click.option('--backend-port', default=None, type=int, help='后端 API 服务端口(优先级高于 --port)')
|
|
12
|
+
@click.option('--frontend-port', default=None, type=int, help='前端静态服务端口(优先级高于 --port,需与 --backend-port 同时指定)')
|
|
13
|
+
@click.option('--data-dir', default=None, help='数据目录(存放SQLite和文件)')
|
|
14
|
+
@click.option('--no-browser', is_flag=True, help='不自动打开浏览器')
|
|
15
|
+
def main(port: int, backend_port: int, frontend_port: int, data_dir: str, no_browser: bool):
|
|
16
|
+
"""启动 Stress Test Kit 本地压测服务"""
|
|
17
|
+
import sys
|
|
18
|
+
from stress_test_kit.process_manager import _is_port_free
|
|
19
|
+
|
|
20
|
+
# 端口配置逻辑
|
|
21
|
+
if backend_port is not None and frontend_port is not None:
|
|
22
|
+
# 前后端分离模式
|
|
23
|
+
actual_backend_port = backend_port
|
|
24
|
+
actual_frontend_port = frontend_port
|
|
25
|
+
frontend_separate = True
|
|
26
|
+
elif backend_port is not None or frontend_port is not None:
|
|
27
|
+
# 只指定了一个,报错
|
|
28
|
+
click.echo("❌ --backend-port 和 --frontend-port 必须同时指定", err=True)
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
else:
|
|
31
|
+
# 使用 --port(前后端同一端口)
|
|
32
|
+
actual_backend_port = port
|
|
33
|
+
actual_frontend_port = None
|
|
34
|
+
frontend_separate = False
|
|
35
|
+
|
|
36
|
+
# 端口占用检查
|
|
37
|
+
if not _is_port_free(actual_backend_port):
|
|
38
|
+
click.echo(f"❌ 后端端口 {actual_backend_port} 已被占用,请先释放该端口或指定其他端口", err=True)
|
|
39
|
+
sys.exit(1)
|
|
40
|
+
|
|
41
|
+
if frontend_separate and not _is_port_free(actual_frontend_port):
|
|
42
|
+
click.echo(f"❌ 前端端口 {actual_frontend_port} 已被占用,请先释放该端口或指定其他端口", err=True)
|
|
43
|
+
sys.exit(1)
|
|
44
|
+
|
|
45
|
+
# 数据目录默认值
|
|
46
|
+
if data_dir is None:
|
|
47
|
+
data_dir = os.path.join(os.path.expanduser("~"), ".stress-test-kit")
|
|
48
|
+
else:
|
|
49
|
+
data_dir = os.path.expanduser(data_dir)
|
|
50
|
+
|
|
51
|
+
# 初始化数据库
|
|
52
|
+
from stress_test_kit.models import init_db
|
|
53
|
+
from stress_test_kit.server import set_data_dir, set_mount_frontend
|
|
54
|
+
from stress_test_kit.sampler import recover_active_samplers, start_periodic_patrol
|
|
55
|
+
|
|
56
|
+
init_db(data_dir)
|
|
57
|
+
set_data_dir(data_dir)
|
|
58
|
+
|
|
59
|
+
# 前后端分离模式下,禁用 FastAPI 挂载静态文件
|
|
60
|
+
if frontend_separate:
|
|
61
|
+
set_mount_frontend(False)
|
|
62
|
+
|
|
63
|
+
# 恢复活跃的采样线程
|
|
64
|
+
recover_active_samplers(data_dir)
|
|
65
|
+
|
|
66
|
+
# 启动定期巡检(每 60 秒检查所有 running 状态的任务)
|
|
67
|
+
start_periodic_patrol(data_dir)
|
|
68
|
+
|
|
69
|
+
click.echo("=" * 60)
|
|
70
|
+
click.echo("🚀 Stress Test Kit 启动中...")
|
|
71
|
+
click.echo("=" * 60)
|
|
72
|
+
click.echo(f"📂 数据目录: {data_dir}")
|
|
73
|
+
|
|
74
|
+
if frontend_separate:
|
|
75
|
+
click.echo(f"🔧 后端 API: http://localhost:{actual_backend_port}")
|
|
76
|
+
click.echo(f"🌐 前端页面: http://localhost:{actual_frontend_port}")
|
|
77
|
+
access_url = f"http://localhost:{actual_frontend_port}"
|
|
78
|
+
|
|
79
|
+
# 启动前端静态文件服务(独立线程)
|
|
80
|
+
def start_frontend_server():
|
|
81
|
+
import http.server
|
|
82
|
+
import socketserver
|
|
83
|
+
import functools
|
|
84
|
+
frontend_dir = os.path.join(os.path.dirname(__file__), "frontend")
|
|
85
|
+
if os.path.exists(frontend_dir):
|
|
86
|
+
os.chdir(frontend_dir)
|
|
87
|
+
handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory=frontend_dir)
|
|
88
|
+
with socketserver.TCPServer(("0.0.0.0", actual_frontend_port), handler) as httpd:
|
|
89
|
+
click.echo(f"✅ 前端服务已启动在端口 {actual_frontend_port}")
|
|
90
|
+
httpd.serve_forever()
|
|
91
|
+
else:
|
|
92
|
+
click.echo(f"⚠️ 前端目录不存在: {frontend_dir},跳过前端服务启动")
|
|
93
|
+
|
|
94
|
+
threading.Thread(target=start_frontend_server, daemon=True).start()
|
|
95
|
+
else:
|
|
96
|
+
click.echo(f"🌐 访问地址: http://localhost:{actual_backend_port}")
|
|
97
|
+
access_url = f"http://localhost:{actual_backend_port}"
|
|
98
|
+
|
|
99
|
+
click.echo("=" * 60)
|
|
100
|
+
|
|
101
|
+
# 自动打开浏览器
|
|
102
|
+
if not no_browser:
|
|
103
|
+
threading.Timer(1.5, lambda: webbrowser.open(access_url)).start()
|
|
104
|
+
|
|
105
|
+
# 启动 FastAPI 服务
|
|
106
|
+
uvicorn.run(
|
|
107
|
+
"stress_test_kit.server:app",
|
|
108
|
+
host="0.0.0.0",
|
|
109
|
+
port=actual_backend_port,
|
|
110
|
+
log_level="info"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
main()
|