In this section you’ll find the latest Real Load documentation.
If you’d like to provide feedback in relation to the product documentation please email use at support@realload.com.
This the multi-page printable view of this section. Click here to print.
In this section you’ll find the latest Real Load documentation.
If you’d like to provide feedback in relation to the product documentation please email use at support@realload.com.
This section of the documentation will walk you through the first steps in order to getting started with the Real Load product.
Follow the next sections of the document and you should be able to run your first basic load test script using the SaaS Evaluaiton scenario within 20 minutes or so.
Please to let us know if encounter any issues while getting started, as that will help us updating this documentation to make it as clear and user friendly as possible.
First of all you’ll have to decide which Real Load deployment type better suits your needs. These guidlines might assist you in making an informed decision.
If your intent is to first evaluate the product we strongly suggest to chose the “quick evaluation” option.
There are two key components that make up the Real Load application:
Depending on your network topology, the location of the Measuring Agent (externally exposed or not) will be the main factor dictating whether you can use our SaaS solution (cloud hosted) or you’ll have to proceed with an on-premises deployment.
The following diagram summarizes the architecture:
If you’d just like to perform an initial evaluation the Real Load product your best option would be to use our SaaS offering. Simply create yourself an account in our cloud based portal and once you’re setup you’ll be able to prepare a load testing script and perform a low-volume test against an intenet exposed server.
- Perform a functional evaluation without having to deploy any software on-premises.
- Do not want to incure any cloud related (AWS / Azure) costs.
- The website you want to run the load test against need to be publicly reachable.
If all the servers you’re planning to run your load test against are cloud hosted (AWS, Azure, etc…) you might be able to use our existing AWZ or Azure agent image as load test generators, controlled by our cloud based portal.
- The website you want to run the load test is hosted in the cloud but doesn’t need to be publicly reachable. It needs to be reachable from a cloud deployed Real Load agent.
- You’ll have to start a Real Load agent instance (Virtual Machine) under your own cloud account.
- You’ll have to run some instances of our agent AWS or Azure images under your own cloud account. A suitable AWS or Azure subscription will be required. This machine needs to be assigned a public IP address so that it is reachable from our Portal Server.
If at least some of the servers you’re planning to run your load test against are hosted within an internal network that is not externally reachable and exposing the real-load agents to the internet is not an option, you’ll have to deploy the Real Load portal on-premises, so that both internal and external (if any agent) Real Load agents are reachable.
- At least some of the servers you want to load test are not exposed externally.
- Exposing the Real Load agent externally is not an option.
- You’ll have to deploy the Real Load portal internally on a supported operating system.
- You’ll have to deploy the Real Load agent(s) internally on a supported operating system.
- If required, you might have to run some instances of our agent AWS or Azure images under your own cloud account. A suitable AWS or Azure subscription will be required.
Obviously you can run all of your Real Load infrastructure internally. The Real Load software doesn’t require any connecivity to external systeems in this deployment scneario. This scenario is very similar to the last scenario…
- At least some of the servers you want to load test are not exposed externally.
- Exposing the Real Loaf agent externally is not an option.
- You’ll have to deploy the Real Load portal internally on a supported operating system.
- You’ll have to deploy the Real Load agent(s) internally on a supported operating system.
If you already have an account, you can login at this link:
In order to login to the portal you’ll first have to setup an account. Go to the portal URL and click on the Sign Up button or go this URL: https://portal.realload.com/SignUp
You’ll need to provide:
A free account allows you to prepare and execute both synthetic monitoring & load tests with the following limitations:
You can add a Real Load license to your account at any time, even if your account is expired (no longer than 6 months ago), by purchasing licenses at https://shop.realload.com .
When sign up, you will get 20 free Cloud Credits, which can be used to start Measuring Agents (= load generators) directly from the portal server.
This is a brief description of the information required to sing up to the Real Load portal.
Provide your details, including email and mobile number.
Validate your email address.
Validate your mobile number
Configure your nickname and password
Once you signed up, you will be automatically loggedIn, and you can take a tour on our user guide. Two shared Measuring Agents are now assigned to your user account. Also for customers (user accounts) who do not operate their own HTTP/S Remote Proxy Recorder, a temporary HTTP/S Remote Proxy Recorder from a pool is now assigned each time they sign-in.
Once you had quick tour on our user guide, you can set up your test scripts here, either by recording the browser or mobile traffic by the HTTP/S Remote Proxy Recorder or set up API test scripts directly from the HTTP Test Wizard.
In order to debug and execute a load test, you’ll need at least a Measuring Agent (= load generator).
There are 3 ways to set up Measuring Agents:
Option 2 and 3 do not require any Cloud Credits.
Video: Define and run a simple test with a Measurement Agent instance launched by Cloud Credits.
To configure and execute this simple test you’ll need:
Then define a new resource set in the freshly created project. I’ll call this “GET tests”, but again feel free to chose any name that makes sense to you.
Now we’ll create the test script with the help of the HTTP test wizard.
Enter a name for the test script and click on OK.
Then click on “Add” and select “URL” from the menu. This is to add a new URL request to the test script.
Enter the URL of the REST API endpoint, for example https://www.realload.com/RealLoadListImagesWS/rest/AWSImages
You can now test with the debugger that your test does what it is supposed to do.
Click on “Debug Session”:
Then click on Next Step to execute the REST request. Note the update in the area highlighted in red.
You can inspect the response header and body by clicking on the icons pointed at by the arrows:
The response content (body) will appear in the debugger. If all looks good, close the window.
The last step is to save the test and the execute it. First exit from the debugger window:
.. then save the session using a suitable name. Also select the resource group the test should be saved to.
Now generate the Java code that will contain your test logic which will be executed on the Measuring Agent. Click on “Generate Code”:
Then click on “Generate Source Code” and “Compile & Generate Jar”.
Now that the test code is compiled, you can define a new test that by clicking on “Define New Test”.
You’ll have to give a name to this test job, enter something meaningful to you:
You’re now ready to execute the test. Click on the test you’ve just defined to create a new test job:
… select “continue”…
… select the agent to run the test job from.
You’re now ready to start the test. Click on “Test jobs” then click on “Start Test Job”:
.. select the number of Virtual Users to simulate, duration of the test and think time between test loops:
A free account allows you to prepare and execute load tests with the following limitations:
You can add a Real Load license to your account at any time by purchasing it in our shop https://shop.realload.com .
Once the test job is running click on the “Monitor Jobs” menu item:
… and you’ll be able to see measurement related to your test job:
Done, congrats, you’ve run your first load test with Real Load.
To learn more we suggest heading to the User Guide section where you’ll find detailed documentation in relation to the steps outlined in this document.
Real Load is an Enterprise tool to perform next generation Load Testing and Synthetic Monitoring.
At the core of the Real Load product is a universal measurement interface that supports to capture data of performance tests which can run against anything that has a response time. The product is highly scalable and can be used to run tests from a few hundred simulated users up to an almost unlimited load with millions of concurrent users.
In addition, It can be used for periodically tests your critical use cases for proactive monitoring .
The executed tests can be either generated automatically by using the wizards, or alternatively programmed by hand, with all libraries and interfaces being fully documented in detail.
Regardless of what type of test you are running, all data reported to the universal interface during a test are displayed directly in real time in form of statistics and charts. Results from load releasing clusters are even displayed in real time by combining the cluster members data on the fly.
Real Load itself is written in Java - but can execute tests written in any programming language, since the universal measurement interface is file-based and supports any programming language that is capable to write data into a file.
In order to enable the automatic Java memory configuration of a Measuring Agent 4.1.0, the following Java program arguments must be set in the startup script: -autoAdjustMemory -osReservedMemory 1GB
Furthermore, the Java memory of the Measuring Agent should be set in the startup script as shown in the table below:
OS Physical Memory | Measuring Agent Java -Xmx setting |
---|---|
<2 GiB | 256m |
2..3 GiB | 512m |
4..7 GiB | 512m |
8..15 GiB | 1536m |
16..31 GiB | 3072m |
32..63 GiB | 4096m |
64..96 GiB | 6144m |
>96 GiB | 8192m |
Odd number of GiB should be rounded up (e.g. 7.7 = 8 = 1536m). |
Example: sudo -H -u dkfqs bash -c ‘CLASSPATH=/home/dkfqs/agent/bin/bcpkix-jdk15on-160.jar:/home/dkfqs/agent/bin/bcprov-jdk15on-160.jar:/home/dkfqs/agent/bin/bctls-jdk15on-160.jar:/home/dkfqs/agent/bin/DKFQSMeasuringAgent.jar;export CLASSPATH;nohup java -Xmx512m -DdkfqsMeasuringAgentProperties=/home/dkfqs/agent/config/measuringagent.properties -Dnashorn.args="–no-deprecation-warning" com.dkfqs.measuringagent.internal.StartDKFQSMeasuringAgent -autoAdjustMemory -osReservedMemory 1GB 1>/home/dkfqs/agent/log/MeasuringAgent.log 2>&1 &’
Advantages and disadvantages of ‘Cloud Credits’ versus launching AWS/EC2 instances by the ‘Desktop Companion’:
Benefits of ‘Cloud Credits’:
Advantages of the ‘Desktop Companion’:
Portal Server Installation / Ubuntu 20: The “fontconfig” package has to be installed in order that the captcha generator is working:
sudo apt-get update
sudo apt-get install fontconfig
in /etc/security/limits.conf add or modify:
# TCP/IP Tuning
# =============
* soft nproc 262140
* hard nproc 262140
* soft nofile 262140
* hard nofile 262140
root soft nproc 262140
root hard nproc 262140
root soft nofile 262140
root hard nofile 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=8966
if you get a value less than 262140 then add in /etc/systemd/system.conf
# System Tuning
# =============
DefaultTasksMax=262140
Reboot the system and verify the settings. Enter: ulimit -n
output: 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=262140
This document explains:
The All Purpose Interface is the core of the product.
The architecture and the provided components that support this interface are referred as the Real Load Platform, which is optimized for performing load and stress tests with thousands of concurrent users.
This interface can be implemented by any programming language and regulates:
What requirements a script or program must comply in order to be executed by the Real Load Platform.
How the runtime behavior of the simulated users and the measured data of a script or program are reported to the Real Load Platform.
The great advantage of using the Real Load Platform is that only the basic functionality of a test has to be implemented. The powerful features of the Real Load Platform takes care of everything else, such as executing tests on remote systems and displaying the measured results in the form of diagrams, tables and statistics - in real time as well as final test result.
The product’s open architecture enables you to develop plug-ins, scripts and programs that measure anything that has numeric value - no matter which protocol is used!
The measured data are evaluated in real time and displayed as diagrams and lists. In addition to successfully measured values, also errors like timeouts or invalid response data can be collected and displayed in real time.
At least in theory, programs and scripts of any programming language can be executed, as long as such a program or script supports the All Purpose Interface.
In practice there are currently two options for integrating your own measurements into the Real Load Platform:
Write an HTTP Test Wizard Plug-In in Java that performs the measurement. This has the advantage that you only have to implement a subset of the “All Purpose Interface” yourself:
Such plug-ins can be developed quite quickly, as all other functions of the “All Purpose Interface” are already implemented by the HTTP Test Wizard.
Tip: An HTTP Test Wizard session can also only consist of plug-ins, i.e. you can “misuse” the HTTP Test Wizard to only carry out measurements that you have programmed yourself: Plug-In Example
Write a test program or from scratch. This can currently be programmed in Java or PowerShell (support for additional programming languages will be added in the future). This is more time-consuming, but has the advantage that you have more freedom in program development. In this case you have to implement all functions of the “All Purpose Interface”.
The All Purpose Interface must be implemented by all programs and scripts which are executed on the Real Load Platform. The interface is independent of any programming language and has only three requirements:
All of this seems a bit trivial, but has been chosen deliberately. So that the interface can support almost all programming languages.
Each executed program or script must support at least the following arguments:
Implementation Note: The test ends if either the Test Duration is elapsed or if Max Session Loops are reached for all simulated users. Currently executed sessions are not aborted.
In addition, the following arguments are optional, but also standardized:
Argument | Java | PowerShell |
---|---|---|
Number of Users | -users number | -totalUsers number |
Test Duration | -duration seconds | -inputTestDuration seconds |
Ramp Up Time | -rampupTime seconds | -rampUpTime seconds |
Max Session Loops | -maxLoops number | -inputMaxLoops number |
Delay Per Session Loop | -delayPerLoop milliseconds | -inputDelayPerLoopMillis milliseconds |
Data Output Directory | -dataOutputDir path | -dataOutDirectory path |
Description | -description text | -description text |
Debug Execution | -debugExec | -debugExecution |
Debug Measuring | -debugData | -debugMeasuring |
For scripts which don’t support multiple threads the Real Load Platform starts for each simulated user a own operating system process per simulated user. On the other hand, for programs which support multiple threads, only one operating system process is started for all simulated users.
Scripts which are not able to run multiple threads must support the following additional generic command line argument:
Argument | PowerShell |
---|---|
Executed User Number | -inputUserNo number |
Additional program and script specific arguments are supported by the Real Load Platform. Hoverer, their values are not validated by the platform.
During the execution of a test the Real Load Platform can create and delete at runtime additional control files in the Data Output Directory of a test job. The existence, and respectively the absence of such control files must be frequently checked by the running script or program, but not too often to avoid CPU and I/O overload. Rule of thumb: Multi-threaded programs should check the existence of such files every 5..10 seconds. Single-threaded scripts should check such files before executing a new session loop iteration.
The following control files are created or removed in the Data Output Directory by the Real Load Platform:
When a test job is started by the Real Load Platform on a Measuring Agent, then the Real Load Platform creates at first for each simulated user an empty data file in the Data Output Directory of the test job:
Data File: user_<Executed User Number>_statistics.out
Example: user_1_statistics.out, user_2_statistics.out, user_3_statistics.out, .. et cetera.
After that, the test script(s) or test program is started as operating system process. The test script or the test program has to write the current state of the simulated user and measured data to the corresponding Data File of the simulated user in JSON object format (append data to the file only – don’t create new files).
The Real Load Platform component Measuring Agent and the corresponding Data Collector are listening to these data files and interpret the measured data at real-time, line by line as JSON objects.
The following JSON Objects can be written to the Data Files:
JSON Object | Description |
---|---|
Declare Statistic | Declare a new statistic |
Register Execute Start | Registers the start of a user |
Register Execute Suspend | Registers that the execution of a user is suspended |
Register Execute Resume | Registers that the execution of a user is resumed |
Register Execute End | Registers that a user has ended |
Register Loop Start | Registers that a user has started a session loop iteration |
Register Loop Passed | Registers that a session loop iteration of a user has passed |
Register Loop Failed | Registers that a session loop iteration of a user has failed |
Register Sample Start | Statistic-type sample-event-time-chart: Registers the start of measuring a sample |
Add Sample Long | Statistic-type sample-event-time-chart: Registers that a sample has measured and report the value |
Add Sample Error | Statistic-type sample-event-time-chart: Registers that the measuring of a sample has failed |
Add Counter Long | Statistic-type cumulative-counter-long: Add a positive delta value to the counter |
Add Average Delta And Current Value | Statistic-type average-and-current-value: Add delta values to the average and set the current value |
Add Efficiency Ratio Delta | Statistic-type efficiency-ratio-percent: Add efficiency ratio delta values |
Add Throughput Delta | Statistic-type throughput-time-chart: Add a delta value to a throughput |
Add Test Result Annotation Exec Event | Add an annotation event to the test result |
Note that the data of each JSON object must be written as a single line which end with a \r\n line terminator.
Before the measurement of data begins, the corresponding statistics must be declared at runtime. Each declared statistic must have a unique ID. Multiple declarations with the same ID are crossed out by the platform.
Currently 5 types of statistics are supported:
It’s also supported to declare new statistics at any time during test execution, but the statistics must be declared first, before the measured data are added.
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "DeclareStatistic",
"type": "object",
"required": ["subject", "statistic-id", "statistic-type", "statistic-title"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'declare-statistic'"
},
"statistic-id": {
"type": "integer",
"description": "Unique statistic id"
},
"statistic-type": {
"type": "string",
"description": "'sample-event-time-chart' or 'cumulative-counter-long' or 'average-and-current-value' or 'efficiency-ratio-percent' or 'throughput-time-chart'"
},
"statistic-title": {
"type": "string",
"description": "Statistic title"
},
"statistic-subtitle": {
"type": "string",
"description": "Statistic subtitle | only supported by 'sample-event-time-chart'"
},
"y-axis-title": {
"type": "string",
"description": "Y-Axis title | only supported by 'sample-event-time-chart'. Example: 'Response Time'"
},
"unit-text": {
"type": "string",
"description": "Text of measured unit. Example: 'ms'"
},
"sort-position": {
"type": "integer",
"description": "The UI sort position"
},
"add-to-summary-statistic": {
"type": "boolean",
"description": "If true = add the number of measured and failed samples to the summary statistic | only supported by 'sample-event-time-chart'. Note: Synthetic measured data like Measurement Groups or Delay Times should not be added to the summary statistic"
},
"background-color": {
"type": "string",
"description": "The background color either as #hex-triplet or as bootstrap css class name, or an empty string = no special background color. Examples: '#cad9fa', 'table-info'"
}
}
}
Example:
{
"subject":"declare-statistic",
"statistic-id":1,
"statistictype":"sample-event-time-chart",
"statistic-title":"GET http://192.168.0.111/",
"statistic-subtitle":"",
"y-axis-title":"Response Time",
"unit-text":"ms",
"sort-position":1,
"add-to-summarystatistic":true,
"background-color":""
}
After the statistics are declared then the activities of the simulated users can be started. Each simulated user must report the following changes of the current user-state:
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterExecuteStart",
"type": "object",
"required": ["subject", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-execute-start'"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-execute-start","timestamp":1596219816129}
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterExecuteSuspend",
"type": "object",
"required": ["subject", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-execute-suspend'"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-execute-suspend","timestamp":1596219816129}
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterExecuteResume",
"type": "object",
"required": ["subject", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-execute-resume'"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-execute-resume","timestamp":1596219816129}
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterExecuteEnd",
"type": "object",
"required": ["subject", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-execute-end'"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-execute-end","timestamp":1596219816129}
Once a simulated user has started its activity it measures the data in so called ‘session loops’. Each simulated must report when a session loop iteration starts and ends:
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterLoopStart",
"type": "object",
"required": ["subject", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-loop-start'"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-loop-start","timestamp":1596219816129}
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterLoopPassed",
"type": "object",
"required": ["subject", "loop-time", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-loop-passed'"
},
"loop-time": {
"type": "integer",
"description": "The time it takes to execute the loop in milliseconds"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-loop-passed","loop-time":1451, "timestamp":1596219816129}
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterLoopFailed",
"type": "object",
"required": ["subject", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-loop-failed'"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-loop-failed","timestamp":1596219816129}
Within a session loop iteration the samples of the declared statistics are measured. For sample-event-time-chart statistics the simulated user must report when the measuring of a sample starts and ends:
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "RegisterSampleStart",
"type": "object",
"required": ["subject", "statistic-id", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'register-sample-start'"
},
"statistic-id": {
"type": "integer",
"description": "The unique statistic id"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"register-sample-start","statisticid":2,"timestamp":1596219816165}
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "AddSampleLong",
"type": "object",
"required": ["subject", "statistic-id", "value", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'add-sample-long'"
},
"statistic-id": {
"type": "integer",
"description": "The unique statistic id"
},
"value": {
"type": "integer",
"description": "The measured value"
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{"subject":"add-sample-long","statisticid":2,"value":105,"timestamp":1596219842468}
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "AddSampleError",
"type": "object",
"required": ["subject", "statistic-id", "error-subject", "error-severity",
"timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'add-sample-error'"
},
"statistic-id": {
"type": "integer",
"description": "The unique statistic id"
},
"error-subject": {
"type": "string",
"description": "The subject or title of the error"
},
"error-severity": {
"type": "string",
"description": "'warning' or 'error' or 'fatal'"
},
"error-type": {
"type": "string",
"description": "The type of the error. Errors which contains the same error
type can be grouped."
},
"error-log": {
"type": "string",
"description": "The error log. Multiple lines are supported by adding \r\n line terminators."
},
"error-context": {
"type": "string",
"description": " Context information about the condition under which the error occurred. Multiple lines are supported by adding \r\n line terminators."
},
"timestamp": {
"type": "integer",
"description": "Unix-like time stamp"
}
}
}
Example:
{
"subject":"add-sample-error",
"statistic-id":2,
"error-subject":"Connection refused (Connection refused)",
"error-severity":"error",
"error-type":"java.net.ConnectException",
"error-log":"2020-08-01 21:24:51.662 | main-HTTPClientProcessing[3] | INFO | GET http://192.168.0.111/\r\n2020-08-01 21:24:51.670 | main-HTTPClientProcessing[3] | ERROR | Failed to open or reuse connection to 192.168.0.111:80 |
java.net.ConnectException: Connection refused (Connection refused)\r\n",
"error-context":"HTTP Request Header\r\nhttp://192.168.0.111/\r\nGET / HTTP/1.1\r\nHost: 192.168.0.111\r\nConnection: keep-alive\r\nAccept: */*\r\nAccept-Encoding: gzip, deflate\r\n",
"timestamp":1596309891672
}
Note about the error-severity :
Implementation note: After an error has occurred, the simulated user should wait at least 100 milliseconds before continuing his activities. This is to prevent that within a few seconds several thousand errors are measured and reported to the UI
For cumulative-counter-long statistics there is no such 2-step mechanism as for ‘sample-event-time-chart’ statistics. The value can simple increased by reporting a Add Counter Long object.
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "AddCounterLong",
"type": "object",
"required": ["subject", "statistic-id", "value"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'add-counter-long'"
},
"statistic-id": {
"type": "integer",
"description": "The unique statistic id"
},
"value": {
"type": "integer",
"description": "The value to increment"
}
}
}
Example:
{"subject":"add-counter-long","statistic-id":10,"value":2111}
To update a average-and-current-value statistic the delta (difference) values of the cumulated sum and the delta (difference) of the cumulated number of values has to be reported. The platform calculates then the average value by dividing the cumulated sum by the cumulated number of values. In addition, the last measured value must also be reported.
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "AddAverageDeltaAndCurrentValue",
"type": "object",
"required": ["subject", "statistic-id", "sumValuesDelta", "numValuesDelta", "currentValue", "currentValueTimestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'add-average-delta-and-current-value'"
},
"statistic-id": {
"type": "integer",
"description": "The unique statistic id"
},
"sumValuesDelta": {
"type": "integer",
"description": "The sum of delta values to add to the average"
},
"numValuesDelta": {
"type": "integer",
"description": "The number of delta values to add to the average"
},
"currentValue": {
"type": "integer",
"description": "The current value, or -1 if no such data is available"
},
"currentValueTimestamp": {
"type": "integer",
"description": "The Unix-like timestamp of the current value, or -1 if no such data is available"
}
}
}
Example:
{
"subject":"add-average-delta-and-current-value",
"statistic-id":100005,
"sumValuesDelta":6302,
"numValuesDelta":22,
"currentValue":272,
"currentValueTimestamp":1634401774374
}
To update a efficiency-ratio-percent statistic, the delta (difference) of the number of efficient performed procedures and the delta (difference) of the number of inefficient performed procedures has to be reported.
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "AddEfficiencyRatioDelta",
"type": "object",
"required": ["subject", "statistic-id", "efficiencyDeltaValue", "inefficiencyDeltaValue"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'add-efficiency-ratio-delta'"
},
"statistic-id": {
"type": "integer",
"description": "The unique statistic id"
},
"efficiencyDeltaValue": {
"type": "integer",
"description": "The number of efficient performed procedures to add"
},
"inefficiencyDeltaValue": {
"type": "integer",
"description": "The number of inefficient performed procedures to add"
}
}
}
Example:
{
"subject":"add-efficiency-ratio-delta",
"statistic-id":100006,
"efficiencyDeltaValue":6,
"inefficiencyDeltaValue":22
}
To update a throughput-time-chart statistic, the delta (difference) value from a last absolute, cumulated value to the current cumulated value has to be reported, whereby the current time stamp is included in the calculation.
Although this type of statistic always has the unit throughput per second, a measured delta (difference) value can be reported at any time.
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "AddThroughputDelta",
"type": "object",
"required": ["subject", "statistic-id", "delta-value", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'add-throughput-delta'"
},
"statistic-id": {
"type": "integer",
"description": "The unique statistic id"
},
"delta-value": {
"type": "number",
"description": "the delta (difference) value"
},
"timestamp": {
"type": "integer",
"description": "The Unix-like timestamp of the delta (difference) value"
}
}
}
Example:
{
"subject":"add-throughput-delta",
"statistic-id":100003,
"delta-value":0.53612,
"timestamp":1634401774410
}
Add an annotation event to the test result.
{
"$schema": "http://json-schema.org/draft/2019-09/schema",
"title": "AddTestResultAnnotationExecEvent",
"type": "object",
"required": ["subject", "event-id", "event-text", "timestamp"],
"properties": {
"subject": {
"type": "string",
"description": "Always 'add-test-result-annotation-exec-event'"
},
"event-id": {
"type": "integer",
"description": "The event id, valid range: -1 .. -999999"
},
"event-text": {
"type": "string",
"description": "the event text"
},
"timestamp": {
"type": "integer",
"description": "The Unix-like timestamp of the event"
}
}
}
Example:
{
"subject":"add-test-result-annotation-exec-event",
"event-id":-1,
"event-text":"Too many errors: Test job stopped by plug-in",
"timestamp":1634401774410
}
Notes:
This plug-in “measures” a random value, and is executed in this example as the only part of an HTTP Test Wizard session.
The All Purpose Interface JSON objects are written using the corresponding methods of the com.dkfqs.tools.javatest.AbstractJavaTest class. This class is located in the JAR file com.dkfqs.tools.jar which is already predefined for all plug-ins.
import com.dkfqs.tools.javatest.AbstractJavaTest;
import com.dkfqs.tools.javatest.AbstractJavaTestPluginContext;
import com.dkfqs.tools.javatest.AbstractJavaTestPluginInterface;
import com.dkfqs.tools.javatest.AbstractJavaTestPluginSessionFailedException;
import com.dkfqs.tools.javatest.AbstractJavaTestPluginTestFailedException;
import com.dkfqs.tools.javatest.AbstractJavaTestPluginUserFailedException;
import com.dkfqs.tools.logging.LogAdapterInterface;
import java.util.ArrayList;
import java.util.List;
// add your imports here
/**
* HTTP Test Wizard Plug-In 'All Purpose Interface Example'.
* Plug-in Type: Normal Session Element Plug-In.
* Created by 'DKF' at 24 Sep 2021 22:50:04
* DKFQS 4.3.22
*/
@AbstractJavaTestPluginInterface.PluginResourceFiles(fileNames={"com.dkfqs.tools.jar"})
public class AllPurposeInterfaceExample implements AbstractJavaTestPluginInterface {
private LogAdapterInterface log = null;
private static final int STATISTIC_ID = 1000;
private AbstractJavaTest javaTest = null; // refrence to the generated test program
/**
* Called by environment when the instance is created.
* @param log the log adapter
*/
@Override
public void setLog(LogAdapterInterface log) {
this.log = log;
}
/**
* On plug-in initialize. Called when the plug-in is initialized. <br>
* Depending on the initialization scope of the plug-in the following specific exceptions can be thrown:<ul>
* <li>Initialization scope <b>global:</b> AbstractJavaTestPluginTestFailedException</li>
* <li>Initialization scope <b>user:</b> AbstractJavaTestPluginTestFailedException, AbstractJavaTestPluginUserFailedException</li>
* <li>Initialization scope <b>session:</b> AbstractJavaTestPluginTestFailedException, AbstractJavaTestPluginUserFailedException, AbstractJavaTestPluginSessionFailedException</li>
* </ul>
* @param javaTest the reference to the executed test program, or null if no such information is available (in debugger environment)
* @param pluginContext the plug-in context
* @param inputValues the list of input values
* @return the list of output values
* @throws AbstractJavaTestPluginSessionFailedException if the plug-in signals that the 'user session' has to be aborted (abort current session - continue next session)
* @throws AbstractJavaTestPluginUserFailedException if the plug-in signals that the user has to be terminated
* @throws AbstractJavaTestPluginTestFailedException if the plug-in signals that the test has to be terminated
* @throws Exception if an error occurs in the implementation of this method
*/
@Override
public List<String> onInitialize(AbstractJavaTest javaTest, AbstractJavaTestPluginContext pluginContext, List<String> inputValues) throws AbstractJavaTestPluginSessionFailedException, AbstractJavaTestPluginUserFailedException, AbstractJavaTestPluginTestFailedException, Exception {
// log.message(log.LOG_INFO, "onInitialize(...)");
// --- vvv --- start of specific onInitialize code --- vvv ---
if (javaTest != null) {
this.javaTest = javaTest;
// declare the statistic
javaTest.declareStatistic(STATISTIC_ID,
AbstractJavaTest.STATISTIC_TYPE_SAMPLE_EVENT_TIME_CHART,
"My Measurement",
"",
"My Response Time",
"ms",
STATISTIC_ID,
true,
"");
}
// --- ^^^ --- end of specific onInitialize code --- ^^^ ---
return new ArrayList<String>(); // no output values
}
/**
* On plug-in execute. Called when the plug-in is executed. <br>
* Depending on the execution scope of the plug-in the following specific exceptions can be thrown:<ul>
* <li>Initialization scope <b>global:</b> AbstractJavaTestPluginTestFailedException</li>
* <li>Initialization scope <b>user:</b> AbstractJavaTestPluginTestFailedException, AbstractJavaTestPluginUserFailedException</li>
* <li>Initialization scope <b>session:</b> AbstractJavaTestPluginTestFailedException, AbstractJavaTestPluginUserFailedException, AbstractJavaTestPluginSessionFailedException</li>
* </ul>
* @param pluginContext the plug-in context
* @param inputValues the list of input values
* @return the list of output values
* @throws AbstractJavaTestPluginSessionFailedException if the plug-in signals that the 'user session' has to be aborted (abort current session - continue next session)
* @throws AbstractJavaTestPluginUserFailedException if the plug-in signals that the user has to be terminated
* @throws AbstractJavaTestPluginTestFailedException if the plug-in signals that the test has to be terminated
* @throws Exception if an error occurs in the implementation of this method
*/
@Override
public List<String> onExecute(AbstractJavaTestPluginContext pluginContext, List<String> inputValues) throws AbstractJavaTestPluginSessionFailedException, AbstractJavaTestPluginUserFailedException, AbstractJavaTestPluginTestFailedException, Exception {
// log.message(log.LOG_INFO, "onExecute(...)");
// --- vvv --- start of specific onExecute code --- vvv ---
if (javaTest != null) {
// register the start of the sample
javaTest.registerSampleStart(STATISTIC_ID);
// measure the sample
final long min = 1L;
final long max = 20L;
long responseTime = Math.round(((Math.random() * (max - min)) + min));
// add the measured sample to the statistic
javaTest.addSampleLong(STATISTIC_ID, responseTime);
/*
// error case
javaTest.addSampleError(STATISTIC_ID,
"My error subject",
AbstractJavaTest.ERROR_SEVERITY_WARNING,
"My error type",
"My error response text or log",
"");
*/
}
// --- ^^^ --- end of specific onExecute code --- ^^^ ---
return new ArrayList<String>(); // no output values
}
/**
* On plug-in deconstruct. Called when the plug-in is deconstructed.
* @param pluginContext the plug-in context
* @param inputValues the list of input values
* @return the list of output values
* @throws Exception if an error occurs in the implementation of this method
*/
@Override
public List<String> onDeconstruct(AbstractJavaTestPluginContext pluginContext, List<String> inputValues) throws Exception {
// log.message(log.LOG_INFO, "onDeconstruct(...)");
// --- vvv --- start of specific onDeconstruct code --- vvv ---
// no code here
// --- ^^^ --- end of specific onDeconstruct code --- ^^^ ---
return new ArrayList<String>(); // no output values
}
}
The portal server has three APIs:
All APIs require so-called “Authentication Tokens” to verify the access authorization. If 5 or more invalid “Authentication Tokens” are sent within 60 seconds, the corresponding remote IP address is blocked for 30 minutes.
To perform a Remote Admin API call, you must first generate an “Admin API Auth Token” in the Administrator Menu of the portal. When generating the token you can enter a purpose (only used as information) and also restrict the remote IP addresses for which the token is valid. You can also specify whether the token has read/write access or read/only access.
The API supports the following functions (so-called “actions”):
URL | HTTP Method |
---|---|
https://portal.realload.com/RemoteAdminAPI | POST |
All data are sent and received in JSON data format. The “authTokenValue” and the “action” must always be sent when an API call is made. |
curl -v --request POST --header "Content-Type: application/json" --data "@getAllUserAccounts.json" https://portal.realload.com/RemoteAdminAPI
{
"authTokenValue": "8mKSz1UzaQg17kfu",
"action": "getAllUserAccounts"
}
{"allUserAccountsArray":
[{"userId":13,"nickname":"DKF","firstName":"Max","lastName":"Fischer","primaryEmail":"max@dkfqa.com","primarySMSPhone":"+41771111111","secondaryEmail":"","secondarySMSPhone":"","accountBlocked":false,"accountCreateTime":1538556183756,"lastLoginTime":1625181623869,"lastLoginIP":"127.0.0.1","pricePlanId":1,"accountExpiresTime":-1,"pricePlanTitle":"Unlimited"},{"userId":18,"nickname":"AX","firstName":"Alex","lastName":"Fischer","primaryEmail":"alexfischer66@yahoo.com","primarySMSPhone":"+41781111111","secondaryEmail":"","secondarySMSPhone":"","accountBlocked":false,"accountCreateTime":1539874749677,"lastLoginTime":1616111301975,"lastLoginIP":"127.0.0.1","pricePlanId":1,"accountExpiresTime":-1,"pricePlanTitle":"Unlimited"},{"userId":22,"nickname":"Kes","firstName":"Kesorn","lastName":"Fischer","primaryEmail":"gsklsta@yahoo.com","primarySMSPhone":"+66000000000","secondaryEmail":"","secondarySMSPhone":"","accountBlocked":false,"accountCreateTime":1605303204754,"lastLoginTime":1624389324770,"lastLoginIP":"127.0.0.1","pricePlanId":6,"accountExpiresTime":-1,"pricePlanTitle":"BASIC1"},{"userId":48,"nickname":"BET","firstName":"Bettina","lastName":"Meier","primaryEmail":"b123456@lucini.id.au","primarySMSPhone":"+61404905702","secondaryEmail":"","secondarySMSPhone":"","accountBlocked":false,"accountCreateTime":1623719604561,"lastLoginTime":-1,"lastLoginIP":"","pricePlanId":6,"accountExpiresTime":1625061600000,"pricePlanTitle":"BASIC1"}],
"isError":false}
If the API call is successful, then the response field “isError” is false. If a numeric field has a value of -1 (minus one), this means “no data” or “unlimited” depending on the context.
Specific Request Fields:
Specific Error Flags:
Specific Request Fields:
Specific Error Flags:
Specific Request Fields:
The license is successfully assigned to a user if either mapToUserEmailAddress or mapToUserMobilePhone matches to a user account.
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"8mKSz1UzaQg17kfu",
"action":"addLicenseCertificateToUser",
"licenseProvider": "Real Load Pty Ltd / nopCommerce",
"mapToUserEmailAddress": "max@dkfqa.com",
"mapToUserMobilePhone": "+41771111111",
"licenseCertificate": "-----BEGIN CERTIFICATE-----\r\nMIIEnjCCA4agAwIBAgIEyDnukzANBgkqhkiG9w0BA ...... Hn/UMGAGRB6xF4w+TewYqTAZrdhi/WLyYwg==\r\n-----END CERTIFICATE-----"
}
JSON Response Example (Success Case):
{"licenseId":12,"cloudCreditLicenseId":-1,"userId":13,"isCloudCreditsLicense":false,"isError":false}
JSON Response Example (Error Case):
{"isError":true,"genericErrorText":"","writeAccessError":false,"licenseProviderError":false,"mapToUserError":false,"pricePlanError":false,"licenseCertificateAlreadyAddedError":false,"licenseCertificateError":true}
Specific Request Fields:
Specific Error Flags:
JSON Response Example:
{
"isServerMaintenanceMode":false,
"isSignInSelectPricePlanFromMultipleValidLicenseCertificates":true,
"isSignInExpiredAccountCanEnterLicenseCertificate":true,
"isSignUpEnabled":true,
"isSignUpRequiresInvitationTicket":false,
"signUpDefaultPricePlanId":2,
"signUpDefaultAccountExpiresInDays":14,
"deleteExpiredUserAccountsAfterDays":183,
"isError":false
}
Specific Request Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"8mKSz1UzaQg17kfu",
"action":"setServerMaintenanceMode",
"serverMaintenanceMode":true
}
JSON Response Example (Success Case):
{"isServerMaintenanceMode":true,"isError":false}
To perform a Remote User API call, you must first sign in into the portal and generate an “API Authentication Token”. When generating the token you can enter a purpose (only used as information) and also restrict the remote IP addresses for which the token is valid.
The API supports the following functions (so-called “actions”):
Common Functions:
Projects, Resource Sets and Files Functions:
Measuring Agents Functions:
Measuring Agent Cluster Functions:
HTTP/S Remote Proxy Recorders Functions:
Load Test Jobs Functions:
URL | HTTP Method |
---|---|
https://portal.realload.com/RemoteUserAPI | POST |
All data are sent and received in JSON data format. The “authTokenValue” and the “action” must always be sent when an API call is made. |
curl -v --request POST --header "Content-Type: application/json" --data {\"authTokenValue\":\"jPmFClqeDUXaEk8Q274q\",\"action\":\"getUserAccountInfo\"} https://portal.realload.com/RemoteUserAPI
{
"authTokenValue": "jPmFClqeDUXaEk8Q274q",
"action": "getUserAccountInfo"
}
{
"userAccountInfo":{
"userId":48,
"nickname":"BET",
"firstName":"Bettina",
"lastName":"MeierHans",
"primaryEmail":"bettina@meierhans.id.au",
"primarySMSPhone":"+61401111111",
"secondaryEmail":"",
"secondarySMSPhone":"",
"accountBlocked":false,
"accountCreateTime":1623719604561,
"lastLoginTime":1625348376450,
"lastLoginIP":"127.0.0.1",
"pricePlanId":6,
"accountExpiresTime":1625953109397,
"pricePlanTitle":"BASIC1"
},
"isError":false
}
If the API call is successful, then the response field “isError” is false. If a numeric field has a value of -1 (minus one), this means “no data” or “unlimited” depending on the context.
Specific Request Fields:
Specific Error Flags:
Specific Request Fields:
Specific Error Flags:
JSON Response Example:
{
"pricePlanInfo":{
"pricePlanId":6,
"title":"BASIC1",
"description":"",
"isDeprecated":false,
"lastModified":1625348413042,
"maxDiskSpaceMB":1024,
"maxSubUserAccounts":0,
"maxMeasuringAgentsOwnedByUser":3,
"maxRemoteProxyRecordersOwnedByUser":3,
"executeLoadJobsEnabled":true,
"executeMonitoringJobsEnabled":false,
"apiAccessEnabled":true,
"maxStartLoadJobsLast24h":24,
"maxUsersPerLoadJob":500,
"maxDurationPerLoadJob":1800
},
"isError":false
}
The unit for “maxDurationPerLoadJob” is seconds.
Specific Request Fields:
Specific Error Flags:
JSON Response Example:
{
"projectsArray": [
{
"projectId": 97,
"projectName": "Common",
"projectDescription": "",
"resourceSetsArray": [
{
"resourceSetId": 154,
"resourceSetName": "Input Files",
"resourceSetDescription": "",
"filesArray": [
{
"fileName": "InputFile.txt",
"fileSize": 233,
"fileHashCode": 1873256029,
"fileLastModified": 1613835992073
}
]
},
{
"resourceSetId": 155,
"resourceSetName": "Jar Files",
"resourceSetDescription": "",
"filesArray": [
{
"fileName": "com.dkfqs.tools.jar",
"fileSize": 578087,
"fileHashCode": -2033420926,
"fileLastModified": 1613838181727
}
]
},
{
"resourceSetId": 156,
"resourceSetName": "Plug-Ins",
"resourceSetDescription": "",
"filesArray": [
{
"fileName": "HttpSessionPlugin_ChangeCopyright.json",
"fileSize": 5321,
"fileHashCode": 1958407366,
"fileLastModified": 1613838287871
}
]
}
]
},
...
...
...
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"createProject",
"projectName":"My New Project",
"projectDescription": "Created by API call"
}
JSON Response Example (Success Case):
{"projectId":113,"isError":false}
JSON Response Example (Error Case):
{"isError":true,"genericErrorText":"","diskSpaceLimitExceededError":false,"projectNameError":true}
Specific Request Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteProject",
"projectId":113,
"moveToTrash":false
}
Specific Request Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getResourceSetsOfProject",
"projectId":97
}
JSON Response Example (Success Case):
{
"resourceSetsArray": [
{
"resourceSetId": 154,
"resourceSetName": "Input Files",
"resourceSetDescription": "",
"filesArray": [
{
"fileName": "InputFile.txt",
"fileSize": 233,
"fileHashCode": 1873256029,
"fileLastModified": 1613835992073
}
]
},
{
"resourceSetId": 155,
"resourceSetName": "Jar Files",
"resourceSetDescription": "",
"filesArray": [
{
"fileName": "com.dkfqs.tools.jar",
"fileSize": 578087,
"fileHashCode": -2033420926,
"fileLastModified": 1613838181727
}
]
},
{
"resourceSetId": 156,
"resourceSetName": "Plug-Ins",
"resourceSetDescription": "",
"filesArray": [
{
"fileName": "HttpSessionPlugin_ChangeCopyright.json",
"fileSize": 5321,
"fileHashCode": 1958407366,
"fileLastModified": 1613838287871
}
]
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"createResourceSet",
"projectId":97,
"resourceSetName":"My New Resource Set",
"resourceSetDescription": "Created by API call"
}
JSON Response Example (Success Case):
{"resourceSetId":172,"isError":false}
JSON Response Example (Error Case):
{"isError":true,"genericErrorText":"","resourceSetNameError":true,"projectIdError":false,"diskSpaceLimitExceededError":false}
Specific Request Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteResourceSet",
"projectId":97,
"resourceSetId":172,
"moveToTrash":false
}
Specific Request Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getFilesInfoOfResourceSet",
"projectId":23,
"resourceSetId":143
}
JSON Response Example:
{
"filesArray": [
{
"fileName": "DKFQSLibrary2.psm1",
"fileSize": 16339,
"fileHashCode": -1503445747,
"fileLastModified": 1603566144851
},
{
"fileName": "powershell-http-bern2.ps1",
"fileSize": 12900,
"fileHashCode": -1174212096,
"fileLastModified": 1603566162094
},
{
"fileName": "TestResult_powershell-http-bern2Neu_2020-10-24@21-06-04.json",
"fileSize": 14395,
"fileHashCode": -951574615,
"fileLastModified": 1603566379097
},
{
"fileName": "TestResult_powershell-http-bern2Neu_2020-10-24@21-09-45.json",
"fileSize": 55128,
"fileHashCode": 1499924815,
"fileLastModified": 1603566591322
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"createFile",
"projectId":23,
"resourceSetId":143,
"fileName":"test.txt",
"fileContentB64":"VGhpcyBpcyB0aGUgY29udGVudCBvZiB0aGUgZmlsZS4="
}
JSON Response Example (Success Case):
{
"fileName":"test.txt",
"fileSize":32,
"fileHashCode":-1460278014,
"fileLastModified":1625423562384,
"isError":false
}
JSON Response Example (Error Case):
{"isError":true,"genericErrorText":"","projectIdError":false,"resourceSetIdError":false,"diskSpaceLimitExceededError":false,"fileNameError":true}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getFile",
"projectId":23,
"resourceSetId":143,
"fileName":"test.txt"
}
JSON Response Example (Success Case):
{
"fileName":"test.txt",
"fileContentB64":"VGhpcyBpcyB0aGUgY29udGVudCBvZiB0aGUgZmlsZS4=",
"fileSize":32,
"fileHashCode":-1460278014,
"fileLastModified":1625423562384,
"isError":false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteFile",
"projectId":23,
"resourceSetId":143,
"fileName":"test.txt",
"moveToTrash":false
}
JSON Response Example (Success Case):
{"fileDeleted":true,"isError":false}
JSON Response Example (Error Case):
{"isError":true,"genericErrorText":"","projectIdError":false,"resourceSetIdError":false,"fileNameError":true}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getMeasuringAgents"
}
JSON Response Example (Success Case):
{
"measuringAgentsArray": [
{
"agentId": 46,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Local Agent",
"agentHost": "127.0.0.1",
"agentPort": 8080,
"authToken": "OrKmpkbyNWEHok"
},
{
"agentId": 49,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": false,
"agentDescription": "Rasberry 1",
"agentHost": "192.168.0.51",
"agentPort": 8080,
"authToken": ""
},
{
"agentId": 50,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Ubuntu 10",
"agentHost": "192.168.0.110",
"agentPort": 8080,
"authToken": ""
},
{
"agentId": 51,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Ubuntu 11",
"agentHost": "192.168.0.111",
"agentPort": 8080,
"authToken": ""
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getMinRequiredMeasuringAgentVersion"
}
JSON Response Example (Success Case):
{
"minRequiredMeasuringAgentVersion":"3.9.34",
"isError":false
}
Specific Request Fields:
Response Fields (JSON object “measuringAgent”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"addMeasuringAgent",
"agentDescription":"Ubuntu 12",
"agentHost":"192.168.0.112",
"agentPort":8080,
"agentActive": true,
"agentAuthToken": "nixda"
}
JSON Response Example (Success Case):
{
"measuringAgent": {
"agentId": 53,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Ubuntu 12",
"agentHost": "192.168.0.112",
"agentPort": 8080,
"authToken": "nixda"
},
"isError": false
}
Specific Request Fields:
Response Fields (JSON object “agentResponse”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"pingMeasuringAgent",
"agentId":48
}
JSON Response Example (Success Case):
{
"agentResponse": {
"pingFromRemoteIp": "83.150.39.44",
"pingFromRemoteUserId": 13,
"productVersion": "3.9.30",
"limitMaxUsersPerJob": 500,
"limitMaxJobDurationSeconds": 300,
"osName": "Linux",
"osVersion": "4.15.0-136-generic",
"javaVersion": "11.0.1",
"javaVendor": "Oracle Corporation",
"javaMaxMemory":"2048 MB",
"systemTime": 1625513238236,
"deltaTimeMillis": 841,
"agentStartupTimeStamp": 1622836702172,
"httpExecuteTimeMillis": 247
},
"isError": false
}
JSON Response Example (Error Case 1):
{
"isError": true,
"genericErrorText": "API V1 request to 192.168.0.51:8080 timed out",
"agentIdError": false,
"agentAccessDeniedError": false,
"agentNotReachableError": true,
"agentVersionOutdatedError": false
}
JSON Response Example (Error Case 2):
{
"isError": true,
"genericErrorText": "Min. measuring agent version required: 3.9.30",
"agentIdError": false,
"agentAccessDeniedError": false,
"agentNotReachableError": false,
"agentVersionOutdatedError": true
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"setMeasuringAgentActive",
"agentId":46,
"agentActive":false
}
JSON Response Example (Success Case):
{"isError":false}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteMeasuringAgent",
"agentId":54
}
JSON Response Example (Success Case):
{"isError":false}
Specific Request Fields:
Response Fields (JSON array “measuringAgentClustersArray”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getMeasuringAgentClusters"
}
JSON Response Example:
{
"measuringAgentClustersArray": [
{
"clusterId": 11,
"createdBySystem": false,
"ownerUserId": 13,
"clusterActive": true,
"clusterDescription": "C1",
"controllerHost": "192.168.0.50",
"controllerPort": 8083,
"controllerAuthToken": "aberaber",
"clusterMembersArray": [
{
"clusterMemberId": 59,
"loadFactor": 1,
"agentId": 64,
"agentActive": true,
"agentDescription": "Agent 1",
"agentHost": "192.168.0.10",
"agentPort": 8080,
"agentAuthToken": "OrKmAAbyNWEHok"
},
{
"clusterMemberId": 60,
"loadFactor": 1,
"agentId": 59,
"agentActive": true,
"agentDescription": "Ubuntu 10",
"agentHost": "192.168.0.110",
"agentPort": 8080,
"agentAuthToken": "asc7jhacab"
},
{
"clusterMemberId": 61,
"loadFactor": 1,
"agentId": 60,
"agentActive": true,
"agentDescription": "Ubuntu 11",
"agentHost": "192.168.0.111",
"agentPort": 8080,
"agentAuthToken": "66ascascsdac"
}
]
},
{
"clusterId": 14,
"createdBySystem": false,
"ownerUserId": 13,
"clusterActive": true,
"clusterDescription": "C2",
"controllerHost": "192.168.0.50",
"controllerPort": 8083,
"controllerAuthToken": "aberaber",
"clusterMembersArray": [
{
"clusterMemberId": 66,
"loadFactor": 1,
"agentId": 56,
"agentActive": true,
"agentDescription": "Test System",
"agentHost": "192.168.0.60",
"agentPort": 8080,
"agentAuthToken": "aberdoch"
},
{
"clusterMemberId": 67,
"loadFactor": 1,
"agentId": 59,
"agentActive": true,
"agentDescription": "Ubuntu 10",
"agentHost": "192.168.0.110",
"agentPort": 8080,
"agentAuthToken": "asc7jhacab"
}
]
}
],
"isError": false
}
Specific Request Fields:
Response Fields (JSON array “clusterControllersArray”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getClusterControllers"
}
JSON Response Example:
{
"clusterControllersArray": [
{
"controllerHost": "192.168.0.33",
"controllerPort": 8083,
"controllerAuthToken": "2fasdtfffe",
"measuringAgentClustersArray": [
{
"clusterId": 11,
"clusterDescription": "C1",
"clusterActive": 1
},
{
"clusterId": 13,
"clusterDescription": "C2",
"clusterActive": 1
},
{
"clusterId": 14,
"clusterDescription": "C3",
"clusterActive": 1
}
]
},
{
"controllerHost": "192.168.0.50",
"controllerPort": 8083,
"controllerAuthToken": "asfsdgh763",
"measuringAgentClustersArray": [
{
"clusterId": 15,
"clusterDescription": "C4",
"clusterActive": 1
},
{
"clusterId": 16,
"clusterDescription": "C7",
"clusterActive": 1
}
]
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getMinRequiredClusterControllerVersion"
}
JSON Response Example:
{
"minRequiredClusterControllerVersion":"4.0.4",
"isError":false
}
Specific Request Fields:
Response Fields (JSON object “controllerResponse”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"pingClusterController",
"controllerHost":"192.168.0.50",
"controllerPort":8083,
"controllerAuthToken":"hagsajjs99"
}
JSON Response Example (Success Case):
{
"controllerResponse": {
"pingFromRemoteIp": "192.168.0.100",
"pingFromRemoteUserId": 13,
"productVersion": "4.0.4",
"osName": "Linux",
"osVersion": "4.15.0-135-generic",
"javaVersion": "11.0.1",
"javaVendor": "Oracle Corporation",
"javaMaxMemory": "512 MB",
"systemTime": 1643406118552,
"deltaTimeMillis": 1120,
"controllerStartupTimeStamp": 1643322597013,
"httpExecuteTimeMillis": 249,
"clusterControllerOutdated": false
},
"isError": false
}
JSON Response Example (Error Case 1):
{
"isError": true,
"genericErrorText": "API call pingGetControllerInfo failed. Error code = 18, Error message = Invalid authentication token",
"controllerHostError": false,
"controllerVersionOutdatedError": false,
"controllerNotReachableError": true,
"controllerPortError": false
}
JSON Response Example (Error Case 2):
{
"isError": true,
"genericErrorText": "Min. cluster controller version required: 4.0.4",
"controllerHostError": false,
"controllerVersionOutdatedError": true,
"controllerNotReachableError": false,
"controllerPortError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"addMeasuringAgentCluster",
"clusterActive":true,
"clusterDescription":"C7",
"controllerHost":"192.168.0.50",
"controllerPort":8083,
"controllerAuthToken":"aberaber",
"clusterMembersArray":[
{
"agentId":59,
"loadFactor":1
},
{
"agentId":60,
"loadFactor":1
}
]
}
JSON Response Example (Success Case):
{
"clusterId":16,
"clusterMembersArray":[
{
"clusterMemberId":71,
"agentId":59,
"loadFactor":1
},
{
"clusterMemberId":72,
"agentId":60,
"loadFactor":1
}
],
"isError":false
}
JSON Response Example (Error Case):
{
"isError": true,
"genericErrorText": "Invalid agentId = 101",
"controllerHostError": false,
"agentIdError": true,
"controllerPortError": false,
"loadFactorError": false,
"clusterDescriptionError": false
}
Specific Request Fields:
Response Fields (JSON object “clusterMember”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"addMemberToMeasuringAgentCluster",
"clusterId":17,
"agentId":64,
"loadFactor":1
}
JSON Response Example:
{
"clusterMember": {
"clusterMemberId": 75,
"agentId": 64,
"loadFactor": 1
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"removeMemberFromMeasuringAgentCluster",
"clusterId":17,
"clusterMemberId":75
}
JSON Response Example:
{"isError":false}
Specific Request Fields:
Response Fields (JSON object “controllerResponse”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"pingMeasuringAgentClusterMembers",
"clusterId":16
}
JSON Response Example (Success Case):
{
"controllerResponse": {
"productVersion": "4.0.4",
"clusterConnectResult": {
"measuringAgentClusterMemberArray": [
{
"clusterMemberId": 71,
"loadFactor": 1,
"agentId": 59,
"agentActive": true,
"agentDescription": "Ubuntu 10",
"agentHost": "192.168.0.110",
"agentPort": 8080,
"agentAuthToken": "agsdhagsj"
},
{
"clusterMemberId": 72,
"loadFactor": 1,
"agentId": 60,
"agentActive": true,
"agentDescription": "Ubuntu 11",
"agentHost": "192.168.0.111",
"agentPort": 8080,
"agentAuthToken": "nvbjnvbnn"
}
],
"connectSuccessfulClusterMemberArray": [
71,
72
],
"connectFailedClusterMemberArray": [],
"clusterConnectStartTimestamp": 1643410829270,
"clusterConnectDurationMillis": 79
},
"clusterActionResult": {
"actionSuccessfulClusterMemberArray": [
71,
72
],
"actionFailedClusterMemberArray": [],
"jsonResponseClusterMemberArray": [
{
"clusterMemberId": 71,
"jsonResponseObject": {
"productVersion": "4.0.4",
"systemTime": 1643410829340,
"deltaTimeMillis": -10,
"osName": "Linux",
"osVersion": "5.4.0-92-generic",
"javaVersion": "11.0.1",
"javaVendor": "Oracle Corporation",
"javaMaxMemory": "2048 MB",
"samplingGranularityMillis": 4000,
"isError": false,
"measuringAgentOutdated": false
}
},
{
"clusterMemberId": 72,
"jsonResponseObject": {
"productVersion": "4.0.4",
"systemTime": 1643410829351,
"deltaTimeMillis": -10,
"osName": "Linux",
"osVersion": "5.4.0-92-generic",
"javaVersion": "11.0.1",
"javaVendor": "Oracle Corporation",
"javaMaxMemory": "2048 MB",
"samplingGranularityMillis": 4000,
"isError": false,
"measuringAgentOutdated": false
}
}
],
"clusterActionStartTimestamp": 1643410829349,
"clusterActionDurationMillis": 43
},
"httpExecuteTimeMillis": 1778,
"clusterControllerOutdated": false
},
"isError": false
}
JSON Response Example (Error Case / Partly failed):
{
"controllerResponse": {
"productVersion": "4.0.4",
"clusterConnectResult": {
"measuringAgentClusterMemberArray": [
{
"clusterMemberId": 71,
"loadFactor": 1,
"agentId": 59,
"agentActive": true,
"agentDescription": "Ubuntu 10",
"agentHost": "192.168.0.110",
"agentPort": 8080,
"agentAuthToken": "marderzahn"
},
{
"clusterMemberId": 72,
"loadFactor": 1,
"agentId": 60,
"agentActive": true,
"agentDescription": "Ubuntu 11",
"agentHost": "192.168.0.111",
"agentPort": 8080,
"agentAuthToken": "marderzahn"
}
],
"connectSuccessfulClusterMemberArray": [
72
],
"connectFailedClusterMemberArray": [
{
"clusterMemberId": 71,
"errorMessage": "Connection refused (Connection refused)"
}
],
"clusterConnectStartTimestamp": 1643414272214,
"clusterConnectDurationMillis": 97
},
"clusterActionResult": {
"actionSuccessfulClusterMemberArray": [
72
],
"actionFailedClusterMemberArray": [],
"jsonResponseClusterMemberArray": [
{
"clusterMemberId": 72,
"jsonResponseObject": {
"productVersion": "4.0.4",
"systemTime": 1643414272310,
"deltaTimeMillis": -8,
"osName": "Linux",
"osVersion": "5.4.0-92-generic",
"javaVersion": "11.0.1",
"javaVendor": "Oracle Corporation",
"javaMaxMemory": "2048 MB",
"samplingGranularityMillis": 4000,
"isError": false,
"measuringAgentOutdated": false
}
}
],
"clusterActionStartTimestamp": 1643414272311,
"clusterActionDurationMillis": 21
},
"httpExecuteTimeMillis": 1769,
"clusterControllerOutdated": false
}
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"setMeasuringAgentClusterActive",
"clusterId":16,
"clusterActive":true
}
JSON Response Example (Success Case):
{"isError":false}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteMeasuringAgentCluster",
"clusterId":16
}
JSON Response Example (Success Case):
{"isError":false}
Specific Request Fields:
Response Fields (JSON array “proxyRecordersArray”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getProxyRecorders"
}
JSON Response Example:
{
"proxyRecordersArray": [
{
"recorderId": 3,
"createdBySystem": false,
"ownerUserId": 13,
"recorderDescription": "Erster",
"recorderProxyHost": "192.168.0.40",
"recorderProxyPort": 8082,
"recorderProxyAuthUsername": "",
"recorderProxyAuthPassword": "",
"recorderControlPort": 8081,
"recorderControlAuthToken": ""
},
{
"recorderId": 4,
"createdBySystem": false,
"ownerUserId": 13,
"recorderDescription": "proxy.realload.com",
"recorderProxyHost": "proxy.realload.com",
"recorderProxyPort": 8082,
"recorderProxyAuthUsername": "max.meier",
"recorderProxyAuthPassword": "123456",
"recorderControlPort": 8081,
"recorderControlAuthToken": "aZujkl97zuwert"
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getMinRequiredProxyRecorderVersion"
}
JSON Response Example (Success Case):
{
"minRequiredProxyRecorderVersion":"0.2.2",
"isError":false
}
Specific Request Fields:
Response Fields (JSON object “proxyRecorder”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"addProxyRecorder",
"recorderDescription":"My New Proxy Recorder",
"recorderProxyHost":"192.168.0.148",
"recorderProxyPort":8082,
"recorderProxyAuthUsername":"max.meier",
"recorderProxyAuthPassword":"123456",
"recorderControlPort":8081,
"recorderControlAuthToken":"aZujkl97zuwert"
}
JSON Response Example (Success Case):
{
"proxyRecorder": {
"recorderId": 10,
"createdBySystem": false,
"ownerUserId": 13,
"recorderDescription": "My New Proxy Recorder",
"recorderProxyHost": "192.168.0.148",
"recorderProxyPort": 8082,
"recorderProxyAuthUsername": "max.meier",
"recorderProxyAuthPassword": "123456",
"recorderControlPort": 8081,
"recorderControlAuthToken": "aZujkl97zuwert"
},
"isError": false
}
Specific Request Fields:
Response Fields (JSON object “pongResponse”):
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"pingProxyRecorder",
"recorderId":4
}
JSON Response Example (Success Case):
{
"pongResponse": {
"pingFromRemoteIp": "83.150.39.44",
"pingFromRemoteUserId": 13,
"productVersion": "0.2.0",
"recorderComponentVersion": "1.1.0",
"isRecording": false,
"recordHostFilter": "www.dkfqa.com",
"numRecordedElements": 0,
"osName": "Linux",
"osVersion": "5.4.0-74-generic",
"javaMemoryMB": 2048,
"javaVersion": "11.0.1",
"javaVendor": "Oracle Corporation",
"systemTime": 1625529858405,
"deltaTimeMillis": 790,
"httpExecuteTimeMillis": 88
},
"isError": false
}
JSON Response Example (Error Case):
{
"isError": true,
"genericErrorText": "connect timed out",
"recorderNotReachableError": true,
"recorderIdError": false,
"recorderAccessDeniedError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteProxyRecorder",
"recorderId":10
}
JSON Response Example (Success Case):
{"isError":false}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getProxyRecordersClientCertificates"
}
JSON Response Example (Success Case):
{
"clientCertificatesArray": [
{
"certificateId": 1,
"ownerUserId": 13,
"recorderId": -1,
"originalCertFileName": "fischer@dkfqa.com.p12",
"certFileType": "PKCS#12",
"certFileDataB64": "MIIRQQ.....CAA=",
"certPassword": "12345678",
"certDescription": "Fischer's Cert",
"certActive": true,
"applyForHost": "192.168.0.100",
"applyForPort": 499
},
{
"certificateId": 3,
"ownerUserId": 13,
"recorderId": -1,
"originalCertFileName": "miller@dkfqa.com.p12",
"certFileType": "PKCS#12",
"certFileDataB64": "MIIRXB.....CCAA=",
"certPassword": "abcdefgh",
"certDescription": "",
"certActive": false,
"applyForHost": "www.werwaswo.com",
"applyForPort": 443
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"addProxyRecordersClientCertificate",
"recorderId": -1,
"certFileName": "felix@dkfqa.com.p12",
"certFileType": "PKCS#12",
"certFileDataB64": "MIIRQQIBAzCCEQ.....3dUWQICCAA=",
"certPassword": "mammamia",
"certDescription":"",
"certActive": true,
"applyForHost": "www.dkfqa.com",
"applyForPort": 443
}
JSON Response Example (Success Case):
{
"addedClientCertificate": {
"certificateId": 5,
"ownerUserId": 13,
"recorderId": -1,
"originalCertFileName": "felix@dkfqa.com.p12",
"certFileType": "PKCS#12",
"certDescription": "",
"certActive": true,
"applyForHost": "www.dkfqa.com",
"applyForPort": 443
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"setProxyRecordersClientCertificateActive",
"certificateId": 5,
"certActive": false
}
JSON Response Example (Success Case):
{
"updatedClientCertificate": {
"certificateId": 5,
"ownerUserId": 13,
"recorderId": -1,
"originalCertFileName": "felix@dkfqa.com.p12",
"certFileType": "PKCS#12",
"certDescription": "",
"certActive": false,
"applyForHost": "www.dkfqa.com",
"applyForPort": 443
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"modifyProxyRecordersClientCertificate",
"certificateId": 5,
"certDescription": "My Cert",
"applyForHost": "www.dkfqa.com",
"applyForPort": 444
}
JSON Response Example (Success Case):
{
"updatedClientCertificate": {
"certificateId": 5,
"ownerUserId": 13,
"recorderId": -1,
"originalCertFileName": "felix@dkfqa.com.p12",
"certFileType": "PKCS#12",
"certDescription": "My Cert",
"certActive": false,
"applyForHost": "www.dkfqa.com",
"applyForPort": 444
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteProxyRecordersClientCertificate",
"certificateId": 5
}
JSON Response Example (Success Case):
{"isError": false}
JSON Response Example (Error Case):
{"isError": true, "genericErrorText": "Invalid certificate Id"}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getTestjobTemplates"
}
JSON Response Example (Success Case):
{
"testjobTemplatesArray": [
{
"testjobTemplate": {
"templateId": 10,
"templateName": "SimpleTest 1VU",
"templateDescription": "",
"testjobProperties": {
"testjobResultFileName": "",
"executeMeasuringAgentClusterInfo": "",
"testjobConcurrentUsers": "1",
"testjobDescription": "SimpleTest",
"testjobDebugMeasuring": "false",
"testjobMaxTestDuration": "30",
"isClusterJob": "",
"testjobRampUpTime": "10",
"localTestjobId": "",
"testjobMaxLoopsPerUser": "1",
"productVersion": "4.8.23",
"remoteTestjobId": "",
"testjobAdditionalArguments": "",
"definedFromTestId": "384",
"testjobSignature": "",
"testjobDelayPerLoop": "1000",
"testjobExitCode": "",
"createTimeStamp": "1694549684261",
"userInputFieldsFileName": "",
"testjobType": "load test",
"enableAutomaticFileSync": "true",
"testjobState": "invalid",
"isClusterControllerJobProperties": "",
"testjobDebugExecution": "false",
"executeOnUserMeasuringAgentId": "",
"definedFromTimeZoneId": "Europe/Berlin",
"executeMeasuringAgentInfo": "",
"executeOnMeasuringAgentClusterId": ""
},
"hasUserInputFields": false
},
"testIsHealthy": true
},
{
"testjobTemplate": {
"templateId": 11,
"templateName": "SimpleTestWithInputFields 10VU",
"templateDescription": "",
"testjobProperties": {
"testjobResultFileName": "",
"executeMeasuringAgentClusterInfo": "",
"testjobConcurrentUsers": "10",
"testjobDescription": "SimpleTestWithInputFields",
"testjobDebugMeasuring": "false",
"testjobMaxTestDuration": "60",
"isClusterJob": "",
"testjobRampUpTime": "10",
"localTestjobId": "",
"testjobMaxLoopsPerUser": "5",
"productVersion": "4.8.23",
"remoteTestjobId": "",
"testjobAdditionalArguments": "",
"definedFromTestId": "385",
"testjobSignature": "",
"testjobDelayPerLoop": "1000",
"testjobExitCode": "",
"createTimeStamp": "1695047319785",
"userInputFieldsFileName": "InputFields_SimpleTestWithInputFields.json",
"testjobType": "load test",
"enableAutomaticFileSync": "true",
"testjobState": "invalid",
"isClusterControllerJobProperties": "",
"testjobDebugExecution": "true",
"executeOnUserMeasuringAgentId": "",
"definedFromTimeZoneId": "Europe/Berlin",
"executeMeasuringAgentInfo": "",
"executeOnMeasuringAgentClusterId": ""
},
"hasUserInputFields": true,
"userInputFieldsFile": {
"useShortNames": false,
"magicPattern": "UserInputFields",
"productVersion": "4.8.23",
"userInputFieldsArray": [
{
"useShortNames": false,
"productVersion": "4.8.23",
"label": "Input Host",
"variableName": "vHost",
"inputType": "string",
"defaultValue": "126.3.4.5",
"currentValue": "126.3.4.5"
},
{
"useShortNames": false,
"productVersion": "4.8.23",
"label": "Input Port",
"variableName": "vPort",
"inputType": "integer",
"defaultValue": "444",
"currentValue": "444"
}
]
}
},
"testIsHealthy": true
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"defineNewTestjobFromTemplate",
"templateId":10,
"measuringAgentOrClusterId":65,
"isCluster":false,
"jobDescription": "Simple Test"
}
JSON Response Example (Success Case):
{
"newTestjobId":33533,
"isError":false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"submitTestjob",
"localTestjobId":33534
}
JSON Response Example (Success Case):
{
"isClusterJob": false,
"agentResponse": {
"remoteTestjobId": 24129,
"httpExecuteTimeMillis": 338
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"makeTestjobReadyToRun",
"localTestjobId":33534
}
JSON Response Example (Success Case):
{
"isClusterJob": false,
"agentResponse": {
"testjobProperties": {
"testjobResultFileName": "",
"executeMeasuringAgentClusterInfo": "",
"testjobConcurrentUsers": "1",
"testjobDescription": "Simple Test",
"testjobDebugMeasuring": "false",
"testjobMaxTestDuration": "30",
"isClusterJob": "false",
"testjobRampUpTime": "10",
"localTestjobId": "33534",
"testjobMaxLoopsPerUser": "1",
"productVersion": "4.8.18",
"remoteTestjobId": "24129",
"testjobAdditionalArguments": "",
"definedFromTestId": "384",
"testjobSignature": "Z9B963yIj232nht1DIX5aSRt8m77QuXpvVA5736Tl9Wc7UZ7jOiU3l6UC7y3Nx6CXDDZB4qUg4FHDtTuHsD9xd0T/CSq/g==",
"testjobDelayPerLoop": "1000",
"testjobExitCode": "",
"createTimeStamp": "1695050460395",
"userInputFieldsFileName": "",
"testjobType": "load test",
"enableAutomaticFileSync": "true",
"testjobState": "ready to run",
"isClusterControllerJobProperties": "",
"testjobDebugExecution": "false",
"executeOnUserMeasuringAgentId": "65",
"definedFromTimeZoneId": "Europe/Berlin",
"executeMeasuringAgentInfo": "agent2.realload.com:8080",
"executeOnMeasuringAgentClusterId": ""
},
"httpExecuteTimeMillis": 2871
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"startTestjob",
"localTestjobId":33534
}
JSON Response Example (Success Case):
{
"isClusterJob": false,
"agentResponse": {
"testjobProperties": {
"testjobResultFileName": "",
"executeMeasuringAgentClusterInfo": "",
"testjobConcurrentUsers": "1",
"testjobDescription": "Simple Test",
"testjobDebugMeasuring": "false",
"testjobMaxTestDuration": "30",
"isClusterJob": "false",
"testjobRampUpTime": "10",
"localTestjobId": "33534",
"testjobMaxLoopsPerUser": "1",
"productVersion": "4.8.18",
"remoteTestjobId": "24129",
"testjobAdditionalArguments": "",
"definedFromTestId": "384",
"testjobSignature": "Z9B963yIj232nht1DIX5aSRt8m77QuXpvVA5736Tl9Wc7UZ7jOiU3l6UC7y3Nx6CXDDZB4qUg4FHDtTuHsD9xd0T/CSq/g==",
"testjobDelayPerLoop": "1000",
"testjobExitCode": "",
"createTimeStamp": "1695050460395",
"userInputFieldsFileName": "",
"testjobType": "load test",
"enableAutomaticFileSync": "true",
"testjobState": "running",
"isClusterControllerJobProperties": "",
"testjobDebugExecution": "false",
"executeOnUserMeasuringAgentId": "65",
"definedFromTimeZoneId": "Europe/Berlin",
"executeMeasuringAgentInfo": "agent2.realload.com:8080",
"executeOnMeasuringAgentClusterId": ""
},
"httpExecuteTimeMillis": 249
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getMeasuringAgentTestjobs",
"measuringAgentId":65,
"synchronizeLocalTestjobsState":true
}
JSON Response Example (Success Case):
{
"agentResponse": {
"allTestjobsArray": [
{
"testjobProperties": {
"testjobResultFileName": "TestResult_RealloadTest_2023-09-09@23-45-34.json",
"executeMeasuringAgentClusterInfo": "",
"testjobConcurrentUsers": "1",
"testjobDescription": "RealloadTest",
"testjobDebugMeasuring": "false",
"testjobMaxTestDuration": "60",
"isClusterJob": "false",
"testjobRampUpTime": "10",
"localTestjobId": "30717",
"testjobMaxLoopsPerUser": "1",
"productVersion": "4.8.18",
"remoteTestjobId": "15240",
"testjobAdditionalArguments": "",
"definedFromTestId": "379",
"testjobSignature": "NeYJG4vf8/joAwz4nR4Fie3W0Qr7ijps25ONuk6F5BLghuD8/clPL9mBKc/ogQiic7wI8OXOf53Mi4YDCpg4dQzuaWQ==",
"testjobDelayPerLoop": "1000",
"testjobExitCode": "0",
"createTimeStamp": "1694295923799",
"userInputFieldsFileName": "",
"testjobType": "load test",
"enableAutomaticFileSync": "true",
"testjobState": "completed",
"isClusterControllerJobProperties": "",
"testjobDebugExecution": "true",
"executeOnUserMeasuringAgentId": "65",
"definedFromTimeZoneId": "Europe/Berlin",
"executeMeasuringAgentInfo": "agent2.realload.com:8080",
"executeOnMeasuringAgentClusterId": ""
},
"testProperties": {
"referencedResourceFilesList": [
{
"projectId": 130,
"testplanId": 203,
"fileName": "com.dkfqs.selenium.jar"
},
{
"projectId": 130,
"testplanId": 203,
"fileName": "commons-io-2.13.0.jar"
},
{
"projectId": 130,
"testplanId": 203,
"fileName": "hamcrest-core-1.3.jar"
},
{
"projectId": 130,
"testplanId": 203,
"fileName": "com.dkfqs.tools.jar"
},
{
"projectId": 130,
"testplanId": 203,
"fileName": "junit-4.13.2.jar"
},
{
"projectId": 130,
"testplanId": 203,
"fileName": "selenium_bundle-4.12.1.jar"
}
],
"jsonConfigObject": {
"productVersion": "4.8.20",
"jUnitConfigExecutionClassArray": [
{
"productVersion": "4.8.20",
"executingClassName": "RealloadTest",
"testMethodNamesArray": [
"realload"
]
}
],
"seleniumWebBrowserType": "Firefox"
},
"executingScript": "RealloadTest.jar",
"executingScriptResourceFileList": "",
"createTimeStamp": "1694293491984",
"testDescription": "",
"definedFromTestplanId": "251",
"productVersion": "4.8.20",
"definedFromProjectId": "137",
"visibleTestName": "RealloadTest",
"scriptType": "Selenium4byJUnit4",
"testId": "379"
}
},
{
"testjobProperties": {
"testjobResultFileName": "TestResult_SimpleTest_2023-09-18@17-01-08.json",
"executeMeasuringAgentClusterInfo": "",
"testjobConcurrentUsers": "1",
"testjobDescription": "Simple Test",
"testjobDebugMeasuring": "false",
"testjobMaxTestDuration": "30",
"isClusterJob": "false",
"testjobRampUpTime": "10",
"localTestjobId": "33533",
"testjobMaxLoopsPerUser": "1",
"productVersion": "4.8.18",
"remoteTestjobId": "24112",
"testjobAdditionalArguments": "",
"definedFromTestId": "384",
"testjobSignature": "JYstx+myVNqbyVMr24u4Pi8IXkLGH0iXUquRh5+NL0veKs4DRJX/w2ZT77wLXF70J9YmTPzR7g==",
"testjobDelayPerLoop": "1000",
"testjobExitCode": "0",
"createTimeStamp": "1695049264730",
"userInputFieldsFileName": "",
"testjobType": "load test",
"enableAutomaticFileSync": "true",
"testjobState": "completed",
"isClusterControllerJobProperties": "",
"testjobDebugExecution": "false",
"executeOnUserMeasuringAgentId": "65",
"definedFromTimeZoneId": "Europe/Berlin",
"executeMeasuringAgentInfo": "agent2.realload.com:8080",
"executeOnMeasuringAgentClusterId": ""
},
"testProperties": {
"referencedResourceFilesList": [
{
"projectId": 130,
"testplanId": 203,
"fileName": "com.dkfqs.tools.jar"
}
],
"jsonConfigObject": {},
"executingScript": "SimpleTest.jar",
"executingScriptResourceFileList": "",
"createTimeStamp": "1694549112155",
"testDescription": "",
"definedFromTestplanId": "251",
"productVersion": "4.8.21",
"definedFromProjectId": "137",
"visibleTestName": "SimpleTest",
"scriptType": "OpenJDK11Jar",
"testId": "384"
}
},
{
"testjobProperties": {
"testjobResultFileName": "TestResult_SimpleTest_2023-09-18@17-51-53.json",
"executeMeasuringAgentClusterInfo": "",
"testjobConcurrentUsers": "1",
"testjobDescription": "Simple Test",
"testjobDebugMeasuring": "false",
"testjobMaxTestDuration": "30",
"isClusterJob": "false",
"testjobRampUpTime": "10",
"localTestjobId": "33534",
"testjobMaxLoopsPerUser": "1",
"productVersion": "4.8.18",
"remoteTestjobId": "24129",
"testjobAdditionalArguments": "",
"definedFromTestId": "384",
"testjobSignature": "Z9B963yIj232nht1DIX5aSRt8m77QuXYjP9rn4OBSq/g==",
"testjobDelayPerLoop": "1000",
"testjobExitCode": "0",
"createTimeStamp": "1695050460395",
"userInputFieldsFileName": "",
"testjobType": "load test",
"enableAutomaticFileSync": "true",
"testjobState": "completed",
"isClusterControllerJobProperties": "",
"testjobDebugExecution": "false",
"executeOnUserMeasuringAgentId": "65",
"definedFromTimeZoneId": "Europe/Berlin",
"executeMeasuringAgentInfo": "agent2.realload.com:8080",
"executeOnMeasuringAgentClusterId": ""
},
"testProperties": {
"referencedResourceFilesList": [
{
"projectId": 130,
"testplanId": 203,
"fileName": "com.dkfqs.tools.jar"
}
],
"jsonConfigObject": {},
"executingScript": "SimpleTest.jar",
"executingScriptResourceFileList": "",
"createTimeStamp": "1694549112155",
"testDescription": "",
"definedFromTestplanId": "251",
"productVersion": "4.8.21",
"definedFromProjectId": "137",
"visibleTestName": "SimpleTest",
"scriptType": "OpenJDK11Jar",
"testId": "384"
}
}
],
"httpExecuteTimeMillis": 141
},
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getTestjobOutDirectoryFilesInfo",
"localTestjobId":33534
}
JSON Response Example (Success Case):
{
"isClusterJob": false,
"measuringAgentData": {
"agentId": 65,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Demo Agent 2",
"agentHost": "agent2.realload.com",
"agentPort": 8080,
"authToken": "************",
"sharedMeasuringAgentTemplateId": -1,
"isLaunchedByCloudCredits": false
},
"filesInfoArray": [
{
"fileName": "DataCollector.err",
"fileSize": 0,
"lastModified": 1695051456261,
"mimeType": "application/octet-stream"
},
{
"fileName": "DataCollector.out",
"fileSize": 5647,
"lastModified": 1695052318516,
"mimeType": "application/octet-stream"
},
{
"fileName": "DataCollector.pid",
"fileSize": 8,
"lastModified": 1695051456273,
"mimeType": "application/octet-stream"
},
{
"fileName": "DataCollector.port",
"fileSize": 6,
"lastModified": 1695051457729,
"mimeType": "application/octet-stream"
},
{
"fileName": "DataCollector.state",
"fileSize": 2,
"lastModified": 1695052318512,
"mimeType": "application/octet-stream"
},
{
"fileName": "TestResult_SimpleTest_2023-09-18@17-51-53.json",
"fileSize": 7421,
"lastModified": 1695052315488,
"mimeType": "application/json"
},
{
"fileName": "user_1_statistics.out",
"fileSize": 5037,
"lastModified": 1695052313788,
"mimeType": "application/octet-stream"
},
{
"fileName": "users.out",
"fileSize": 1923,
"lastModified": 1695052314000,
"mimeType": "application/octet-stream"
}
],
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"getTestjobOutDirectoryFile",
"localTestjobId":33534,
"fileName":"users.out"
}
JSON Response Example (Success Case):
{
"isClusterJob": false,
"measuringAgentData": {
"agentId": 65,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Demo Agent 2",
"agentHost": "agent2.realload.com",
"agentPort": 8080,
"authToken": "************",
"sharedMeasuringAgentTemplateId": -1,
"isLaunchedByCloudCredits": false
},
"fileContentB64": "MjAyMy0wOS0xOCAxNTo1MTo1Mi42MjYgfCBtYWluIHwgSU5GTyB8IE1heC4gSmF2YSBNZW1vcnkgPSAzMzAwIE1CCjIwMjMtMDktMTggMTU6NTE6NTIuNjU1IHwgbWFpbiB8IElORk8gfCBUaW1lIFpvbmUgPSBDb29yZGluYXRlZCBVbml2ZXJzYWwgVGltZSArMDA6MDAKMjAyMy0wOS0xOCAxNTo1MTo1Mi42NjggfCBtYWluIHwgSU5GTyB8IC0tLSB2dnYgLS0tIHJlc291cmNlIGZpbGVzIC0tLSB2dnYgLS0tCjIwMjMtMDktMTggMTU6NTE6NTIuNjY5IHwgbWFpbiB8IElORk8gfCAtLS0gXl5eIC0tLSByZXNvdXJjZSBmaWxlcyAtLS0gXl5eIC0tLQoyMDIzLTA5LTE4IDE1OjUxOjUyLjY2OSB8IG1haW4gfCBJTkZPIHwgLS0tIHZ2diAtLS0gZ2VuZXJpYyBhcmd1bWVudHMgLS0tIHZ2diAtLS0KMjAyMy0wOS0xOCAxNTo1MTo1Mi42NjkgfCBtYWluIHwgSU5GTyB8IHVzZXJzID0gMQoyMDIzLTA5LTE4IDE1OjUxOjUyLjY2OSB8IG1haW4gfCBJTkZPIHwgZHVyYXRpb24gPSAzMAoyMDIzLTA5LTE4IDE1OjUxOjUyLjY3MCB8IG1haW4gfCBJTkZPIHwgbWF4TG9vcHMgPSAxCjIwMjMtMDktMTggMTU6NTE6NTIuNjcwIHwgbWFpbiB8IElORk8gfCBkZWxheVBlckxvb3AgPSAxMDAwCjIwMjMtMDktMTggMTU6NTE6NTIuNjcwIHwgbWFpbiB8IElORk8gfCByYW1wdXBUaW1lID0gMTAKMjAyMy0wOS0xOCAxNTo1MTo1Mi42NzAgfCBtYWluIHwgSU5GTyB8IGRhdGFPdXRwdXREaXIgPSAvaG9tZS9ka2Zxcy9hZ2VudC91c2Vyc0RhdGEvVXNlcl8xMy9UZXN0Sm9icy9UZXN0am9iXzI0MTI5L291dAoyMDIzLTA5LTE4IDE1OjUxOjUyLjY3MCB8IG1haW4gfCBJTkZPIHwgZGVidWdFeGVjID0gZmFsc2UKMjAyMy0wOS0xOCAxNTo1MTo1Mi42NzEgfCBtYWluIHwgSU5GTyB8IGRlYnVnRGF0YSA9IGZhbHNlCjIwMjMtMDktMTggMTU6NTE6NTIuNjcxIHwgbWFpbiB8IElORk8gfCBkZXNjcmlwdGlvbiA9IFNpbXBsZSBUZXN0CjIwMjMtMDktMTggMTU6NTE6NTIuNjcxIHwgbWFpbiB8IElORk8gfCAtLS0gXl5eIC0tLSBnZW5lcmljIGFyZ3VtZW50cyAtLS0gXl5eIC0tLQoyMDIzLTA5LTE4IDE1OjUxOjUyLjkyMSB8IG1haW4gfCBJTkZPIHwgSlZNIFdhcm11cCBwZXJmb3JtZWQgaW4gMjM2IG1zCjIwMjMtMDktMTggMTU6NTE6NTIuOTc3IHwgbWFpbiB8IElORk8gfCAtLS0gdnZ2IC0tLSBzcGVjaWZpYyBhcmd1bWVudHMgLS0tIHZ2diAtLS0KMjAyMy0wOS0xOCAxNTo1MTo1Mi45OTQgfCBtYWluIHwgSU5GTyB8IHRjcFRpbWVvdXQgPSAxMDAwMAoyMDIzLTA5LTE4IDE1OjUxOjUyLjk5NSB8IG1haW4gfCBJTkZPIHwgc3NsVGltZW91dCA9IDUwMDAKMjAyMy0wOS0xOCAxNTo1MTo1Mi45OTcgfCBtYWluIHwgSU5GTyB8IGh0dHBUaW1lb3V0ID0gMzAwMDAKMjAyMy0wOS0xOCAxNTo1MTo1Mi45OTcgfCBtYWluIHwgSU5GTyB8IC0tLSBeXl4gLS0tIHNwZWNpZmljIGFyZ3VtZW50cyAtLS0gXl5eIC0tLQoyMDIzLTA5LTE4IDE1OjUxOjUzLjAwMiB8IG1haW4gfCBJTkZPIHwgW1N0YXJ0IG9mIFRlc3RdCjIwMjMtMDktMTggMTU6NTE6NTMuMDAzIHwgVXNlci0xIHwgSU5GTyB8IFVzZXIgc3RhcnRlZAoyMDIzLTA5LTE4IDE1OjUxOjUzLjAyNiB8IHBlcmlvZGljLXRocmVhZCB8IElORk8gfCBUaHJlYWQgc3RhcnRlZAoyMDIzLTA5LTE4IDE1OjUxOjUzLjAyNiB8IFVzZXItMSB8IElORk8gfCBTdGFydCBleGVjdXRlIHNlc3Npb24gbm8uIDEgLi4uCjIwMjMtMDktMTggMTU6NTE6NTMuNTk3IHwgVXNlci0xIHwgSU5GTyB8IC4uLiBFbmQgZXhlY3V0ZSBzZXNzaW9uIG5vLiAxIHN1Y2Nlc3NmdWwgcGFzc2VkCjIwMjMtMDktMTggMTU6NTE6NTMuNjQ5IHwgVXNlci0xIHwgSU5GTyB8IFVzZXIgbm9ybWFsIHRlcm1pbmF0ZWQKMjAyMy0wOS0xOCAxNTo1MTo1NC4wMDMgfCBtYWluIHwgSU5GTyB8IFtFbmQgb2YgVGVzdF0K",
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"saveTestjobOutDirectoryFileToProjectTree",
"localTestjobId":33534,
"fileName":"users.out",
"saveAsFileName":"users.out",
"projectId":137,
"resourceSetId":251
}
JSON Response Example (Success Case):
{
"isClusterJob": false,
"fileHashCode": 4557110,
"isError": false
}
Specific Request Fields:
Response Fields:
Specific Error Flags:
JSON Request Example:
{
"authTokenValue":"jPmFClqeDUXaEk8Q274q",
"action":"deleteTestjob",
"localTestjobId":33534,
"deleteAlsoRemoteTestjob":true
}
JSON Response Example (Success Case):
{
"isClusterJob": false,
"localTestjobState": "completed",
"agentResponse": {
"httpExecuteTimeMillis": 143
},
"isError": false
}
The “Remote User Monitoring API” is a WebSocket API that supports developers to implement their own version of a Synthetic Monitoring “Real Time Dashboard”.
Similar to the Remote User API there is also an “API Authentication Token” required to access the API.
The API supports the following functions (so-called “actions”):
WebSocket URL |
---|
wss://portal.realload.com/RemoteUserMonitoringAPI |
HTTP Request Header Fields | |
---|---|
x-api-key: <API Authentication Token> | required |
subscribeToHeartbeat: true | optional |
subscribeToRealtimeMonitor: true | optional |
The subscribed data are received in JSON format. The received JSON values are never null.
{
"action":"heartbeat",
"timestamp":1677521478771,
"isError":false
}
As first you will receive instantly the data of all already defined Monitoring Groups and Monitoring Jobs, and also the data of the last Execution Result of the Monitoring Groups and Monitoring Jobs (if they have been executed in the past).
After that you will receive update information of all Monitoring Groups and Monitoring Jobs when they are new-defined/modified/deleted, and you will receive also update information about the result of executed Monitoring Groups and Monitoring Jobs.
{
"action":"onMonitoringGroupEvent",
"monitoringGroupId":17,
"monitoringEvent":
{
"eventTimestamp":1677522195873,
"monitoringGroup":
{
"monitoringGroupId":17,
"ownerUserId":13,
"title":"Group 1",
"description":"My First Group",
"maxDataStorageDays":14,
"agentType":"agent",
"executionEnabled":false,
"executionInterval":180,
"executionTimeout":300,
"currentExecutionState":"dormant",
"lastExecutionStartTime":1677506934041
},
"monitoringGroupAction":"groupExists"
},
"isError":false
}
The executionInterval and the executionTimeout are in seconds. The lastExecutionStartTime has a value of -1 (minus one) if the Monitoring Group was never executed. The agentType has currently no meaning.
Any modification of a Monitoring Group made by the Portal Server Web Interface such as modify executionEnabled or title effects that a “groupModified” action is released.
{
"action":"onMonitoringJobEvent",
"monitoringGroupId":17,
"monitoringJobId":39,
"monitoringEvent":
{
"eventTimestamp":1677522195875,
"monitoringJobProperties":
{
"enableJobExecution":"true",
"testjobConcurrentUsers":"1",
"testjobDelayPerLoop":"1000",
"testjobDebugMeasuring":"false",
"enableAutomaticFileSync":"false",
"testjobMaxTestDuration":"60",
"testjobDebugExecution":"false",
"testjobRampUpTime":"5",
"definedFromMonitoringGroupId":"17",
"testjobMaxLoopsPerUser":"1",
"productVersion":"4.8.3",
"monitoringJobId":"39",
"monitoringJobTitle":"SimpleTest",
"lastExecutionStartTime":"1677506934086",
"testjobAdditionalArguments":"",
"definedFromTestId":"311",
"testjobUserInputFieldsValuesJsonArray":"[]",
"monitoringJobDescription":""
},
"monitoringTestProperties":
{
"referencedResourceFilesList":[{"projectId":130,"testplanId":203,"fileName":"com.dkfqs.tools.jar"}],
"productVersion":"4.7.14",
"executingScript":"SimpleTest.jar",
"definedFromProjectId":"137",
"executingScriptResourceFileList":"",
"visibleTestName":"SimpleTest",
"scriptType":"OpenJDK11Jar",
"createTimeStamp":"1675464639177",
"testId":"311",
"testDescription":"",
"definedFromTestplanId":"251"
},
"monitoringTestIsHealthy":true,
"monitoringJobAction":"jobExists"
},
"isError":false
}
The testjobMaxTestDuration and the testjobRampUpTime are in seconds. The testjobDelayPerLoop are in milliseconds. The lastExecutionStartTime has a value of -1 (minus one) if the Monitoring Job was never executed.
Any modification of a Monitoring Job made by the Portal Server Web Interface such as modify enableJobExecution or monitoringJobTitle effects that a “jobModified” action is released.
{
"action":"onMonitoringGroupExecuted",
"monitoringGroupId":17,
"monitoringEvent":
{"
eventTimestamp":1677522195877,
"oldEvent":true,
"groupExecutionResult":
{
"magicPattern":"MonitoringGroupExecutionResult",
"productVersion":"4.8.3",
"userId":13,
"monitoringGroupId":17,
"groupExecutionId":2430,
"resultTimestamp":1677506950103,
"monitoringJobIdToLocalTestjobIdArray":[{"monitoringJobId":39,"localTestjobId":5015}],
"groupSystemStatus":0,
"groupCombinedTestjobState":"completed",
"groupExecutionLogArray":[
"2023-02-27 15:08:54.067 | | INFO | Monitoring Group Execution Thread started",
"2023-02-27 15:09:10.102 | | INFO | Monitoring Job Id 39 executed",
"2023-02-27 15:09:10.103 | | INFO | Monitoring Group Execution Thread terminated"],
"numberOfPassedSamples":6,
"numberOfFailedSamples":0,
"numberOfPassedLoops":2,
"numberOfFailedLoops":0,
"sumErrorsSeverityWarning":0,
"sumErrorsSeverityError":0,
"sumErrorsSeverityFatal":0
}
},
"isError":false
}
groupSystemStatus:
groupCombinedTestjobState
Hint for groupCombinedTestjobState : Note that is value does not reflect if any warnings or errors have been measured by the testjobs.
The Reference Implementation on the Real Load Portal Server shows the measured (sumErrorsSeverityError + sumErrorsSeverityFatal) simple as “number of measured errors”.
{
"action": "onMonitoringJobExecuted",
"monitoringGroupId": 17,
"monitoringJobId": 39,
"monitoringEvent": {
"eventTimestamp": 1677522195878,
"oldEvent": true,
"jobExecutionResult": {
"magicPattern": "MonitoringJobExecutionResult",
"productVersion": "4.8.3",
"userId": 13,
"monitoringGroupId": 17,
"groupExecutionId": 2430,
"monitoringJobId": 39,
"localTestjobId": 5015,
"resultTimestamp": 1677506949101,
"systemStatus": 0,
"jobExecutionLogArray": [
"2023-02-27 15:08:54.085 | | INFO | Monitoring Job Execution Thread started",
"2023-02-27 15:08:54.436 | Ubuntu 10 | INFO | Job submitted to measuring agent",
"2023-02-27 15:08:59.854 | Ubuntu 10 | INFO | Job executed on measuring agent, exit code = process executed successfully",
"2023-02-27 15:09:01.847 | Ubuntu 11 | INFO | Job submitted to measuring agent",
"2023-02-27 15:09:07.438 | Ubuntu 11 | INFO | Job executed on measuring agent, exit code = process executed successfully",
"2023-02-27 15:09:09.101 | | INFO | Monitoring Job Execution Thread terminated"
],
"combinedTestjobState": "completed",
"hasCombinedTestResult": true,
"combinedTestResultFileName": "TestResult_MonitoringJob_39_2023-02-27@15-09-09.json",
"combinedTestResultSummaryStatistic": {
"productVersion": "4.8.3",
"localTestjobId": 5015,
"remoteTestjobId": 2430,
"samplingGranularity": 4000,
"jobStartTimestamp": 1677506938135,
"jobEndTimestamp": 1677506945975,
"osCpuLoadPercent": -1,
"numberOfPassedLoopsTimeSum": 506,
"numberOfConcurrentUsers": 0,
"currentlyPendingSamples": -1,
"numberOfPassedSamples": 6,
"numberOfFailedSamples": 0,
"numberOfPassedLoops": 2,
"numberOfFailedLoops": 0
},
"averagePassedLoopTime": 266,
"sumErrorsSeverityWarning": 0,
"sumErrorsSeverityError": 0,
"sumErrorsSeverityFatal": 0,
"measuringAgentResultArray": [
{
"userId": 13,
"monitoringGroupId": 17,
"groupExecutionId": 2430,
"monitoringJobId": 39,
"localTestjobId": 5015,
"resultTimestamp": 1677506949076,
"measuringAgent": {
"agentId": 69,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Ubuntu 10",
"agentHost": "192.168.0.110",
"agentPort": 8080
},
"systemStatus": 0,
"testjobState": "completed",
"testjobExitCode": 0,
"remoteTestjobId": 2169,
"testjobResultFileName": "TestResult_SimpleTest_2023-02-27@15-08-58.json",
"averagePassedLoopTime": 232,
"sumErrorsSeverityWarning": 0,
"sumErrorsSeverityError": 0,
"sumErrorsSeverityFatal": 0,
"additionalTextFilesArray": [
{
"fileName": ".testjob.properties",
"fileLinesArray": [
"#Test Job Properties",
"#Mon Feb 27 15:08:59 CET 2023",
"testjobResultFileName=TestResult_SimpleTest_2023-02-27@15-08-58.json",
"testjobConcurrentUsers=1",
"testjobDescription=SimpleTest",
"testjobDebugMeasuring=false",
"testjobMaxTestDuration=60",
"testjobRampUpTime=5",
"isClusterJob=false",
"localTestjobId=5015",
"testjobMaxLoopsPerUser=1",
"productVersion=4.8.3",
"remoteTestjobId=2169",
"testjobAdditionalArguments=",
"definedFromTestId=311",
"testjobSignature=T9E26sxc4yzIxFsaV3J8nn9XJIbBX137/GMDJODyGQG73pES7iSopralt4rTLoqq9VG/cMFiTxexzCLYksYlF2w8sMls+9oWkPk/Yd0cjSAZgUO24gr7pCjJfU+GuJ6uJ/ts5XeHUSXPqFWiNh0SJG2dBx5wnuyGbvlsYKuUck6c51+6pjz1EaO3k+1eVgri9oREDBZEMOIf4ePlrbmgEf+Y9/X/dm0+PjdxZoi+AKKhK+TpXiWpmyyiw8X6RrckznJ3z/XhRFxcAAzurcz7qxa7Qjb2z64lO0lMMelLjXnTXRgSCVhYngKq6HWvoFUclGK8Z1Ju3cgiGtKT3Bn/mw\\=\\=",
"testjobDelayPerLoop=1000",
"testjobExitCode=0",
"userInputFieldsFileName=",
"createTimeStamp=1677506934097",
"testjobType=monitoring",
"enableAutomaticFileSync=false",
"testjobState=completed",
"testjobDebugExecution=false",
"executeOnUserMeasuringAgentId=69",
"definedFromTimeZoneId=Europe/Berlin",
"executeMeasuringAgentInfo=192.168.0.110\\:8080"
]
},
{
"fileName": "DataCollector.err",
"fileLinesArray": []
},
{
"fileName": "DataCollector.out",
"fileLinesArray": [
"Max. Java Memory = 128 MB",
"--- vvv --- TestjobProperties --- vvv ---",
"testjobResultFileName=",
"executeMeasuringAgentClusterInfo=",
"testjobConcurrentUsers=1",
"testjobDescription=SimpleTest",
"testjobDebugMeasuring=false",
"testjobMaxTestDuration=60",
"isClusterJob=false",
"testjobRampUpTime=5",
"localTestjobId=5015",
"testjobMaxLoopsPerUser=1",
"productVersion=4.8.1",
"remoteTestjobId=2169",
"testjobAdditionalArguments=",
"definedFromTestId=311",
"testjobSignature=T9E26sxc4yzIxFsaV3J8nn9XJIbBX137/GMDJODyGQG73pES7iSopralt4rTLoqq9VG/cMFiTxexzCLYksYlF2w8sMls+9oWkPk/Yd0cjSAZgUO24gr7pCjJfU+GuJ6uJ/ts5XeHUSXPqFWiNh0SJG2dBx5wnuyGbvlsYKuUck6c51+6pjz1EaO3k+1eVgri9oREDBZEMOIf4ePlrbmgEf+Y9/X/dm0+PjdxZoi+AKKhK+TpXiWpmyyiw8X6RrckznJ3z/XhRFxcAAzurcz7qxa7Qjb2z64lO0lMMelLjXnTXRgSCVhYngKq6HWvoFUclGK8Z1Ju3cgiGtKT3Bn/mw==",
"testjobDelayPerLoop=1000",
"testjobExitCode=",
"createTimeStamp=1677506935549",
"userInputFieldsFileName=",
"testjobType=monitoring",
"enableAutomaticFileSync=false",
"testjobState=submitted",
"isClusterControllerJobProperties=",
"testjobDebugExecution=false",
"executeOnUserMeasuringAgentId=69",
"definedFromTimeZoneId=Europe/Berlin",
"executeMeasuringAgentInfo=192.168.0.110:8080",
"executeOnMeasuringAgentClusterId=",
"--- ^^^ --- TestjobProperties --- ^^^ ---",
"--- vvv --- TestProperties --- vvv ---",
"referencedResourceFilesList=[{\"projectId\":130,\"testplanId\":203,\"fileName\":\"com.dkfqs.tools.jar\"}]",
"productVersion=4.7.14",
"executingScript=SimpleTest.jar",
"definedFromProjectId=137",
"executingScriptResourceFileList=",
"visibleTestName=SimpleTest",
"scriptType=OpenJDK11Jar",
"createTimeStamp=1675464639177",
"testId=311",
"testDescription=",
"definedFromTestplanId=251",
"--- ^^^ --- TestProperties --- ^^^ ---",
"X509 TLS server certificate generated for CN = 127.0.0.1",
"Internal RSA 2048 bit keypair generated in 96 ms",
"2023-02-27 14:08:56.682 | QAHTTPd | WARN | QAHTTPd V1.4-B started",
"2023-02-27 14:08:56.709 | QAHTTPd | INFO | HTTPS server starting at port 44941",
"2023-02-27 14:08:56.727 | QAHTTPd | INFO | HTTPS server ready at port 44941",
"2023-02-27 14:08:57.697 | DataCollector PID 280356 | INFO | Use data collector protocol #1 = \"one output file per user DKFQS tailer\"",
"2023-02-27 14:08:57.711 | DataCollector PID 280356 | INFO | Initialize data collector protocol #1 ...",
"2023-02-27 14:08:57.716 | DataCollector PID 280356 | INFO | Data collector protocol #1 testjob out subdirectory = /home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_2169/out",
"2023-02-27 14:08:57.717 | DataCollector PID 280356 | INFO | Number of concurrent users = 1",
"2023-02-27 14:08:57.726 | DataCollector PID 280356 | INFO | File '/home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_2169/out/user_1_statistics.out' created",
"2023-02-27 14:08:57.726 | DataCollector PID 280356 | INFO | ... Initialize data collector protocol #1 done",
"2023-02-27 14:08:57.777 | 127.0.0.1 : 50610 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:08:57.799 | 127.0.0.1 : 50610 | INFO | InternalApi action = checkStartupCompleted",
"2023-02-27 14:08:57.803 | 127.0.0.1 : 50610 | INFO | HTTP/1.1 200 OK [34 application/json]",
"2023-02-27 14:08:57.899 | 127.0.0.1 : 50612 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:08:57.901 | 127.0.0.1 : 50612 | INFO | InternalApi action = startProtocol",
"2023-02-27 14:08:57.904 | 127.0.0.1 : 50612 | INFO | Start data collector protocol #1",
"2023-02-27 14:08:57.905 | 127.0.0.1 : 50612 | INFO | Tailer delay millis = 500",
"2023-02-27 14:08:57.905 | 127.0.0.1 : 50612 | INFO | Start tailer for user no. 1",
"2023-02-27 14:08:57.911 | SamplingGranularityThread | INFO | SamplingGranularityThread started. Sampling granularity = 4000 ms",
"2023-02-27 14:08:57.962 | 127.0.0.1 : 50612 | INFO | HTTP/1.1 200 OK [11 application/json]",
"2023-02-27 14:08:59.988 | 127.0.0.1 : 50616 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:08:59.990 | 127.0.0.1 : 50616 | INFO | InternalApi action = stopProtocol",
"2023-02-27 14:08:59.990 | 127.0.0.1 : 50616 | INFO | Stop data collector protocol #1",
"2023-02-27 14:09:00.991 | 127.0.0.1 : 50616 | INFO | Stop tailer for user no. 1",
"2023-02-27 14:09:00.996 | SamplingGranularityThread | INFO | SamplingGranularityThread stopped",
"2023-02-27 14:09:00.996 | 127.0.0.1 : 50616 | INFO | HTTP/1.1 200 OK [11 application/json]",
"2023-02-27 14:09:01.017 | 127.0.0.1 : 50618 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:09:01.018 | 127.0.0.1 : 50618 | INFO | InternalApi action = writeTestResultToDisk",
"2023-02-27 14:09:01.033 | 127.0.0.1 : 50618 | INFO | Test result file = TestResult_SimpleTest_2023-02-27@15-08-58.json",
"2023-02-27 14:09:01.039 | 127.0.0.1 : 50618 | INFO | HTTP/1.1 200 OK [80 application/json]"
]
},
{
"fileName": "user_1_statistics.out",
"fileLinesArray": [
"{\"subject\":\"declare-statistic\",\"statistic-id\":0,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"Measurement Group «Group 1»\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Execution Time\",\"unit-text\":\"ms\",\"sort-position\":0,\"add-to-summary-statistic\":false,\"background-color\":\"table-info\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":1,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"GET https://192.168.0.112/\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Response Time\",\"unit-text\":\"ms\",\"sort-position\":1,\"add-to-summary-statistic\":true,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":2,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"GET https://192.168.0.112/images/RealLoadPortal.gif\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Response Time\",\"unit-text\":\"ms\",\"sort-position\":2,\"add-to-summary-statistic\":true,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":3,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"GET https://192.168.0.112/images/QAHTTPd_188x112.gif\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Response Time\",\"unit-text\":\"ms\",\"sort-position\":3,\"add-to-summary-statistic\":true,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100001,\"statistic-type\":\"cumulative-counter-long\",\"statistic-title\":\"Total Bytes Sent\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"Bytes\",\"sort-position\":100001,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100002,\"statistic-type\":\"cumulative-counter-long\",\"statistic-title\":\"Total Bytes Received\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"Bytes\",\"sort-position\":100002,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100003,\"statistic-type\":\"throughput-time-chart\",\"statistic-title\":\"Network Throughput\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Network Throughput\",\"unit-text\":\"Mbps\",\"sort-position\":100003,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100004,\"statistic-type\":\"average-and-current-value\",\"statistic-title\":\"Avg. TCP Connect Time\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"ms\",\"sort-position\":100004,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100005,\"statistic-type\":\"average-and-current-value\",\"statistic-title\":\"Avg. SSL Handshake Time\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"ms\",\"sort-position\":100005,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100006,\"statistic-type\":\"efficiency-ratio-percent\",\"statistic-title\":\"HTTP Keep-Alive Efficiency\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"%\",\"sort-position\":100006,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"register-execute-start\",\"timestamp\":1677506938135}",
"{\"subject\":\"register-loop-start\",\"timestamp\":1677506938136}",
"{\"subject\":\"register-sample-start\",\"statistic-id\":0,\"timestamp\":1677506938136}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":0}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":0}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0,\"timestamp\":1677506938137}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":-1,\"currentValueTimestamp\":-1}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":-1,\"currentValueTimestamp\":-1}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":0,\"inefficiencyDeltaValue\":0}",
"{\"subject\":\"register-sample-start\",\"statistic-id\":1,\"timestamp\":1677506938151}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":1,\"value\":167,\"timestamp\":1677506938335}",
"{\"subject\":\"register-sample-start\",\"statistic-id\":2,\"timestamp\":1677506938336}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":2,\"value\":8,\"timestamp\":1677506938346}",
"{\"subject\":\"register-sample-start\",\"statistic-id\":3,\"timestamp\":1677506938347}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":3,\"value\":4,\"timestamp\":1677506938353}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":0,\"value\":217,\"timestamp\":1677506938353}",
"{\"subject\":\"register-loop-passed\",\"loop-time\":217,\"timestamp\":1677506938353}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":1038}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":48631}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0.397352,\"timestamp\":1677506938389}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":2,\"numValuesDelta\":1,\"currentValue\":2,\"currentValueTimestamp\":1677506938322}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":61,\"numValuesDelta\":1,\"currentValue\":61,\"currentValueTimestamp\":1677506938322}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":2,\"inefficiencyDeltaValue\":1}",
"{\"subject\":\"register-execute-end\",\"timestamp\":1677506938406}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":0}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":0}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0,\"timestamp\":1677506938640}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":2,\"currentValueTimestamp\":1677506938322}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":61,\"currentValueTimestamp\":1677506938322}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":0,\"inefficiencyDeltaValue\":0}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":0}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":0}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0,\"timestamp\":1677506938891}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":2,\"currentValueTimestamp\":1677506938322}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":61,\"currentValueTimestamp\":1677506938322}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":0,\"inefficiencyDeltaValue\":0}"
]
},
{
"fileName": "users.out",
"fileLinesArray": [
"2023-02-27 14:08:58.097 | main | INFO | Max. Java Memory = 256 MB",
"2023-02-27 14:08:58.106 | main | INFO | --- vvv --- resource files --- vvv ---",
"2023-02-27 14:08:58.107 | main | INFO | --- ^^^ --- resource files --- ^^^ ---",
"2023-02-27 14:08:58.107 | main | INFO | --- vvv --- generic arguments --- vvv ---",
"2023-02-27 14:08:58.107 | main | INFO | users = 1",
"2023-02-27 14:08:58.107 | main | INFO | duration = 60",
"2023-02-27 14:08:58.107 | main | INFO | maxLoops = 1",
"2023-02-27 14:08:58.107 | main | INFO | delayPerLoop = 1000",
"2023-02-27 14:08:58.108 | main | INFO | rampupTime = 5",
"2023-02-27 14:08:58.108 | main | INFO | dataOutputDir = /home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_2169/out",
"2023-02-27 14:08:58.108 | main | INFO | debugExec = false",
"2023-02-27 14:08:58.108 | main | INFO | debugData = false",
"2023-02-27 14:08:58.108 | main | INFO | description = SimpleTest",
"2023-02-27 14:08:58.108 | main | INFO | --- ^^^ --- generic arguments --- ^^^ ---",
"2023-02-27 14:08:58.108 | main | INFO | --- vvv --- specific arguments --- vvv ---",
"2023-02-27 14:08:58.114 | main | INFO | tcpTimeout = 10000",
"2023-02-27 14:08:58.114 | main | INFO | sslTimeout = 5000",
"2023-02-27 14:08:58.115 | main | INFO | httpTimeout = 30000",
"2023-02-27 14:08:58.115 | main | INFO | --- ^^^ --- specific arguments --- ^^^ ---",
"2023-02-27 14:08:58.123 | main | INFO | [Start of Test]",
"2023-02-27 14:08:58.124 | User-1 | INFO | User started",
"2023-02-27 14:08:58.136 | periodic-thread | INFO | Thread started",
"2023-02-27 14:08:58.136 | User-1 | INFO | Start execute session no. 1 ...",
"2023-02-27 14:08:58.353 | User-1 | INFO | ... End execute session no. 1 successful passed",
"2023-02-27 14:08:58.406 | User-1 | INFO | User normal terminated",
"2023-02-27 14:08:59.124 | main | INFO | [End of Test]"
]
}
]
},
{
"userId": 13,
"monitoringGroupId": 17,
"groupExecutionId": 2430,
"monitoringJobId": 39,
"localTestjobId": 5015,
"resultTimestamp": 1677506949077,
"measuringAgent": {
"agentId": 70,
"createdBySystem": false,
"ownerUserId": 13,
"agentActive": true,
"agentDescription": "Ubuntu 11",
"agentHost": "192.168.0.111",
"agentPort": 8080
},
"systemStatus": 0,
"testjobState": "completed",
"testjobExitCode": 0,
"remoteTestjobId": 1676,
"testjobResultFileName": "TestResult_SimpleTest_2023-02-27@15-09-05.json",
"averagePassedLoopTime": 299,
"sumErrorsSeverityWarning": 0,
"sumErrorsSeverityError": 0,
"sumErrorsSeverityFatal": 0,
"additionalTextFilesArray": [
{
"fileName": ".testjob.properties",
"fileLinesArray": [
"#Test Job Properties",
"#Mon Feb 27 15:09:07 CET 2023",
"testjobResultFileName=TestResult_SimpleTest_2023-02-27@15-09-05.json",
"testjobConcurrentUsers=1",
"testjobDescription=SimpleTest",
"testjobDebugMeasuring=false",
"testjobMaxTestDuration=60",
"testjobRampUpTime=5",
"isClusterJob=false",
"localTestjobId=5015",
"testjobMaxLoopsPerUser=1",
"productVersion=4.8.3",
"remoteTestjobId=1676",
"testjobAdditionalArguments=",
"definedFromTestId=311",
"testjobSignature=T9E26sxc4yzIxFsaV3J8nn9XJIbBX137/GMDJODyGQG73pES7iSopralt4rTLoqq9VG/cMFiTxexzCLYksYlF2w8sMls+9oWkPk/Yd0cjSAZgUO24gr7pCjJfU+GuJ6uJ/ts5XeHUSXPqFWiNh0SJG2dBx5wnuyGbvlsYKuUck6c51+6pjz1EaO3k+1eVgri9oREDBZEMOIf4ePlrbmgEf+Y9/X/dm0+PjdxZoi+AKKhK+TpXiWpmyyiw8X6RrckznJ3z/XhRFxcAAzurcz7qxa7Qjb2z64lO0lMMelLjXnTXRgSCVhYngKq6HWvoFUclGK8Z1Ju3cgiGtKT3Bn/mw\\=\\=",
"testjobDelayPerLoop=1000",
"testjobExitCode=0",
"userInputFieldsFileName=",
"createTimeStamp=1677506941508",
"testjobType=monitoring",
"enableAutomaticFileSync=false",
"testjobState=completed",
"testjobDebugExecution=false",
"executeOnUserMeasuringAgentId=70",
"definedFromTimeZoneId=Europe/Berlin",
"executeMeasuringAgentInfo=192.168.0.111\\:8080"
]
},
{
"fileName": "DataCollector.err",
"fileLinesArray": []
},
{
"fileName": "DataCollector.out",
"fileLinesArray": [
"Max. Java Memory = 128 MB",
"--- vvv --- TestjobProperties --- vvv ---",
"testjobResultFileName=",
"executeMeasuringAgentClusterInfo=",
"testjobConcurrentUsers=1",
"testjobDescription=SimpleTest",
"testjobDebugMeasuring=false",
"testjobMaxTestDuration=60",
"isClusterJob=false",
"testjobRampUpTime=5",
"localTestjobId=5015",
"testjobMaxLoopsPerUser=1",
"productVersion=4.8.1",
"remoteTestjobId=1676",
"testjobAdditionalArguments=",
"definedFromTestId=311",
"testjobSignature=T9E26sxc4yzIxFsaV3J8nn9XJIbBX137/GMDJODyGQG73pES7iSopralt4rTLoqq9VG/cMFiTxexzCLYksYlF2w8sMls+9oWkPk/Yd0cjSAZgUO24gr7pCjJfU+GuJ6uJ/ts5XeHUSXPqFWiNh0SJG2dBx5wnuyGbvlsYKuUck6c51+6pjz1EaO3k+1eVgri9oREDBZEMOIf4ePlrbmgEf+Y9/X/dm0+PjdxZoi+AKKhK+TpXiWpmyyiw8X6RrckznJ3z/XhRFxcAAzurcz7qxa7Qjb2z64lO0lMMelLjXnTXRgSCVhYngKq6HWvoFUclGK8Z1Ju3cgiGtKT3Bn/mw==",
"testjobDelayPerLoop=1000",
"testjobExitCode=",
"createTimeStamp=1677506942962",
"userInputFieldsFileName=",
"testjobType=monitoring",
"enableAutomaticFileSync=false",
"testjobState=submitted",
"isClusterControllerJobProperties=",
"testjobDebugExecution=false",
"executeOnUserMeasuringAgentId=70",
"definedFromTimeZoneId=Europe/Berlin",
"executeMeasuringAgentInfo=192.168.0.111:8080",
"executeOnMeasuringAgentClusterId=",
"--- ^^^ --- TestjobProperties --- ^^^ ---",
"--- vvv --- TestProperties --- vvv ---",
"referencedResourceFilesList=[{\"projectId\":130,\"testplanId\":203,\"fileName\":\"com.dkfqs.tools.jar\"}]",
"productVersion=4.7.14",
"executingScript=SimpleTest.jar",
"definedFromProjectId=137",
"executingScriptResourceFileList=",
"visibleTestName=SimpleTest",
"scriptType=OpenJDK11Jar",
"createTimeStamp=1675464639177",
"testId=311",
"testDescription=",
"definedFromTestplanId=251",
"--- ^^^ --- TestProperties --- ^^^ ---",
"X509 TLS server certificate generated for CN = 127.0.0.1",
"Internal RSA 2048 bit keypair generated in 58 ms",
"2023-02-27 14:09:04.195 | QAHTTPd | WARN | QAHTTPd V1.4-B started",
"2023-02-27 14:09:04.226 | QAHTTPd | INFO | HTTPS server starting at port 44448",
"2023-02-27 14:09:04.258 | QAHTTPd | INFO | HTTPS server ready at port 44448",
"2023-02-27 14:09:05.189 | DataCollector PID 262208 | INFO | Use data collector protocol #1 = \"one output file per user DKFQS tailer\"",
"2023-02-27 14:09:05.194 | DataCollector PID 262208 | INFO | Initialize data collector protocol #1 ...",
"2023-02-27 14:09:05.197 | DataCollector PID 262208 | INFO | Data collector protocol #1 testjob out subdirectory = /home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_1676/out",
"2023-02-27 14:09:05.198 | DataCollector PID 262208 | INFO | Number of concurrent users = 1",
"2023-02-27 14:09:05.214 | 127.0.0.1 : 50182 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:09:05.215 | DataCollector PID 262208 | INFO | File '/home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_1676/out/user_1_statistics.out' created",
"2023-02-27 14:09:05.218 | DataCollector PID 262208 | INFO | ... Initialize data collector protocol #1 done",
"2023-02-27 14:09:05.249 | 127.0.0.1 : 50182 | INFO | InternalApi action = checkStartupCompleted",
"2023-02-27 14:09:05.257 | 127.0.0.1 : 50182 | INFO | HTTP/1.1 200 OK [34 application/json]",
"2023-02-27 14:09:05.355 | 127.0.0.1 : 50184 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:09:05.359 | 127.0.0.1 : 50184 | INFO | InternalApi action = startProtocol",
"2023-02-27 14:09:05.370 | 127.0.0.1 : 50184 | INFO | Start data collector protocol #1",
"2023-02-27 14:09:05.371 | 127.0.0.1 : 50184 | INFO | Tailer delay millis = 500",
"2023-02-27 14:09:05.371 | 127.0.0.1 : 50184 | INFO | Start tailer for user no. 1",
"2023-02-27 14:09:05.378 | SamplingGranularityThread | INFO | SamplingGranularityThread started. Sampling granularity = 4000 ms",
"2023-02-27 14:09:05.428 | 127.0.0.1 : 50184 | INFO | HTTP/1.1 200 OK [11 application/json]",
"2023-02-27 14:09:05.933 | User 1 | ERROR | Tailer: Failed to parse JSON data at line 22 of file '/home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_1676/out/user_1_statistics.out'",
"2023-02-27 14:09:05.933 | User 1 | ERROR | libs.com.eclipsesource.json.ParseException: Unexpected character at 1:65",
"2023-02-27 14:09:05.933 | User 1 | ERROR | \tat libs.com.eclipsesource.json.JsonParser.error(JsonParser.java:490)",
"2023-02-27 14:09:05.934 | User 1 | ERROR | \tat libs.com.eclipsesource.json.JsonParser.parse(JsonParser.java:155)",
"2023-02-27 14:09:05.934 | User 1 | ERROR | \tat libs.com.eclipsesource.json.JsonParser.parse(JsonParser.java:91)",
"2023-02-27 14:09:05.934 | User 1 | ERROR | \tat libs.com.eclipsesource.json.Json.parse(Json.java:295)",
"2023-02-27 14:09:05.934 | User 1 | ERROR | \tat com.dkfqs.measuringagent.datacollector.ProtocolType1AdapterTailerListener.onExtractLine(ProtocolType1AdapterTailerListener.java:91)",
"2023-02-27 14:09:05.934 | User 1 | ERROR | \tat com.dkfqs.measuringagent.product.DKFQSFileTailerThread.convertOutputBufferToLines(DKFQSFileTailerThread.java:152)",
"2023-02-27 14:09:05.934 | User 1 | ERROR | \tat com.dkfqs.measuringagent.product.DKFQSFileTailerThread.run(DKFQSFileTailerThread.java:86)",
"2023-02-27 14:09:05.934 | User 1 | ERROR | Tailer: Invalid JSON data received at line 23 of file '/home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_1676/out/user_1_statistics.out'",
"2023-02-27 14:09:07.470 | 127.0.0.1 : 50188 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:09:07.472 | 127.0.0.1 : 50188 | INFO | InternalApi action = stopProtocol",
"2023-02-27 14:09:07.472 | 127.0.0.1 : 50188 | INFO | Stop data collector protocol #1",
"2023-02-27 14:09:08.473 | 127.0.0.1 : 50188 | INFO | Stop tailer for user no. 1",
"2023-02-27 14:09:08.475 | 127.0.0.1 : 50188 | INFO | HTTP/1.1 200 OK [11 application/json]",
"2023-02-27 14:09:08.476 | SamplingGranularityThread | INFO | SamplingGranularityThread stopped",
"2023-02-27 14:09:08.512 | 127.0.0.1 : 50190 | INFO | https POST /dataCollectorApi HTTP/1.1",
"2023-02-27 14:09:08.514 | 127.0.0.1 : 50190 | INFO | InternalApi action = writeTestResultToDisk",
"2023-02-27 14:09:08.541 | 127.0.0.1 : 50190 | INFO | Test result file = TestResult_SimpleTest_2023-02-27@15-09-05.json",
"2023-02-27 14:09:08.548 | 127.0.0.1 : 50190 | INFO | HTTP/1.1 200 OK [80 application/json]"
]
},
{
"fileName": "user_1_statistics.out",
"fileLinesArray": [
"{\"subject\":\"declare-statistic\",\"statistic-id\":0,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"Measurement Group «Group 1»\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Execution Time\",\"unit-text\":\"ms\",\"sort-position\":0,\"add-to-summary-statistic\":false,\"background-color\":\"table-info\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":1,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"GET https://192.168.0.112/\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Response Time\",\"unit-text\":\"ms\",\"sort-position\":1,\"add-to-summary-statistic\":true,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":2,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"GET https://192.168.0.112/images/RealLoadPortal.gif\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Response Time\",\"unit-text\":\"ms\",\"sort-position\":2,\"add-to-summary-statistic\":true,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":3,\"statistic-type\":\"sample-event-time-chart\",\"statistic-title\":\"GET https://192.168.0.112/images/QAHTTPd_188x112.gif\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Response Time\",\"unit-text\":\"ms\",\"sort-position\":3,\"add-to-summary-statistic\":true,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100001,\"statistic-type\":\"cumulative-counter-long\",\"statistic-title\":\"Total Bytes Sent\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"Bytes\",\"sort-position\":100001,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100002,\"statistic-type\":\"cumulative-counter-long\",\"statistic-title\":\"Total Bytes Received\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"Bytes\",\"sort-position\":100002,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100003,\"statistic-type\":\"throughput-time-chart\",\"statistic-title\":\"Network Throughput\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"Network Throughput\",\"unit-text\":\"Mbps\",\"sort-position\":100003,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100004,\"statistic-type\":\"average-and-current-value\",\"statistic-title\":\"Avg. TCP Connect Time\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"ms\",\"sort-position\":100004,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100005,\"statistic-type\":\"average-and-current-value\",\"statistic-title\":\"Avg. SSL Handshake Time\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"ms\",\"sort-position\":100005,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"declare-statistic\",\"statistic-id\":100006,\"statistic-type\":\"efficiency-ratio-percent\",\"statistic-title\":\"HTTP Keep-Alive Efficiency\",\"statistic-subtitle\":\"\",\"y-axis-title\":\"\",\"unit-text\":\"%\",\"sort-position\":100006,\"add-to-summary-statistic\":false,\"background-color\":\"\"}",
"{\"subject\":\"register-execute-start\",\"timestamp\":1677506945634}",
"{\"subject\":\"register-loop-start\",\"timestamp\":1677506945635}",
"{\"subject\":\"register-sample-start\",\"statistic-id\":0,\"timestamp\":1677506945635}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":0}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":0}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0,\"timestamp\":1677506945637}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":-1,\"currentValueTimestamp\":-1}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":-1,\"currentValueTimestamp\":-1}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":0,\"inefficiencyDeltaValue\":0}",
"{\"subject\":\"register-sample-start\",\"statistic-id\":1,\"timestamp\":1677506945653}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":1,\"value\":209,\"timestamp\":1677506945886}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":319}{\"subject\":\"register-sample-start\",\"statistic-id\":2,\"timestamp\":1677506945895}",
"",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":2681}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0.024,\"timestamp\":1677506945896}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":2,\"numValuesDelta\":1,\"currentValue\":2,\"currentValueTimestamp\":1677506945867}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":72,\"numValuesDelta\":1,\"currentValue\":72,\"currentValueTimestamp\":1677506945867}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":0,\"inefficiencyDeltaValue\":1}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":2,\"value\":14,\"timestamp\":1677506945911}",
"{\"subject\":\"register-sample-start\",\"statistic-id\":3,\"timestamp\":1677506945912}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":3,\"value\":4,\"timestamp\":1677506945923}",
"{\"subject\":\"add-sample-long\",\"statistic-id\":0,\"value\":288,\"timestamp\":1677506945923}",
"{\"subject\":\"register-loop-passed\",\"loop-time\":289,\"timestamp\":1677506945924}",
"{\"subject\":\"register-execute-end\",\"timestamp\":1677506945975}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":719}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":45950}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0.373352,\"timestamp\":1677506946148}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":2,\"currentValueTimestamp\":1677506945867}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":72,\"currentValueTimestamp\":1677506945867}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":2,\"inefficiencyDeltaValue\":0}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100001,\"value\":0}",
"{\"subject\":\"add-counter-long\",\"statistic-id\":100002,\"value\":0}",
"{\"subject\":\"add-throughput-delta\",\"statistic-id\":100003,\"delta-value\":0,\"timestamp\":1677506946400}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100004,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":2,\"currentValueTimestamp\":1677506945867}",
"{\"subject\":\"add-average-delta-and-current-value\",\"statistic-id\":100005,\"sumValuesDelta\":0,\"numValuesDelta\":0,\"currentValue\":72,\"currentValueTimestamp\":1677506945867}",
"{\"subject\":\"add-efficiency-ratio-delta\",\"statistic-id\":100006,\"efficiencyDeltaValue\":0,\"inefficiencyDeltaValue\":0}"
]
},
{
"fileName": "users.out",
"fileLinesArray": [
"2023-02-27 14:09:05.586 | main | INFO | Max. Java Memory = 256 MB",
"2023-02-27 14:09:05.599 | main | INFO | --- vvv --- resource files --- vvv ---",
"2023-02-27 14:09:05.599 | main | INFO | --- ^^^ --- resource files --- ^^^ ---",
"2023-02-27 14:09:05.599 | main | INFO | --- vvv --- generic arguments --- vvv ---",
"2023-02-27 14:09:05.600 | main | INFO | users = 1",
"2023-02-27 14:09:05.600 | main | INFO | duration = 60",
"2023-02-27 14:09:05.600 | main | INFO | maxLoops = 1",
"2023-02-27 14:09:05.600 | main | INFO | delayPerLoop = 1000",
"2023-02-27 14:09:05.600 | main | INFO | rampupTime = 5",
"2023-02-27 14:09:05.600 | main | INFO | dataOutputDir = /home/dkfqs/agent/usersData/User_13/TestJobs/Testjob_1676/out",
"2023-02-27 14:09:05.601 | main | INFO | debugExec = false",
"2023-02-27 14:09:05.601 | main | INFO | debugData = false",
"2023-02-27 14:09:05.601 | main | INFO | description = SimpleTest",
"2023-02-27 14:09:05.601 | main | INFO | --- ^^^ --- generic arguments --- ^^^ ---",
"2023-02-27 14:09:05.601 | main | INFO | --- vvv --- specific arguments --- vvv ---",
"2023-02-27 14:09:05.609 | main | INFO | tcpTimeout = 10000",
"2023-02-27 14:09:05.609 | main | INFO | sslTimeout = 5000",
"2023-02-27 14:09:05.610 | main | INFO | httpTimeout = 30000",
"2023-02-27 14:09:05.610 | main | INFO | --- ^^^ --- specific arguments --- ^^^ ---",
"2023-02-27 14:09:05.620 | main | INFO | [Start of Test]",
"2023-02-27 14:09:05.621 | User-1 | INFO | User started",
"2023-02-27 14:09:05.635 | periodic-thread | INFO | Thread started",
"2023-02-27 14:09:05.635 | User-1 | INFO | Start execute session no. 1 ...",
"2023-02-27 14:09:05.924 | User-1 | INFO | ... End execute session no. 1 successful passed",
"2023-02-27 14:09:05.975 | User-1 | INFO | User normal terminated",
"2023-02-27 14:09:06.621 | main | INFO | [End of Test]"
]
}
]
}
]
}
},
"isError": false
}
systemStatus:
combinedTestjobState
Hint for combinedTestjobState : Note that is value does not reflect if any warnings or errors have been measured by the testjobs.
The Reference Implementation on the Real Load Portal Server shows the measured (sumErrorsSeverityError + sumErrorsSeverityFatal) simple as “number of measured errors”.
You will also receive other actions than previously described above. These are confirmations that you can ignore. Example:
{
"action":"subscribeToRealtimeMonitor",
"isError":false
}
Usually you just need a Portal Server account and to install the “Desktop Companion” on your laptop which enables you to record and upload HTTP/S sessions and to launch Measuring Agents on Amazon EC2. You don’t need a special installation license for the Desktop Companion. However, user licenses are required for using the Portal Server and to perform tests on Measuring Agents - see https://shop.realload.com/.
The Real Load components Measuring Agent(s), Cluster Controller(s) and Remote Proxy Recorder(s) can also installed/operated on your own hosted machines.
The installation and operation of an own dedicated Portal Server requires a contract with us and a special, commercial license.
The software can be downloaded from https://download.realload.com
Desktop Companion Windows installer: https://download.realload.com/desktop_companion/latest_win64
Follow the links below to perform a manual installation.
Tests performed from ‘Measuring Agents’ which are virtualized or which run in a container environment measure often incorrect results. Because additional CPU and Network delays occur at virtualization/container level. It’s recommended that you use BARE-METAL-SERVERS to perform your tests. Alternatively you can also use Amazon EC2 Cloud instances.
You can place your ‘Measuring Agents’ at any location (anywhere at the internet or inside your local DMZ). Depending on which kind of traffic you have to test. Note that your Measuring Agents - usually running on TCP/IP port 8080 (HTTPS) - must be reachable form the ‘Portal Server’, and that you have to enable the corresponding inbound firewall rule.
In /etc/sysctl.conf add:
# TCP/IP Tuning
# =============
fs.file-max = 524288
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 3
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 16384 60999
net.core.somaxconn = 256
net.core.rmem_max = 1048576
net.core.wmem_max = 1048576
in /etc/security/limits.conf add:
# TCP/IP Tuning
# =============
* soft nproc 262140
* hard nproc 262140
* soft nofile 262140
* hard nofile 262140
root soft nproc 262140
root hard nproc 262140
root soft nofile 262140
root hard nofile 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=8966
if you get a value less than 262140 then add in /etc/systemd/system.conf
# Ubuntu Tuning
# =============
DefaultTasksMax=262140
Reboot the system and verify the settings. Enter: ulimit -n
output: 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=262140
sudo apt-get update
sudo apt-get install haveged
sudo ufw allow ssh
sudo ufw allow 8080/tcp
sudo ufw logging off
sudo ufw enable
Enter: sudo ufw status verbose
Status: active
Logging: off
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
8080/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
8080/tcp (v6) ALLOW IN Anywhere (v6)
wget https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz
wget https://download.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz
gunzip openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz
tar -xvf openjdk-8u41-b04-linux-x64-14_jan_2020.tar
rm openjdk-8u41-b04-linux-x64-14_jan_2020.tar
sudo bash *******
mkdir /opt/OpenJDK
mv java-se-8u41-ri /opt/OpenJDK
cd /opt/OpenJDK
ls -al
chown root -R java-se-8u41-ri
chgrp root -R java-se-8u41-ri
exit # end sudo bash
Verify the Java 8 installation.
/opt/OpenJDK/java-se-8u41-ri/bin/java -version
openjdk version "1.8.0_41"
OpenJDK Runtime Environment (build 1.8.0_41-b04)
OpenJDK 64-Bit Server VM (build 25.40-b25, mixed mode)
gunzip openjdk-11.0.1_linux-x64_bin.tar.gz
tar -xvf openjdk-11.0.1_linux-x64_bin.tar
rm openjdk-11.0.1_linux-x64_bin.tar
sudo bash
mv jdk-11.0.1 /opt/OpenJDK
cd /opt/OpenJDK
ls -al
chown root -R jdk-11.0.1
chgrp root -R jdk-11.0.1
Execute the following commands (still as sudo bash):
update-alternatives --install "/usr/bin/java" "java" "/opt/OpenJDK/jdk-11.0.1/bin/java" 1
update-alternatives --install "/usr/bin/javac" "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac" 1
update-alternatives --install "/usr/bin/keytool" "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool" 1
update-alternatives --install "/usr/bin/jar" "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar" 1
update-alternatives --set "java" "/opt/OpenJDK/jdk-11.0.1/bin/java"
update-alternatives --set "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac"
update-alternatives --set "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool"
update-alternatives --set "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar"
exit # end sudo bash
Verify the Java 11 installation.
java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)
sudo apt install openjdk-8-jre-headless
sudo apt install openjdk-8-jdk-headless
sudo apt install openjdk-11-jre-headless
sudo apt install openjdk-11-jdk-headless
Verify the Java installation.
java -version
openjdk version "11.0.10" 2021-01-19
OpenJDK Runtime Environment (build 11.0.10+9-Ubuntu-0ubuntu1.20.10)
OpenJDK 64-Bit Server VM (build 11.0.10+9-Ubuntu-0ubuntu1.20.10, mixed mode)
You only need to install powershell if you run load tests with powershell scripts.
# Install PowerShell
sudo snap install powershell --classic
# Start PowerShell
pwsh
exit
sudo apt install slim
sudo apt install ubuntu-desktop
Then reboot the machine.
sudo apt-get install xvfb
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb https://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get install google-chrome-stable
sudo adduser dkfqs # follow the questions, remember or write down the password
Login with the dkfqs account (SSH) - or - Enter: sudo -u dkfqs bash | OR: Install Samba to get convenient access to /home/dkfqs as Samba dkfqs user
Create the directory /home/dkfqs/agent (as dkfqs user):
cd /home/dkfqs
mkdir agent
Create the following sub-directories at /home/dkfqs/agent (as dkfqs user):
cd /home/dkfqs/agent
mkdir bin config internalData log scripts usersData
Copy the following files to the bin directory /home/dkfqs/agent/bin
chmod 755 chromedriver
chmod 755 geckodriver
Copy the following files to the config directory /home/dkfqs/agent/config
Modify the measuringagent.properties file. Set the following properties:
# local TCP/HTTPS data collector ports
DataCollectorPortStartRange=44444
DataCollectorPortEndRange=45000
DataCollectorPortExcludeList=
LogLevel=info
MaxLifeTimeMinutes=240
MaxWebSocketConnectTimeSeconds=14400
MaxInboundWebSocketTrafficPerConnection=67108864
MaxInboundWebSocketPayloadPerFrame=1048576
MaxInboundWebSocketFramesPerIPTimeFrame=10
MaxInboundWebSocketFramesPerIPLimit=1000
RealtimeStatisticsSamplingGranularityMillis=4000
HttpsPort=8080
HttpsCertificateCN=agent2.realload.com
HttpsCertificateIP=83.150.39.43
LogLevel=info
# AuthTokenEnabled: true or false, if true = the AuthTokenValue must be configured at portal server measuring agent settings
AuthTokenEnabled=false
# If AuthTokenEnabled is true, but AuthTokenValue is undefined or an empty string, then the (permanent) AuthTokenValue is automatically generated and printed at the log output
# AuthTokenValue=
MeasuringAgentLogFile=/home/dkfqs/agent/log/MeasuringAgent.log
MeasuringAgentInternalDataDirectory=/home/dkfqs/agent/internalData
MeasuringAgentUsersDataRootDirectory=/home/dkfqs/agent/usersData
ApiV1MaxRequestSizeMB=256
ApiV1WorkerThreadBusyTimeoutSeconds=330
ApiV1WorkerThreadExecutionTimeoutSeconds=300
MaxWebSocketConnectTimeSeconds=14400
MaxInboundWebSocketTrafficPerConnection=160000000
MaxInboundWebSocketPayloadPerFrame=80000000
MaxInboundWebSocketFramesPerIPTimeFrame=10
MaxInboundWebSocketFramesPerIPLimit=1000
DataCollectorProcessJavaPath=java
DataCollectorProcessJavaXmx=512m
DataCollectorPropertiesPath=/home/dkfqs/agent/config/datacollector.properties
# Settings for Supported Scripts / Programming Languages
PowerShellCore6Path=/snap/bin/pwsh
OpenJDK8JavaPath=/opt/OpenJDK/java-se-8u41-ri/bin/java
OpenJDK8JavaJobDefaultXmx=512m
OpenJDK11JavaPath=/opt/OpenJDK/jdk-11.0.1/bin/java
OpenJDK11JavaJobDefaultXmx=512m
# Limits
# LimitMaxUsersPerJob=500
# LimitMaxJobDurationSeconds=300
# Settings for Synthetic Monitoring
SyntheticMonitoringDataCollectorProcessJavaXmx=128m
SyntheticMonitoringOpenJDK8JavaJobXmx=256m
SyntheticMonitoringOpenJDK11JavaJobXmx=256m
SyntheticMonitoringLimitMaxUsersPerJob=5
SyntheticMonitoringLimitMaxJobDurationSeconds=300
SyntheticMonitoringLimitMaxLoopsPerUser=5
# Settings for Tests Jobs which require a (virtual) display. If VirtualDisplayPerRemoteUserIdEnabled = false then the value of DebugDisplay is used
DebugDisplay=:0.0
VirtualDisplayPerRemoteUserIdEnabled=true
VirtualDisplayType=Xvfb
XvfbPath=Xvfb
SeleniumTestJobsEnabled=true
SeleniumLimitMaxUsersPerJob=20
SeleniumWebBrowserTypesSupported=Chrome,Firefox
SeleniumChromeDriverPath=/home/dkfqs/agent/bin/chromedriver
SeleniumGeckoDriverPath=/home/dkfqs/agent/bin/geckodriver
SeleniumEdgeDriverPath=
cd /home/dkfqs/agent/bin
export CLASSPATH=bcpkix-jdk15on-160.jar:bcprov-jdk15on-160.jar:bctls-jdk15on-160.jar:DKFQSMeasuringAgent.jar
java -Xmx512m -DdkfqsMeasuringAgentProperties=../config/measuringagent.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.measuringagent.internal.StartDKFQSMeasuringAgent
Data Collector service port range from 44444 to 45000
LimitMaxUsersPerJob = unlimited
LimitMaxJobDurationSeconds = unlimited
X509 TLS server certificate generated for CN = 192.168.0.51
Internal RSA 2048 bit keypair generated in 373 ms
2021-03-11 18:20:27.947 | QAHTTPd | WARN | QAHTTPd V1.3-U started
2021-03-11 18:20:27.990 | QAHTTPd | INFO | HTTPS server starting at port 8080
2021-03-11 18:20:28.089 | QAHTTPd | INFO | HTTPS server ready at port 8080
sudo bash # become root
cd /etc/init.d
vi MeasuringAgent
Edit - create /etc/init.d/MeasuringAgent
#!/bin/sh
# /etc/init.d/MeasuringAgent
# install with: update-rc.d MeasuringAgent defaults
### BEGIN INIT INFO
# Provides: MeasuringAgent
# Required-Start: $local_fs $network $time $syslog
# Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start MeasuringAgent daemon at boot time
# Description: MeasuringAgent daemon
### END INIT INFO
case "$1" in
start)
if [ -f /home/dkfqs/agent/log/MeasuringAgent.log ]; then
mv /home/dkfqs/agent/log/MeasuringAgent.log /home/dkfqs/agent/log/MeasuringAgent.log_$(date +"%Y_%m_%d_%H_%M")
fi
sudo -H -u dkfqs bash -c 'CLASSPATH=/home/dkfqs/agent/bin/bcpkix-jdk15on-160.jar:/home/dkfqs/agent/bin/bcprov-jdk15on-160.jar:/home/dkfqs/agent/bin/bctls-jdk15on-160.jar:/home/dkfqs/agent/bin/DKFQSMeasuringAgent.jar;export CLASSPATH;nohup java -Xmx512m -DdkfqsMeasuringAgentProperties=/home/dkfqs/agent/config/measuringagent.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.measuringagent.internal.StartDKFQSMeasuringAgent -autoAdjustMemory -osReservedMemory 1GB 1>/home/dkfqs/agent/log/MeasuringAgent.log 2>&1 &'
;;
stop)
PID=`ps -o pid,args -e | grep "StartDKFQSMeasuringAgent" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "MeasuringAgent stopped with pid(s) : $PID"
kill -9 ${PID} 1> /dev/null 2>&1
fi
;;
status)
PID=`ps -o pid,args -e | grep "StartDKFQSMeasuringAgent" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "MeasuringAgent running with pid(s) : $PID"
else
echo "No MeasuringAgent running"
fi
;;
*)
echo "Usage: /etc/init.d/MeasuringAgent {start|stop|status}"
exit 1
;;
esac
exit 0
The Java memory of the Measuring Agent should be set in the startup script as shown in the table below:
OS Physical Memory | Java -Xmx setting |
---|---|
<2 GiB | 256m |
2..3 GiB | 512m |
4..7 GiB | 512m |
8..15 GiB | 1536m |
16..31 GiB | 3072m |
32..63 GiB | 4096m |
64..96 GiB | 6144m |
>96 GiB | 8192m |
Odd number of GiB should be rounded up (e.g. 7.7 = 8 = 1536m). |
Change owner and file protection of /etc/init.d/MeasuringAgent (root at /etc/init.d):
chown root MeasuringAgent
chgrp root MeasuringAgent
chmod 755 MeasuringAgent
Register /etc/init.d/MeasuringAgent to be started at system boot (root at /etc/init.d):
update-rc.d MeasuringAgent defaults
Reboot the system. Login as dkfqs and check /home/dkfqs/agent/log/MeasuringAgent.log
In terms of network technology, the cluster controller should be as close as possible to the cluster members.
The simultaneous operation of a cluster controller together with one or more measuring agents on the same machine is possible, although not recommended. This means that the cluster controller should be operated on its own machine - especially if a cluster contains more than 100 members.
The time difference of the operating system time between the cluster controller and the cluster members must not be greater than one second (1000 ms). It is recommended to use the same time server for the cluster controller and the cluster members.
The Portal Server supports the use of multiple cluster controllers. Each cluster controller can manage multiple clusters. And each measuring agent can be a member of multiple clusters.
In /etc/sysctl.conf add:
# TCP/IP Tuning
# =============
fs.file-max = 524288
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 3
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 16384 60999
net.core.somaxconn = 256
net.core.rmem_max = 1048576
net.core.wmem_max = 1048576
in /etc/security/limits.conf add:
# TCP/IP Tuning
# =============
* soft nproc 262140
* hard nproc 262140
* soft nofile 262140
* hard nofile 262140
root soft nproc 262140
root hard nproc 262140
root soft nofile 262140
root hard nofile 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=8966
if you get a value less than 262140 then add in /etc/systemd/system.conf
# Ubuntu Tuning
# =============
DefaultTasksMax=262140
Reboot the system and verify the settings. Enter: ulimit -n
output: 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=262140
sudo apt-get update
sudo apt-get install haveged
wget https://download.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz
gunzip openjdk-11.0.1_linux-x64_bin.tar.gz
tar -xvf openjdk-11.0.1_linux-x64_bin.tar
rm openjdk-11.0.1_linux-x64_bin.tar
sudo bash
mv jdk-11.0.1 /opt/OpenJDK
cd /opt/OpenJDK
ls -al
chown root -R jdk-11.0.1
chgrp root -R jdk-11.0.1
Execute the following commands (still as sudo bash):
update-alternatives --install "/usr/bin/java" "java" "/opt/OpenJDK/jdk-11.0.1/bin/java" 1
update-alternatives --install "/usr/bin/javac" "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac" 1
update-alternatives --install "/usr/bin/keytool" "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool" 1
update-alternatives --install "/usr/bin/jar" "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar" 1
update-alternatives --set "java" "/opt/OpenJDK/jdk-11.0.1/bin/java"
update-alternatives --set "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac"
update-alternatives --set "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool"
update-alternatives --set "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar"
exit # end sudo bash
Verify the Java 11 installation.
java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)
sudo adduser dkfqs # follow the questions, remember or write down the password
Login with the dkfqs account (SSH) - or - Enter: sudo -u dkfqs bash | OR: Install Samba to get convenient access to /home/dkfqs as Samba dkfqs user
Create the directory /home/dkfqs/controller (as dkfqs user):
cd /home/dkfqs
mkdir controller
Create the following sub-directories at /home/dkfqs/controller (as dkfqs user):
cd /home/dkfqs/controller
mkdir bin config internalData log scripts usersData
Copy the following files to the bin directory /home/dkfqs/controller/bin
Copy the following files to the config directory /home/dkfqs/controller/config
Modify the clustercontroller.properties file. Set the following properties:
HttpsPort=8083
HttpsCertificateCN=192.168.0.50
HttpsCertificateIP=192.168.0.50
LogLevel=info
# AuthTokenEnabled: true or false, if true = the AuthTokenValue must be configured at portal server measuring agent cluster settings
AuthTokenEnabled=true
# If AuthTokenEnabled is true, but AuthTokenValue is undefined or an empty string, then the (permanent) AuthTokenValue is automatically generated and printed at the log output
AuthTokenValue=aberaber
ClusterControllerLogFile=/home/dkfqs/controller/log/ClusterController.log
ClusterControllerInternalDataDirectory=/home/dkfqs/controller/internalData
ClusterControllerUsersDataRootDirectory=/home/dkfqs/controller/usersData
ApiMaxRequestSizeMB=256
ApiWorkerThreadBusyTimeoutSeconds=330
ApiWorkerThreadExecutionTimeoutSeconds=300
MaxWebSocketConnectTimeSeconds=14400
MaxInboundWebSocketTrafficPerConnection=83886080
MaxInboundWebSocketPayloadPerFrame=20971520
MaxInboundWebSocketFramesPerIPTimeFrame=10
MaxInboundWebSocketFramesPerIPLimit=1000
cd /home/dkfqs/controller/bin
export CLASSPATH=bcpkix-jdk15on-160.jar:bcprov-jdk15on-160.jar:bctls-jdk15on-160.jar:DKFQSMeasuringAgent.jar
java -Xmx512m -DdkfqsClusterControllerProperties=../config/clustercontroller.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.measuringagent.clustercontroller.StartDKFQSClusterController
Cluster Controller V4.0.4
Max. Memory = 512 MB
AuthTokenEnabled = true
AuthTokenValue = ********
X509 TLS server certificate generated for CN = 192.168.0.50
Internal RSA 2048 bit keypair generated in 305 ms
2022-01-29 20:45:20.118 | QAHTTPd | WARN | QAHTTPd V1.3-Y started
2022-01-29 20:45:20.219 | QAHTTPd | INFO | HTTPS server starting at port 8083
2022-01-29 20:45:20.278 | QAHTTPd | INFO | HTTPS server ready at port 8083
sudo bash # become root
cd /etc/init.d
vi ClusterController
Edit - create /etc/init.d/ClusterController
#!/bin/sh
# /etc/init.d/ClusterController
# install with: update-rc.d ClusterController defaults
### BEGIN INIT INFO
# Provides: ClusterController
# Required-Start: $local_fs $network $time $syslog
# Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start ClusterController daemon at boot time
# Description: ClusterController daemon
### END INIT INFO
case "$1" in
start)
if [ -f /home/dkfqs/controller/log/ClusterController.log ]; then
mv /home/dkfqs/controller/log/ClusterController.log /home/dkfqs/controller/log/ClusterController.log_$(date +"%Y_%m_%d_%H_%M")
fi
sudo -H -u dkfqs bash -c 'CLASSPATH=/home/dkfqs/controller/bin/bcpkix-jdk15on-160.jar:/home/dkfqs/controller/bin/bcprov-jdk15on-160.jar:/home/dkfqs/controller/bin/bctls-jdk15on-160.jar:/home/dkfqs/controller/bin/DKFQSMeasuringAgent.jar;export CLASSPATH;nohup java -Xmx6144m -DdkfqsClusterControllerProperties=/home/dkfqs/controller/config/clustercontroller.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.measuringagent.clustercontroller.StartDKFQSClusterController 1>/home/dkfqs/controller/log/ClusterController.log 2>&1 &'
;;
stop)
PID=`ps -o pid,args -e | grep "StartDKFQSClusterController" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "ClusterController stopped with pid(s) : $PID"
kill -9 ${PID} 1> /dev/null 2>&1
fi
;;
status)
PID=`ps -o pid,args -e | grep "StartDKFQSClusterController" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "ClusterController running with pid(s) : $PID"
else
echo "No ClusterController running"
fi
;;
*)
echo "Usage: /etc/init.d/ClusterController {start|stop|status}"
exit 1
;;
esac
exit 0
Change owner and file protection of /etc/init.d/ClusterController (root at /etc/init.d):
chown root ClusterController
chgrp root ClusterController
chmod 755 ClusterController
Register /etc/init.d/ClusterController to be started at system boot (root at /etc/init.d):
update-rc.d ClusterController defaults
Reboot the system. Login as dkfqs and check /home/dkfqs/controller/log/ClusterController.log
The Portal Server sends its emails via SMTP. You need an email server which receive and forward these SMTP messages.
If the Portal Server will be operated/configured in such a way that any person can “sign up” (= self registration) you need a customer account for the Twilio SMS Gateway www.twilio.com/docs/sms
In /etc/sysctl.conf add:
# TCP/IP Tuning
# =============
fs.file-max = 524288
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 3
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 16384 60999
net.core.somaxconn = 256
net.core.rmem_max = 1048576
net.core.wmem_max = 1048576
In /etc/security/limits.conf add:
# TCP/IP Tuning
# =============
* soft nproc 262140
* hard nproc 262140
* soft nofile 262140
* hard nofile 262140
root soft nproc 262140
root hard nproc 262140
root soft nofile 262140
root hard nofile 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=8966
if you get a value less than 262140 then add in /etc/systemd/system.conf
# Ubuntu Tuning
# =============
DefaultTasksMax=262140
Reboot the system and verify the settings. Enter: ulimit -n
output: 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=262140
Create/edit the file DKFQSiptables in /etc/network/if-pre-up.d/ and add:
#!/bin/sh
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8000
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j REDIRECT --to-ports 8000
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8001
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 443 -j REDIRECT --to-ports 8001
exit 0
Then give execute permission to /etc/network/if-pre-up.d/DKFQSiptables : sudo chmod 755 /etc/network/if-pre-up.d/DKFQSiptables
Reboot the machine and check with:
sudo iptables -L -t nat
> Chain PREROUTING (policy ACCEPT)
> target prot opt source destination
> REDIRECT tcp -- anywhere anywhere tcp dpt:http redir ports 8000
> REDIRECT tcp -- anywhere anywhere tcp dpt:https redir ports 8001
> REDIRECT tcp -- anywhere anywhere tcp dpt:http redir ports 8000
> REDIRECT tcp -- anywhere anywhere tcp dpt:https redir ports 8001
>
> Chain INPUT (policy ACCEPT)
> target prot opt source destination
>
> Chain OUTPUT (policy ACCEPT)
> target prot opt source destination
> REDIRECT tcp -- anywhere localhost tcp dpt:https redir ports 8001
> REDIRECT tcp -- anywhere localhost tcp dpt:http redir ports 8000
> REDIRECT tcp -- anywhere localhost tcp dpt:https redir ports 8001
> REDIRECT tcp -- anywhere localhost tcp dpt:http redir ports 8000
>
> Chain POSTROUTING (policy ACCEPT)
> target prot opt source destination
sudo apt-get update
sudo apt-get install fontconfig
sudo apt-get update
sudo apt-get install haveged
sudo apt-get update
sudo apt install sqlite
wget https://download.java.net/openjdk/jdk8u41/ri/openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz
wget https://download.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz
gunzip openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz
tar -xvf openjdk-8u41-b04-linux-x64-14_jan_2020.tar
rm openjdk-8u41-b04-linux-x64-14_jan_2020.tar
sudo bash *******
mkdir /opt/OpenJDK
mv java-se-8u41-ri /opt/OpenJDK
cd /opt/OpenJDK
ls -al
chown root -R java-se-8u41-ri
chgrp root -R java-se-8u41-ri
exit # end sudo bash
Verify the Java 8 installation.
/opt/OpenJDK/java-se-8u41-ri/bin/java -version
openjdk version "1.8.0_41"
OpenJDK Runtime Environment (build 1.8.0_41-b04)
OpenJDK 64-Bit Server VM (build 25.40-b25, mixed mode)
gunzip openjdk-11.0.1_linux-x64_bin.tar.gz
tar -xvf openjdk-11.0.1_linux-x64_bin.tar
rm openjdk-11.0.1_linux-x64_bin.tar
sudo bash
mv jdk-11.0.1 /opt/OpenJDK
cd /opt/OpenJDK
ls -al
chown root -R jdk-11.0.1
chgrp root -R jdk-11.0.1
Execute the following commands (still as sudo bash):
update-alternatives --install "/usr/bin/java" "java" "/opt/OpenJDK/jdk-11.0.1/bin/java" 1
update-alternatives --install "/usr/bin/javac" "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac" 1
update-alternatives --install "/usr/bin/keytool" "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool" 1
update-alternatives --install "/usr/bin/jar" "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar" 1
update-alternatives --set "java" "/opt/OpenJDK/jdk-11.0.1/bin/java"
update-alternatives --set "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac"
update-alternatives --set "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool"
update-alternatives --set "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar"
exit # end sudo bash
Verify the Java 11 installation.
java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)
sudo adduser dkfqs # follow the questions, remember or write down the password
Login with the dkfqs account (SSH) - or - Enter: sudo -u dkfqs bash | OR: Install Samba to get convenient access to /home/dkfqs as Samba dkfqs user
Create the directory /home/dkfqs/portal (as dkfqs user):
cd /home/dkfqs
mkdir portal
Create the following sub-directories at /home/dkfqs/agent (as dkfqs user):
cd /home/dkfqs/portal
mkdir backup bin config db developerExamples htdocs javaUsersLib jks log reportTemplate scripts temp usersLib usersData
Copy the following files to the bin directory /home/dkfqs/portal/bin
Copy the following files to the db directory /home/dkfqs/portal/db
Edit the file CreateNewUsersDB.sql and modify the following line to set the nickname, the email, the phone number and the temporary password of the Admin account. Note: The nickname must always start with “Admin-”
insert into AdminAccountsTable (adminUserId, nickname, adminPrimaryEmail, adminPrimaryPhone, initialPassword) values (1, "Admin-One", "falarasorn@yahoo.com", "+43123456789", "ginkao1234");
Navigate to /home/dkfqs/portal/db and create the Admin, Operations and the Users DB (as dkfqs user):
sqlite3 AdminAccounts.db < CreateNewAdminDB.sql
sqlite3 Monitoring.db < CreateNewMonitoringDB.sql
sqlite3 Operations.db < CreateNewOperationsDB.sql
sqlite3 Users.db < CreateNewUsersDB.sql
Copy the following file to the htdocs directory /home/dkfqs/portal/htdocs
Navigate to /home/dkfqs/portal/htdocs and execute (as dkfqs user):
jar -xvf htdocs.jar
rm htdocs.jar # delete the jar)
rm -R META-INF # delete the META-INF directory)
Copy the following files to the javaUsersLib directory /home/dkfqs/portal/javaUsersLib
Copy the following file to the jks directory /home/dkfqs/portal/jks
Copy the following files to the usersLib directory /home/dkfqs/portal/usersLib
Copy the following files to the bin directory /home/dkfqs/portal/reportTemplate
Copy the following files to the bin directory /home/dkfqs/portal/config
Modify the dkfqs.properties file. Set the following properties:
Example: dkfqs.properties
IsProduction=true
ServerName=192.168.0.50
ServerDNSName=192.168.0.50
DiskDocumentRootDirectory=/home/dkfqs/portal/htdocs
SQLiteDBDirectory=/home/dkfqs/portal/db
ReportTemplateDirectory=/home/dkfqs/portal/reportTemplate/
JasperReportsTemporaryDirectory=/home/dkfqs/portal/temp/
UsersDataRootDirectory=/home/dkfqs/portal/usersData
OSProcessLogFile=/home/dkfqs/portal/log/DKFQS.log
LogLevel=info
StaticContentMaxAgeTime=7200
MaxHTTPRequestSize=20240000
MaxInvalidAnonymousSessionsPerIPLimit=32
AnonymousSessionTimeout=1200
MaxAnonymousSessionTime=21600
MaxWebSocketConnectTimeSeconds=14400
MaxInboundWebSocketTrafficPerConnection=67108864
MaxInboundWebSocketPayloadPerFrame=1048576
MaxInboundWebSocketFramesPerIPTimeFrame=10
MaxInboundWebSocketFramesPerIPLimit=1000
HTTPExternalServerPort=80
HTTPInternalServerPort=8000
HTTPSExternalServerPort=443
HTTPSInternalServerPort=8001
HTTPSKeyStoreFile=/home/dkfqs/portal/jks/dkfqscom.jks
HTTPSKeyStorePassword=topsecret
#
FileTreeApiMaxRequestSizeMB=256
FileTreeApiWorkerThreadBusyTimeoutSeconds=330
FileTreeApiWorkerThreadExecutionTimeoutSeconds=300
TestjobsApiMaxRequestSizeMB=256
TestjobsApiWorkerThreadBusyTimeoutSeconds=330
TestjobsApiWorkerThreadExecutionTimeoutSeconds=300
#
DNSJavaDefaultDNSServers=8.8.8.8,8.8.4.4
#
JavaSDK8BinaryPath=/opt/OpenJDK/java-se-8u41-ri/bin
JavaSDK11BinaryPath=/opt/OpenJDK/jdk-11.0.1/bin
HTTPTestWizardJavaCodeLibraries=/home/dkfqs/portal/usersLib/com.dkfqs.tools.jar
#
UserSignInURL=/SignIn
UsersMailServerHost=192.168.1.4
UsersMailFrom=xxxxxxxxx@xxxxxxx.com
UsersMailServerAuthUser=xxxxxxxxx@xxxxxxx.com
UsersMailServerAuthPassword=*********
UsersMailTransmitterThreads=2
UsersMailDebugSMTP=false
#
smsGatewaysClassNames=com.dkfqs.server.sms.twilio.TwilioSMSGateway
#
# ServerStatusPageEnabledIPList=127.0.0.1,192.168.0.99
ServerStatusPageEnabledIPList=*.*.*.*
AdminSignInURL=/AdminSignIn
AlertMailEnabled=true
AlertMailServerHost=192.168.1.4
AlertMailFrom=xxxxxxxxx@xxxxxxx.com
AlertMailToList=yyyyyyyyy@xxxxxxx.com,zzzzzzzzz@xxxxxxx.com
AlertMailBounceAddress=bbbbbbb@xxxxxxx.com
AlertMailServerAuthUser=xxxxxxxxx@xxxxxxx.com
AlertMailServerAuthPassword=*******
AlertMailDebugSMTP=false
AlertMailNotifyStartup=false
SecurityMaxRequestsPerIpLimit=200
SecurityMaxRequestsPerIpTimeFrame=10
SecurityMaxInvalidRequestsPerIpLimit=12
SecurityMaxInvalidRequestsPerIpTimeFrame=60
SecurityMaxAnonymousFormSubmitPerIpLimit=8
SecurityMaxAnonymousFormSubmitPerIpTimeFrame=60
SecurityMaxAuthenticationFailuresPerIpLimit=5
SecurityMaxAuthenticationFailuresPerIpTimeFrame=60
#
MeasuringAgentConnectTimeout=10
# Support of license provider 'Real Load Pty Ltd / nopCommerce', if enabled then the LicenseProviderRealLoadPtyLtdNopCommerceCARootFileName is located in the config directory of the portal server
LicenseProviderRealLoadPtyLtdNopCommerceEnabled=true
LicenseProviderRealLoadPtyLtdNopCommerceCARootFileName=nopCommerceCARoot.pem
# Synthetic Monitoring settings
MonitoringJobSchedulerMainThreadIntervalSeconds=10
MonitoringJobSchedulerInitialDBLogLevel=warn
MonitoringJobSchedulerInitialStdoutLogLevel=info
MonitoringJobSchedulerInitialUserFileLogLevel=info
MonitoringGroupThreadsStartDelayMillis=1000
# Support for compiling Junit and Selenium Tests
JavaUsersLibDirectory=/home/dkfqs/portal/javaUsersLib
JavaJUnit4CompilerLibraries=hamcrest-core-1.3.jar,junit-4.13.2.jar
JavaJUnit4TestExecutionLibraries=com.dkfqs.selenium.jar,com.dkfqs.tools.jar,commons-io-2.13.0.jar,hamcrest-core-1.3.jar,junit-4.13.2.jar
JavaSelenium4CompilerLibraries=hamcrest-core-1.3.jar,junit-4.13.2.jar,selenium_bundle-4.12.1.jar,com.dkfqs.selenium.jar
JavaSelenium4TestExecutionLibraries=selenium_bundle-4.12.1.jar,com.dkfqs.selenium.jar,com.dkfqs.tools.jar,commons-io-2.13.0.jar,hamcrest-core-1.3.jar,junit-4.13.2.jar
Modify the twilio.properties file. Set the following properties:
Example: twilio.properties
apiURLMainPath=https://api.twilio.com/2010-04-01/Accounts/
sid=********************************
authToken=********************************
fromTwilioPhoneNumber=+1123456789
fromTwilioAlphanumericSenderID=RealLoad
tcpConnectTimoutMillis=10000
sslHandshakeTimeoutMillis=5000
httpProcessingTimeoutMillis=10000
debugAPI=false
cd /home/dkfqs/portal/bin
export CLASSPATH=bcpkix-jdk15on-160.jar:bcprov-jdk15on-160.jar:bctls-jdk15on-160.jar:DKFQS.jar
java -Xmx2048m -DdkfqsProperties=../config/dkfqs.properties -DrewriteProperties=../config/rewrite.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.server.internal.StartDKFQSserver
Internal RSA 2048 bit keypair generated in 1220 ms
2021-03-10 22:27:25.040 | QAHTTPd | INFO | SQL connection pool for DB "UsersDB" initialized
2021-03-10 22:27:25.062 | QAHTTPd | INFO | SQL connection pool for DB "AdminAccountsDB" initialized
2021-03-10 22:27:25.068 | QAHTTPd | INFO | Alarm adapter "IP Blacklist Alarm Adapter" started
2021-03-10 22:27:25.069 | QAHTTPd | WARN | QAHTTPd V1.3-U started
2021-03-10 22:27:25.071 | QAHTTPd | INFO | Execute PreUpStartupLoadIPRangeBlacklist
2021-03-10 22:27:25.082 | QAHTTPd | INFO | HTTP server starting at port 8000
2021-03-10 22:27:25.109 | QAHTTPd | INFO | HTTP server ready at port 8000
2021-03-10 22:27:25.110 | QAHTTPd | INFO | HTTPS server starting at port 8001
2021-03-10 22:27:25.124 | QAHTTPd | INFO | HTTPS server ready at port 8001
2021-03-10 22:27:25.821 | EMAIL-1 | INFO | Email transmitter thread started
2021-03-10 22:27:25.822 | EMAIL-2 | INFO | Email transmitter thread started
2021-03-10 22:27:25.828 | main | INFO | Twilio SMS Gateway registered
2021-03-10 22:27:25.853 | main | INFO | Twilio SMS Gateway initialized
2021-03-10 22:27:25.857 | SMS-Dispatcher | INFO | Thread started
sudo bash # become root
cd /etc/init.d
vi DKFQS
Edit - create /etc/init.d/DKFQS
#!/bin/sh
# /etc/init.d/DKFQS
# install with: update-rc.d DKFQS defaults
### BEGIN INIT INFO
# Provides: DKFQS
# Required-Start: $local_fs $network $time $syslog
# Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start DKFQS daemon at boot time
# Description: DKFQS daemon
### END INIT INFO
case "$1" in
start)
if [ -f /home/dkfqs/portal/log/DKFQS.log ]; then
mv /home/dkfqs/portal/log/DKFQS.log /home/dkfqs/portal/log/DKFQS.log_$(date +"%Y_%m_%d_%H_%M")
fi
sudo -H -u dkfqs bash -c 'CLASSPATH=/home/dkfqs/portal/bin/bcpkix-jdk15on-160.jar:/home/dkfqs/portal/bin/bcprov-jdk15on-160.jar:/home/dkfqs/portal/bin/bctls-jdk15on-160.jar:/home/dkfqs/portal/bin/jasperreports-fonts-6.20.5.jar:/home/dkfqs/portal/bin/DKFQS.jar;export CLASSPATH;cd /home/dkfqs/portal/temp;nohup java -Xmx3072m -DdkfqsProperties=/home/dkfqs/portal/config/dkfqs.properties -DrewriteProperties=/home/dkfqs/portal/config/rewrite.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.server.internal.StartDKFQSserver 1>/home/dkfqs/portal/log/DKFQS.log 2>&1 &'
;;
stop)
PID=`ps -o pid,args -e | grep "StartDKFQSserver" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "DKFQS stopped with pid(s) : $PID"
kill -9 ${PID} 1> /dev/null 2>&1
fi
;;
status)
PID=`ps -o pid,args -e | grep "StartDKFQSserver" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "DKFQS running with pid(s) : $PID"
else
echo "No DKFQS running"
fi
;;
*)
echo "Usage: /etc/init.d/DKFQS {start|stop|status}"
exit 1
;;
esac
exit 0
Change owner and file protection of /etc/init.d/DKFQS (root at /etc/init.d):
chown root DKFQS
chgrp root DKFQS
chmod 755 DKFQS
Register /etc/init.d/DKFQS to be started at system boot (root at /etc/init.d):
update-rc.d DKFQS defaults
Reboot the system. Then check /home/dkfqs/portal/log/DKFQS.log
Enter in your browser https://admin-portal-host/admin .
You will get a browser warning because the SSL server certificate is expired. Ignore the warning and enter in the Sign In the email address and the password as you have set in CreateNewAdminDB.sql.
You will now asked to set a new password. Then you are signed in.
Disable Sign Up if you don’t have an SMS gateway:
User accounts can be added directly:
If you or your company can already issue SSL server certificates you can skip the next sub-chapter. Continue in such a case with “Convert and Install the SSL Server Certificate”.
Make sure that your portal server has a public, valid DNS name.
Install certbot:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Stop the Portal Server:
sudo /etc/init.d/DKFQS stop
To get the SSL server certificate enter:
sudo certbot certonly --standalone # enter your email address and the DNS name ou your portal server, follow the instructions
On success certbot generates the following two files:
Start the Portal Server:
sudo /etc/init.d/DKFQS start
Become root and navigate to the directory where the fullchain.pem and privkey.pem files are located. Enter:
sudo bash
openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out your-certificate-name.p12 # convert cert to PKCS12 file
keytool -importkeystore -srckeystore your-certificate-name.p12 -srcstoretype PKCS12 -destkeystore your-certificate-name.jks -deststoretype JKS # convert PKCS12 file to Java keystore file
Copy the Java keystore file to /home/dkfqs/portal/jks
cp your-certificate-name.jks /home/dkfqs/portal/jks
Edit /home/dkfqs/portal/config/dkfqs.properties and replace:
HTTPSKeyStoreFile=/home/dkfqs/portal/jks/your-certificate-name.jks
HTTPSKeyStorePassword=*********
Restart the Portal Server
sudo /etc/init.d/DKFQS stop
sudo /etc/init.d/DKFQS start
Create at your home directory the sub-directory system_cronjobs_scripts and add/edit the file “DKFQS_certbot_renew” in this directory. Replace the ********* placeholders with your real values.
#!/bin/sh
#
# renew the letsencrypt DKFQS certificate
# =======================================
certbot renew
#
# set the default working directory
cd /home/*********/system_cronjobs_scripts
#
# cleanup in any case
rm -f *.jks
rm -f *.p12
#
# convert the letsencrypt certificate to PKCS12 and place it in the default directory
openssl pkcs12 -export -in /etc/letsencrypt/live/*********/fullchain.pem -inkey /etc/letsencrypt/live/*********/privkey.pem -out ./*********.p12 -passin pass:******** -passout pass:********
#
# convert the PKCS12 certificate to a Java keystore
echo ******** | keytool -importkeystore -srckeystore *********.p12 -srcstoretype PKCS12 -destkeystore *********.jks -deststoretype JKS -storepass ********
#
# update DKFQS keystore file
cp *********.jks /home/dkfqs/portal/jks
chown dkfqs /home/dkfqs/portal/jks/*********.jks
chgrp dkfqs /home/dkfqs/portal/jks/*********.jks
chmod 600 /home/dkfqs/portal/jks/*********.jks
#
# restart DKFQS server
/etc/init.d/DKFQS stop
sleep 5
sudo /etc/init.d/DKFQS start
#
# cleanup again in any case
rm -f *.jks
rm -f *.p12
#
# display DKFQS log file
sleep 5
cat /home/dkfqs/portal/log/DKFQS.log
#
# all done
exit 0
sudo bash # become root
chmod 700 DKFQS_certbot_renew # change file protection and set execute bit
./DKFQS_certbot_renew # try out manually
Add the file to crontab. Important: The last line in crontab must be an empty line!
sudo crontab -e
1 1 1 * * /home/*********/system_cronjobs_scripts/DKFQS_certbot_renew > /home/*********/system_cronjobs_scripts/DKFQS_certbot_renew.log 2>&1
The Remote Proxy Recorder can be placed at any network location, but the control port must be reachable from the Portal Server.
In /etc/sysctl.conf add:
# TCP/IP Tuning
# =============
fs.file-max = 524288
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 3
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 16384 60999
net.core.somaxconn = 256
net.core.rmem_max = 1048576
net.core.wmem_max = 1048576
in /etc/security/limits.conf add:
# TCP/IP Tuning
# =============
* soft nproc 262140
* hard nproc 262140
* soft nofile 262140
* hard nofile 262140
root soft nproc 262140
root hard nproc 262140
root soft nofile 262140
root hard nofile 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=8966
if you get a value less than 262140 then add in /etc/systemd/system.conf
# Ubuntu Tuning
# =============
DefaultTasksMax=262140
Reboot the system and verify the settings. Enter: ulimit -n
output: 262140
Enter: systemctl show -p TasksMax user-0
output: TasksMax=262140
sudo apt-get update
sudo apt-get install haveged
wget https://download.java.net/java/GA/jdk11/13/GPL/openjdk-11.0.1_linux-x64_bin.tar.gz
gunzip openjdk-11.0.1_linux-x64_bin.tar.gz
tar -xvf openjdk-11.0.1_linux-x64_bin.tar
rm openjdk-11.0.1_linux-x64_bin.tar
sudo bash
mv jdk-11.0.1 /opt/OpenJDK
cd /opt/OpenJDK
ls -al
chown root -R jdk-11.0.1
chgrp root -R jdk-11.0.1
Execute the following commands (still as sudo bash):
update-alternatives --install "/usr/bin/java" "java" "/opt/OpenJDK/jdk-11.0.1/bin/java" 1
update-alternatives --install "/usr/bin/javac" "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac" 1
update-alternatives --install "/usr/bin/keytool" "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool" 1
update-alternatives --install "/usr/bin/jar" "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar" 1
update-alternatives --set "java" "/opt/OpenJDK/jdk-11.0.1/bin/java"
update-alternatives --set "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac"
update-alternatives --set "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool"
update-alternatives --set "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar"
exit # end sudo bash
Verify the Java 11 installation.
java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)
For technical reasons, the Remote Proxy Recorder generates “fake” web server certificates during operation in order to break the encryption between the web browser and the web servers and to record the data exchanged.
In order for this to work, the Remote Proxy Recorder needs its own CA root certificate, which you then have to import into your browser.
Thus for security reasons, never use a CA root certificate from us or someone else for the Remote Proxy Recorder root certificate. Always create your own CA root certificate.
Example:
C:\Scratch2>openssl genrsa -des3 -out myCAPrivate.key 2048
Generating RSA private key, 2048 bit long modulus
.......................+++
.............................+++
unable to write 'random state'
e is 65537 (0x10001)
Enter pass phrase for myCAPrivate.key:
Verifying - Enter pass phrase for myCAPrivate.key:
C:\Scratch2>openssl pkcs8 -topk8 -inform PEM -outform PEM -in myCAPrivate.key -out myCAPrivateKey.pem -nocrypt
Enter pass phrase for myCAPrivate.key:
C:\Scratch2>openssl req -x509 -new -nodes -key myCAPrivate.key -sha256 -days 3700 -out myCARootCert.pem
Enter pass phrase for myCAPrivate.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CH
State or Province Name (full name) [Some-State]:Bern
Locality Name (eg, city) []:Bern
Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Pty Ltd
Organizational Unit Name (eg, section) []:QA
Common Name (e.g. server FQDN or YOUR name) []:DKFQS Proxy Recorder Root
Email Address []:
C:\Scratch2>dir
Volume in drive C is OS
Volume Serial Number is AEF7-CFB1
Directory of C:\Scratch2
06 Feb 2022 20:44 <DIR> .
06 Feb 2022 20:44 <DIR> ..
06 Feb 2022 20:40 1.743 myCAPrivate.key
06 Feb 2022 20:41 1.704 myCAPrivateKey.pem
06 Feb 2022 20:44 1.350 myCARootCert.pem
3 File(s) 4.797 bytes
2 Dir(s) 310.772.580.352 bytes free
sudo adduser dkfqs # follow the questions, remember or write down the password
Login with the dkfqs account (SSH) - or - Enter: sudo -u dkfqs bash | OR: Install Samba to get convenient access to /home/dkfqs as Samba dkfqs user
Create the directory /home/dkfqs/proxy (as dkfqs user):
cd /home/dkfqs
mkdir proxy
Create the following sub-directories at /home/dkfqs/proxy (as dkfqs user):
cd /home/dkfqs/proxy
mkdir bin config log
Copy the following files to the bin directory /home/dkfqs/proxy/bin
Copy the following files to the config directory /home/dkfqs/proxy/config
Modify the config.properties file. Set (modify) the following properties:
ControlServerLogLevel=info
ControlServerHttpsPort=8081
ControlServerHttpsCertificateCN=proxy2.realload.com
ControlServerHttpsCertificateIP=83.150.39.45
#Note: the control server authentication token is required to connect to the control server
ControlServerAuthToken=krungthep
ProxyServerLogLevel=warn
ProxyServerPort=8082
ProxyServerDefaultCaRootCertFilePath=/home/dkfqs/proxy/config/myCARootCert.pem
ProxyServerDefaultCaRootPrivateKeyFilePath=/home/dkfqs/proxy/config/myCAPrivateKey.pem
#Note: the proxy authentication credentials are replaced on the fly when the portal user connects via the control interface to the control server
ProxyServerDefaultAuthenticationUsername=max
ProxyServerDefaultAuthenticationPassword=meier
cd /home/dkfqs/proxy/bin
export CLASSPATH=bcmail-jdk15on-168.jar:bcpg-jdk15on-168.jar:bcpkix-jdk15on-168.jar:bcprov-jdk15on-168.jar:bctls-jdk15on-168.jar:com.dkfqs.remoteproxyrecorder.jar
java -Xmx2048m -DconfigProperties=../config/config.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.remoteproxyrecorder.main.StartRemoteProxyRecorder
> Remote Proxy Recorder V0.2.0
> Max. Memory = 2048 MB
> Internal RSA 2048 bit keypair generated in 85 ms
> 2021-06-05 23:24:37.710 | QAHTTPd | WARN | QAHTTPd V1.3-V started
> 2021-06-05 23:24:37.710 | QAHTTPd | INFO | HTTPS server starting at port 8081
> 2021-06-05 23:24:37.726 | QAHTTPd | INFO | HTTPS server ready at port 8081
> 2021-06-05 23:24:38.722 | Proxy | WARN | ProxyRecorder V1.1.0 started at port 8082
sudo bash # become root
cd /etc/init.d
vi RemoteProxyRecorder
Edit - create /etc/init.d/RemoteProxyRecorder
#!/bin/sh
# /etc/init.d/RemoteProxyRecorder
# install with: update-rc.d RemoteProxyRecorder defaults
### BEGIN INIT INFO
# Provides: RemoteProxyRecorder
# Required-Start: $local_fs $network $time $syslog
# Required-Stop: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start RemoteProxyRecorder daemon at boot time
# Description: RemoteProxyRecorder daemon
### END INIT INFO
case "$1" in
start)
if [ -f /home/dkfqs/proxy/log/RemoteProxyRecorder.log ]; then
mv /home/dkfqs/proxy/log/RemoteProxyRecorder.log /home/dkfqs/proxy/log/RemoteProxyRecorder.log_$(date +"%Y_%m_%d_%H_%M")
fi
sudo -H -u dkfqs bash -c 'CLASSPATH=/home/dkfqs/proxy/bin/bcmail-jdk15on-168.jar:/home/dkfqs/proxy/bin/bcpg-jdk15on-168.jar:/home/dkfqs/proxy/bin/bcpkix-jdk15on-168.jar:/home/dkfqs/proxy/bin/bcprov-jdk15on-168.jar:/home/dkfqs/proxy/bin/bctls-jdk15on-168.jar:/home/dkfqs/proxy/bin/com.dkfqs.remoteproxyrecorder.jar;export CLASSPATH;nohup java -Xmx4096m -DconfigProperties=/home/dkfqs/proxy/config/config.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.remoteproxyrecorder.main.StartRemoteProxyRecorder 1>/home/dkfqs/proxy/log/RemoteProxyRecorder.log 2>&1 &'
;;
stop)
PID=`ps -o pid,args -e | grep "StartRemoteProxyRecorder" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "RemoteProxyRecorder stopped with pid(s) : $PID"
kill -9 ${PID} 1> /dev/null 2>&1
fi
;;
status)
PID=`ps -o pid,args -e | grep "StartRemoteProxyRecorder" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "RemoteProxyRecorder running with pid(s) : $PID"
else
echo "No RemoteProxyRecorder running"
fi
;;
*)
echo "Usage: /etc/init.d/RemoteProxyRecorder {start|stop|status}"
exit 1
;;
esac
exit 0
Change owner and file protection of /etc/init.d/RemoteProxyRecorder (root at /etc/init.d):
chown root RemoteProxyRecorder
chgrp root RemoteProxyRecorder
chmod 755 RemoteProxyRecorder
Register /etc/init.d/RemoteProxyRecorder to be started at system boot (root at /etc/init.d):
update-rc.d RemoteProxyRecorder defaults
Reboot the system. Login as dkfqs and check /home/dkfqs/proxy/log/RemoteProxyRecorder.log
Install Centos 8 minimal server.
Disable SELinux in /etc/selinux/config
Open ports 443 and 80 on firewall:
firewall-cmd --zone=public --add-service=http
firewall-cmd --zone=public --add-service=https
firewall-cmd --zone=public --permanent --add-service=http
firewall-cmd --zone=public --permanent --add-service=https
firewall-cmd --reload
In /etc/sysctl.conf add:
# TCP/IP Tuning
# =============
fs.file-max = 524288
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 3
net.ipv4.tcp_max_orphans = 65536
net.ipv4.tcp_fin_timeout = 30
net.ipv4.ip_local_port_range = 16384 60999
net.core.somaxconn = 256
net.core.rmem_max = 1048576
net.core.wmem_max = 1048576
in /etc/security/limits.conf add:
# TCP/IP Tuning
# =============
* soft nproc 262140
* hard nproc 262140
* soft nofile 262140
* hard nofile 262140
root soft nproc 262140
root hard nproc 262140
root soft nofile 262140
root hard nofile 262140
Reboot system and check with ulimit -n : The output should be 262140
sudo yum update
yum install sqlite
yum -y install epel-release
yum repolist
yum install haveged
yum install unzip
yum install tar
Download OpenJDK 11 and 8 (TODO: URLs) and then:
cd /opt/OpenJDK
tar xzvf openjdk-11.0.1_linux-x64_bin.tar.gz
update-alternatives --install "/usr/bin/java" "java" "/opt/OpenJDK/jdk-11.0.1/bin/java" 1
update-alternatives --install "/usr/bin/javac" "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac" 1
update-alternatives --install "/usr/bin/keytool" "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool" 1
update-alternatives --install "/usr/bin/jar" "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar" 1
update-alternatives --set "java" "/opt/OpenJDK/jdk-11.0.1/bin/java"
update-alternatives --set "javac" "/opt/OpenJDK/jdk-11.0.1/bin/javac"
update-alternatives --set "keytool" "/opt/OpenJDK/jdk-11.0.1/bin/keytool"
update-alternatives --set "jar" "/opt/OpenJDK/jdk-11.0.1/bin/jar"
tar xzvf openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz
Java installation validation steps
java -version
openjdk version "11.0.1" 2018-10-16/
opt/OpenJDK/java-se-8u41-ri/bin/java -version
openjdk version "1.8.0_41"
sudo adduser -m dkfqs
su - dkfqs
cd /home/dkfqs
mkdir portal
cd /home/dkfqs/portal
mkdir backup bin config db htdocs jks log scripts usersLib usersData
cp /opt/install_sw/Common/*.jar /home/dkfqs/portal/bin/
cp /opt/install_sw/V4.2.11/PortalServer/bin/DKFQS.jar /home/dkfqs/portal/bin/
cp /opt/install_sw/V4.2.11/PortalServer/config/* /home/dkfqs/portal/config/
Copy the htdocs.jar file to the htdocs directory /home/dkfqs/portal/htdocs
Navigate to /home/dkfqs/portal/htdocs and un-jar the file:
jar -xvf htdocs.jar
rm htdocs.jar (and delete the jar)
rm -R META-INF (delete the META-INF directory)
Copy the following files to the db directory /home/dkfqs/portal/db
Login with the dkfqs account, navigate to /home/dkfqs/portal/db and create the Admin, Operations and the Users DB:
sqlite3 AdminAccounts.db < CreateNewAdminDB.sql
sqlite3 Operations.db < CreateNewOperationsDB.sql
sqlite3 Users.db < CreateNewUsersDB.sql
Allow un-privileged accounts to bind to privileged ports (80, 443)
sysctl net.ipv4.ip_unprivileged_port_start=0
Create the /home/dkfqs/portal/bin/portal.sh file:
#!/usr/bin/bash
case "$1" in
start)
if [ -f /home/dkfqs/portal/log/DKFQS.log ]; then
mv /home/dkfqs/portal/log/DKFQS.log /home/dkfqs/portal/log/DKFQS.log_$(date +"%Y_%m_%d_%H_%M")
fi
CLASSPATH=/home/dkfqs/portal/bin/bcpkix-jdk15on-160.jar:/home/dkfqs/portal/bin/bcprov-jdk15on-160.jar:/home/dkfqs/portal/bin/bctls-jdk15on-160.jar:/home/dkfqs/portal/bin/DKFQS.jar;export CLASSPATH;nohup java -Xmx2048m -DdkfqsProperties=/home/dkfqs/portal/config/dkfqs.properties -DrewriteProperties=/hom
e/dkfqs/portal/config/rewrite.properties -Dnashorn.args="--no-deprecation-warning" com.dkfqs.server.internal.StartDKFQSserver 1>/home/dkfqs/portal/log/DKFQS.log 2>&1 &
;;
stop)
PID=`ps -o pid,args -e | grep "StartDKFQSserver" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "DKFQS stopped with pid(s) : $PID"
kill -9 ${PID} 1> /dev/null 2>&1
fi
;;
status)
PID=`ps -o pid,args -e | grep "StartDKFQSserver" | egrep -v grep | awk '{print $1}'`
if [ ! -z "$PID" ] ; then
echo "DKFQS running with pid(s) : $PID"
else
echo "No DKFQS running"
fi
;;
*)
echo "Usage: /etc/init.d/DKFQS {start|stop|status}"
exit 1
;;
esac
exit 0
Create the file /etc/systemd/system/DKFQSPortal.service with the below content:
[Unit]
Description=DKFQS portal
After=network.target
[Service]
User=dkfqs
Group=dkfqs
Type=simple
RemainAfterExit=yes
ExecStart=/home/dkfqs/portal/bin/portal.sh start
ExecStop=/home/dkfqs/portal/bin/portal.sh stop
TimeoutStartSec=0
[Install]
WantedBy=default.target
systemctl daemon-reload
systemctl enable DKFQSPortal.service
systemctl start DKFQSPortal.service
journalctl -ex (... to check that no errors occured..)
Thank you for using the Real Load product.
On this first page of the user guide you will learn:
After you have signed in to the portal server, you will see a navigation bar whose first menu on the left is Projects. This is a file browser that displays all of your files. The view is divided into Projects and Resource Sets which contain the files for executing your tests and the measured test results. You can also store additional files in a Resource Set which contain e.g. instructions on how a test should be performed.
Among other things, you can:
There is also a recycle bin from which you can restore deleted projects, resources sets and files.
Tests can be created in a number of different ways. You can even develop test programs from scratch that measure anything and use any protocol.
To keep it simple in the first step, we introduce the “HTTP Test Wizard”, with which you can easily define HTTP/S sessions and run them as tests.
You now have an empty session to which you can add HTTP requests (URL calls).
Now add one or more URLs to the test. If you want to subdivide the URLs into individual groups, first add a “Measuring Group”, then add the associated URLs and then again, add the next “Measuring Group” with the corresponding URLs.
If you define a “Measuring Group”, the (separately measured) response time of the group is measured overall URLs of the group.
Entering a URL is easy. Select the HTTP method (GET, POST, …) and enter the absolute URL. If you want to execute an HTTP POST method, first select the requests content type and then enter the data of the post request. Finally click at the “Add URL” button at the bottom of the dialog.
After you’ve created the test, it looks similar to this:
Save the test again (save session) and then debug the test.
In order to debug a test, at least one “Measuring Agent” must be available. This is because it is a remote debugger.
If you click on “Debug Session”, the test is automatically transmitted to one of your measuring agents and the debugger is started. If you have registered several measuring agents, you can select in the debugger at the top right on which measuring agent the debug session will be executed.
During debugging, please pay close attention to the HTTP status code you get from the URLs. For example, if you receive a 404 status code (not found), you have probably entered a faulty url. In such a case, cancel the debug session, correct the URL and then start the debugger once again.
As you may have already noticed, the HTTP status code of the URLs has not yet been checked by the debugger. Return to the HTTP Session Wizard and configure the corresponding HTTP status code for each URL (section “Verify HTTP Response”). Don’t forget to click at the “Modify URL” button at the bottom of the dialog.
Debug your test one last time and then save it.
Generating the code is pretty easy. First click on “Generate Source Code” and then on “Compile & Generate JAR”.
Then click on “Define New Test”.
Defining a test with the “HTTP Test Wizarzd” is also quite easy. Optionally, you can enter here a test description. Then click on “Define Test”.
After you have clicked on “Define Test” the test is created and the view changes from the “HTTP Test Wizarzd” menu to the “Tests” menu.
The Test Menu shows all tests that you have defined - across all Projects and Resource Sets. You can also filter the view according to Projects and Resource Sets, and sort the tests in different ways.
Note that a test is something like a bracket that only contains references to the files that are required for the test execution. There a no files stored inside the test itself.
On the one hand, this means that a test become invalid/corrupted if you delete the corresponding resource files of the test in the Projects Menu. On the other hand, this also means that all changes to files that are saved in the tree of the Projects Menu are immediately applied to the test.
Each test has a base location from which it was defined (Project and Resource Set) and to where also the test results are saved.
A test itself can reference its resource files in two ways:
Referenced files which are used/shared by multiple tests (such as libraries, plug-ins and input files) can be stored in the predifined special project “Resources Library”.
After you have clicked on a test on “Define Test Job” and then on “Continue”, the intermediate “Define Test Job” menu is displayed.
In contrast to a “test”, all referenced files of the test are copied into the “test job”. For this reason there is also the option “Synchronize Files at Start of Job” which you should always have switched on. At “Additional Job Arguments” you can enter test-specific command line arguments that are transferred directly to the test program or test script. However, you usually do not need to enter anything.
After you have clicked on “Define Load Test Job” the test job is created and the view changes from the “Tests” menu to the “Test Jobs” menu.
In this menu all test jobs are displayed with their states. The green point at the top right next to the title indicates that all measurement agents that are set to active can also be reached. The color of the point changes to yellow or red if one or more measuring agents cannot be reached / are not available.
A test job can have one of the following state:
As soon as a job is in the “defined” state, it has a “local job Id”. If the job is then transmitted to a measuring agent, the job has additionally a “remote job Id”.
After you have clicked on “Start Test Job” in a test job you can select/modify the measuring agent on which the job will be executed and configure the job settings.
Input Fields:
Normally you do not have to enter any “Additional Arguments” and leave “Debug Execution” and “Debug Measuring” switched off.
After clicking on “Start Test Job”, the job is started on the measuring agent and the status of the job is now “Running”. Then click on “Monitor Jobs”.
The real-time display shows all currently running jobs including their measured values and measured errors.
You can also suspend a running job for a while and resume it later. However this has no effect on the “Max. Test Duration”.
After the job is completed you can click on “Analyze Result”. The view changes then to the “Test Results” menu.
If you click on “Analyze Result”, the test result is also copied (once) from the Measuring Agent into the Project / Resource Set from which the test was defined. From there you can reload the test result into the “Test Results” menu at any time.
The “Test Results” menu is a workspace into which you can load multiple test results. You can switch back and forth between the test results. As in the “Real-Time Monitor” menu, all measured values and all measured errors are displayed. In addition, percentile statistics and diagrams of error types are also displayed in this menu.
This menu enables you also to combine several test results into a so-called “load curve” - and thus to determine the maximum number of users that a system such a Web server can handle (see next chapter).
The Summary Statistic of a test result contains some interesting values:
Since several thousand to several million response times can be measured in a very short time during a test, the successfully measured response times are summarized in the response time diagrams at 4-second intervals. For this reason, a minimum value, a average value and a maximum value is displayed for each 4-second interval in such diagrams.
However, this summarization is not performed for percentile statistics and for measured errors. Every single measured value is taken into account here.
The maximum capacity of a system, such as the maximum number of users that a web server can handle, can be determined by a so-called “load curve”.
To obtain such a load curve, you must repeat the same test several times, by increasing the number of users with each test. For example a test series with 10, 50, 100, 200, 400, 800, 1200 and 1600 users.
The easiest way to repeat a test is to clone a test job. You can then enter the higher number of users when starting the test.
A measured load curve looks like this, for example:
As you can see, the throughput of the server increases linearly up to 400 users - with the response times remaining more or less the same (Avg. Passed Session Time). Then, with 800, 1200 and 1600 users, only individual errors are measured at first, then also many errors, with the response times now increasing sharply.
This means that the server can serve up to 400 users without any problems.
But could you operate the server with 800 users if you accept longer response times? With 800 users, 745,306 URL calls were successfully measured, with only 50 errors occurring.
To find it out, let’s compare the detailed response times of “Page 1” of 400 users with 800 users.
Response Times of “Page 1” at 400 Users:
Response Times of “Page 1” at 800 Users:
The 95% percentile value at 400 users is 224 milliseconds and increases to 1952 milliseconds at 800 users. Now you could say that it just takes longer. However, if you look at the red curve of the outliers, these are only one time a little bit more than 1 second at 400 users, but often more than 8 seconds at 800 users. Conclusion: The server cannot be operated with 800 users because it is then overloaded.
Now let’s do one last test with 600 users. Result:
The throughput of the server at 600 users is a little bit higher than at 400 users and also little bit higher than at 800 users. No errors were measured.
Response Times of “Page 1” at 600 Users:
The 95% percentile value at 600 users is 650 milliseconds, and there are only two outliers with a little bit more than one second. Final Conclusion: The server can serve up to 600 Users, but no more.
In rare cases it can happen that a test does not measure anything (neither measurement results nor errors). In this case you should either wait until the test is finished or stop it directly in the “Real Time Monitor” menu.
Then you can then acquire the test log files in the “Test Jobs” menu and search for errors.
If your test has problems when extracting and assigning variable values, you should also search the log files for error messages. To get detailed information you can run the test once again - but this time with the option “Debug Execution” enabled.
Don’t forget to turn off the “Debug Execution” option after the problem has been solved.
This document describes how to launch Measuring Agents in AWS as EC2 instances. Readers are assumed to be familiar with AWS EC2 terms used in here, in particular if launching Measuring Agents manually.
We make pre-installed Measuring Agents available for everybody to use in AWS redy-to-run AMIs. No additional costs (beyong the costs charged by AWS) apply when using these images.
To obtain a list of these ready to run AMIs proceed you can use one of these options:
Our Desktop Companion allows you to manage AWS Measuring Agents. You can launch and terminate agents as well as register them directly with the Real Load Portal with a few mouseclicks.
Refer to the Desktop Companion Documentation for further information.
Login to the Real Load portal and then head to the Measuring Agents configuration section. Then click on the AWS logo:
… and a list of available AWS AMIs will be displayed.
Using the AWS console locate AMIs belonging to our AWS account 775953462348 in your preferred AWS region. This can be done by looking for public images owned by our account, as illustrated in this screenshot:
For example in the Sydney region (ap-southeast-2) you’ll find the above listed AMI. If you can’t find an AMI in your desired region please contact us so that we can make it available.
Our Desktop Companion allows you to launch AMIs with a mouseclick.
Refer to the Desktop Companion Documentation for further information.
Once you’ve located a suitable AMI you can launch it as you would with any other Linux image as illustrated in this section.
In order for the AMI to be reachable from the Real Load Portal you’ll need to configure a Security Group allowing inbound connections to port 8080 as a minimum.
In order to protect access to your Measuring Agent we strongly recommend setting a non-default secret when launching the AMI.
The secret can be set at launch time by providing User Data to the AMI as follows (replace “secret” with the secret of your choice):
#!/bin/sh
echo "AGENT_SECRET=secret" > /home/ec2-user/agent_secret.sh
If you want this instance to appear in the Desktop Companion application then you’ll have to set the “REAL_LOAD_AGENT” tag to “true” when launching.
If for some reasons you think you might need to login via SSH to the Measuring Agent instance, then select an SSH key. This is not required for normal agent operations.
Our Desktop Companion allows you to configue EC2 instances with a mouseclick.
Refer to the Desktop Companion Documentation for further information.
Once the EC2 instance is up and running, you’ll need to configure it in the Real Load portal so that you can execute load tests from it.
Once added you can validate connectivity to the agent as shown in this screenshot:
Once you’ve completed your load testing it’s important to terminate the Measuring Agent instance to avoid unwatend AWS charges.
Our Desktop Companion allows you to terminate EC2 instances and remove it from the Real Load Portal configuration with a mouseclick.
Refer to the Desktop Companion Documentation for further information.
Terminate the instace as you would terminate any other Linux instance.
Our Desktop Companion allows you to remove Measuring Agent instances with a mouseclick.
Refer to the Desktop Companion Documentation for further information.
From the Meausring Agents menu select to delete the agent.
Alternatively you could decide to keep the agent configured and simply deactivate it. Disabling is recommended to avoid warning messages in the Portal console about failing connectivity tests.
The HTTP Tests Wizard supports you to create sophisticated tests in an easy way. You can compile (define) the entire test via the user interface and then generate a ready-to-run test program from this definition. A powerful debugger helps you to perfect your test.
As the name suggests, the HTTP Tests Wizard is optimized for the execution of HTTP/S tests. However, by using plug-ins, any other protocols can also be tested and measured (such as SMTP, DNS queries, DB-SQL queries, etc.).
HTTP Tests Wizard Features:
The test sequence is referred to as a so-called “Session”, whereby each simulated user repeatedly executes the session in a loop (so called “User Session” or “Session Loop”).
In order to define a test sequence, you can add various “Session Elements” to a session:
Adding session elements is in most cases quite simple and self-explanatory, but it can be a bit challenging for URLs and Input Files. For this reason, adding of these two session elements is described in more detail in the next two sub-chapters.
When adding an URL you have at least to select the HTTP Method (for example GET) and to enter the absolute URL (https://<host>/path).
Checking the HTTP response code and the HTTP response content is optional, but strongly recommended, as otherwise the test result may contain false positive results.
The following fields can be entered or selected:
Input files are text files (*.txt, *.csv) whose content is read line by line during the test. Each line is divided into tokens from which values of variables are extracted. Empty lines are skipped. Note that the variables must first be defined before you can add an input file.
The following fields can be entered or selected:
The HTTP Tests Wizard (as well as the debugger) supports to define variables and to extract and assign variable values from/to session elements. Variable definitions which are (remotely) made in the debugger are automatically synchronized with the HTTP Test Wizard at portal server side.
The data type of a variable is always a string, which can also be empty, but is usually never null.
When defining a variable, the following attributes can be set:
For variables with the scope “Global” there is only one instance which is initialized when the test is started.
For variables that have the scope “User”, there is a separate instance for each simulated user, which is initialized when the user is started.
In the case of variables with the scope “User Session”, a new instance is created and initialized at the start of each iteration of the session loop. The visibility is resricted to the current session loop of the simulated user.
Variable extractors are definitions which contain instructions about how to extract a value from a session element into a variable. Variable assigners, on the other hand, are definitions that contain instructions how to assign or replace a value of a session element.
The following two images show a variable extractor that extracts a dynamic value from URL[2], and a variable assigner which assigns the value to a JSON post request of URL[3].
While variables (almost) always have to be defined manually, the definition of variable extractors and assigners is usually done implicitly (semi-automatically), depending on the context of the session element.
For example, if you define an input file, you must first create the variables that contain the extracted values (for username and password in this example). If you then assign the line token numbers to the variables, the corresponding variable extractors are automatically created.
Note: In this example above, a separate username and password are read from the input file for each simulated user and assigned to the value of the corresponding variables. For this reason the variables have the scope “User”, and the input file has the scope “Get Next Line per User”.
Apart from Implicit Assigners (see “Adding URLs”), variable values of URLs can only be extracted and assigned by using the debugger. However, this is not a problem as definitions made in the debugger are automatically synchronized with the portal server.
Extracting variable values from URLs during debugging is quite easy. After executing a URL in the debugger, click on the symbol of the HTTP response header or of the HTTP response content and then extract the value.
Assigning variable values to URLs is a little bit more tricky. You have to interrupt the HTTP request in the debugger in the middle - after the request is initialized, but before the request is send to the server.
For this you have temporary to enable the option “HTTP Request Breakpoint” in the debugger, before you execute the URL (Next Step):
After you have clicked on “Next Step” you can assign the variable value to the pending HTTP request:
Click on the symbol of the URL, or of the HTTP request header or of the HTTP request content, and then assign the variable value:
Plug-Ins are reusable HTTP Test Wizard extensions that are manually programmed. They can also be published by manufacturing users and imported by other users. Therefore, before you start programming your own plug-in, take first a look at the already published plug-ins.
There are 3 types of plug-ins:
For copyright and security reasons, the published plug-ins only contain the source code, but not the compiled code and no third-party JAR libraries that may be required.
If third-party JAR libraries are required, the “Plug-in Description” provides instructions on how to download these libraries. Third-party JAR libraries should always be saved in the project/resouce set “Resources Library/Java”.
After you have imported the plug-in you have to load and compile it - then save the compiled plug-in.
After you have saved the compiled plug-in you can add it to your HTTP Test Wizard session. Plug-ins of the type “Java Source Code Modifier Plug-Ins” do not have to be added, but can be called directly after the source code of the test program has been generated.
In order to get support from the plug-in manufacturer, you have to enable in your Profile Settings the option “Public In-App User”. Then you can communicate with the plug-in manufacturer via “In-App Messages”.
Own plug-ins can be developed in Java 8 or 11. The following example shows a plug-in which decode a base64 encoded string.
After clicking at “New Plug-In” the plugin type has to be selected (in this example “Normal Session Element Plug-In”):
At the “General Settings” tab you have at least to enter the Plug-In Title and the Java Class Name. You should als enter a Plug-In Description which can be formatted by simple HTML tags. The onInitialize Scope can be set to “Global”, as this plug-in does not require any initialization. The onExecute Scope is set to “User Session” in order that all kind of variabe scopes are supported.
At the next tab - “Input & Output Values” - a plug-in input and a plug-in output (Java-)variable is defined for the plug-in method onExecute. The values of this two Java variables will later correspond with two HTTP Test Wizard variables (which may have a different variable name):
When you click at the next tab - “Resources Files” - you will see that the Java library com.dkfqs.tools.jar is already added to the plugin. This is normal as all kind of plug-ins require this library. Here you may add also other Java libraries required by the plug-in - but in this case no other libraries are needed.
Now at the “Source Code & Compile” tab, you can first generate the plug-in template. Then you have to extend the generated code with your own code, ie in this example you have to complete the Java import definitions and program the inner logic of the Java method onExecute. Then compile the plug-in.
At the last tab “Test & Save” you can first test the plug-in (remotely) on any Measuring Agent. To perform the test enter for example “SGVsbG8gV29ybGQ=” as input and you will see as output “Hello World”.
Finally save the plug-in:
After you have saved the plug-in click at the “Close” button. Then you will see the new plug-in in the plug-in list:
If your plug-in can be used universally, it would be nice if you also publish it - to make it available to other users.
Note that you have to enable in your Profile Settings the option “Public In-App User” in order that you entitled to publish plug-ins.
Publishing plug-ins is especially useful for users who have additionally activated the option “Publish My Profile as Technical Expert” in their Profile Settings. This will significantly improve your visibility and competence.
By using an HTTP/S Proxy Recorder, the HTTP/S traffic from Web browsers and technical Web clients can be recorded and easily converted into a HTTP Test Wizard session.
The HTTP Test Wizard session can then be debugged and post-processed. Finally, an executable test program can be generated from the recorded session.
An HTTP/S Remote Proxy Recorder has two service ports:
All data traffic that passes through the proxy port is first decrypted by the Proxy Recorder and then encrypted again before it is forwarded to the target Web server(s).
In order to record a Web surfing session by a Web browser you have to start two different Web browser products on your local machine. For example:
We recommend to use always Firefox as Web Browser 2.
To be able to record a Web surfing session, you have to reconfigure Web Browser 2:
Additional note: Before you start recording a Web surfing session in Web Browser 2, you must always clear the browser cache.
Once the recording is completed you should undo the configuration changes in Web Browser 2 (restore the original network settings and delete the Proxy Server CA Root Certificate).
After you have started a HTTP/S Proxy Recorder as a cloud instance or installed it on one of your systems, you have to register it at the Portal Server.
You can set any user name and password for Proxy Authentication. The Control API Authentication Token was defined/set by the person who started or installed the Proxy Recorder.
Once you have registered the Proxy Recorder you can try to ping it on the application level:
Then try to connect to the Control Port of the Proxy Recorder. If this works, the Proxy Recorder is now ready for use.
Click at the certificate icon and store the certificate at any location.
Then open the Web browser settings and import the certificate.
Since there is a small bug in some versions of Firefox, you have to close and reopen the Certificate Manager to view the imported certificate.
Navigate with Web Browser 1 to the Proxy Recorder control menu.
Then configure the “Hosts Recording Filter” and click on the “Start Recording” icon.
In Web Browser 2, first clear the browser cache and then enter the URL where you want the recording to start.
In Web Browser 1 you can now see the recording of the first page. Before navigating to the next page in Web Browser 2, first insert a “Page Break” in Web Browser 1 with a brief description of the next page.
Then navigate to the next page in Web Browser 2.
In Web Browser 1 you can now see the recording of the next page.
Then continue as before. Insert a Page Break in Web Browser 1, navigate to a next page in Web Browser 2. and so on …
After you have done the recording click on the “Stop Recording” icon. Then convert the recording into an HTTP Test Wizard session.
Here you can select different options. The HTTP Status Code Filter also supports * as a wildcard. An exclamation mark in the font of a value means “do not / exclude”.
The option Enable Parallel Execution of HTTP Requests should be enabled if you have recorded a session with a Web browser (as described above), but should be disabled if the recording was performed by a technical Web client.
Once you have clicked on the Convert button, the recorded session is converted and directly loaded into the HTTP Test Wizard.
After that debug the converted session in the HTTP Test Wizard and then save the HTTP Test Wizard session. Finally generate and execute the test.
This browser extension will ask for the RealLoad proxy configurations, then automatically set Proxy in the browser. Using the extension user can clear cache, start recording, stop recording, clear recording and add page breaks while recording the user journeys in the browser.
Before you start installing the browser extension, Please make sure that you have already followed the steps mentioned in the doc HTTP/S Remote Proxy Recorder) , Registering a Proxy Recorder at the Portal and Import the Proxy Server CA Root Certificate.
Browser extension for Chrome
Please open the link https://chrome.google.com/webstore/detail/mlindhmkpdadnkdoicbmijgdecpbioai/ in Chrome and Add to Chrome.
After adding the extension to Chrome, the next step will be setting the proxy details for recording in the extension options like below.
Once you have entered all the necessary RealLoad proxy details and save, you are ready to use the Browser Recorder extension for Chrome
Now you can go ahead and record your browser sessions by pressing Start Recording, You can add page breaks while recording by adding the page break name and press icon marked in the below screenshot.
Once you are done with your recording, you can press Stop Recording, which will revert the configured RealLoad Proxy to the Browser Automatic Proxy.
Now when you sign in to the RealLoad portal https://portal.realload.com/, you can see the recordings under the configured HTTP/S Remote Proxy Recorder screen.
The same steps are described below for the extension for Firefox.
Browser extension for Firefox
Please open the link https://addons.mozilla.org/en-US/firefox/addon/realload-test-recorder/ in Firefox and Add to Firefox. Please make sure that you have checked this option “Allow this extension to run in Private Windows” during the installation.
After adding the add-ons to the firefox, the next step will be setting the proxy details for recording in the add-on preferences like below.
Once you have entered all the necessary RealLoad proxy details and save, you are ready to use the Browser Recorder extension for Firefox.
Now you can go ahead and record your browser sessions by pressing Start Recording, You can add page breaks while recording by adding the page break name and press icon marked in the below screenshot.
Once you are done with your recording, you can press Stop Recording, which will revert the configured RealLoad Proxy to the Browser Automatic Proxy.
Now when you sign in to the RealLoad portal https://portal.realload.com/, you can see the recordings under the configured HTTP/S Remote Proxy Recorder screen.
The Desktop Companion is a small application that allows you to manage some features related to the Real Load Platform.
In particular the desktop companion allows you to:
See sections below to learn more about the Desktop Companion.
Before running the Desktop Companion make sure you satisfy the following pre-requisites:
The Desktop Companion is a Java application currently delivered as a .jar file. At this stage there is no full installer for the application, which means that as a pre-requisite to run the application you’ll need to install a Java 11 JRE.
While it should run on any systems that support Java 11 and FXML, it was only tested on the following platforms:
Operating System | JRE 11 Vendor and Build | JRE download link | Comments |
---|---|---|---|
Windows 10 | Microsoft “11.0.11” 2021-04-20 | https://docs.microsoft.com/en-au/java/openjdk/download | |
Windows 11 | Microsoft | https://docs.microsoft.com/en-au/java/openjdk/download | |
Apple OS X | Microsoft “build 11.0.13+8-LTS” | https://docs.microsoft.com/en-au/java/openjdk/download |
In order to use the AWS integration features, you’ll need to prepare Security Credentials with AWS IAM.
Seach for “IAM” in the AWS search bar and click on “Users”:
Then add a new user:
Enter a suitable user name and select “Access key” as the AWS credential type.
On the next page set an appropriate policy for the user. Usin the “AmazonEC2FullAccess” provides sufficinet permissions.
Skip the “Add tags” screen and go to the “Review” screen and click on “Create user”. Make sure the permissions you’ve assigned to the user appear on this screen.
Finally take a note of the Access Key ID and Secret Access Key as thess need to be configured in the Real Load Desktop Companion.
In order to register with the Real Load portal the AWS EC2 instances you’ve launched, the Desktop Companion requires that you configure an authentication token.
To create an authentication token proceed as follows:
Login to the Real Load Portal and click on the User -> API Authenticaiton Tokens menu.
Then click on the “Add API Authentication Tokens” button and enter a suitable purpose description. Optionally you can restrict the src IP address from where this token can be used.
Take note of the authentication Token Value as you’ll need to configure it in the Desktop Companion.
The full installer includes a JRE as well as the Desktop Companion application itself. This is the preferred method of deploying the application, as it avoids issues that might occur because of JRE customization, etc…
Additionally the application can be started from the Windows start menu, as any other application.
The latest version of the full installer can be downloaded from here:
You can download the latest version of the Desktop Companion as an executable .jar file from here: https://download.realload.com/desktop_companion/latest
There is no installer to be executed, the application can be launched by double clicking on the .jar file. If that doesn’t work, consider launching from the command line.
If you’ve only got one JDK/JRE version installed on your Windows computer then it’s very likely that .jar files are associated with the correct JRE. In that case you should be able to launch the application by double clicking on the .jar file.
If the application doesn’t start it’s possible the .jar extensions is associated with the incorrect JRE or another application altogether. You can try to right click on the .jar file and the “Open with” from the context menu.
Then selecte the OpenJRE launcher:
… or alternatively navigate to the JRE 11 binary, as shown in this screenshot:
Similarly on Windows 11:
s
If the application doesn’t start, consider starting it from the command line as explained below.
Open a Terminal window. First validate that the java binary in your path is a JRE 11 binary by running this command:
java -version
The output should indicate you’re running a JRE 11 binary, as shown here:
If the version of the JRE is 11 then you can run the following command from the folder where the Desktop Companion .jar file was downloaded:
java.exe -jar .\RealLoadCompanionFXML-0.1.jar
If you only have JRE 11 installed on your Mac, you should be able to launch the application simply by double clicking on its icon:
Alternatively right-click on the icon and “Opne With” Jar Launcher.
If this doesn’t work, refer below on how to launch from the command line.
Open a Terminal window. First validate that the java binary in your path is a JRE 11 binary by running this command:
java -version
The output should indicate you’re running a JRE 11 binary, as shown here:
If a different JRE version is returned (like for example a JRE 8 binary) then you’ll need to specify the full path to the java 11 command. For example, assuming you installed the Microsoft OpenJDK 11, you would typically find it at this location:
/Library/Java/JavaVirtualMachines/microsoft-11.jdk/Contents/Home/bin/java
To run the Desktop Companion, assuming the .jar file is present in the current directory, run the following command from a Terminal window:
/Library/Java/JavaVirtualMachines/microsoft-11.jdk/Contents/Home/bin/java -jar RealLoadCompanionFXML-0.1.jar
Various application settings are configurable in the File -> Settings menu.
Default HAR input folder: Location where to look for .har (HTTP Archives) files by default. This should be the location where your browser writes files to.
Default export folder: This is the location where Real Load HTTP test scripts will be exported to in JSON format.
Agent Secret: The Measuring Agent secret to authenticate connections from the Real Load Portal to the Cloud Agent instance (AWS EC2 and Azure instances in future).
Portal URL: The endpoint of the Real Load portal User API. Unless you have an on-premise installation, use the default value https://portal.realload.com/RemoteUserAPI
Authentication Token: Enter here the authentication token that was generated by the Portal as part of the pre-requisites steps. Click on the “Test” button to test the API token.
Refresh Interval: How frequently should the list of Measuring Agents registered with the Real Cloud portal be refreshed. Any value 60 seconds or lower indicates no background refresh, you’ll need to manually trigger a refresh via context menu. By default set to 61 seconds (background refresh enabled).
AWS Access Key: Paste the AWS Access Key that was obained as part of the preparation steps.
Secret Access Key: Paster the AWS Secret Access key that was obained as part of the preparation steps. Use the “Test” button to validate the credentials.
Preferred Instance Type: The EC2 instance type to use when launching a new Mesauring Agent instance.
AWS EC2 Refresh Interval: How frequently should the list of AWS EC2 instances be refreshed. Any value 60 seconds or lower indicates no background refresh, you’ll need to manually trigger a refresh via context menu. By default set to 61 seconds (background refresh enabled).
My AWS Regions: Select the AWS regions you commonly use. To select multiple regions hold the CTRL key while selecting.
Proxy Port: The TCP port on the local machine that will listen for incoming proxy connections. You’ll need to configure this port as the HTTP proxy in your browser.
Export CA Certificate: This exports the CA certificate used by reverse proxy to sign SSL certificates. The exported CA should be added as a trusted CA to the browser you’re planning to use to record HTTP requests.
The next settings should be left to default values, unless there are specific reasons for changing them.
To import an HTTP Archive generate by a browser use the corresponding option in the file menu and select the relevant .har file. All requests present in the file will appear in the editor tab.
You can export your test script to a Real Load JSON session file by selecting the corresponding option in the file menu. The file will be saved in the folder you select.
You’ll then need to manually upload the file to a Resource Set in the Real Load Portal using the upload function.
Test scripts can be directly uploaded to the Real Load Portal via the “Export session to portal…” menu. You’ll need to select the resource set to save the load test to:
You have 2 options:
In the request editor tab you’ll be able to perform some basic editing of the requests imported from an HAR file or recorded by the proxy recorder.
For more complex editing please use the HTTP wizard in the Real Cloud portal after uploading your test script there.
The Editor tab is split in 3 main parts:
You can mark requestes in the main editor window by clicking on them. Hold the ctrl keyty to mark multiple request or use the shift key to mark a range of requests.
Once marked you can delete the requests by right-clicking on a marked request and selecting “Delete selected” from the context menu:
To add a time delay (currently hardcoded to 1 second) before or after a request, select the relevant context menu item while hovering over a request.
Time delays rows appear as requests of type “T” in the main editor window:
In order to bulk select all requests belonging to specific domains select one or more domains (by holding the CTRL key). This will select corresponding requests in the requests list which can then be easilly deleted.
It is also possible to directly delete requests belonging to one or multiple domains using the context menu.
The Measuring Agents tab allows you to manage Cloud Based (… currently AWS) Measuring Agents. This section of the application will be of most use if you configured AWS credentials in the preferences section of the application.
If no AWS credentials are configured, you won’t be able to start and terminate AWS instances.
In the left pane you’ll see a list of available AWS AMIs. You can further filter the list of AMIs by selecting a specific version and/or by selecteing an AWS region.
To launch an new EC2 instance right-click on the relevant AMI and select “Launch”. A screen to confirm the launch will be displayed. Confirm by clicking on the “Launch” button.
When launching an instance in an AWS EC2 region that is not yet part of your “My Regions” list, the region will be automatically added to the list.
Launching a new instaance will automatically trigger a refresh of the AWS Measuring Agents list. It might take a few second for the list to update and the new instance to be reflected in it.
Then confirm the launch action:
After launching an instance go to the top right part of the window listing the running instances and right click on “Refresh”. This will retrieve all running EC2 instances from the preferred AWS regions and display them in the table.
To register an AWS instance with the Real Load Portal right-click on the instance and then select the “Register with portal” menu item. The instance ID will be used as the description in the Real Load Portal.
In the left bottom part of the window you’ll see the Measuring Agents currently registered on the Portal. To update the list right click and select the “Refresh” option.
In order to de-register an instance from the Portal right click on the instance name and select De-register.
To terminate an AWS EC2 instance right click on the instance name.
The Desktop Companion allows you to run the Proxy Recorder locally on your desktop. Recorded requests will then appear in the Editor tab. Refer to the Proxy Recorder documentation for further information on how it works.
There are two main sections in this chapter:
You’ll have to configure the port the Real Load Proxy listens on (default: 18080) in your browser. We recommend to use a browser that allows you to configure proxy settings independently from the Operating System proxy settings. FireFox is a good candidate for this and we’ve documented its configuration in this section.
For the browser to trust SSL certificates issued by the Recording Proxy, you’ll need to import the Proxy’s CA certificate as follows:
Then click on the “Auhtorities” tab, “Import” button and select the “RecProxyCert.cer” that you’ve just exported from the Desktop Companion.
Make sure you trust the certificate to identify websites:
In the FireFox “Settings” and scroll to the bottom of the page where “Network Settings” are located . The below window should be displayed and configure the Port to be 18080 for both HTTP and HTTPS. Configure the host and port as shown in the below screenshot. Also tick the “Also use this proxy for HTTPS”.
Navigate to any SSL enabled page. You shouldn’t see any warnings about untrusted SSL certificates beings used.
If you check the certificate of the site you’re visiting, the issuer should be “Real Load Pty Ltd”, as shown in this screenshot.
To start the recording process go to the Proxy Recorder tab and click on the “Start Recorder” button. Note that when the recording process is started, previous Proxy Recorder logs are purged.
To stop the recording process clik on the “Stop Recorder” button. Then navigate to the “Editor” window and you should see all recorded requests as in this example:
Synthetic Monitoring is an essential part of Digital Experience Monitoring, where organizations can detect their service outages or performance degrade proactively by periodically running the tests.
Real Load provides an easy way of configuring synthetic tests with an outcome of accurate metrics, alerting and SLA details.
Below illustrates Synthetic Tests configurations, Alerts configurations, Real-Time Dashboard, Statistics with SLA measured.
Please define a test by following the steps here until Define New Test, After you can see all the tests you have defined like below under Tests page
Next step is to create Monitoring Groups and add & define tests under each group as jobs like below, Agents will be available for selection based on how many agents are already configured on different geographical locations, please refer here for more details
Now the created monitoring groups with its monitoring jobs will be available under the Real-Time Dashboard like below with the important metrics and also have the option to drill down into test results
Custom dashboards can be created on third party products like Grafana, using our WebSocket API
Next explains how to configure the Alerting, below illustrates how to configure alerting for created Monitoring Groups or Jobs
Next explains about the statistics data, which will be the source for many KPIs , for example to calculate the defined SLA for an application or an API service
It is an API Service which holds all the API requests, which can be used to store the test data in table formats in a Database, which can be consumed/produced by both load test and synthetic monitoring tests. So it acts like a Test Data database where multiple scripts can consume common test data.
Currently, the Tests need Plugins to communicate with the Table Server API, but in near future we will come up with a solution where performance Engineers can write inline javascript in the test to communicate with the Table Server APIs.
Below are the API Requests that Table Server supports
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "createNewTable",
"tableName": "Products",
"columnNamesAndValues": [
{
"ProductGroup": "Icecream",
"ProductName": "Vanilla"
},
{
"ProductGroup": "Pizza",
"ProductName": "Margareta"
}
]
}'
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "createNewTableFromCSVFile",
"uploadFileName": "Products.csv",
"delimiter": ",",
"uploadFileDataB64": "UHJvZHVjdEdyb3VwLFByb2R1Y3ROYW1lLFByaWNlDURyaW5rcyxDb2NhQ29sYSwxMApEcmlua3MsUGVwc2ksNwpEcmlua3MsN1VwLDgKRHJpbmtzLEZhbnRhLDkKUGl6emEsTWFyZ2FyZXRhLDEwDQ=="
}'
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "getAllTables",
"includeColumns": true
}'
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "insertColumn",
"table": "Products",
"column": "ProductGroup",
"value": "Sweets"
}'
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "retrieveColumn",
"table": "Products",
"column": "ProductName"
}'
Update a single test data.
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "updateColumn",
"table": "Products",
"column": "ProductGroup",
"value": "Fruits",
"rowIndex":1
}'
Create multiple test data.
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "insertRow",
"table": "Products",
"columnsAndValues": [
{
"ProductGroup": "Vegetables",
"ProductName": "Carrot"
}
]
}'
curl --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "retrieveRow",
"table": "Products",
"columns": [
"ProductGroup",
"ProductName"
]
}'
curl -k --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "queryTable",
"table": "Products",
"columnNamesAndValues": [
{
"ProductGroup": "Vegetables",
"ProductName": "Carrot"
}
]
}'
curl --location --request POST 'https://{{tableserverURL}}:8084/Api' \
--header 'Content-Type: application/json' \
--data-raw '{
"apiAuthToken": "{{apiAuthToken}}",
"action": "exportTableToCSV",
"table": "Products"
}'