diff --git a/.github/workflows/build-cicd.yaml b/.github/workflows/build-cicd.yaml index da0fb4f..24e9d32 100644 --- a/.github/workflows/build-cicd.yaml +++ b/.github/workflows/build-cicd.yaml @@ -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: | @@ -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 diff --git a/README.md b/README.md index f099b3c..ceecb70 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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" \ diff --git a/src/main.rs b/src/main.rs index 906baf1..ae066de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -545,6 +545,7 @@ async fn main() -> Result<(), Box> { 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 { @@ -574,20 +575,21 @@ async fn main() -> Result<(), Box> { 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) => {