Hi everybody,
We have developed a Gatling loadtest testing an Application Lifecycle Management (ALM) tool. There are four scenarios:
- requirements-engineer
- lead-engineer
- test-engineer
*business admin
for each of these scenarios I want to have a httpProtocol with perUserKeyManager property so that the virtual users can perform a X509 authentication against keycloak using the .p12 certificate that are named after them.
Thus in advance of the load test we prepare certificate per user, e.g.
requirements-engineer-1.p12 … requirements-engineer-n.p12 .
lead-engineer-1.p12 … lead-engineer-n.p12
and so on.
It could be said that there is a certificate pool per user role prepared in advance of the test.
We tried to configure a httpProtocol per scenario hoping that userIds would somehow be naturally divided according to the separate protocols.
val httpProtocolReqEng = http.baseUrl("http://localhost:8080")
.inferHtmlResources(AllowList(), DenyList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.woff2""", """.*\.(t|o)tf""", """.*\.png""", """.*\.svg""", """.*detectportal\.firefox\.com.*"""))
.userAgentHeader("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
.disableWarmUp
.perUserKeyManagerFactory{userId =>
val keyStore = KeyStore.getInstance("PKCS12")
val keyStorePassword = "password"
val keyStoreFile = new File(s"path\\requirements-engineer-$userId.p12")
keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray)
val keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray)
keyManagerFactory}
val httpProtocolLeadEng = http.baseUrl("http://localhost:8080")
.inferHtmlResources(AllowList(), DenyList(""".*\.js""", """.*\.css""", """.*\.gif""", """.*\.jpeg""", """.*\.jpg""", """.*\.ico""", """.*\.woff""", """.*\.woff2""", """.*\.(t|o)tf""", """.*\.png""", """.*\.svg""", """.*detectportal\.firefox\.com.*"""))
.userAgentHeader("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
.disableWarmUp
.perUserKeyManagerFactory{userId =>
val keyStore = KeyStore.getInstance("PKCS12")
val keyStorePassword = "password"
val keyStoreFile = new File(s"path\\lead-engineer-$userId.p12")
keyStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray)
val keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray)
keyManagerFactory}
However we noticed that the Gatling userId is incremented irrespective of the httpProtocol, depending (I presume through logs and docs), on the total number of users given the setup clause below.
I need to match the virtual user instance wtih a specific certificate by means of the userId. So in a way
if I know that the userId 2 is a lead engineer, I’d like keyManager to go pick up a certificate from the lead engineer certificate pool,
if I then know userId 4 is a lead engineer I’d like keyManager to pick up the next available certificate from the pool
It would be okay to have round-robin here so that once all avaialble certificates are used, it can start picking certificates from the beginning.
The experimental setup we made in our unsuccessful attempt is as below. we try to log each user before the load test because of the way keylcloak integrates with our app. Basically a user needs to login so that it appears as valid user over the application that we’re testing. So before preparing test data and running the test, we got to login all the users.
private def inject(scenario: ScenarioBuilder, from: Int, to: Int): PopulationBuilder = {
scenario.inject(
rampConcurrentUsers(from).to(to).during(rampDuringSeconds),
constantConcurrentUsers(to).during(keepForSeconds))
}
setUp(
preparationReqEng.inject(
atOnceUsers(number of REs)
).protocols(httpProtocolRequirementEngineer)
.andThen(
preparationLeadEng.inject(
atOnceUsers(number of LEs)
).protocols(httpProtocolLeadEngineer)
.andThen(
preparationTestEng.inject(
atOnceUsers(number of TEs)
).protocols(httpProtocolTestEngineer)
.andThen(
preparation.inject(
atOnceUsers(if (withPreparation) 1 else 0)
).protocols(httpProtocolAdmin)
.andThen(
inject(requirementsEngineer, rampNumberOfRequirementsEngineersFrom, toNumberOfRequirementsEngineers).protocols(httpProtocolRequirementEngineer),
inject(businessAdministrator, rampNumberOfBusinessAdministratorsFrom, toNumberOfBusinessAdministrators).protocols(httpProtocolAdmin),
inject(leadEngineer, rampNumberOfLeadEngineersFrom, toNumberOfLeadEngineers).protocols(httpProtocolLeadEngineer),
inject(testEngineer, rampNumberOfTestEngineersFrom, toNumberOfTestEngineers).protocols(httpProtocolTestEngineer)
)
)
)
)
)
I’ve also read this piece on the community belog that is helpful but not quite specific to the problem we are facing because of the way we need to associate userIds with scenarios.
List item