添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Building a REST Service That Collects HTML Form Data Using Netbeans, Jersey, Apache Tomcat, and Java JAX-WS Five-Minute Tutorial Modes and Modality in Performance Testing Custom Elements Manifest: The Key to Seamless Web Component Discovery and Documentation

The Need for the Creation of the STS Plugin

From a Web Application in Tomcat

The idea of having a server to manage the dataset was born during the performance tests of the income tax declaration application of the French Ministry of Public Finance in 2012. The dataset consisted of millions of lines to simulate tens of thousands of people who filled out their income tax return form per hour and there were a dozen injectors to distribute the injection load of a performance shot. The dataset was consumed, that is to say, once the line with the person's information was read or consumed, we could no longer take the person's information again.

The management of the dataset in a centralized way had been implemented with a Java web application (war) running in Tomcat . Injectors requesting a row of the dataset from the web application.

To a Plugin for Apache JMeter

The need to have centralized management of the dataset, especially with an architecture of several JMeter injectors, was at the origin of the creation in 2014 of the plugin for Apache JMeter named HTTP Simple Table Server or STS. This plugin takes over the features of the dedicated application for Tomcat mentioned above but with a lighter and simpler technical solution based on the NanoHTTPD library.

Manage the Dataset With HTTP Simple Table Server (STS)

Adding Centralized Management of the Dataset

Performance tests with JMeter can be done with several JMeter injectors or load generators (without interface, on a remote machine) and a JMeter controller (with user interface or command line interface on the local machine). JMeter script and properties are sent by RMI protocol to injectors. The results of the calls are returned periodically to the JMeter controller.

However, the dataset and CSV files are not transferred from the controller to the injectors.

It is natively not possible with JMeter to read the dataset randomly or in reverse order. However, there are several external plugins that allow you to randomly read a data file, but not in a centralized way.

It is natively not possible to save data created during tests such as file numbers or new documents in a file. The possibility of saving values can be done with the Groovy script in JMeter, but not in a centralized way if you use several injectors during the performance test.

The main idea is to use a small HTTP server to manage the dataset files with simple commands to retrieve or add data lines to the data files. This HTTP server can be launched alone in an external program or in the JMeter tool.

The HTTP server is called the " S imple T able S erver" or STS. The name STS is also a reference to the Virtual Table Server (VTS) program of LoadRunner with different functionalities and a different technical implementation, but close in the use cases.

STS is very useful in a test with multiple JMeter injectors, but it also brings interesting features with a single JMeter for performance testing.

Some Possibilities of Using the HTTP Simple Table Server

Reading Data in a Distributed and Collision-Free Way

Some applications do not tolerate that 2 users connect with the same login at the same time. It is often recommended not to use the same data for 2 users connected with the same login at the same time to avoid conflicts on the data used.

The STS can easily manage the dataset in a distributed way to ensure that logins are different for each virtual user at a given time T of the test. A dataset with logins/passwords with a number of lines greater than the number of active threads at a given time is required.

We manually load at the start of the STS or by script the logins/password file, and the injectors ask the STS for a line with login/password by the command READ , KEEP=TRUE , and READ_MODE=FIRST .

We can consider that the reading of the dataset is done in a circular way.

Reading Single-Use Data

The dataset can be single-use, meaning that it is used only once during the test. For example, people who register on a site can no longer register with the same information because the system detects a duplicate. Documents are awaiting validation by an administrator. When the documents are validated, they are no longer in the same state and can no longer be validated again.

To do this, we will read a data file in the memory of the HTTP STS and the virtual users will read by deleting the value at the top of the list. When the test is stopped, we can save the values that remain in memory in a file (with or without a timestamp prefix) or let the HTTP STS run for another test while keeping the values still in memory.

Producers and Consumers of a Queue

With the STS, we can manage a queue with producers who deposit in the queue and consumers who consume the data of the queue. In practice, we start a script with producers who create data like new documents or new registered people. The identifiers of created documents or the information of newly registered people are stored in the HTTP STS by the ADD command in mode ADD_MODE=LAST . The consumers start a little later so that there is data in the queue.

It is also necessary that the consumers do not consume too quickly compared to the producers or it is necessary to manage the case where the list no longer contains a value by detecting that there is no more value available and waiting a few seconds before repeating in a loop.

The consumers consume the values by the commands READ , FIRST , KEEP=FALSE . Here is a schema to explain how the producers ADD and consumers READ in the same queue.

Producer and Consumer With Search By FIND

This is a variation of the previous solution.

Producer

A user with rights limited to a geographical sector creates documents and adds a line with his login + the document number (ex: login23;D12223 ).

login1;D120000
login2;D120210
login23;D12223
login24;D12233
login2;D120214
login23;D12255

Consumer

A user will modify the characteristics of the document, but to do so, he must choose from the list in memory only the lines with the same login as the one he currently uses for questions of rights and geographic sector.

Search in the list with the FIND command and FIND_MODE=SUBSTRING . The string searched for is the login of the connected person (ex: login23) so LINE=login23; (with the separator ; ). In this example, the returned line will be the 1st line login23 and the file number will be used in searching for files in the tested application.

Here, the result of the FIND by substring (SUBSTRING) is: login23;D12223. The line can be consumed with KEEP=FALSE or kept and placed at the end of the list with KEEP=TRUE .

Enrich the Dataset as the Shot Progresses

The idea is to start with a reduced dataset that is read at the start of the shot and to add new lines to the initial dataset as the shot progresses in order to increase or enrich the dataset. The dataset is therefore larger at the end of the shot than at the beginning. At the end of the shot, the enriched dataset can be saved with the SAVE command and the new file can be the future input file for a new shot.

For example, we add people by a scenario. We add to the search dataset these people in the list so the search is done on the first people of the file read at the beginning but also the people added as the performance test progresses.

Verification of the Dataset

The initial dataset can contain values that will generate errors in the script because the navigation falls into a particular case or the entered value is refused because it is incorrect or already exists.

We read the dataset by INITFILE or at the start of the STS, we read (READ) and use the value if the script goes to the end (the Thread Group is configured with " Start Next Thread Loop on Sampler Error"), we save the value by ADD in a file ( valuesok.csv ). At the end of the test, the values of the valuesok.csv file are saved (for example, with a "tearDown Thread Group"). The verified data of the valuesok.csv file will then be used.

Storing the Added Values in a File

In the script, the values added to the application database are saved in a file by the ADD command. At the end of the test, the values in memory are saved in a file (for example, with a "tearDown Thread Group"). The file containing the created values can be used to verify the additions to the database a posteriori or to delete the created values in order to return to an initial state before the test.

A script dedicated to creating a data set can create values and store them in a data file. This file will then be used in the JMeter script during performance tests. On the other hand, a dedicated erase script can take the file of created values to erase them in a loop.

Communication Between Software

The HTTP STS can be used as a means to communicate values between JMeter and other software. The software can be a heavy client, a web application, a shell script, a Selenium test, another JMeter, a LoadRunner, etc.  We can also launch 2 command line tests with JMeter in a row by using an "external standalone" STS as a means to store values created by the first test and used in the second JMeter test. The software can add or read values by calling the URL of the HTTP STS, and JMeter can read these added values or add them itself. This possibility facilitates performance tests but also non-regression tests.

Enrich the Dataset as the Shot Progresses

Gradual Exiting the Test on All JMeter Injectors

In JMeter, there is no notion as in LoadRunner of " GradualExiting ," that is to say, to indicate to the vuser at the end of the iteration if it should continue or not to repeat and therefore stop. We can simulate this " GradualExiting " with the STS and a little code in the JMeter script. With the STS we can load a file " status.csv ," which contains a line with a particular value like the line " RUN ." The vuser asks at the beginning of the iteration the value of the line of the file " status.csv ." If the value is equal to " STOP " then the vuser stops. If the value is zero or different from STOP like " RUN " then the user continues.

Gradual Exiting After Fixed Date Time

We can also program the stop request after a fixed time with this system. We indicate as a parameter the date and time to change the value of the status to STOP ; e.g., 2024-07-31_14h30m45s by a JMeter script that runs in addition to the current load testing. The script is launched, and we calculate the number of milliseconds before the indicated date of the requested stop.

The vuser is put on hold for the calculated duration.

Then the " status.csv " file in the STS is deleted to put the STOP value, which will allow the second JMeter script that is already running to read the status value if status == "STOP" value and to stop properly on all the JMeter injectors or the JMeter alone.

Start the HTTP Simple Table Server

Declaration and Start of the STS by the Graphical Interface

The Simple Table Server is located in the "Non-Test Elements" menu:

Click on the "Start" button to start the HTTP STS.

By default, the directory containing the files is <JMETER_HOME>/bin .

Start From the Command Line

It is possible to start the STS server from the command line.

Or automatically when starting JMeter from the command line (CLI) by declaring the file these 2 lines in jmeter.properties :

  • jsr223.init.file=simple-table-server.groovy
  • jmeterPlugin.sts.loadAndRunOnStartup=true
  • If the value is false , then the STS is not started when launching JMeter from command line without GUI.

    The default port is 9191. It can be changed by the property:

    # jmeterPlugin.sts.port=9191

    If jmeterPlugin.sts.port=0 , then the STS does not start when launching JMeter in CLI mode.

    The property jmeterPlugin.sts.addTimestamp=true indicates if the backup of the file (e.g., info.csv) will be prefixed by the date and time (e.g.: 2 0240112T13h00m50s.info.csv ); otherwise, jmeterPlugin.sts.addTimestamp=false writes/overwrites the file info.csv
    # jmeterPlugin.sts.addTimestamp=true .

    The property jmeterPlugin.sts.daemon=true is used when the STS is launched as an external application with the Linux nohup command (example: nohup ./simple-table-server.sh & ).
    In this case, the STS does not listen to the keyboard. Use the <ENTER> key to exit.
    The STS enters an infinite loop, so you must call the /sts/STOP command to stop the STS or the killer.

    When jmeterPlugin.sts.daemon=false , the STS waits for the entry of <ENTER> to exit. This is the default mode.

    Loading Files at Simple Table Server Startup

    The STS has the ability to load files into memory at STS startup. Loading files is done when the STS is launched as an external application ( <JMETER_HOME>\bin\simple-table-server.cmd or <JMETER_HOME>/bin/simple-table-server.sh ) and also when JMeter is launched from the command line without GUI or via the JMeter Maven Plugin.

    Loading files is not done with JMeter in GUI mode.

    The files are read in the directory indicated by the property jmeterPlugin.sts.datasetDirectory , and if this property is null , then in the directory <JMETER_HOME>/bin .

    The declaration of the files to be loaded is done by the following properties:

    jmeterPlugin.sts.initFileAtStartup=article.csv,filename.csv

    jmeterPlugin.sts.initFileAtStartupRegex=false

    jmeterPlugin.sts.initFileAtStartup=.+?\.csv

    jmeterPlugin.sts.initFileAtStartupRegex=true

    When jmeterPlugin.sts.initFileAtStartupRegex=false then the property jmeterPlugin.sts.initFileAtStartup contains the list of files to be loaded with the comma character “ , ” as the file name separator. (e.g., jmeterPlugin.sts.initFileAtStartup=article.csv,filename.csv ). The STS at startup will try to load ( INITFILE ) the files articles.csv then filename.csv.

    When jmeterPlugin.sts.initFileAtStartupRegex=true then the property jmeterPlugin.sts.initFileAtStartup contains a regular expression that will be used to match the files in the directory of the property jmeterPlugin.sts.datasetDirectory (e.g.,
    jmeterPlugin.sts.initFileAtStartup=.+?\.csv loads into memory ( INITFILE ) all files with the extension " .csv ".

    The file name must not contain special characters that would allow changing the reading directory such as ..\..\fichier.csv , /etc/passwd , or ../../../tomcat/conf/server.xml .

    The maximum size of a file name is 128 characters (without taking into account the directory path).

    Management of the Encoding of Files to Read/Write and the HTML Response

    It is possible to define the encoding when reading files or writing data files. The properties are as follows:

  • Read (INITFILE) or write (SAVE) file with an accent from the text file in the charset like UTF-8 or ISO8859_15
  • All CSV files need to be in the same charset encoding:
  • Files will be read ( INITFILE ) with the charset declared by the value of jmeterPlugin.sts.charsetEncodingReadFile .
  • Files will be written ( SAVE ) with the charset declared by the value of jmeterPlugin.sts.charsetEncodingWriteFile .
  • The default value jmeterPlugin.sts.charsetEncodingReadFile corresponds to the System property: file.encoding .
  • The default value jmeterPlugin.sts.charsetEncodingWriteFile corresponds to the System property: file.encoding .
  • All data files must be in the same charset if they contain non-ASCII characters.
  • To respond in HTML to different commands, especially READ , the charset found in the response header is indicated by jmeterPlugin.sts.charsetEncodingHttpResponse .
  • jmeterPlugin.sts.charsetEncodingHttpResponse=<charset> (Use UTF-8) : In the HTTP header add " Content-Type:text/html; charset=<charset> "
  • The default value is the JMeter property: sampleresult.default.encoding
  • The list of charsets is declared in the HTML page (take the java.io API column)
  • For the name of the charset look, see Oracle docs for Supported Encodings .
  • Column Canonical Name for java.io API and java.lang API
  • Help With Use

    The URL of an STS command is of the form: <HOSTNAME>:<PORT>/sts/<COMMAND>?<PARAMETERS> .

    The commands and the names of the parameters are in uppercase (case sensitive).

    If no command is indicated then the help message is returned: http://localhost:9191/sts/ .

    Commands and Configuration

    The following is a list of commands and configuration of the HTTP STS with extracts from the documentation of the JMeter-plugins.org site.

    The calls are atomic (with synchronized ) => Reading or adding goes to the end of the current processing before processing the next request.

    The commands to the Simple Table Server are performed by HTTP GET and/or POST calls depending on the command.

    Documentation is available on the JMeter plugin website .

    Distributed Architecture for JMeter

    The Simple Table Server runs on the JMeter controller (master) and load generators (slaves) or injectors make calls to the STS to get, find, or add some data.

    At the beginning of the test, the first load generator will load data in memory (initial call) and at the end of the test, it asks for the STS saving values in a file.

    All the load generators ask for data from the same STS which is started on the JMeter controller.

    The INITFILE can also be done at STS startup time (without the first load generator initial call).

    Example of a dataset file logins.csv:

    The files are read in the directory indicated by the property: jmeterPlugin.sts.datasetDirectory ; if this property is null, then in the directory<JMETER_HOME>/bin/ .

    READ: Get One Line From List
  • http://hostname:port/sts/
  • READ_MODE=FIRST => login1;password1
  • READ_MODE=LAST => login5;password5
  • READ_MODE=RANDOM => login?;password?
  • KEEP=TRUE => The data is kept and put to the end of the list
  • KEEP=FALSE => The data is removed
  • READMULTI: Get Multi Lines From List in One Request

  • GET Protocol
  • http://hostname:port/sts/READMULTI?FILENAME=logins.csv&NB_LINES={Nb lines to read}&READ_MODE={FIRST, LAST, RANDOM}&KEEP={TRUE, FALSE}
  • Available options:
  • NB_LINES=Number of lines to read : 1 <= Nb lines (Integer) and Nb lines <= list size
  • READ_MODE=FIRST => Start to read at the first line
  • READ_MODE=LAST => Start to read at the last line (reverse)
  • READ_MODE=RANDOM => read n lines randomly
  • KEEP=TRUE => The data is kept and put to the end of list
  • KEEP=FALSE => The data is removed
  • ADD: Add a Line Into a File (GET OR POST HTTP Protocol)

  • FILENAME=dossier.csv, LINE=D0001123, ADD_MODE={FIRST, LAST}
  • HTML format:
  • ADD_MODE=FIRST => Add to the beginning of the list
  • ADD_MODE=LAST => Add to the end of the list
  • FILENAME=dossier.csv => If doesn't already exist it creates a LinkList in memory
  • LINE=1234;98763 =>Tthe line to add
  • UNIQUE => Do not add a line if the list already contains such a line (return KO)
  • HTTP POST request:
  • Method GET:
  • GET Protocol: http://hostname:port/sts/ADD FILENAME=dossier.csv&LINE=D0001123&ADD_MODE={FIRST, LAST}
  • FIND: Find a Line in the File (GET OR POST HTTP Protocol)

  • Command FIND
  • Find a line ( LINE ) in a file ( FILENAME ) (GET or POST HTTP protocol)
  • The LINE to find is for FIND_MODE :
  • A string: SUBSTRING (Default, ALineInTheFile contains the stringToFind ) or EQUALS ( stringToFind == ALineInTheFile )
  • A regular expression with REGEX_FIND (contains) and REGEX_MATCH (entire region matches the pattern)
  • KEEP=TRUE => The data is kept and put to the end of the list
  • KEEP=FALSE => The data is removed
  • GET Protocol: http://hostname:port/sts/FIND?FILENAME=colors.txt&LINE=(BLUE|RED)&[FIND_MODE=[SUBSTRING,EQUALS,REGEX_FIND,REGEX_MATCH]]&KEEP={TRUE, FALSE}
  • If find return the first line found, start reading at the first line in the file (linked list):

    LENGTH: Return the Number of Remaining Lines of a Linked List

  • http://hostname:port/sts/LENGTH?FILENAME=logins.csv
  • HTML format:
  • STATUS: Display the List of Loaded Files and the Number of Remaining Lines
  • http://hostname:port/sts/STATUS
  • HTML format:
  • SAVE: Save the Specified Linked list in a File to the datasetDirectory Location
  • http://hostname:port/sts/SAVE?FILENAME=logins.csv
  • If jmeterPlugin.sts.addTimestamp is set to true, then a timestamp will be added to the filename. The file is stored in jmeterPlugin.sts.datasetDirectory or if null in the <JMETER_HOME>/bin directory: 20240520T16h33m27s.logins.csv.
  • You can force the addTimestamp value with parameter ADD_TIMESTAMP in the URL like :
    http://hostname:port/sts/SAVE?FILENAME=logins.csv &ADD_TIMESTAMP ={true,false}
  • HTML format:
  • RESET: Remove All Elements From the Specified List:

  • http://hostname:port/sts/ RESET ?FILENAME=logins.csv
  • HTML format:
  • The Reset command is often used in the “setUp Thread Group” to clear the values in the memory Linked List from a previous test.

    It always returns OK even if the file does not exist.

    STOP: Shutdown the Simple Table Server

  • http://hostname:port/sts/ STOP
  • The stop command is used usually when the HTTP STS server is launched by a script shell and we want to stop the STS at the end of the test.
  • When the jmeterPlugin.sts.daemon=true , you need to call http://hostname:port/sts/STOP or kill the process to stop the STS.
  • CONFIG: Display STS Configuration

  • http://hostname:port/sts/ CONFIG
  • Display the STS configuration, e.g.:
  • jmeterPlugin.sts.port=9191 jmeterPlugin.sts.datasetDirectory=null jmeterPlugin.sts.addTimestamp=true jmeterPlugin.sts.demon=false jmeterPlugin.sts.charsetEncodingHttpResponse=UTF-8 jmeterPlugin.sts.charsetEncodingReadFile=UTF-8 jmeterPlugin.sts.charsetEncodingWriteFile=UTF-8 jmeterPlugin.sts.initFileAtStartup= jmeterPlugin.sts.initFileAtStartupRegex=false databaseIsEmpty=false

    Error Response KO

    When the command and/or a parameter are wrong, the result is a page html status 200 but the title contains the label KO .

    Examples:

  • Send an unknown command. Be careful as the command a case sensitive ( READ != read ).
  • -DjmeterPlugin.sts.port=<port number>
    -DjmeterPlugin.sts.loadAndRunOnStartup=<true/false>
    -DjmeterPlugin.sts.datasetDirectory=<path/to/your/directory>
    -DjmeterPlugin.sts.addTimestamp=<true/false>
    -DjmeterPlugin.sts.daemon=<true/false>
    -DjmeterPlugin.sts.charsetEncodingHttpResponse=<charset like UTF-8>
    -DjmeterPlugin.sts.charsetEncodingReadFile=<charset like UTF-8>
    -DjmeterPlugin.sts.charsetEncodingWriteFile=<charset like UTF-8>
    -DjmeterPlugin.sts.initFileAtStartup=<files to read when STS startup, e.g : article.csv,users.csv>
    -DjmeterPlugin.sts.initFileAtStartupRegex=false=<false : no regular expression, files with comma separator, true : read files matching the regular expression>

    STS in the POM of a Test With the jmeter-maven-plugin

    It is possible to use STS in a performance test launched with the jmeter-maven-plugin. To do this:

  • Put your CSV files in the <project>/src/test/jmeter directory (e.g., logins.csv ).
  • Put the simple-table-server.groovy (Groovy script) in the <project>/src/test/jmeter directory.
  • Put your JMeter script in <project>/src/test/jmeter directory (e.g., test_login.jmx ).
  • Declare in the Maven build section, in the configuration <jmeterExtensions> declare the artifact kg.apc:jmeter-plugins-table-server:<version> .
  • Declare user properties for STS configuration and automatic start.
  • If you use a localhost and a proxy configuration, you could add a proxy configuration with <hostExclusions>localhost</hostExclusions> .
  • Extract pom.xml dedicated to HTTP Simple Table Server :
  • <groupId>com.lazerycode.jmeter</groupId> <artifactId>jmeter-maven-plugin</artifactId> <version>3.8.0</version> <configuration> <jmeterExtensions> <artifact>kg.apc:jmeter-plugins-table-server:5.0</artifact> </jmeterExtensions> <propertiesUser> <!-- properties configuration for Http Simple Table Server with automatic start when JMeter start --> <jmeterPlugin.sts.port>9191</jmeterPlugin.sts.port> <jmeterPlugin.sts.addTimestamp>true</jmeterPlugin.sts.addTimestamp> <jmeterPlugin.sts.datasetDirectory>${project.build.directory}/jmeter/testFiles</jmeterPlugin.sts.datasetDirectory> <jmeterPlugin.sts.loadAndRunOnStartup>true</jmeterPlugin.sts.loadAndRunOnStartup> <jsr223.init.file>${project.build.directory}/jmeter/testFiles/simple-table-server.groovy</jsr223.init.file> </propertiesUser> </configuration> </plugin> </plugins> </build>