Added JMeter. Added KeycloakPerfServer into maven.

This commit is contained in:
mposolda 2014-06-27 18:14:42 +02:00
parent b6fd58e644
commit cb9f159091
6 changed files with 644 additions and 15 deletions

View file

@ -1,13 +1,106 @@
Keycloak Web Performance Testsuite
==================================
To run web performance testsuite, you need to:
1) Run Keycloak server
2) Add some users into your Keycloak
3) Run JMeter performance tests
Keycloak server
---------------
In this project you can run:
```shell
mvn exec:java -Pkeycloak-perf-server
````
which will execute embedded Undertow server with:
* Keycloak server
* Performance-tools for mass adding of new users
* Simple web application for testing performance
It will also automatically import realm "perf-realm" into Keycloak from file src/main/resources/perfrealm.json
Note that by default it will use in-memory H2 database, which means that all changes (for example all added users) are discarded after server restart. For performance testing, it's recommended to use some database like PostgreSQL or MySQL
To run server with PostgreSQL you may use command like this (change host,port,dbName and credentials according your DB configuration):
```shell
mvn exec:java -Pkeycloak-perf-server -Dhibernate.connection.url=jdbc:postgresql://localhost:5432/keycloak_perf -Dhibernate.connection.driver_class=org.postgresql.Driver -Dhibernate.connection.username=postgres -Dhibernate.connection.password=postgres -Dhibernate.connection.autocommit=false
````
To run server with MySQL you may use command like this (change host,port,dbName and credentials according your DB configuration):
```shell
mvn exec:java -Pkeycloak-perf-server -Dhibernate.connection.url=jdbc:mysql://localhost/keycloak_perf -Dhibernate.connection.driver_class=com.mysql.jdbc.Driver -Dhibernate.connection.username=portal -Dhibernate.connection.password=portal -Dhibernate.connection.autocommit=false
````
To run server with Mongo you may use command like this (change host,port,dbName and credentials according your DB configuration):
```shell
mvn exec:java -Pkeycloak-perf-server -Dkeycloak.model.provider=mongo -Dkeycloak.model.mongo.db=keycloak-perf
````
To enable cache, you can add additional property:
```shell
-Dkeycloak.model.cache.provider=simple
````
Adding users
------------
-----------------
Adding 1000 new users (will start from last added user, so you don't need to explicitly check how many users to create are needed:
http://localhost:8081/keycloak-tools/perf/perf-realm/create-available-users?prefix=user&count=1000&batch=100&roles=user
Performance test is using users with prefix "user" (so users like "user-0", "user-1", ... , "user-123456" etc). So you first need to add some of these users into your database.
Checking users count:
For checking users count, you can open this URL:
```shell
http://localhost:8081/keycloak-tools/perf/perf-realm/get-users-count?prefix=user
````
Switching to Mongo
------------------
Start with: (TODO)
-Dkeycloak.model.provider=mongo -Dkeycloak.model.mongo.db=keycloak-perf
For adding 10000 new users into your database (will start from last added user, so you don't need to explicitly check how many users to create are needed:
```shell
http://localhost:8081/keycloak-tools/perf/perf-realm/create-available-users?prefix=user&count=10000&batch=100&roles=user
````
Seeing progress of job for creating users
```shell
http://localhost:8081/keycloak-tools/perf/jobs
````
Note that with default H2 are all data automatically cleared after server restart. So it's recommended to use different DB like PostgreSQL or Mongo.
Execute performance test
------------------------
When server is started and some users are created, you can run performance test. It's possible to run it from Command line with:
```shell
mvn verify -Pperformance-test
````
By default, test is using Keycloak on localhost:8081 and 50 concurrent clients (threads) and each client doing 50 test iterations. Each iterations is:
- Login user into KC and retrieve code
- Exchange code for accessToken
- Refresh token 2 times
- Logout user
Each client is using separate username, so actually you need at least 50 users created into your DB (users "user-0", "user-1", ... "user-49" . See above)
ATM it's possible to adjust behaviour with properties:
* host --- Keycloak host ("localhost" by default)
* port --- Keycloak port ("8081" by default)
* userPrefix --- prefix of users ("user" by default)
* concurrentUsers --- Number of concurrent clients (50 by default). RampUp time is configured to start 5 new users each second, so with 50 users are all clients started in like 10 seconds.
* iterationsPerUser --- Number of iterations per each client (50 by default). So by default we have 50*50 = 2500 iterations in total per whole test
* refreshTokenRequestsPerIteration --- Number of refresh token iterations (2 by default)
You can change configuration by adding some properties into command line for example to start just with 10 concurrent clients and 10 iterations per client (so just 100 test iterations) you can use:
```shell
mvn verify -Pperformance-test -DconcurrentUsers=10 -DiterationsPerUser=10
````
After triggering test are results in file target/jmeter/results/aggregatedRequests-durations-<TIMESTAMP>-keycloak_web_perf_test.html
Execute performance test from JMeter GUI
----------------------------------------
You can run
```shell
mvn jmeter:gui
````
and then open file src/test/jmeter/keycloak_web_perf_test.jmx and trigger test from JMeter GUI. It may be good as you can see the progress of whole test during execution.

View file

@ -88,6 +88,30 @@
<artifactId>resteasy-undertow</artifactId>
<version>${resteasy.version.latest}</version>
</dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_java</artifactId>
<exclusions>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk15on</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk15</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
@ -117,4 +141,108 @@
</plugins>
</build>
<profiles>
<profile>
<id>keycloak-perf-server</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>org.keycloak.testsuite.performance.web.KeycloakPerfServer</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>performance-test</id>
<properties>
<host>localhost</host>
<port>8081</port>
<userPrefix>user</userPrefix>
<concurrentUsers>50</concurrentUsers>
<iterationsPerUser>50</iterationsPerUser>
<refreshTokenRequestsPerIteration>2</refreshTokenRequestsPerIteration>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-maven-plugin</artifactId>
<configuration>
<suppressJMeterOutput>false</suppressJMeterOutput>
<propertiesSystem>
<host>${host}</host>
<port>${port}</port>
<userPrefix>${userPrefix}</userPrefix>
<concurrentUsers>${concurrentUsers}</concurrentUsers>
<iterationsPerUser>${iterationsPerUser}</iterationsPerUser>
<refreshTokenRequestsPerIteration>${refreshTokenRequestsPerIteration}</refreshTokenRequestsPerIteration>
</propertiesSystem>
</configuration>
<executions>
<execution>
<id>jmeter-tests</id>
<phase>verify</phase>
<goals>
<goal>jmeter</goal>
</goals>
</execution>
</executions>
<dependencies>
</dependencies>
</plugin>
<plugin>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-analysis-maven-plugin</artifactId>
<executions>
<execution>
<id>jmeter-tests-analyze</id>
<phase>verify</phase>
<goals>
<goal>analyze</goal>
</goals>
<configuration>
<source>${project.build.directory}/jmeter/results/*.jtl</source>
<targetDirectory>${project.build.directory}/jmeter/results</targetDirectory>
<preserveDirectories>false</preserveDirectories>
<requestGroups>
<requestGroup>
<name>aggregatedRequests</name>
<pattern>* request</pattern>
</requestGroup>
<requestGroup>
<name>codes</name>
<pattern>**/perf-app/perf-servlet?code=*</pattern>
</requestGroup>
</requestGroups>
<writers>
<com.lazerycode.jmeter.analyzer.writer.SummaryTextToStdOutWriter/>
<!--<com.lazerycode.jmeter.analyzer.writer.SummaryTextToFileWriter/>-->
<com.lazerycode.jmeter.analyzer.writer.HtmlWriter/>
<!--<com.lazerycode.jmeter.analyzer.writer.DetailsToCsvWriter/>-->
<com.lazerycode.jmeter.analyzer.writer.DetailsToHtmlWriter/>
<com.lazerycode.jmeter.analyzer.writer.ChartWriter/>
</writers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View file

@ -24,6 +24,13 @@ public class KeycloakPerfServer {
private KeycloakServer keycloakServer;
public static void main(String[] args) throws Throwable {
// TODO: should be better than programmatic setup here, but don't copy persistence.xml again...
System.setProperty("hibernate.hbm2ddl.auto", "update");
if (System.getProperty("undertowWorkerThreads") == null) {
System.setProperty("undertowWorkerThreads", "256");
}
KeycloakServer keycloakServer = KeycloakServer.bootstrapKeycloakServer(args);
System.out.println("Keycloak server bootstrapped");

View file

@ -113,16 +113,10 @@ public class PerfAppServlet extends HttpServlet {
}
protected void logoutRedirect(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String sessionState = null;
AccessToken accessTokenParsed = (AccessToken)req.getSession().getAttribute("accessTokenParsed");
if (accessTokenParsed != null) {
sessionState = accessTokenParsed.getSessionState();
}
// Invalidate http session
req.getSession(false).invalidate();
String logoutURL = oauthClient.getLogoutUrl(oauthClient.getRedirectUri(), sessionState);
String logoutURL = oauthClient.getLogoutUrl(oauthClient.getRedirectUri(), null);
resp.sendRedirect(logoutURL);
}

View file

@ -0,0 +1,20 @@
#Thu Mar 07 18:46:04 BRT 2013
not_in_menu=HTML Parameter Mask,HTTP User Parameter Modifier
xml.parser=org.apache.xerces.parsers.SAXParser
cookies=cookies
wmlParser.className=org.apache.jmeter.protocol.http.parser.RegexpHTMLParser
HTTPResponse.parsers=htmlParser wmlParser
remote_hosts=127.0.0.1
system.properties=system.properties
beanshell.server.file=../extras/startup.bsh
log_level.jmeter.junit=DEBUG
sampleresult.timestamp.start=true
jmeter.laf.mac=System
log_level.jorphan=INFO
classfinder.functions.contain=.functions.
user.properties=user.properties
wmlParser.types=text/vnd.wap.wml
log_level.jmeter=DEBUG
classfinder.functions.notContain=.gui.
htmlParser.types=text/html application/xhtml+xml application/xml text/xml
upgrade_properties=/bin/upgrade.properties

View file

@ -0,0 +1,387 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.6" jmeter="2.11 r1554548">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="host" elementType="Argument">
<stringProp name="Argument.name">host</stringProp>
<stringProp name="Argument.value">${__P(host, localhost)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="port" elementType="Argument">
<stringProp name="Argument.name">port</stringProp>
<stringProp name="Argument.value">${__P(port, 8081)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="userPrefix" elementType="Argument">
<stringProp name="Argument.name">userPrefix</stringProp>
<stringProp name="Argument.value">${__P(userPrefix, user)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="concurrentUsers" elementType="Argument">
<stringProp name="Argument.name">concurrentUsers</stringProp>
<stringProp name="Argument.value">${__P(concurrentUsers, 50)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="iterationsPerUser" elementType="Argument">
<stringProp name="Argument.name">iterationsPerUser</stringProp>
<stringProp name="Argument.value">${__P(iterationsPerUser, 50)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="refreshTokenRequestsPerIteration" elementType="Argument">
<stringProp name="Argument.name">refreshTokenRequestsPerIteration</stringProp>
<stringProp name="Argument.value">${__P(refreshTokenRequestsPerIteration, 2)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</Arguments>
<hashTree/>
<CookieManager guiclass="CookiePanel" testclass="CookieManager" testname="HTTP Cookie Manager" enabled="true">
<collectionProp name="CookieManager.cookies"/>
<boolProp name="CookieManager.clearEachIteration">true</boolProp>
<stringProp name="CookieManager.implementation">org.apache.jmeter.protocol.http.control.HC4CookieHandler</stringProp>
</CookieManager>
<hashTree/>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Keycloak test" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">${iterationsPerUser}</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">${concurrentUsers}</stringProp>
<stringProp name="ThreadGroup.ramp_time">${__javaScript(${concurrentUsers} / 5)}</stringProp>
<longProp name="ThreadGroup.start_time">1403769177000</longProp>
<longProp name="ThreadGroup.end_time">1403769177000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<UserParameters guiclass="UserParametersGui" testclass="UserParameters" testname="User Parameters" enabled="true">
<collectionProp name="UserParameters.names">
<stringProp name="-265713450">username</stringProp>
</collectionProp>
<collectionProp name="UserParameters.thread_values">
<collectionProp name="-1547483968">
<stringProp name="1649970578">user-${__javaScript(${__threadNum}-1)}</stringProp>
</collectionProp>
</collectionProp>
<boolProp name="UserParameters.per_iteration">false</boolProp>
</UserParameters>
<hashTree/>
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="HTTP Request Defaults" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">${host}</stringProp>
<stringProp name="HTTPSampler.port">${port}</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path"></stringProp>
<stringProp name="HTTPSampler.concurrentPool">4</stringProp>
</ConfigTestElement>
<hashTree/>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Check 200 response" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="49586">200</stringProp>
</collectionProp>
<stringProp name="TestPlan.comments">Check that status is 200 in each HTTP response</stringProp>
<stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">8</intProp>
</ResponseAssertion>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Login request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="action" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">code</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">action</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/perf-app/perf-servlet</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert KC login page" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="-2012386511">Log in to perf-realm</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">2</intProp>
</ResponseAssertion>
<hashTree/>
</hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Confirm Login request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments">
<elementProp name="username" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">${username}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">username</stringProp>
</elementProp>
<elementProp name="password" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">password</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
<boolProp name="HTTPArgument.use_equals">true</boolProp>
<stringProp name="Argument.name">password</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/auth/realms/perf-realm/tokens/auth/request/login?response_type=code&amp;redirect_uri=http%3A%2F%2Flocalhost%3A8081%2Fperf-app%2Fperf-servlet&amp;state=123&amp;client_id=perf-app</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert code retrieved" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="726495917">RequestAction=Code retrieved</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">2</intProp>
</ResponseAssertion>
<hashTree/>
<RegexExtractor guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor" enabled="true">
<stringProp name="RegexExtractor.useHeaders">false</stringProp>
<stringProp name="RegexExtractor.refname">code</stringProp>
<stringProp name="RegexExtractor.regex">Code=([\w\.]+)</stringProp>
<stringProp name="RegexExtractor.template">$1$</stringProp>
<stringProp name="RegexExtractor.default"></stringProp>
<stringProp name="RegexExtractor.match_number">1</stringProp>
</RegexExtractor>
<hashTree/>
</hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Exchange code request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/perf-app/perf-servlet?action=exchangeCode</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert token retrieved" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="-1001303095">RequestAction=Token retrieved</stringProp>
<stringProp name="1027121929">Username=${username}</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">16</intProp>
</ResponseAssertion>
<hashTree/>
</hashTree>
<LoopController guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">true</boolProp>
<stringProp name="LoopController.loops">${refreshTokenRequestsPerIteration}</stringProp>
</LoopController>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="RefreshToken request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/perf-app/perf-servlet?action=refresh</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert token refreshed" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="-544743205">RequestAction=Token refreshed</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">16</intProp>
</ResponseAssertion>
<hashTree/>
</hashTree>
</hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Logout request" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/perf-app/perf-servlet?action=logout</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Assert logged out" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="275024728">RequestAction=</stringProp>
<stringProp name="-1938181625">Username=</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">20</intProp>
</ResponseAssertion>
<hashTree/>
</hashTree>
</hashTree>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<objProp>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>