strobengine 0.1.0__tar.gz → 0.2.1__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.
- {strobengine-0.1.0 → strobengine-0.2.1}/.github/workflows/publish-test.yml +18 -3
- {strobengine-0.1.0 → strobengine-0.2.1}/.github/workflows/publish.yml +17 -3
- strobengine-0.2.1/CHANGELOG.md +131 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/Cargo.lock +106 -1
- {strobengine-0.1.0 → strobengine-0.2.1}/Cargo.toml +7 -3
- strobengine-0.1.0/README.md → strobengine-0.2.1/PKG-INFO +106 -7
- strobengine-0.1.0/PKG-INFO → strobengine-0.2.1/README.md +89 -19
- strobengine-0.2.1/docs/benchmarks.md +213 -0
- strobengine-0.2.1/docs/http_methods.md +165 -0
- strobengine-0.2.1/docs/infrastructure.md +238 -0
- strobengine-0.2.1/docs/roadmap.md +89 -0
- strobengine-0.2.1/examples/http_methods.py +67 -0
- strobengine-0.2.1/examples/load_test.py +14 -0
- strobengine-0.2.1/examples/spike_test.py +16 -0
- strobengine-0.2.1/examples/stress_test.py +15 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/pyproject.toml +11 -1
- strobengine-0.2.1/src/chaos.rs +34 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/src/config.rs +97 -16
- strobengine-0.2.1/src/lib.rs +493 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/src/metrics.rs +28 -13
- strobengine-0.2.1/src/progress.rs +105 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/src/strobengine/__init__.py +2 -1
- {strobengine-0.1.0 → strobengine-0.2.1}/src/strobengine/_strobengine.pyi +21 -1
- {strobengine-0.1.0 → strobengine-0.2.1}/src/strobengine/cli.py +168 -24
- strobengine-0.2.1/src/strobengine/constants.py +14 -0
- strobengine-0.2.1/src/strobengine/engine.py +176 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/src/strobengine/reporter.py +14 -0
- strobengine-0.2.1/src/worker.rs +162 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/tests/conftest.py +3 -1
- {strobengine-0.1.0 → strobengine-0.2.1}/tests/test_cli.py +8 -5
- {strobengine-0.1.0 → strobengine-0.2.1}/tests/test_engine.py +11 -5
- {strobengine-0.1.0 → strobengine-0.2.1}/uv.lock +4 -4
- strobengine-0.1.0/CHANGELOG.md +0 -25
- strobengine-0.1.0/src/lib.rs +0 -239
- strobengine-0.1.0/src/strobengine/engine.py +0 -122
- strobengine-0.1.0/src/worker.rs +0 -58
- {strobengine-0.1.0 → strobengine-0.2.1}/.github/workflows/ci.yml +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/.gitignore +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/.python-version +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/LICENSE +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/cliff.toml +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/src/logging.rs +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/src/strobengine/py.typed +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/tests/__init__.py +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/tests/test_logging.py +0 -0
- {strobengine-0.1.0 → strobengine-0.2.1}/tests/test_reporter.py +0 -0
|
@@ -6,11 +6,24 @@ on:
|
|
|
6
6
|
|
|
7
7
|
jobs:
|
|
8
8
|
build-wheels:
|
|
9
|
-
name: Build wheels on ${{ matrix.os }}
|
|
9
|
+
name: Build wheels on ${{ matrix.os }} (${{ matrix.target || 'native' }})
|
|
10
10
|
runs-on: ${{ matrix.os }}
|
|
11
11
|
strategy:
|
|
12
|
+
fail-fast: false
|
|
12
13
|
matrix:
|
|
13
|
-
|
|
14
|
+
include:
|
|
15
|
+
# Linux
|
|
16
|
+
- os: ubuntu-latest
|
|
17
|
+
target: x86_64
|
|
18
|
+
# Windows
|
|
19
|
+
- os: windows-latest
|
|
20
|
+
target: x64
|
|
21
|
+
# macOS Apple Silicon (ARM64)
|
|
22
|
+
- os: macos-latest
|
|
23
|
+
target: aarch64
|
|
24
|
+
# macOS Intel (x86_64) cross-compiled on macos-latest
|
|
25
|
+
- os: macos-latest
|
|
26
|
+
target: x86_64
|
|
14
27
|
steps:
|
|
15
28
|
- uses: actions/checkout@v7
|
|
16
29
|
|
|
@@ -22,6 +35,7 @@ jobs:
|
|
|
22
35
|
- name: Build wheels via Maturin
|
|
23
36
|
uses: PyO3/maturin-action@v1
|
|
24
37
|
with:
|
|
38
|
+
target: ${{ matrix.target }}
|
|
25
39
|
args: --release --out dist --find-interpreter
|
|
26
40
|
sccache: 'true'
|
|
27
41
|
sdist: false
|
|
@@ -29,7 +43,7 @@ jobs:
|
|
|
29
43
|
- name: Upload wheel artifacts
|
|
30
44
|
uses: actions/upload-artifact@v7
|
|
31
45
|
with:
|
|
32
|
-
name: wheels-${{ matrix.os }}
|
|
46
|
+
name: wheels-${{ matrix.os }}-${{ matrix.target }}
|
|
33
47
|
path: dist/*.whl
|
|
34
48
|
|
|
35
49
|
build-sdist:
|
|
@@ -71,3 +85,4 @@ jobs:
|
|
|
71
85
|
with:
|
|
72
86
|
repository-url: https://test.pypi.org/legacy/
|
|
73
87
|
packages-dir: dist/
|
|
88
|
+
skip-existing: true # Skips 400 errors for already uploaded files
|
|
@@ -9,11 +9,24 @@ on:
|
|
|
9
9
|
|
|
10
10
|
jobs:
|
|
11
11
|
build-wheels:
|
|
12
|
-
name: Build wheels on ${{ matrix.os }}
|
|
12
|
+
name: Build wheels on ${{ matrix.os }} (${{ matrix.target || 'native' }})
|
|
13
13
|
runs-on: ${{ matrix.os }}
|
|
14
14
|
strategy:
|
|
15
|
+
fail-fast: false
|
|
15
16
|
matrix:
|
|
16
|
-
|
|
17
|
+
include:
|
|
18
|
+
# Linux
|
|
19
|
+
- os: ubuntu-latest
|
|
20
|
+
target: x86_64
|
|
21
|
+
# Windows
|
|
22
|
+
- os: windows-latest
|
|
23
|
+
target: x64
|
|
24
|
+
# macOS Apple Silicon (ARM64)
|
|
25
|
+
- os: macos-latest
|
|
26
|
+
target: aarch64
|
|
27
|
+
# macOS Intel (x86_64) cross-compiled on macos-latest
|
|
28
|
+
- os: macos-latest
|
|
29
|
+
target: x86_64
|
|
17
30
|
steps:
|
|
18
31
|
- uses: actions/checkout@v7
|
|
19
32
|
|
|
@@ -25,6 +38,7 @@ jobs:
|
|
|
25
38
|
- name: Build wheels via Maturin
|
|
26
39
|
uses: PyO3/maturin-action@v1
|
|
27
40
|
with:
|
|
41
|
+
target: ${{ matrix.target }}
|
|
28
42
|
args: --release --out dist --find-interpreter
|
|
29
43
|
sccache: 'true'
|
|
30
44
|
sdist: false
|
|
@@ -32,7 +46,7 @@ jobs:
|
|
|
32
46
|
- name: Upload wheel artifacts
|
|
33
47
|
uses: actions/upload-artifact@v7
|
|
34
48
|
with:
|
|
35
|
-
name: wheels-${{ matrix.os }}
|
|
49
|
+
name: wheels-${{ matrix.os }}-${{ matrix.target }}
|
|
36
50
|
path: dist/*.whl
|
|
37
51
|
|
|
38
52
|
build-sdist:
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `strobengine` will be documented in this file.
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.2.1] - 2026-08-03
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
- *(types)* Correct headers type in _strobengine.pyi from dict to list of tuples (#41)
|
|
12
|
+
- Replace build_client panic with proper error propagation (#42)
|
|
13
|
+
- Replace std::process::exit with safe PyKeyboardInterrupt on SIGINT (#43)
|
|
14
|
+
- *(progress)* Guard against zero total_duration in progress bar calculation (#44)
|
|
15
|
+
- Improve worker shutdown and panic handling (#45)
|
|
16
|
+
- *(metrics)* Normalize counter types to AtomicU64 for 32-bit safety (#46)
|
|
17
|
+
- *(cli)* Add type annotation to _output_results summary parameter (#48)
|
|
18
|
+
|
|
19
|
+
### Documentation
|
|
20
|
+
|
|
21
|
+
- Add comment explaining SystemExit re-raise pattern (#50)
|
|
22
|
+
|
|
23
|
+
### Miscellaneous Tasks
|
|
24
|
+
|
|
25
|
+
- Remove unnecessary clippy allow on run_load_test (#47)
|
|
26
|
+
- Add multi-architecture matrix for macOS wheel builds (#52)
|
|
27
|
+
|
|
28
|
+
### Refactoring
|
|
29
|
+
|
|
30
|
+
- Extract magic number 8192 to named constant METRIC_CHANNEL_BUFFER (#49)
|
|
31
|
+
- Extract magic numbers to named constants across Rust and Python (#51)
|
|
32
|
+
## [0.2.0] - 2026-08-02
|
|
33
|
+
|
|
34
|
+
### Bug Fixes
|
|
35
|
+
|
|
36
|
+
- *(progress)* Downgrade expected HTTP errors from warn to debug
|
|
37
|
+
- *(cli)* Move logging flags to subcommands for natural syntax
|
|
38
|
+
- *(engine)* Resolve null options and attribute access bugs (#38)
|
|
39
|
+
|
|
40
|
+
### Documentation
|
|
41
|
+
|
|
42
|
+
- Add benchmark methodology, infrastructure setup, and project roadmap
|
|
43
|
+
- Add tool versions to benchmark methodology (#29)
|
|
44
|
+
- Document verbosity, progress bar, and CLI flags
|
|
45
|
+
- Update roadmap to reflect changes (#34)
|
|
46
|
+
- Add HTTP method, body, and header documentation
|
|
47
|
+
- Add code examples (#37)
|
|
48
|
+
- *(changelog)* Update CHANGELOG.md for v0.2.0 release
|
|
49
|
+
|
|
50
|
+
### Features
|
|
51
|
+
|
|
52
|
+
- *(reporter)* Add metric descriptions to CLI summary output (#30)
|
|
53
|
+
- Add chaos testing engine (#32)
|
|
54
|
+
- Add indicatif dependency for progress bar rendering
|
|
55
|
+
- Add progress bar module and live render loop
|
|
56
|
+
- *(metrics)* Add atomic fields to LiveCounters for active workers and latency tracking
|
|
57
|
+
- *(worker)* Track active workers and update live request metrics
|
|
58
|
+
- *(config)* Support no_progress flag in TestConfig
|
|
59
|
+
- *(engine)* Spawn live progress bar during load test runs
|
|
60
|
+
- *(cli)* Add --no-progress option to suppress live progress bar
|
|
61
|
+
- Progress indicators (#33)
|
|
62
|
+
- Add HTTP request configuration
|
|
63
|
+
- Support custom HTTP requests
|
|
64
|
+
- *(cli)* Add HTTP request options
|
|
65
|
+
- Add support for HTTP methods, request bodies, and custom headers (#35)
|
|
66
|
+
- Implement graceful shutdown on SIGINT (#39)
|
|
67
|
+
|
|
68
|
+
### Miscellaneous Tasks
|
|
69
|
+
|
|
70
|
+
- *(release)* Prepare v0.1.0 changelog and tag
|
|
71
|
+
- Add PyPI publish workflow with tag-based triggering (#26)
|
|
72
|
+
- *(pyproject)* Add license metadata and project URLs, bump version
|
|
73
|
+
- *(release)* Merge v0.2.0 release prep into main (#40)
|
|
74
|
+
|
|
75
|
+
### Performance
|
|
76
|
+
|
|
77
|
+
- Switch global allocator to mimalloc for reduced lock contention (#28)
|
|
78
|
+
- Optimize connection pooling with tcp_nodelay, pre-warming, and body consumption (#31)
|
|
79
|
+
|
|
80
|
+
### Refactoring
|
|
81
|
+
|
|
82
|
+
- *(engine)* Encapsulate request options into RequestOptions dataclass (#36)
|
|
83
|
+
|
|
84
|
+
### Testing
|
|
85
|
+
|
|
86
|
+
- *(config)* Simplify header setup in custom config test
|
|
87
|
+
## [0.1.0] - 2026-07-23
|
|
88
|
+
|
|
89
|
+
### Bug Fixes
|
|
90
|
+
|
|
91
|
+
- *(tests)* Fix backward-compat tests to go through main()
|
|
92
|
+
- *(docs)* Correct print_summary import and add results display to examples
|
|
93
|
+
- *(docs)* Correct print_summary import and add results display to examples (#23)
|
|
94
|
+
|
|
95
|
+
### Documentation
|
|
96
|
+
|
|
97
|
+
- *(changelog)* Configure git-cliff and generate initial CHANGELOG.md (#16)
|
|
98
|
+
- Add logging flags and tracing crates to README
|
|
99
|
+
|
|
100
|
+
### Features
|
|
101
|
+
|
|
102
|
+
- *(config)* Add TestConfig pyclass with Python default arguments (#5)
|
|
103
|
+
- *(metrics)* Add TestSummary pyclass and calculate_summary (#6)
|
|
104
|
+
- Add StrobEngine class with sync and async interfaces (#11)
|
|
105
|
+
- Dynamic load profiling (#17)
|
|
106
|
+
- *(cli)* Add -V/--version flag with importlib.metadata
|
|
107
|
+
- *(rust)* Add tracing instrumentation and init_logging binding
|
|
108
|
+
- *(cli)* Add -v/-q/--log-file flags with stderr logging
|
|
109
|
+
- *(logging)* Unify system logging (#20)
|
|
110
|
+
|
|
111
|
+
### Miscellaneous Tasks
|
|
112
|
+
|
|
113
|
+
- Add Python environment and build artifacts to .gitignore
|
|
114
|
+
- Initialize strobengine hybrid workspace architecture
|
|
115
|
+
- *(cargo)* Fix formatting and wrap comment for abi3-py38 feature (#1)
|
|
116
|
+
- *(python)* Add __all__ to package init for explicit public API (#8)
|
|
117
|
+
- Add GitHub Actions workflow for Rust and Python checks (#10)
|
|
118
|
+
- Update minimum Python version to 3.13 for abi3-py313
|
|
119
|
+
- *(lint)* Add ruff rules and auto-fix pyupgrade suggestions
|
|
120
|
+
- Bump minimum python version to 3.13 and expand ruff rules (#21)
|
|
121
|
+
- Add TestPyPI publish workflow with OIDC trusted publishing
|
|
122
|
+
- Lower minimum Python version to 3.11 for broader compatibility
|
|
123
|
+
- Lower minimum Python version to 3.11 for broader compatibility (#24)
|
|
124
|
+
- Add testpypi environment to publish workflow
|
|
125
|
+
- Add testpypi environment to publish workflow (#25)
|
|
126
|
+
- Add PyPI publish workflow with tag-based triggering
|
|
127
|
+
|
|
128
|
+
### Refactoring
|
|
129
|
+
|
|
130
|
+
- Clean up __init__.py public API exports (#14)
|
|
131
|
+
- *(cli)* Migrate CLI from argparse to typer (#18)
|
|
@@ -118,6 +118,18 @@ dependencies = [
|
|
|
118
118
|
"memchr",
|
|
119
119
|
]
|
|
120
120
|
|
|
121
|
+
[[package]]
|
|
122
|
+
name = "console"
|
|
123
|
+
version = "0.16.4"
|
|
124
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
125
|
+
checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c"
|
|
126
|
+
dependencies = [
|
|
127
|
+
"encode_unicode",
|
|
128
|
+
"libc",
|
|
129
|
+
"unicode-width",
|
|
130
|
+
"windows-sys 0.61.2",
|
|
131
|
+
]
|
|
132
|
+
|
|
121
133
|
[[package]]
|
|
122
134
|
name = "core-foundation"
|
|
123
135
|
version = "0.9.4"
|
|
@@ -170,6 +182,12 @@ version = "1.0.5"
|
|
|
170
182
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
171
183
|
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
|
172
184
|
|
|
185
|
+
[[package]]
|
|
186
|
+
name = "encode_unicode"
|
|
187
|
+
version = "1.0.0"
|
|
188
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
189
|
+
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
|
190
|
+
|
|
173
191
|
[[package]]
|
|
174
192
|
name = "encoding_rs"
|
|
175
193
|
version = "0.8.35"
|
|
@@ -185,6 +203,22 @@ version = "1.0.2"
|
|
|
185
203
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
186
204
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|
187
205
|
|
|
206
|
+
[[package]]
|
|
207
|
+
name = "errno"
|
|
208
|
+
version = "0.3.14"
|
|
209
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
210
|
+
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
|
211
|
+
dependencies = [
|
|
212
|
+
"libc",
|
|
213
|
+
"windows-sys 0.52.0",
|
|
214
|
+
]
|
|
215
|
+
|
|
216
|
+
[[package]]
|
|
217
|
+
name = "fastrand"
|
|
218
|
+
version = "2.5.0"
|
|
219
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
220
|
+
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
|
221
|
+
|
|
188
222
|
[[package]]
|
|
189
223
|
name = "find-msvc-tools"
|
|
190
224
|
version = "0.1.9"
|
|
@@ -534,6 +568,19 @@ dependencies = [
|
|
|
534
568
|
"hashbrown",
|
|
535
569
|
]
|
|
536
570
|
|
|
571
|
+
[[package]]
|
|
572
|
+
name = "indicatif"
|
|
573
|
+
version = "0.18.6"
|
|
574
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
575
|
+
checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c"
|
|
576
|
+
dependencies = [
|
|
577
|
+
"console",
|
|
578
|
+
"portable-atomic",
|
|
579
|
+
"unicode-width",
|
|
580
|
+
"unit-prefix",
|
|
581
|
+
"web-time",
|
|
582
|
+
]
|
|
583
|
+
|
|
537
584
|
[[package]]
|
|
538
585
|
name = "ipnet"
|
|
539
586
|
version = "2.12.0"
|
|
@@ -628,6 +675,15 @@ version = "0.2.186"
|
|
|
628
675
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
629
676
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
630
677
|
|
|
678
|
+
[[package]]
|
|
679
|
+
name = "libmimalloc-sys"
|
|
680
|
+
version = "0.1.49"
|
|
681
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
682
|
+
checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
|
|
683
|
+
dependencies = [
|
|
684
|
+
"cc",
|
|
685
|
+
]
|
|
686
|
+
|
|
631
687
|
[[package]]
|
|
632
688
|
name = "litemap"
|
|
633
689
|
version = "0.8.2"
|
|
@@ -661,6 +717,15 @@ version = "2.8.3"
|
|
|
661
717
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
662
718
|
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
663
719
|
|
|
720
|
+
[[package]]
|
|
721
|
+
name = "mimalloc"
|
|
722
|
+
version = "0.1.52"
|
|
723
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
724
|
+
checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
|
|
725
|
+
dependencies = [
|
|
726
|
+
"libmimalloc-sys",
|
|
727
|
+
]
|
|
728
|
+
|
|
664
729
|
[[package]]
|
|
665
730
|
name = "mime"
|
|
666
731
|
version = "0.3.17"
|
|
@@ -1152,6 +1217,16 @@ version = "2.0.1"
|
|
|
1152
1217
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1153
1218
|
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
|
1154
1219
|
|
|
1220
|
+
[[package]]
|
|
1221
|
+
name = "signal-hook-registry"
|
|
1222
|
+
version = "1.4.8"
|
|
1223
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1224
|
+
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
|
1225
|
+
dependencies = [
|
|
1226
|
+
"errno",
|
|
1227
|
+
"libc",
|
|
1228
|
+
]
|
|
1229
|
+
|
|
1155
1230
|
[[package]]
|
|
1156
1231
|
name = "simd_cesu8"
|
|
1157
1232
|
version = "1.2.0"
|
|
@@ -1198,8 +1273,13 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|
|
1198
1273
|
|
|
1199
1274
|
[[package]]
|
|
1200
1275
|
name = "strobengine"
|
|
1201
|
-
version = "0.1
|
|
1276
|
+
version = "0.2.1"
|
|
1202
1277
|
dependencies = [
|
|
1278
|
+
"bytes",
|
|
1279
|
+
"fastrand",
|
|
1280
|
+
"http",
|
|
1281
|
+
"indicatif",
|
|
1282
|
+
"mimalloc",
|
|
1203
1283
|
"pyo3",
|
|
1204
1284
|
"reqwest",
|
|
1205
1285
|
"tokio",
|
|
@@ -1347,10 +1427,23 @@ dependencies = [
|
|
|
1347
1427
|
"libc",
|
|
1348
1428
|
"mio",
|
|
1349
1429
|
"pin-project-lite",
|
|
1430
|
+
"signal-hook-registry",
|
|
1350
1431
|
"socket2",
|
|
1432
|
+
"tokio-macros",
|
|
1351
1433
|
"windows-sys 0.61.2",
|
|
1352
1434
|
]
|
|
1353
1435
|
|
|
1436
|
+
[[package]]
|
|
1437
|
+
name = "tokio-macros"
|
|
1438
|
+
version = "2.7.1"
|
|
1439
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1440
|
+
checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba"
|
|
1441
|
+
dependencies = [
|
|
1442
|
+
"proc-macro2",
|
|
1443
|
+
"quote",
|
|
1444
|
+
"syn 2.0.119",
|
|
1445
|
+
]
|
|
1446
|
+
|
|
1354
1447
|
[[package]]
|
|
1355
1448
|
name = "tokio-rustls"
|
|
1356
1449
|
version = "0.26.4"
|
|
@@ -1493,6 +1586,18 @@ version = "1.0.24"
|
|
|
1493
1586
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1494
1587
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
1495
1588
|
|
|
1589
|
+
[[package]]
|
|
1590
|
+
name = "unicode-width"
|
|
1591
|
+
version = "0.2.2"
|
|
1592
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1593
|
+
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
|
|
1594
|
+
|
|
1595
|
+
[[package]]
|
|
1596
|
+
name = "unit-prefix"
|
|
1597
|
+
version = "0.5.2"
|
|
1598
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1599
|
+
checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3"
|
|
1600
|
+
|
|
1496
1601
|
[[package]]
|
|
1497
1602
|
name = "untrusted"
|
|
1498
1603
|
version = "0.9.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "strobengine"
|
|
3
|
-
version = "0.1
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
|
|
@@ -16,8 +16,12 @@ crate-type = ["cdylib", "rlib"]
|
|
|
16
16
|
# minimum Python version 3.11
|
|
17
17
|
pyo3 = { version = "0.29", features = ["extension-module", "abi3-py311"] }
|
|
18
18
|
reqwest = { version = "0.13.4" }
|
|
19
|
-
|
|
19
|
+
http = "1"
|
|
20
|
+
bytes = "1"
|
|
21
|
+
tokio = { version = "1.53.0", features = ["sync", "time", "rt", "rt-multi-thread", "macros", "signal"] }
|
|
20
22
|
tokio-util = { version = "0.7", features = ["rt"] }
|
|
21
23
|
tracing = "0.1"
|
|
22
24
|
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "registry"] }
|
|
23
|
-
|
|
25
|
+
mimalloc = "0.1.52"
|
|
26
|
+
fastrand = "2.5"
|
|
27
|
+
indicatif = "0.18.6"
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: strobengine
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Requires-Dist: rich>=13.0.0
|
|
5
|
+
Requires-Dist: typer>=0.27.0
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Summary: A load testing framework with a Python UI and a bare-metal Rust engine core.
|
|
8
|
+
Author-email: riccione <28346232+riccione@users.noreply.github.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
12
|
+
Project-URL: Changelog, https://github.com/strobe-ops/strobengine/blob/main/CHANGELOG.md
|
|
13
|
+
Project-URL: Documentation, https://github.com/strobe-ops/strobengine
|
|
14
|
+
Project-URL: Homepage, https://github.com/strobe-ops/strobengine
|
|
15
|
+
Project-URL: Source, https://github.com/strobe-ops/strobengine
|
|
16
|
+
|
|
1
17
|
# strobengine
|
|
2
18
|
|
|
3
19
|
A high-performance HTTP load testing engine with a Python API and a bare-metal Rust core.
|
|
@@ -18,6 +34,10 @@ A high-performance HTTP load testing engine with a Python API and a bare-metal R
|
|
|
18
34
|
| tokio-util | 0.7 | CancellationToken for graceful worker shutdown |
|
|
19
35
|
| tracing | 0.1 | Structured logging instrumentation |
|
|
20
36
|
| tracing-subscriber | 0.3 | Log formatting and output (stderr/file) |
|
|
37
|
+
| indicatif | 0.17 | Terminal progress bar rendering |
|
|
38
|
+
| fastrand | 2 | Fast random number generation for chaos injection |
|
|
39
|
+
| http | 1 | HTTP method types and header primitives |
|
|
40
|
+
| bytes | 1 | Zero-copy byte buffer for request payloads |
|
|
21
41
|
|
|
22
42
|
## Installation & Compilation
|
|
23
43
|
|
|
@@ -63,6 +83,15 @@ engine = StrobEngine.spike_test(
|
|
|
63
83
|
summary = engine.run()
|
|
64
84
|
|
|
65
85
|
print_summary(summary, url=engine._url, duration_secs=30)
|
|
86
|
+
|
|
87
|
+
# POST request with JSON body and custom headers
|
|
88
|
+
engine = StrobEngine(
|
|
89
|
+
url="http://localhost:8080/api/data",
|
|
90
|
+
method="POST",
|
|
91
|
+
body='{"name": "test", "value": 42}',
|
|
92
|
+
headers=[("Authorization", "Bearer token123")],
|
|
93
|
+
)
|
|
94
|
+
summary = engine.run()
|
|
66
95
|
```
|
|
67
96
|
|
|
68
97
|
For async contexts (FastAPI, Typer, etc.):
|
|
@@ -85,6 +114,25 @@ strobengine spike http://localhost:8080/api/health --baseline 5 --peak 1000 --pr
|
|
|
85
114
|
|
|
86
115
|
# JSON output for CI/CD
|
|
87
116
|
strobengine load http://localhost:8080/api/health --json
|
|
117
|
+
|
|
118
|
+
# Chaos/fault injection test (~10% of requests get faults)
|
|
119
|
+
strobengine load http://localhost:8080/api/health --chaos
|
|
120
|
+
|
|
121
|
+
# POST with JSON body
|
|
122
|
+
strobengine load http://localhost:8080/api/data --method POST --body '{"key": "val"}'
|
|
123
|
+
|
|
124
|
+
# PUT with custom headers
|
|
125
|
+
strobengine load http://localhost:8080/api/resource/1 \
|
|
126
|
+
--method PUT --body '{"name": "updated"}' --header "Authorization: Bearer token"
|
|
127
|
+
|
|
128
|
+
# DELETE
|
|
129
|
+
strobengine load http://localhost:8080/api/resource/1 --method DELETE
|
|
130
|
+
|
|
131
|
+
# Verbose debug output
|
|
132
|
+
strobengine load http://localhost:8080/api/health -vv
|
|
133
|
+
|
|
134
|
+
# Quiet mode (suppress logs, keep progress bar)
|
|
135
|
+
strobengine load http://localhost:8080/api/health -q
|
|
88
136
|
```
|
|
89
137
|
|
|
90
138
|
By default, this spawns **10 concurrent workers** for **10 seconds** with a **10-second request timeout**. Results are displayed as a formatted table with total requests, errors, requests/sec, and latency percentiles (avg, p95, p99).
|
|
@@ -104,6 +152,14 @@ By default, this spawns **10 concurrent workers** for **10 seconds** with a **10
|
|
|
104
152
|
| `-c`, `--concurrency` | `10` | Number of concurrent workers |
|
|
105
153
|
| `-d`, `--duration` | `10` | Duration in seconds |
|
|
106
154
|
| `-t`, `--timeout` | `10` | Per-request timeout in seconds |
|
|
155
|
+
| `--method` | `GET` | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) |
|
|
156
|
+
| `--body` | none | Request body (raw string) |
|
|
157
|
+
| `--header` | none | Custom header key:value (repeatable) |
|
|
158
|
+
| `--chaos` | off | Enable fault injection (~10% of requests) |
|
|
159
|
+
| `--no-progress` | off | Suppress live progress bar |
|
|
160
|
+
| `-v`, `-vv`, `-vvv` | warn | Increase verbosity (INFO, DEBUG, TRACE) |
|
|
161
|
+
| `-q`, `--quiet` | off | Suppress all output |
|
|
162
|
+
| `--log-file <path>` | none | Write logs to file |
|
|
107
163
|
| `--json` | off | Output raw JSON instead of formatted table |
|
|
108
164
|
|
|
109
165
|
### Stress Subcommand Options
|
|
@@ -115,6 +171,14 @@ By default, this spawns **10 concurrent workers** for **10 seconds** with a **10
|
|
|
115
171
|
| `--ramp` | `60` | Ramp duration in seconds |
|
|
116
172
|
| `--hold` | `30` | Hold duration at target concurrency |
|
|
117
173
|
| `-t`, `--timeout` | `10` | Per-request timeout in seconds |
|
|
174
|
+
| `--method` | `GET` | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) |
|
|
175
|
+
| `--body` | none | Request body (raw string) |
|
|
176
|
+
| `--header` | none | Custom header key:value (repeatable) |
|
|
177
|
+
| `--chaos` | off | Enable fault injection (~10% of requests) |
|
|
178
|
+
| `--no-progress` | off | Suppress live progress bar |
|
|
179
|
+
| `-v`, `-vv`, `-vvv` | warn | Increase verbosity (INFO, DEBUG, TRACE) |
|
|
180
|
+
| `-q`, `--quiet` | off | Suppress all output |
|
|
181
|
+
| `--log-file <path>` | none | Write logs to file |
|
|
118
182
|
| `--json` | off | Output raw JSON |
|
|
119
183
|
|
|
120
184
|
### Spike Subcommand Options
|
|
@@ -127,16 +191,48 @@ By default, this spawns **10 concurrent workers** for **10 seconds** with a **10
|
|
|
127
191
|
| `--spike-duration` | `10` | Spike duration in seconds |
|
|
128
192
|
| `--post-spike` | `5` | Post-spike duration in seconds |
|
|
129
193
|
| `-t`, `--timeout` | `10` | Per-request timeout in seconds |
|
|
194
|
+
| `--method` | `GET` | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) |
|
|
195
|
+
| `--body` | none | Request body (raw string) |
|
|
196
|
+
| `--header` | none | Custom header key:value (repeatable) |
|
|
197
|
+
| `--chaos` | off | Enable fault injection (~10% of requests) |
|
|
198
|
+
| `--no-progress` | off | Suppress live progress bar |
|
|
199
|
+
| `-v`, `-vv`, `-vvv` | warn | Increase verbosity (INFO, DEBUG, TRACE) |
|
|
200
|
+
| `-q`, `--quiet` | off | Suppress all output |
|
|
201
|
+
| `--log-file <path>` | none | Write logs to file |
|
|
130
202
|
| `--json` | off | Output raw JSON |
|
|
131
203
|
|
|
132
204
|
### Global Options
|
|
133
205
|
|
|
134
|
-
| Flag |
|
|
135
|
-
|
|
136
|
-
| `-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
206
|
+
| Flag | Description |
|
|
207
|
+
|------|-------------|
|
|
208
|
+
| `-V`, `--version` | Show version and exit |
|
|
209
|
+
|
|
210
|
+
> **HTTP Methods, Bodies & Headers:** See [docs/http_methods.md](docs/http_methods.md) for detailed documentation on supported HTTP methods, request body handling, custom headers, and performance characteristics.
|
|
211
|
+
|
|
212
|
+
### Live Progress Bar
|
|
213
|
+
|
|
214
|
+
During test execution, a live progress bar displays on stderr with real-time telemetry:
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
⠋ [00:00:05] [==============>-------------] 40% | 1250 req/s | 20 VUs | 12 err | avg 4.2ms
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
- **RPS**: Instantaneous requests per second (sampled every 200ms)
|
|
221
|
+
- **VUs**: Active virtual users / concurrent workers
|
|
222
|
+
- **Errors**: Total error count
|
|
223
|
+
- **Avg latency**: Running average across all completed requests
|
|
224
|
+
|
|
225
|
+
The progress bar auto-detects non-TTY environments (CI/CD, piped output) and suppresses itself. Use `--no-progress` to explicitly disable it on interactive terminals.
|
|
226
|
+
|
|
227
|
+
### Verbosity Levels
|
|
228
|
+
|
|
229
|
+
| Flag | Level | Shows |
|
|
230
|
+
|------|-------|-------|
|
|
231
|
+
| (default) | `warn` | Errors and warnings only |
|
|
232
|
+
| `-v` | `info` | Engine start/stop, test configuration |
|
|
233
|
+
| `-vv` | `debug` | Worker spawn, HTTP errors, connection events |
|
|
234
|
+
| `-vvv` | `trace` | Per-request latency, status codes, chaos injection |
|
|
235
|
+
| `-q` | off | Suppress all log output (progress bar remains) |
|
|
140
236
|
|
|
141
237
|
Logs stream to **stderr** by default, keeping stdout clean for JSON output piping:
|
|
142
238
|
|
|
@@ -149,8 +245,10 @@ strobengine load http://localhost:8080/api/health -vv --json > results.json
|
|
|
149
245
|
strobengine separates configuration, execution, and metrics into clean Rust modules, exposed to Python via PyO3:
|
|
150
246
|
|
|
151
247
|
- **`config`** -- `TestConfig` for static load, `LoadProfile` enum for dynamic profiles (Constant, Ramp, Spike) with target concurrency interpolation.
|
|
152
|
-
- **`worker`** -- Async worker loops
|
|
248
|
+
- **`worker`** -- Async worker loops with method-aware request building, static payload reuse (Bytes), and zero-allocation header management via `ClientBuilder::default_headers()`.
|
|
153
249
|
- **`metrics`** -- Lock-free atomic counters (`AtomicUsize`) track total requests and errors without contention. An aggregator task collects raw latencies, then `calculate_summary` computes average, p95, and p99 percentiles in Rust at bare-metal speed.
|
|
250
|
+
- **`chaos`** -- Protocol-agnostic fault injection engine with `ChaosEngine` evaluator and `ChaosFault` enum (LatencySpike, CorruptedPayload, MetadataCorruption, ConnectionDrop).
|
|
251
|
+
- **`progress`** -- Background Tokio render task sampling atomic metrics every 200ms, displaying live RPS, active VUs, and latency via indicatif.
|
|
154
252
|
- **Orchestrator** -- Supervisor task ticks every 200ms, calculates target concurrency from the active profile curve, spawns/aborts workers dynamically.
|
|
155
253
|
|
|
156
254
|
The Python GIL is released entirely via `py.detach()` during test execution, allowing the full Tokio thread pool to run concurrently without throttling Python.
|
|
@@ -185,3 +283,4 @@ uv run pytest -v
|
|
|
185
283
|
## License
|
|
186
284
|
|
|
187
285
|
This project is licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full text.
|
|
286
|
+
|