drun 7.2.6__tar.gz → 7.2.7__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.
- {drun-7.2.6 → drun-7.2.7}/PKG-INFO +226 -28
- {drun-7.2.6 → drun-7.2.7}/README.md +225 -27
- {drun-7.2.6 → drun-7.2.7}/drun/__init__.py +1 -1
- {drun-7.2.6 → drun-7.2.7}/drun/cli.py +1 -2
- {drun-7.2.6 → drun-7.2.7}/drun/runner/runner.py +138 -6
- {drun-7.2.6 → drun-7.2.7}/drun.egg-info/PKG-INFO +226 -28
- {drun-7.2.6 → drun-7.2.7}/pyproject.toml +1 -1
- {drun-7.2.6 → drun-7.2.7}/tests/test_cli_help_width.py +16 -2
- {drun-7.2.6 → drun-7.2.7}/tests/test_repeat_steps.py +107 -0
- {drun-7.2.6 → drun-7.2.7}/LICENSE +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/commands/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/commands/check.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/commands/fix.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/commands/run.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/commands/tags.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/db/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/db/database_proxy.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/db/generate_mysql_config.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/engine/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/engine/http.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/engine/request_files.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/exporters/curl.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/exporters/snippet.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/extensions.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/importers/base.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/importers/curl.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/importers/har.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/importers/openapi.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/importers/postman.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/loader/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/loader/collector.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/loader/env.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/loader/hooks.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/loader/yaml_loader.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/models/case.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/models/config.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/models/report.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/models/request.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/models/step.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/models/validators.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/notifier/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/notifier/base.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/notifier/dingtalk.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/notifier/emailer.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/notifier/feishu.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/notifier/format.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/reporter/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/reporter/allure_reporter.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/reporter/html_reporter.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/reporter/json_reporter.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/runner/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/runner/asserting.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/runner/assertions.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/runner/extractors.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/runner/hooks.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/runner/invoke.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/scaffolds/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/scaffolds/templates.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/server/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/server/app.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/server/database.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/server/scanner.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/server/services.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/server/templates/detail.html +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/server/templates/index.html +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/templating/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/templating/builtins.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/templating/compat.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/templating/context.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/templating/engine.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/__init__.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/config.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/curl.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/data_exporter.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/env_writer.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/errors.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/logging.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/mask.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun/utils/timeit.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun.egg-info/SOURCES.txt +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun.egg-info/dependency_links.txt +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun.egg-info/entry_points.txt +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun.egg-info/requires.txt +0 -0
- {drun-7.2.6 → drun-7.2.7}/drun.egg-info/top_level.txt +0 -0
- {drun-7.2.6 → drun-7.2.7}/setup.cfg +0 -0
- {drun-7.2.6 → drun-7.2.7}/tests/test_binary_response.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/tests/test_invoke_case_selection.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/tests/test_request_files.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/tests/test_run_env.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/tests/test_run_outputs.py +0 -0
- {drun-7.2.6 → drun-7.2.7}/tests/test_template_engine.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drun
|
|
3
|
-
Version: 7.2.
|
|
3
|
+
Version: 7.2.7
|
|
4
4
|
Summary: Easy-to-use API testing with DevOps automation support
|
|
5
5
|
Author: Drun Team
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -22,7 +22,7 @@ Dynamic: license-file
|
|
|
22
22
|
|
|
23
23
|
# Drun — Modern HTTP API Testing Framework
|
|
24
24
|
|
|
25
|
-
[](https://github.com/Devliang24/drun)
|
|
26
26
|
[](https://www.python.org/downloads/)
|
|
27
27
|
[](LICENSE)
|
|
28
28
|
|
|
@@ -48,7 +48,7 @@ Dynamic: license-file
|
|
|
48
48
|
- **Streaming Support**: SSE (Server-Sent Events) with per-event assertions
|
|
49
49
|
- **File Uploads**: Multipart/form-data support
|
|
50
50
|
- **Smart File Discovery**: Run tests without `.yaml` extension
|
|
51
|
-
- **Test Case Invoke**: Nested test case calls with variable passing
|
|
51
|
+
- **Test Case Invoke**: Nested test case calls with variable passing
|
|
52
52
|
|
|
53
53
|
### Variable Management
|
|
54
54
|
- **Auto-Persist**: Extracted variables automatically saved to `.env`
|
|
@@ -61,7 +61,7 @@ Dynamic: license-file
|
|
|
61
61
|
- **Test Suites**: Ordered execution with variable chaining and caseflow
|
|
62
62
|
- **Authentication**: Basic/Bearer auth with auto-injection
|
|
63
63
|
- **Tag Filtering**: Boolean expressions like `smoke and not slow`
|
|
64
|
-
- **Database
|
|
64
|
+
- **Database Validation via Hooks**: Integrate DB checks through custom hook functions
|
|
65
65
|
|
|
66
66
|
### Reports & Integrations
|
|
67
67
|
- **HTML Reports**: Single-file, shareable test reports
|
|
@@ -181,6 +181,10 @@ steps:
|
|
|
181
181
|
drun run testcases/test_user_api.yaml -env dev
|
|
182
182
|
drun run test_user_api -env dev
|
|
183
183
|
|
|
184
|
+
# Run specific case(s) from a file
|
|
185
|
+
drun run "test_channel_token_flow:获取渠道 token" -env dev
|
|
186
|
+
drun run "test_channel_token_flow:获取渠道 token,刷新渠道 token" -env dev
|
|
187
|
+
|
|
184
188
|
# Run with HTML report
|
|
185
189
|
drun run test_user_api -env dev -html reports/report.html
|
|
186
190
|
|
|
@@ -191,8 +195,55 @@ drun run testcases -env dev -k "smoke and not slow"
|
|
|
191
195
|
drun run testsuite_e2e -env dev
|
|
192
196
|
```
|
|
193
197
|
|
|
198
|
+
By default:
|
|
199
|
+
- Temporary single-file run (outside scaffold) writes only one log file in current directory
|
|
200
|
+
- Scaffold project run keeps default outputs in `logs/`, `reports/`, `snippets/`
|
|
201
|
+
|
|
194
202
|
## Core Concepts
|
|
195
203
|
|
|
204
|
+
### YAML Case Authoring Quick Reference
|
|
205
|
+
|
|
206
|
+
Use one of these two file shapes:
|
|
207
|
+
|
|
208
|
+
**1) Single case file (`config + steps`)**
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
config:
|
|
212
|
+
name: Login API
|
|
213
|
+
base_url: ${ENV(BASE_URL)}
|
|
214
|
+
|
|
215
|
+
steps:
|
|
216
|
+
- name: Login
|
|
217
|
+
request:
|
|
218
|
+
method: POST
|
|
219
|
+
path: /login
|
|
220
|
+
body:
|
|
221
|
+
username: admin
|
|
222
|
+
password: pass123
|
|
223
|
+
extract:
|
|
224
|
+
token: $.data.token
|
|
225
|
+
validate:
|
|
226
|
+
- eq: [status_code, 200]
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**2) Suite file (`config + caseflow`)**
|
|
230
|
+
|
|
231
|
+
```yaml
|
|
232
|
+
config:
|
|
233
|
+
name: Smoke Suite
|
|
234
|
+
|
|
235
|
+
caseflow:
|
|
236
|
+
- name: Login
|
|
237
|
+
invoke: test_login
|
|
238
|
+
- name: User Profile
|
|
239
|
+
invoke: test_profile
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Use this with CLI:
|
|
243
|
+
- `drun run testcases/test_login.yaml -env dev`
|
|
244
|
+
- `drun run testsuites/testsuite_smoke.yaml -env dev`
|
|
245
|
+
- `drun run "test_channel_token_flow:获取渠道 token" -env dev`
|
|
246
|
+
|
|
196
247
|
### Test Case Structure
|
|
197
248
|
|
|
198
249
|
```yaml
|
|
@@ -233,6 +284,24 @@ steps:
|
|
|
233
284
|
- ${cleanup_function()}
|
|
234
285
|
```
|
|
235
286
|
|
|
287
|
+
### Step Syntax Matrix (Writing + Constraints)
|
|
288
|
+
|
|
289
|
+
| Field | Example | Notes |
|
|
290
|
+
| --- | --- | --- |
|
|
291
|
+
| `request.method` / `request.path` | `method: POST` / `path: /users` | Required for request steps |
|
|
292
|
+
| `request.headers` / `request.params` | `headers: {Authorization: Bearer $token}` | Key-value maps |
|
|
293
|
+
| `request.body` | `body: {name: alice}` | JSON-style request body |
|
|
294
|
+
| `request.data` | `data: {model: sensevoice}` | Form fields, commonly with multipart |
|
|
295
|
+
| `request.files` | `files: {file: "data/a.wav"}` or `files: {file: ["data/a.wav", "audio/x-wav"]}` | Supported upload forms; prefer `data + files` for multipart |
|
|
296
|
+
| `request.stream` / `request.stream_timeout` | `stream: true` / `stream_timeout: 30` | For SSE/streaming APIs |
|
|
297
|
+
| `extract` | `extract: {token: $.data.token}` | Extract variables for later steps/cases |
|
|
298
|
+
| `validate` | `- eq: [status_code, 200]` | Assertions on status/body/variables |
|
|
299
|
+
| `setup_hooks` / `teardown_hooks` | `setup_hooks: [${sign($request)}]` | Run Python hooks before/after step |
|
|
300
|
+
| `response.save_body_to` | `response: {save_body_to: artifacts/out.mp3}` | Save binary/non-JSON response to file |
|
|
301
|
+
| `skip` | `skip: true` / `skip: "maintenance"` / `skip: ${remain_quota <= 0}` | Supports bool, reason string, or expression (evaluated per iteration with `repeat`) |
|
|
302
|
+
| `repeat` | `repeat: 3` or `repeat: ${retry_count}` | Must resolve to integer `>= 0`; `0` means skipped |
|
|
303
|
+
| `invoke_case_name` / `invoke_case_names` | `invoke_case_name: 获取渠道 token` | Caseflow-only filter by exact `config.name`; two fields are mutually exclusive |
|
|
304
|
+
|
|
236
305
|
### Variable Extraction & Auto-Persist
|
|
237
306
|
|
|
238
307
|
**Extraction automatically persists to environment:**
|
|
@@ -267,7 +336,7 @@ steps:
|
|
|
267
336
|
user_id: ${ENV(USER_ID)} # Uses extracted userId
|
|
268
337
|
```
|
|
269
338
|
|
|
270
|
-
### Test Suites & Caseflow
|
|
339
|
+
### Test Suites & Caseflow
|
|
271
340
|
|
|
272
341
|
**Modern caseflow syntax with invoke:**
|
|
273
342
|
|
|
@@ -296,30 +365,79 @@ caseflow:
|
|
|
296
365
|
variables:
|
|
297
366
|
order_id: $orderId
|
|
298
367
|
invoke: test_verify
|
|
299
|
-
```
|
|
300
368
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
config:
|
|
307
|
-
name: E2E Test Flow
|
|
308
|
-
base_url: ${ENV(BASE_URL)}
|
|
369
|
+
- name: Invoke specific cases in file
|
|
370
|
+
invoke: test_channel_token_flow
|
|
371
|
+
invoke_case_names:
|
|
372
|
+
- 获取渠道 token
|
|
373
|
+
- 刷新渠道 token
|
|
309
374
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
- testcases/test_verify.yaml
|
|
375
|
+
- name: Repeat invoke step
|
|
376
|
+
invoke: test_channel_token_flow
|
|
377
|
+
invoke_case_name: 获取渠道 token
|
|
378
|
+
repeat: 2
|
|
315
379
|
```
|
|
316
380
|
|
|
381
|
+
> **Note**: In caseflow, `variables` comes before `invoke`. Extracted variables are automatically exported to subsequent steps - no explicit `export` needed.
|
|
382
|
+
> `invoke_case_name` and `invoke_case_names` are mutually exclusive. Matching is exact by `config.name`.
|
|
383
|
+
> `invoke_case_name` selects one case; `invoke_case_names` selects multiple cases. Matched cases run in invoked-file order.
|
|
384
|
+
|
|
317
385
|
**Execution characteristics:**
|
|
318
386
|
- Strict sequential order (top to bottom)
|
|
319
387
|
- Variables shared via memory (no file I/O between tests)
|
|
320
388
|
- `.env` file read once at startup
|
|
321
389
|
- Variables extracted during run are persisted to `.env`
|
|
322
390
|
|
|
391
|
+
### Step Repeat (repeat)
|
|
392
|
+
|
|
393
|
+
Run the same step multiple times:
|
|
394
|
+
|
|
395
|
+
```yaml
|
|
396
|
+
steps:
|
|
397
|
+
- name: Upload Audio
|
|
398
|
+
repeat: 3
|
|
399
|
+
request:
|
|
400
|
+
method: POST
|
|
401
|
+
path: /asr/upload
|
|
402
|
+
files:
|
|
403
|
+
file: data/audio.wav
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
`repeat` also supports expressions:
|
|
407
|
+
|
|
408
|
+
```yaml
|
|
409
|
+
steps:
|
|
410
|
+
- name: Health Check
|
|
411
|
+
repeat: ${retry_count}
|
|
412
|
+
request:
|
|
413
|
+
method: GET
|
|
414
|
+
path: /health
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Behavior:
|
|
418
|
+
- `repeat` must resolve to an integer `>= 0`
|
|
419
|
+
- `repeat: 0` marks the step as skipped (no request sent)
|
|
420
|
+
- Logs and reports show iteration suffix like `[repeat=2/5]`
|
|
421
|
+
|
|
422
|
+
### Conditional Repeat (with skip)
|
|
423
|
+
|
|
424
|
+
Use `skip` with `repeat` when each iteration should decide dynamically whether to run:
|
|
425
|
+
|
|
426
|
+
```yaml
|
|
427
|
+
steps:
|
|
428
|
+
- name: Retry until quota exhausted
|
|
429
|
+
repeat: 10
|
|
430
|
+
skip: ${remain_quota <= 0}
|
|
431
|
+
request:
|
|
432
|
+
method: POST
|
|
433
|
+
path: /quota/check
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Rules:
|
|
437
|
+
- `skip` supports `true/false`, reason strings, and `${...}` expressions
|
|
438
|
+
- With `repeat`, `skip` is evaluated per iteration (after `$repeat_index/$repeat_no` are injected)
|
|
439
|
+
- If a `skip` expression fails to evaluate, the iteration is marked as failed with `skip error`
|
|
440
|
+
|
|
323
441
|
### Template System
|
|
324
442
|
|
|
325
443
|
**Dollar-style syntax:**
|
|
@@ -531,6 +649,16 @@ steps:
|
|
|
531
649
|
|
|
532
650
|
## CLI Reference
|
|
533
651
|
|
|
652
|
+
CLI commands are entry points. YAML authoring syntax is documented in:
|
|
653
|
+
- [YAML Case Authoring Quick Reference](#yaml-case-authoring-quick-reference)
|
|
654
|
+
- [Step Syntax Matrix (Writing + Constraints)](#step-syntax-matrix-writing--constraints)
|
|
655
|
+
- [Test Suites & Caseflow](#test-suites--caseflow)
|
|
656
|
+
- [Step Repeat (repeat)](#step-repeat-repeat)
|
|
657
|
+
- [Conditional Repeat (with skip)](#conditional-repeat-with-skip)
|
|
658
|
+
- [File Upload Testing](#file-upload-testing)
|
|
659
|
+
- [Binary Response Save](#binary-response-save)
|
|
660
|
+
- [Quick Request Debug (`drun q`)](#quick-request-debug-drun-q)
|
|
661
|
+
|
|
534
662
|
### Web Report Server
|
|
535
663
|
|
|
536
664
|
```bash
|
|
@@ -540,6 +668,9 @@ drun server
|
|
|
540
668
|
# Custom port and options
|
|
541
669
|
drun server -port 8080 -headless
|
|
542
670
|
|
|
671
|
+
# Bind host and custom reports directory
|
|
672
|
+
drun server -host 127.0.0.1 -reports-dir reports
|
|
673
|
+
|
|
543
674
|
# Development mode with auto-reload
|
|
544
675
|
drun server -reload
|
|
545
676
|
|
|
@@ -559,6 +690,9 @@ drun server -reload
|
|
|
559
690
|
# Basic execution
|
|
560
691
|
drun run PATH -env <env_name>
|
|
561
692
|
|
|
693
|
+
# PATH supports case selector: <path>:<case[,case]>
|
|
694
|
+
drun run "test_channel_token_flow:获取渠道 token" -env dev
|
|
695
|
+
|
|
562
696
|
# Smart file discovery - extension optional
|
|
563
697
|
drun run test_api_health -env dev # Finds test_api_health.yaml or .yml
|
|
564
698
|
drun run testcases/test_user -env dev # Supports paths without extension
|
|
@@ -568,6 +702,10 @@ drun run test_api_health.yaml -env dev # Traditional format still works
|
|
|
568
702
|
# Default output: only one log file in current directory
|
|
569
703
|
drun run ./test_api_health.yaml -env-file ./demo.env
|
|
570
704
|
|
|
705
|
+
# Scaffold project run keeps default outputs:
|
|
706
|
+
# logs/run-<ts>.log, reports/report-<ts>.html, snippets/<ts>/
|
|
707
|
+
drun run testcases/test_api_health.yaml -env dev
|
|
708
|
+
|
|
571
709
|
# With more options
|
|
572
710
|
drun run testcases/ \
|
|
573
711
|
-env staging \
|
|
@@ -580,14 +718,18 @@ drun run testcases/ \
|
|
|
580
718
|
-failfast
|
|
581
719
|
```
|
|
582
720
|
|
|
721
|
+
YAML writing details for run targets are in the sections above, especially `config + steps`, `config + caseflow`, `repeat`, and invoke case selection.
|
|
722
|
+
|
|
583
723
|
**Options:**
|
|
584
724
|
- `-env NAME`: Optional named environment; prefers `.env.<name>` and merges named env config if present
|
|
585
725
|
- `-env-file FILE`: Explicit environment file path; higher priority than `-env` and default `.env`
|
|
726
|
+
- `-persist-env FILE`: Persist extracted variables to specific env file
|
|
586
727
|
- `-k TAG_EXPR`: Filter by tags (e.g., `smoke and not slow`)
|
|
587
728
|
- `-vars k=v`: Override variables from CLI
|
|
588
729
|
- `-html FILE`: Generate HTML report (temporary single-file runs do not generate one by default)
|
|
589
730
|
- `-report FILE`: Generate JSON report
|
|
590
731
|
- `-allure-results DIR`: Generate Allure results
|
|
732
|
+
- `-httpx-logs`: Enable internal httpx request logging
|
|
591
733
|
- `-secrets mask`: Mask sensitive data in logs/reports
|
|
592
734
|
- `-secrets plain`: Show sensitive data (default for local runs)
|
|
593
735
|
- `-response-headers`: Log response headers
|
|
@@ -595,10 +737,67 @@ drun run testcases/ \
|
|
|
595
737
|
- `-log-level LEVEL`: Set log level (DEBUG, INFO, WARNING, ERROR)
|
|
596
738
|
- `-log-file FILE`: Write logs to file (temporary single-file runs otherwise default to `./<yaml>-<ts>.log`)
|
|
597
739
|
- `-notify CHANNELS`: Enable notifications (feishu, dingtalk, email)
|
|
598
|
-
- `-notify-only POLICY`: Notification policy (
|
|
740
|
+
- `-notify-only POLICY`: Notification policy (`failed` or `always`)
|
|
741
|
+
- `-notify-attach-html`: Attach HTML report in email notifications (when email is enabled)
|
|
599
742
|
- `-snippet off`: Disable code snippet generation (temporary single-file runs are already disabled by default)
|
|
600
743
|
- `-snippet-output DIR`: Custom output directory for snippets
|
|
601
744
|
- `-snippet MODE`: Snippet mode: off|all|curl|python
|
|
745
|
+
- `--help`: Keep double-hyphen for help (`drun run --help`)
|
|
746
|
+
|
|
747
|
+
### Quick Request Debug (`drun q`)
|
|
748
|
+
|
|
749
|
+
`drun q` is the direct-request mode (curl/httpie-like) for quick API debugging without YAML.
|
|
750
|
+
|
|
751
|
+
Migration note:
|
|
752
|
+
- `drun quick` has been removed.
|
|
753
|
+
- Use `drun q ...` instead.
|
|
754
|
+
|
|
755
|
+
```bash
|
|
756
|
+
# Basic GET
|
|
757
|
+
drun q https://httpbin.org/get
|
|
758
|
+
|
|
759
|
+
# POST JSON
|
|
760
|
+
drun q https://httpbin.org/post \
|
|
761
|
+
-X POST \
|
|
762
|
+
-H "Content-Type: application/json" \
|
|
763
|
+
-data '{"name":"alice","role":"admin"}'
|
|
764
|
+
|
|
765
|
+
# With query params + headers
|
|
766
|
+
drun q https://httpbin.org/anything \
|
|
767
|
+
-p page=1 \
|
|
768
|
+
-p size=20 \
|
|
769
|
+
-H "X-Trace-Id: demo-001"
|
|
770
|
+
|
|
771
|
+
# Validate response
|
|
772
|
+
drun q https://httpbin.org/status/200 \
|
|
773
|
+
-validate status_code=200
|
|
774
|
+
|
|
775
|
+
# Extract values
|
|
776
|
+
drun q https://httpbin.org/get \
|
|
777
|
+
-extract origin=$.body.origin
|
|
778
|
+
|
|
779
|
+
# Save full response body
|
|
780
|
+
drun q https://httpbin.org/json \
|
|
781
|
+
-output artifacts/httpbin.json
|
|
782
|
+
|
|
783
|
+
# Save as YAML testcase template
|
|
784
|
+
drun q https://httpbin.org/post \
|
|
785
|
+
-X POST \
|
|
786
|
+
-data '{"hello":"world"}' \
|
|
787
|
+
-save-yaml testcases/from_q.yaml \
|
|
788
|
+
-secrets mask
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
Key options:
|
|
792
|
+
- `-X/-method`: HTTP method
|
|
793
|
+
- `-H/-header`: request header, repeatable
|
|
794
|
+
- `-p/-param`: query param, repeatable
|
|
795
|
+
- `-d/-data` / `-data-file`: request body input
|
|
796
|
+
- `-validate`: assertion expression (repeatable)
|
|
797
|
+
- `-extract`: variable extraction (`name=$expr`)
|
|
798
|
+
- `-o/-output`: write full response body
|
|
799
|
+
- `-save-yaml`: convert current request to YAML testcase
|
|
800
|
+
- `-secrets plain|mask`: output secret mode
|
|
602
801
|
|
|
603
802
|
### Format Conversion
|
|
604
803
|
|
|
@@ -997,7 +1196,7 @@ jobs:
|
|
|
997
1196
|
|
|
998
1197
|
## Advanced Topics
|
|
999
1198
|
|
|
1000
|
-
### Test Case Invoke
|
|
1199
|
+
### Test Case Invoke
|
|
1001
1200
|
|
|
1002
1201
|
Call other test cases from within a test case, enabling modular test design:
|
|
1003
1202
|
|
|
@@ -1113,7 +1312,10 @@ steps:
|
|
|
1113
1312
|
- gt: [$event_count, 0]
|
|
1114
1313
|
```
|
|
1115
1314
|
|
|
1116
|
-
### Database
|
|
1315
|
+
### Database Validation via Hooks
|
|
1316
|
+
|
|
1317
|
+
Drun does not provide built-in SQL validators in step fields.
|
|
1318
|
+
Use hook functions to query databases and assert against extracted values.
|
|
1117
1319
|
|
|
1118
1320
|
**Dhook.py:**
|
|
1119
1321
|
```python
|
|
@@ -1133,10 +1335,6 @@ def setup_hook_assert_sql(hook_ctx, user_id):
|
|
|
1133
1335
|
conn.close()
|
|
1134
1336
|
|
|
1135
1337
|
return {'db_status': result[0] if result else None}
|
|
1136
|
-
|
|
1137
|
-
def expected_sql_value(user_id):
|
|
1138
|
-
"""Get expected value from previous query"""
|
|
1139
|
-
return hook_ctx.get('db_status')
|
|
1140
1338
|
```
|
|
1141
1339
|
|
|
1142
1340
|
**Usage:**
|
|
@@ -1150,7 +1348,7 @@ steps:
|
|
|
1150
1348
|
path: /users/$user_id
|
|
1151
1349
|
validate:
|
|
1152
1350
|
- eq: [status_code, 200]
|
|
1153
|
-
- eq: [$.data.status, $
|
|
1351
|
+
- eq: [$.data.status, $db_status]
|
|
1154
1352
|
```
|
|
1155
1353
|
|
|
1156
1354
|
### Performance Testing
|
|
@@ -1197,7 +1395,7 @@ python -m drun.cli --version
|
|
|
1197
1395
|
- **Language**: Python 3.10+
|
|
1198
1396
|
- **Lines of Code**: ~11,300
|
|
1199
1397
|
- **Modules**: ~66 Python files
|
|
1200
|
-
- **Automated Tests**:
|
|
1398
|
+
- **Automated Tests**: In-repo unittest suite is actively maintained (`python -m unittest discover -s tests -p 'test_*.py'`)
|
|
1201
1399
|
- **Code Style**: PEP 8, type hints, Pydantic models
|
|
1202
1400
|
|
|
1203
1401
|
## Version History
|