Skip to content
Open
Changes from 1 commit
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
113 changes: 64 additions & 49 deletions gatling-tests/src/test/java/simulation/CreateProductSimulation.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static io.gatling.javaapi.core.CoreDsl.jsonPath;
import static io.gatling.javaapi.core.CoreDsl.nothingFor;
import static io.gatling.javaapi.core.CoreDsl.rampUsers;
import static io.gatling.javaapi.core.CoreDsl.rampUsersPerSec;
import static io.gatling.javaapi.core.CoreDsl.scenario;
import static io.gatling.javaapi.http.HttpDsl.header;
import static io.gatling.javaapi.http.HttpDsl.http;
Expand All @@ -18,7 +19,6 @@
import io.gatling.javaapi.core.ChainBuilder;
import io.gatling.javaapi.core.ScenarioBuilder;
import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -33,13 +33,13 @@ public class CreateProductSimulation extends BaseSimulation {
private static final Logger LOGGER = LoggerFactory.getLogger(CreateProductSimulation.class);

// Configuration parameters - can be externalized to properties
private static final int RAMP_USERS = Integer.parseInt(System.getProperty("rampUsers", "3"));
private static final int RAMP_USERS = Integer.parseInt(System.getProperty("rampUsers", "50"));
private static final int CONSTANT_USERS =
Integer.parseInt(System.getProperty("constantUsers", "15"));
Integer.parseInt(System.getProperty("constantUsers", "100"));
private static final int RAMP_DURATION_SECONDS =
Integer.parseInt(System.getProperty("rampDuration", "30"));
private static final int TEST_DURATION_SECONDS =
Integer.parseInt(System.getProperty("testDuration", "60"));
Integer.parseInt(System.getProperty("testDuration", "180"));

// Breaking down the test flow into reusable components for better readability and
// maintainability
Expand Down Expand Up @@ -173,34 +173,39 @@ public class CreateProductSimulation extends BaseSimulation {
private final ScenarioBuilder productWorkflow =
scenario("E2E Product Creation Workflow")
.feed(enhancedProductFeeder())
.exec(createProduct)
.pause(Duration.ofMillis(10)) // Add pause to reduce load
.exec(getProduct)
.pause(Duration.ofMillis(10)) // Add pause to reduce load
.exec(getInventory)
.pause(Duration.ofMillis(20)) // More pause before the critical update
// Simplified workflow to avoid syntax issues
.exec(
session -> {
// Add safeguard to skip inventory update if inventory info is
// missing or invalid
if (session.contains("inventoryResponseBody")
&& session.getString("inventoryResponseBody") != null
&& !Objects.requireNonNull(
session.getString("inventoryResponseBody"))
.trim()
.isEmpty()) {
return session;
} else {
LOGGER.warn(
"Skipping inventory update due to missing inventory data");
// Return marked as failed so we don't attempt to create an
// order based on invalid inventory
return session.markAsFailed();
}
})
.exec(updateInventory)
.pause(Duration.ofMillis(10)) // Add pause to reduce load
.exec(createOrder);
exec(createProduct)
.exec(
session -> {
logRequestTime(
"Create Product Complete",
System.currentTimeMillis());
return session;
})
.pause(200) // Reduced pause time from 500 to 200 ms
.exec(getProduct)
.pause(100) // Reduced pause time from 300 to 100 ms
// .exec(getInventory)
.pause(100) // Reduced pause time
.exec(
session -> {
// Add safeguard to skip inventory update if
// inventory info is missing or invalid
if (session.contains("inventoryResponseBody")
&& session.getString(
"inventoryResponseBody")
!= null) {
return session;
} else {
LOGGER.warn(
"Skipping inventory update due to missing inventory data");
return session.markAsFailed();
}
})
.exec(updateInventory)
.pause(300)
.exec(createOrder));

/**
* Prepares the inventory update request by generating a new inventory quantity
Expand Down Expand Up @@ -323,29 +328,39 @@ public CreateProductSimulation() {
runHealthChecks();

LOGGER.info(
"Running with warm-up phase of {} seconds with a single user to initialize Kafka",
"Running with warm-up phase of {} seconds with multiple users to initialize Kafka",
KAFKA_INIT_DELAY_SECONDS);

// Global assertions to validate overall service performance
this.setUp(
productWorkflow
// Small pause between steps to simulate realistic user behavior
.pause(Duration.ofMillis(500))
.injectOpen(
// Initial single user for Kafka initialization
atOnceUsers(1),
// Wait for Kafka initialization to complete
nothingFor(Duration.ofSeconds(KAFKA_INIT_DELAY_SECONDS)),
// Ramp up users phase for gradual load increase
rampUsers(RAMP_USERS)
.during(Duration.ofSeconds(RAMP_DURATION_SECONDS)),
// Constant load phase to test system stability
constantUsersPerSec(CONSTANT_USERS)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS))))
// Configure simulation with robust load profile
setUp(
productWorkflow.injectOpen(
// Initial users for Kafka initialization and baseline - increased
// from 3 to 10
atOnceUsers(10),

// Wait for Kafka initialization to complete
nothingFor(Duration.ofSeconds(KAFKA_INIT_DELAY_SECONDS)),

// Initial ramp using users - increased for more load
rampUsers(RAMP_USERS)
.during(Duration.ofSeconds(RAMP_DURATION_SECONDS)),

// Constant load phase with shorter duration but higher throughput
constantUsersPerSec(CONSTANT_USERS / 2)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 4)),

// Ramp up to peak load more quickly
rampUsersPerSec(CONSTANT_USERS / 2)
.to(CONSTANT_USERS)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 4)),

// Sustained peak load phase
constantUsersPerSec(CONSTANT_USERS)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 2))))
Comment on lines +348 to +358
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Prevent zero-rate injection when halving constantUsers

Line 348 currently divides the user rate with integer math, so a legitimate override like -DconstantUsers=1 yields CONSTANT_USERS / 2 == 0. Gatling’s constantUsersPerSec(0) and rampUsersPerSec(0) throw an IllegalArgumentException at runtime, so any low-rate configuration now fails outright. Please keep these stages in the positive domain by switching to floating-point division (or otherwise guarding against zero).

-                                constantUsersPerSec(CONSTANT_USERS / 2)
+                                constantUsersPerSec(CONSTANT_USERS / 2.0)
...
-                                rampUsersPerSec(CONSTANT_USERS / 2)
+                                rampUsersPerSec(CONSTANT_USERS / 2.0)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constantUsersPerSec(CONSTANT_USERS / 2)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 4)),
// Ramp up to peak load more quickly
rampUsersPerSec(CONSTANT_USERS / 2)
.to(CONSTANT_USERS)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 4)),
// Sustained peak load phase
constantUsersPerSec(CONSTANT_USERS)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 2))))
constantUsersPerSec(CONSTANT_USERS / 2.0)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 4)),
// Ramp up to peak load more quickly
rampUsersPerSec(CONSTANT_USERS / 2.0)
.to(CONSTANT_USERS)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 4)),
// Sustained peak load phase
constantUsersPerSec(CONSTANT_USERS)
.during(Duration.ofSeconds(TEST_DURATION_SECONDS / 2))))
🤖 Prompt for AI Agents
In gatling-tests/src/test/java/simulation/CreateProductSimulation.java around
lines 348 to 358, dividing CONSTANT_USERS by 2 uses integer division which
yields zero for small values (e.g. 1) and causes Gatling to throw
IllegalArgumentException; change the math to floating-point (e.g. divide by 2.0
or cast to double) or clamp the result to a positive minimum (Math.max(1.0,
CONSTANT_USERS / 2.0)) so constantUsersPerSec(...) and rampUsersPerSec(...)
never receive 0.

.protocols(httpProtocol)
.assertions(
// Add global performance SLA assertions
global().responseTime().mean().lt(1500), // Mean response time under 1.5s
global().responseTime().mean().lt(2000), // Mean response time under 2s
global().responseTime()
.percentile(95)
.lt(5000), // 95% of responses under 5s
Expand Down
Loading