Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-cicd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ jobs:
file: ./Dockerfile
platforms: linux/amd64
tags: cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }}
provenance: true
push: false
load: true

- name: Install Syft
run: |
Expand All @@ -47,7 +47,7 @@ jobs:
- name: Generate SBOM with Syft
run: |
syft --version
syft "cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }}" -o cyclonedx-json > sbom.cyclonedx.json
syft "docker:cbaugus/rust_loadtest:${{ steps.docker_meta.outputs.TAG }}" -o cyclonedx-json > sbom.cyclonedx.json

- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
Expand Down
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The load testing tool is configured primarily through environment variables pass
### Common Environment Variables

* TARGET_URL (Required): The full URL of the endpoint you want to load test (e.g., http://example.com/api/data or https://secure-api.com/status).
* REQUEST_TYPE (Optional, default: POST): The HTTP method to use for requests. Supported values are "GET" and "POST".
* NUM_CONCURRENT_TASKS (Optional, default: 10): The maximum number of concurrent HTTP requests (worker tasks) that the load generator will attempt to maintain. This acts as a concurrency limit.
* TEST_DURATION (Optional, default: 2h): The total duration for which the load test will run. Accepts values like 10m (10 minutes), 1h (1 hour), 3d (3 days).
* SKIP_TLS_VERIFY (Optional, default: false): Set to "true" to skip TLS/SSL certificate verification for HTTPS endpoints. Use with caution, primarily for testing environments with self-signed certificates.
Expand Down Expand Up @@ -155,20 +156,51 @@ docker run --rm \
cbaugus/rust-loadtester:latest
```

### Sending a JSON Payload (e.g., for Login Endpoints)
### Choosing Request Type (GET vs POST)

You can configure the tool to send either GET or POST requests using the `REQUEST_TYPE` environment variable:

* `REQUEST_TYPE` (Optional, default: POST): Set to `"GET"` for GET requests or `"POST"` for POST requests.

**Example with GET requests:**

```bash
docker run --rm \
-e TARGET_URL="https://jsonplaceholder.typicode.com/posts/1" \
-e REQUEST_TYPE="GET" \
-e NUM_CONCURRENT_TASKS="50" \
-e TEST_DURATION="5m" \
-e LOAD_MODEL_TYPE="Concurrent" \
cbaugus/rust-loadtester:latest
```

**Example with POST requests (default):**

```bash
docker run --rm \
-e TARGET_URL="https://your-service.com/api/data" \
-e REQUEST_TYPE="POST" \
-e NUM_CONCURRENT_TASKS="50" \
-e TEST_DURATION="5m" \
-e LOAD_MODEL_TYPE="Concurrent" \
cbaugus/rust-loadtester:latest
```

### Sending a JSON Payload (for POST requests)

You can configure the tool to send a JSON body with each POST request (for example, to test login endpoints that expect a JSON payload). This is controlled by two environment variables:

* `SEND_JSON` (Optional, default: false): Set to `"true"` to enable sending a JSON payload in the body of each POST request.
* `JSON_PAYLOAD` (Required if `SEND_JSON=true`): The JSON string to send as the request body.

If `SEND_JSON` is not set or is not `"true"`, requests will be sent without a body.
If `SEND_JSON` is not set or is not `"true"`, POST requests will be sent without a body. Note that JSON payloads are only sent with POST requests, not GET requests.

**Example:**

```bash
docker run --rm \
-e TARGET_URL="https://your-service.com/login" \
-e REQUEST_TYPE="POST" \
-e SEND_JSON="true" \
-e JSON_PAYLOAD='{"username":"testuser","password":"testpass"}' \
-e NUM_CONCURRENT_TASKS="20" \
Expand Down
16 changes: 9 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let num_concurrent_tasks_clone = num_concurrent_tasks.clone();
let send_json_clone = send_json;
let json_payload_clone = json_payload.clone();
let request_type_clone = request_type.clone();

let handle = tokio::spawn(async move {
loop {
Expand Down Expand Up @@ -574,20 +575,21 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let request_start_time = time::Instant::now(); // Start timer

// --- CHANGED: Support GET request type ---
if request_type == "GET" {
let req = client_client.get(&url_clone)
else if request_type == "POST" {
let req = if request_type_clone == "GET" {
client_clone.get(&url_clone)
} else if request_type_clone == "POST" {
// --- CHANGED: Conditionally send POST with or without JSON ---
let req = client_clone.post(&url_clone);
let req = if send_json_clone {
if send_json_clone {
req.header("Content-Type", "application/json")
.body(json_payload_clone.clone().unwrap())
} else {
req
};
}
} else {
eprintln!("Request type {} not currently supported", request_type);
}
eprintln!("Request type {} not currently supported", request_type_clone);
client_clone.get(&url_clone) // fallback to GET
};

match req.send().await {
Ok(response) => {
Expand Down