Other Samplers

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This page was written against Apache JMeter 5.6.3, the latest release on 2026-10-14. It runs on Java 8 and later, and Java 17 or later is recommended. JMeter 6.0 is not released: the differences noted here are planned per xdocs/changes.xml on the master branch, which requires Java 17 or later (Java 21 recommended). The library versions quoted for 5.6.3 come from its build (src/bom-thirdparty): Apache Commons Net 3.10.0 for FTP, JUnit 4.13.2 for the JUnit Request, Neo4j Java driver 4.4.13 for Bolt and mongo-java-driver 2.14.3 for the deprecated MongoDB elements. No element on this page needs the JMeter Plugins Manager 2.0: all of them ship with JMeter itself. The books on the market target JMeter 2.11 to 3.0; they are cited only for the MongoDB sampler, which they still present as a normal element. Every field, default and rule below comes from the official component reference, the FTP, LDAP, extended LDAP and access-log tutorials, the properties file and the change log. Where the documentation is silent and the behaviour is taken from the 5.6.3 source code, the text says so.

Most of a JMeter plan is HTTP. Earlier pages cover the HTTP Request sampler, and the two pages just before this one cover JDBC, JMS, mail and TCP. What is left is a mixed set of samplers. Some measure a protocol of their own (FTP, LDAP, Bolt). Some let a plan run code JMeter does not know about (OS Process, Java Request, JUnit Request). One replays recorded traffic (Access Log Sampler). Two are tools for building and debugging plans rather than measuring anything (Debug Sampler, Flow Control Action). And one, MongoDB Script, is deprecated and planned for removal. Each section below follows the same order: what the sampler does and when to use it, every field, a minimal example, its cost on the load generator, and its pitfalls.

Sampler overview

All the samplers on this page are added from the same menu, Add → Sampler, on a Thread Group or a controller. They follow the normal execution order described in Test Plan Elements, Execution Order & Scoping: configuration elements, pre-processors and timers in scope run before them, and post-processors, assertions and listeners after them. The one exception is the Flow Control Action, which produces no sample result.

Sampler Companion element When to use it Load-test fit Status

FTP Request

FTP Request Defaults

Download (RETR) or upload (STOR) a file on an FTP server, for example an export or import endpoint.

Good; one connection and login per sample.

Current.

LDAP Request

LDAP Request Defaults, Login Config Element

Simple add, modify, search and delete against a directory, including built-in self-cleaning tests.

Fair; each sample opens its own connection.

Current.

LDAP Extended Request

LDAP Extended Request Defaults

A realistic LDAP session: thread bind, search, compare, add, modify, rename, delete, thread unbind, or a single bind/unbind to check a password.

Good; the bind is reused for the whole thread session.

Current.

OS Process Sampler

None

Run a command on the load generator: a seed script, a health check, a CLI client of the system under test.

Poor; a new operating-system process per sample.

Current.

Java Request

Java Request Defaults

Drive any Java client library through your own AbstractJavaSamplerClient class.

Very good; plain Java code, one instance per thread.

Current.

JUnit Request

None

Reuse an existing JUnit 3 or JUnit 4 test method as a sampler.

Good if the tests are thread-safe.

Current; JUnit 4 is the newest supported API.

Bolt Request

Bolt Connection Configuration

Run Cypher queries against Neo4j over the Bolt protocol.

Good; pooled driver connections.

Current; Neo4j driver 6.x planned for 6.0.

Access Log Sampler

None

Replay the request lines of a web server access log as HTTP requests.

Fair; marked "Beta Code", parses only the request line.

Current.

Debug Sampler

None

Show JMeter variables, JMeter properties and system properties while building a plan.

None; disable it for load runs.

Current.

Flow Control Action

A timer as child (optional)

Pause, stop the thread or the test, or change loop flow, typically inside an If Controller.

Very good; generates no sample.

Current; called Test Action before 5.0.

MongoDB Script

MongoDB Source Config

Functional checks or set-up scripts against MongoDB, through the long-deprecated DB#eval.

Not suitable (global write lock).

Deprecated since 3.0, hidden from the menu, removal planned in 6.0.

The same choice as a decision tree:

flowchart TD A[What must the virtual user do?] --> B{Speak a protocol JMeter knows?} B -- FTP --> FTP[FTP Request] B -- LDAP --> L{Need a session or rename, compare?} L -- no --> LR[LDAP Request] L -- yes --> LX[LDAP Extended Request] B -- Neo4j Bolt --> BO[Bolt Request] B -- MongoDB --> MG[JSR223 Sampler with your own driver] B -- none of these --> C{Is there a Java client or test?} C -- client library --> JR[Java Request] C -- JUnit test --> JU[JUnit Request] C -- only a command line tool --> OS[OS Process Sampler] A --> D{Replay production traffic?} D -- yes --> AL[Access Log Sampler] A --> E{Control the flow or debug the plan?} E -- pause or stop --> FC[Flow Control Action] E -- inspect variables --> DS[Debug Sampler]

Two other samplers are close cousins of this list and are covered elsewhere: the JSR223 Sampler in Scripting with JSR223 & Groovy, and the JDBC, JMS, SMTP, Mail Reader and TCP samplers in the database and messaging pages of this section.

FTP Request

What it does and when to use it

The FTP Request sends one FTP "retrieve file" or "upload file" request per sample. For a download the file can be stored on disk (Local File), kept in the response data, or both. Use it when the system under test exposes FTP as a real interface: a nightly catalogue export a partner downloads, or an import folder a supplier uploads to. It speaks plain FTP only; the element has no option for FTPS or SFTP.

In the 5.6.3 source each sample creates a new Apache Commons Net FTPClient, connects, logs in, switches to passive mode, transfers the file, logs out and disconnects. The component reference states that Latency is set to the time it takes to login; the source takes the latency mark right after the connection is established, before the login. In both readings, the elapsed time of the sample covers the whole connect, login, transfer and logout cycle, so an FTP sample measures a complete session, not just the transfer.

Fields

GUI field Meaning JMX property Required

Name

Label shown in the tree and in results.

testname

No

Server Name or IP

Domain name or IP address of the FTP server.

FTPSampler.server

Yes

Port

Port to use; if it is greater than 0 that port is used, otherwise the default FTP port.

FTPSampler.port

No

Remote File

File to retrieve, or name of the destination file to upload.

FTPSampler.filename

Yes

Local File

File to upload, or destination for downloads (defaults to the remote file name).

FTPSampler.localfilename

Yes, if uploading (or Local File Contents)

Local File Contents

The contents to upload; overrides Local File.

FTPSampler.inputdata

Yes, if uploading (or Local File)

get(RETR) / put(STOR)

Whether to retrieve or upload a file.

FTPSampler.upload (true for put)

Yes

Use Binary mode?

Binary transfer; the default is ASCII.

FTPSampler.binarymode

Yes

Save File in Response?

Store the contents of the retrieved file in the response data. In ASCII mode they are visible in View Results Tree.

FTPSampler.saveresponse

Yes, if downloading

Username

FTP account user name.

ConfigTestElement.username

Usually

Password

FTP account password. It is stored in clear text in the test plan.

ConfigTestElement.password

Usually

FTP Request Defaults (Add → Config Element → FTP Request Defaults) has the same server, port, file and mode fields and supplies them to every FTP Request in its scope that leaves them empty.

Example: download the Bookshelf catalogue export

The official tutorial builds 4 users that fetch two files twice: (4 users) × (2 requests) × (2 loops) = 16 FTP requests. The Bookshelf version below is the same shape, aimed at a local FTP server that publishes the nightly catalogue export:

  1. Select the Test Plan, then Add → Threads (Users) → Thread Group. Name it FTP Users, set Number of Threads to 4, Ramp-up period to 0 and Loop Count to 2.

  2. On FTP Users, Add → Config Element → FTP Request Defaults. Set Server Name or IP to ${__P(host,localhost)}. Leave every other field empty.

  3. Add → Sampler → FTP Request. Name it catalogue.csv, set Remote File to /exports/catalogue.csv, choose get(RETR), tick Use Binary mode?, and fill Username and Password from properties.

  4. Add a second FTP Request named covers.zip for /exports/covers.zip, also in binary mode.

  5. Add → Listener → View Results in Table while checking the plan; remove it for the real run.

<ConfigTestElement guiclass="FtpConfigGui" testclass="ConfigTestElement" testname="FTP Request Defaults">
  <stringProp name="FTPSampler.server">${__P(host,localhost)}</stringProp>
  <stringProp name="FTPSampler.port"></stringProp>
  <stringProp name="FTPSampler.filename"></stringProp>
  <stringProp name="FTPSampler.localfilename"></stringProp>
  <stringProp name="FTPSampler.inputdata"></stringProp>
  <boolProp name="FTPSampler.binarymode">false</boolProp>
  <boolProp name="FTPSampler.saveresponse">false</boolProp>
  <boolProp name="FTPSampler.upload">false</boolProp>
</ConfigTestElement>
<hashTree/>
<FTPSampler guiclass="FtpTestSamplerGui" testclass="FTPSampler" testname="catalogue.csv">
  <stringProp name="FTPSampler.server"></stringProp>
  <stringProp name="FTPSampler.port"></stringProp>
  <stringProp name="FTPSampler.filename">/exports/catalogue.csv</stringProp>
  <stringProp name="FTPSampler.localfilename"></stringProp>
  <stringProp name="FTPSampler.inputdata"></stringProp>
  <boolProp name="FTPSampler.binarymode">true</boolProp>
  <boolProp name="FTPSampler.saveresponse">false</boolProp>
  <boolProp name="FTPSampler.upload">false</boolProp>
  <stringProp name="ConfigTestElement.username">${__P(ftp_user,bookshelf)}</stringProp>
  <stringProp name="ConfigTestElement.password">${__P(ftp_password,changeme)}</stringProp>
</FTPSampler>
<hashTree/>

The response code of a successful transfer is 200 (JMeter’s generic OK), and a refused transfer carries the FTP reply code and reply text (for example 550) as response code and message, so a Response Assertion on the code works as it does for HTTP. A connection failure is reported as 501, Could not connect, and an exception as 000.

Cost and pitfalls

  • Local File for downloads. With Local File set, every thread writes to that same path on disk. Leave it empty and untick Save File in Response? so that the transfer is measured without disk writes or memory use; tick it only on a debug run.

  • Big files in the response. Save File in Response? keeps the whole file in memory for every sample. A 50 MB export downloaded by 4 threads holds 200 MB of heap at once.

  • Clear-text credentials. The password is saved in the .jmx. Use ${__P(ftp_password,changeme)} and pass the real value with -Jftp_password=... on the command line, never commit it.

  • No connection reuse. Each sample pays the connection and login cost. If the real clients keep a session open for many transfers, the test is more pessimistic than production.

LDAP Request

What it does and when to use it

The LDAP Request sends one of four operations to an LDAP server: Add, Modify, Search or Delete. Each operation can run as an inbuilt test or a user defined test:

Operation Inbuilt test User defined test

Add

Adds a predefined entry, measures the time, then deletes the entry.

Adds the entry described in the table; the entry is not deleted afterwards.

Modify

Creates a predefined entry, modifies it, measures the time, then deletes it.

Modifies the entry described in the table; the entry is not deleted.

Search

Creates the entry, searches for its attributes, measures the search, then deletes it.

Searches with the given search filter in the given search base; the entries must already exist.

Delete

Creates a predefined entry, then deletes it and measures the time.

Deletes the given entry, which must already exist.

Inbuilt tests are self-cleaning, which makes them a quick way to check that a directory accepts writes under load. User defined tests are the ones that resemble real traffic. Use the LDAP Request for simple, independent operations. When the traffic is a session (bind once, then several operations), use the LDAP Extended Request instead.

Fields

GUI field Meaning JMX property Required

Server Name or IP

Domain name or IP address of the LDAP server.

servername

Yes

Port

Port to connect to; default 389.

port

Yes

root DN

Base DN for the operations.

rootdn

Yes

Username / Password

LDAP user and password, usually supplied by a Login Config Element. The password is stored unencrypted.

ConfigTestElement.username, ConfigTestElement.password

Usually

Test Configuration (Inbuilt / User defined)

Which kind of test to run.

user_defined (true for user defined)

Yes

Add / Modify / Search / Delete

The operation.

test (add, modify, search, delete)

Yes

Entry DN

Context to create or modify; you must supply its attributes yourself (to add cn=apache,ou=test, add cn = apache to the table).

base_entry_dn

User defined Add or Modify

Delete

Context to delete.

delete

User defined Delete

Search base

Context or object to search.

search

User defined Search

Search filter

Filter expression for the search; may not be null.

searchfilter

User defined Search

add test / modify test table

Name and value pairs for the new or modified object.

arguments

User defined Add or Modify

LDAP Request Defaults (Add → Config Element → LDAP Request Defaults) supplies server, port and DN to every LDAP Request in scope; the Login Config Element (Add → Config Element → Login Config Element) supplies user and password.

Example: the four inbuilt tests

The official tutorial runs the four inbuilt tests with 4 users and 4 loops: (4 users) × (4 requests) × (4 loops) = 64 LDAP requests. Against a local directory for the Bookshelf users (dc=bookshelf,dc=local):

  1. Add → Threads (Users) → Thread Group named LDAP Users: 4 threads, Loop Count 4.

  2. On LDAP Users, Add → Config Element → Login Config Element: Username cn=admin,dc=bookshelf,dc=local, Password ${__P(ldap_password,changeme)}.

  3. Add → Config Element → LDAP Request Defaults: Servername ${__P(host,localhost)}, Port 389, DN dc=bookshelf,dc=local.

  4. Add four LDAP Request samplers named Add, Search, Modify and Delete, and select the Add Test, Search Test, Modify Test and Delete Test radio button on each (Test Configuration left at Inbuilt). JMeter runs them in tree order.

  5. Add → Assertions → Response Assertion on LDAP Users: Text Response, Substring, pattern successful. At that position it applies to every LDAP Request.

  6. Add → Listener → View Results in Table while checking the plan.

<LDAPSampler guiclass="LdapTestSamplerGui" testclass="LDAPSampler" testname="Search">
  <stringProp name="servername"></stringProp>
  <stringProp name="port"></stringProp>
  <stringProp name="rootdn"></stringProp>
  <boolProp name="user_defined">false</boolProp>
  <stringProp name="test">search</stringProp>
  <stringProp name="base_entry_dn"></stringProp>
  <elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
    <collectionProp name="Arguments.arguments"/>
  </elementProp>
  <stringProp name="ConfigTestElement.username"></stringProp>
  <stringProp name="ConfigTestElement.password"></stringProp>
</LDAPSampler>
<hashTree/>

Cost and pitfalls

  • Inbuilt tests measure more than one operation’s setup. An inbuilt Search creates and deletes an entry around the measured search, so the directory sees three writes per sample even though only one search is timed.

  • User defined Add leaves data behind. A load test that adds 10,000 entries leaves 10,000 entries; pair it with a user defined Delete or a clean-up in a tearDown Thread Group.

  • One connection per sample. Each sample is independent; for session traffic the LDAP Extended Request is closer to reality.

  • Credentials in the plan. Like every JMeter password field, it is stored unencrypted; feed it from a property.

LDAP Extended Request

What it does and when to use it

The LDAP Extended Request is the full-featured LDAP sampler. It is harder to configure than the LDAP Request but much closer to a real LDAP session. Any LDAP request is part of a session, so a thread starts with a Thread bind, runs its operations on that connection, and ends with a Thread unbind. The available operations are:

Operation LDAP operation Notes

Thread bind

bind

Opens the thread’s session. With no password, or a wrong password, the session is anonymous; omitting the password does not fail the test, but a wrong one does.

Thread unbind

unbind

Ends the session.

Single bind/unbind

bind + unbind

Opens a new session just to check a user and password, then closes it: an authentication check. It is really two operations that cannot be split.

Rename entry

moddn

Renames an entry, or moves an entry or a whole subtree elsewhere in the tree.

Add test

add

Adds any kind of object.

Delete test

delete

Deletes an object.

Search test

search

Searches with scope, size and time limits.

Modification test

modify

Adds, deletes or replaces attribute values; all modifications must succeed or none is applied.

Compare

compare

Compares an attribute with a value, typically to check group membership (the user’s DN against member of a groupOfNames). A failed compare fails the sample with error code 49.

Fields

Every operation has a Name. The others depend on the selected operation:

Operation GUI field Meaning JMX property

Thread bind

Servername

Name or IP of the LDAP server (required).

servername

Thread bind

Port

Port; if omitted, 389.

port

Thread bind

DN

Base object for every later operation; no operation can start above it.

rootdn

Thread bind / Single bind

Username

Full DN of the user to bind as.

user_dn

Thread bind / Single bind

Password

Password for that user; omitted means anonymous; stored unencrypted.

user_pw

Thread bind

Connection timeout (in milliseconds)

Aborts the connection when exceeded.

connection_timeout

Thread bind

Use Secure LDAP Protocol

Use ldaps:// instead of ldap://.

secure

Thread bind

Trust All Certificates

Trust every certificate; only used with the secure protocol.

trustall

Rename entry

Old entry name / New distinguished name

Current and new DN, relative to the bind DN.

modddn, newdn

Add test

Entry DN / attribute table

DN to add (relative) and its attributes; repeat an attribute for multiple values.

base_entry_dn, arguments

Delete test

Delete

DN to delete, relative to the bind DN.

delete

Search test

Search base

Subtree to search, relative to the bind DN; empty means the bind DN.

search

Search test

Search Filter

Filter in LDAP syntax (required).

searchfilter

Search test

Scope

0 base object, 1 one level, 2 subtree (default 0 per the reference).

scope

Search test

Size Limit

Maximum number of results; 0 means no limit. Hitting it fails the sample with error code 4.

countlimit

Search test

Time Limit

Maximum CPU time in ms the server may spend; 0 means no limit. It says nothing about response time.

timelimit

Search test

Attributes

Attributes to return, separated by semicolons; empty returns all.

attributes

Search test

Return object

Return the Java object attributes too (default false).

return_object

Search test

Dereference aliases

Follow aliases (default false).

deref_aliases

Search test

Parse the search results?

Put the results in the response data; otherwise only a found/not-found marker.

parseflag

Modification test

Entry name / attribute-value-opCode table

DN to modify and the add, delete or replace operations.

base_entry_dn, ldaparguments

Compare

Entry DN / Compare filter

DN to compare and an attribute=value filter.

comparedn, comparefilt

The selected operation is stored in the test property (bind, unbind, sbind, rename, add, delete, search, modify, compare). LDAP Extended Request Defaults (Add → Config Element → LDAP Extended Request Defaults) can pre-fill any of these fields; a value entered in a sampler overrides the default. When a value that a test needs is missing everywhere, the tutorial warns that the test fails in an unpredictable way.

Example: a Bookshelf directory session

The official tutorial adds the nine operations in order for 1 user and 1 loop: (1 user) × (9 requests) × (1 loop) = 9 LDAP requests. A realistic Bookshelf session keeps only the read path: bind as the service account, look the user up, check group membership and unbind.

  1. Add → Threads (Users) → Thread Group named LDAP Ext Users.

  2. Add → Sampler → LDAP Extended Request, named 1. Thread bind: select Thread bind, Servername ${__P(host,localhost)}, Port 389, DN dc=bookshelf,dc=local, Username cn=reader,dc=bookshelf,dc=local, Password ${__P(ldap_password,changeme)}.

  3. 2. Search Test: select Search Test, Search base ou=users, Search Filter (uid=${username}), Scope subtree, Attributes cn;mail.

  4. 3. Compare Test: select Compare, Entry DN cn=librarians,ou=groups, Compare filter member=uid=${username},ou=users,dc=bookshelf,dc=local.

  5. 4. Thread unbind: select Thread unbind.

  6. Add → Listener → View Results Tree while checking: its response data shows the request and the answer in an XML-style format.

<LDAPExtSampler guiclass="LdapExtTestSamplerGui" testclass="LDAPExtSampler" testname="2. Search Test">
  <stringProp name="test">search</stringProp>
  <stringProp name="search">ou=users</stringProp>
  <stringProp name="searchfilter">(uid=${username})</stringProp>
  <stringProp name="scope">2</stringProp>
  <stringProp name="countlimit"></stringProp>
  <stringProp name="timelimit"></stringProp>
  <stringProp name="attributes">cn;mail</stringProp>
  <stringProp name="return_object">false</stringProp>
  <stringProp name="deref_aliases">false</stringProp>
  <stringProp name="parseflag">true</stringProp>
</LDAPExtSampler>
<hashTree/>

username comes from the users.csv CSV Data Set Config that the rest of the section uses (see Parameterization & Test Data).

Cost and pitfalls

  • Special characters in DNs. Escape LDAP special characters with a backslash (cn=smith\+jones for a DN with a plus sign). To put a backslash itself in a DN for an add or rename, the tutorial requires four backslashes.

  • Relative names. Every DN after the thread bind is relative to the bind DN. Entering a full DN in a search base doubles the suffix and the search finds nothing.

  • Time Limit is not a timeout. It caps server CPU time only; a large result over a slow link can still take a long time. Use the connection timeout and a Duration Assertion for response-time limits.

  • Attributes. Requesting all attributes returns large ones such as jpegPhoto; list only what the client really reads, or "" to return none.

  • Parse the search results? Putting the results in the response costs memory per sample; leave it off for load runs unless an assertion needs them.

  • Single bind/unbind for logins. It is the right element for "check this password" traffic, and it is two network operations, not one.

OS Process Sampler

What it does and when to use it

The OS Process Sampler executes a command on the load generator machine. Any command that can be run from the command line can be run, and the return code can be validated. Typical uses: a setUp Thread Group that seeds the Bookshelf database with a script, a health check before the load starts, or driving a command-line client of the system under test when nothing else can speak its protocol.

The sampler deliberately does no parsing or quoting. The command and each parameter are passed as given, so the settings are not portable between operating systems, and shell built-ins (Windows DIR, the POSIX shell’s cd) must be passed to their command interpreter: Command CMD, Param 1 /C, Param 2 DIR, Param 3 the folder.

Fields

GUI field Meaning JMX property Required

Command

Program to execute.

SystemSampler.command

Yes

Working directory

Directory to run in; defaults to the user.dir system property.

SystemSampler.directory

No

Command Parameters

Parameters passed to the program, one per row.

SystemSampler.arguments

No

Environment Parameters

Key/value pairs added to the environment.

SystemSampler.environment

No

Standard input (stdin)

File to read standard input from.

SystemSampler.stdin

No

Standard output (stdout)

File to write standard output to; if omitted it is captured as response data.

SystemSampler.stdout

No

Standard error (stderr)

File to write standard error to; if omitted it is captured as response data.

SystemSampler.stderr

No

Check Return Code

Compare the return code with the expected one.

SystemSampler.checkReturnCode

No

Expected Return Code

Expected code; do not use 500, which JMeter uses as an error indicator.

SystemSampler.expectedReturnCode

If checking

Timeout

Milliseconds; 0 (default) means none. On expiry JMeter tries to kill the process.

SystemSampler.timeout

No

Example: wait for the Bookshelf API before the test

In a setUp Thread Group (1 thread, 1 loop), Add → Sampler → OS Process Sampler: Command curl, parameters --silent, --fail, --retry, 10, --retry-connrefused, and the URL; Check Return Code ticked with expected code 0; Timeout 60000. If the API is still down after the retries, curl returns a non-zero code, the sample fails, and the Thread Group’s Action to be taken after a Sampler error can stop the test before the load starts.

<SystemSampler guiclass="SystemSamplerGui" testclass="SystemSampler" testname="Wait for Bookshelf API">
  <boolProp name="SystemSampler.checkReturnCode">true</boolProp>
  <stringProp name="SystemSampler.expectedReturnCode">0</stringProp>
  <stringProp name="SystemSampler.command">curl</stringProp>
  <elementProp name="SystemSampler.arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
    <collectionProp name="Arguments.arguments">
      <elementProp name="" elementType="Argument">
        <stringProp name="Argument.name"></stringProp>
        <stringProp name="Argument.value">--silent</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
      <elementProp name="" elementType="Argument">
        <stringProp name="Argument.name"></stringProp>
        <stringProp name="Argument.value">--fail</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
      <elementProp name="" elementType="Argument">
        <stringProp name="Argument.name"></stringProp>
        <stringProp name="Argument.value">--retry</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
      <elementProp name="" elementType="Argument">
        <stringProp name="Argument.name"></stringProp>
        <stringProp name="Argument.value">10</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
      <elementProp name="" elementType="Argument">
        <stringProp name="Argument.name"></stringProp>
        <stringProp name="Argument.value">--retry-connrefused</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
      <elementProp name="" elementType="Argument">
        <stringProp name="Argument.name"></stringProp>
        <stringProp name="Argument.value">http://${__P(host,localhost)}:${__P(port,8080)}/api/books?query=health</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
    </collectionProp>
  </elementProp>
  <elementProp name="SystemSampler.environment" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
    <collectionProp name="Arguments.arguments"/>
  </elementProp>
  <stringProp name="SystemSampler.directory"></stringProp>
  <longProp name="SystemSampler.timeout">60000</longProp>
</SystemSampler>
<hashTree/>

The curl options belong to curl itself, not to JMeter. The response code of the sample is the process’s return code; with Check Return Code the response message is OK or Unexpected return code. Expected [0]. Actual [n]. If the process cannot be started or is interrupted, the 5.6.3 source sets response code 500, which is why the documentation reserves that value.

Cost and pitfalls

  • A process per sample. Starting an operating-system process costs far more than an HTTP request: memory for the new process, a fork, and the program’s own start-up. Keep the sampler in setUp and tearDown Thread Groups or in low-rate paths; never put it in the main loop of 50 threads.

  • It measures the command, including its start-up. Timing curl with this sampler measures curl’s start-up as much as the server; the HTTP Request sampler is the right tool for HTTP.

  • Security. The command runs with the rights of the JMeter user on every load generator, including remote servers in distributed tests. Never build a command from response data.

  • Portability. A plan that calls CMD /C does not run on Linux CI agents and vice versa; keep OS-specific steps in a separate Test Fragment.

Java Request

What it does and when to use it

The Java Request controls a Java class that implements org.apache.jmeter.protocol.java.sampler.JavaSamplerClient. By writing such a class you can put any Java client library (a proprietary protocol, a vendor SDK, a cache client) under load and still let JMeter supply threads, parameters and result collection. The Classname drop-down lists every implementation JMeter finds; two examples ship with it, JavaTest and SleepTest. JavaTest lets you set almost every field of the result, which is handy for checking assertions and listeners without a server.

The life cycle comes from the interface’s Javadoc. JMeter creates one instance of the class per thread. When the test starts it calls setupTest on each thread’s instance, then runTest once per iteration, and finally teardownTest. Parameters are read through a JavaSamplerContext, and getDefaultParameters declares the parameter names and default values the GUI shows. Extend AbstractJavaSamplerClient rather than implementing the interface directly: it provides default implementations, and JMeter only calls teardownTest when a subclass overrides it, which reduces memory use.

Fields

GUI field Meaning JMX property Required

Name

Label shown in the tree.

testname

No

Classname

The JavaSamplerClient implementation to run.

classname

Yes

Send Parameters with Request

Arguments passed to the class, all as strings; the rows come from getDefaultParameters. The Add/Delete buttons have no purpose at present.

arguments

No

The parameters of the bundled examples:

Parameter Applies to Meaning

Sleep_Time

SleepTest, JavaTest

How long to sleep, in ms.

Sleep_Mask

SleepTest, JavaTest

Randomness added: total sleep = Sleep_Time + (System.currentTimeMillis() % Sleep_Mask).

Label

JavaTest

Overrides the sample label.

ResponseCode, ResponseMessage

JavaTest

Set the result’s response code and message.

Status

JavaTest

OK (any case) marks the sample successful, anything else failed.

SamplerData, ResultData

JavaTest

Set the request and response data of the result.

Java Request Defaults (Add → Config Element → Java Request Defaults) sets default values for Java Requests in scope.

The class below measures GET /api/books?query= with the JDK’s own HTTP client, standing in for any Java client library. It reads its parameters once in setupTest, times only the call in runTest, and reports the HTTP status:

package com.example.bookshelf.jmeter;

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

public class BookSearchClient extends AbstractJavaSamplerClient {

    private HttpClient client;
    private String baseUrl;

    @Override
    public Arguments getDefaultParameters() {
        Arguments args = new Arguments();
        args.addArgument("baseUrl", "http://${__P(host,localhost)}:${__P(port,8080)}");
        args.addArgument("term", "${term}");
        args.addArgument("timeoutMs", "5000");
        return args;
    }

    @Override
    public void setupTest(JavaSamplerContext context) {
        baseUrl = context.getParameter("baseUrl");
        client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMillis(context.getLongParameter("timeoutMs", 5000)))
                .build();
    }

    @Override
    public SampleResult runTest(JavaSamplerContext context) {
        String term = context.getParameter("term", "java");
        SampleResult result = new SampleResult();
        result.setSampleLabel("Java search");
        result.setSamplerData("GET /api/books?query=" + term);
        HttpRequest request = HttpRequest.newBuilder(URI.create(
                baseUrl + "/api/books?query=" + URLEncoder.encode(term, StandardCharsets.UTF_8))).GET().build();
        result.sampleStart();
        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            result.sampleEnd();
            result.setResponseCode(String.valueOf(response.statusCode()));
            result.setResponseData(response.body(), StandardCharsets.UTF_8.name());
            result.setSuccessful(response.statusCode() == 200);
        } catch (Exception e) {
            result.sampleEnd();
            result.setResponseCode("500");
            result.setResponseMessage(e.toString());
            result.setSuccessful(false);
        }
        return result;
    }
}

Compile it against ApacheJMeter_core and ApacheJMeter_java 5.6.3 (both on Maven Central under org.apache.jmeter) with Java 11 or later (for java.net.http), package it as a jar and copy the jar to lib/ext. The default parameter values are expressions; the Java Request evaluates them per sample like any other field, so term follows the CSV data. The sampler block in the plan then looks like this:

<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java search">
  <elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
    <collectionProp name="Arguments.arguments">
      <elementProp name="baseUrl" elementType="Argument">
        <stringProp name="Argument.name">baseUrl</stringProp>
        <stringProp name="Argument.value">http://${__P(host,localhost)}:${__P(port,8080)}</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
      <elementProp name="term" elementType="Argument">
        <stringProp name="Argument.name">term</stringProp>
        <stringProp name="Argument.value">${term}</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
      <elementProp name="timeoutMs" elementType="Argument">
        <stringProp name="Argument.name">timeoutMs</stringProp>
        <stringProp name="Argument.value">5000</stringProp>
        <stringProp name="Argument.metadata">=</stringProp>
      </elementProp>
    </collectionProp>
  </elementProp>
  <stringProp name="classname">com.example.bookshelf.jmeter.BookSearchClient</stringProp>
</JavaSampler>
<hashTree/>

How the class is found. JMeter 5.6 started loading plugins through Java’s ServiceLoader instead of classpath scanning (PR 5885). In 5.6.3 the Java Request still does both: it loads JavaSamplerClient services and also scans the jars on the search path, and the source marks the scanning as a transition step towards ServiceLoader-only lookup. A jar built today should therefore also carry a service file, so it keeps working when the scanning goes:

src/main/resources/META-INF/services/org.apache.jmeter.protocol.java.sampler.JavaSamplerClient

containing the single line com.example.bookshelf.jmeter.BookSearchClient.

Worked numbers. With the canonical load profile (50 threads, 60 s ramp-up) and the section’s 3 s think time, a Java Request whose call takes 0.2 s cycles every 3.2 s per thread: 50 / 3.2 ≈ 15.6 samples per second at full load, exactly like the HTTP version of the same step. The Java Request adds no overhead of its own beyond the class’s code.

Cost and pitfalls

  • State in fields is per thread. Each thread has its own instance, so fields set in setupTest are safe. Static fields are shared by all threads and need thread-safe types.

  • Time only the call. Put parameter parsing and client creation in setupTest; whatever happens between sampleStart() and sampleEnd() is what the reports show.

  • Classname changes lose parameters. The GUI warns that changing the class of an existing Java Request may drop the parameters of the original plan.

  • Class not found. After copying the jar, restart JMeter; the GUI shows Classname not found in classpath when the class is missing.

  • Reuse versus a plugin. A Java Request has no GUI of its own beyond the parameter table. When a team needs a reusable element with fields, the page on extending JMeter later in this section covers writing a full sampler.

JUnit Request

What it does and when to use it

The JUnit Request runs an existing JUnit test method as a sampler, so a suite of functional tests can be put under load without rewriting it. It supports the standard JUnit 3 convention (classes extending TestCase) and, with Search for JUnit 4 annotations ticked, JUnit 4 annotations. The documentation does not mention JUnit 5 (Jupiter), and 5.6.3 bundles JUnit 4.13.2, so tests written for JUnit 5 only must be adapted or run through a Java Request instead.

Key differences from a normal JUnit runner:

  • JMeter creates one instance of the class per sampler and reuses it, unless Create a new instance per sample is ticked.

  • It measures only the test method: setUp and tearDown (or @Before and @After) run but are not timed.

  • oneTimeSetUp and oneTimeTearDown are supported as methods, and @BeforeClass and @AfterClass are treated as test methods so they can be run on their own, for example in a setUp Thread Group.

  • It looks for a constructor taking a String first, then an empty constructor.

  • Unexpected exceptions are reported as errors.

  • JUnit test jars go in lib/junit, not lib; the user.classpath property can point elsewhere.

The recognised JUnit 4 annotations are @Test (with its expected and timeout attributes), @Before, @After, @BeforeClass and @AfterClass.

Fields

GUI field Meaning JMX property

Search for JUnit 4 annotations

Look for @Test methods instead of JUnit 3 TestCase classes.

junitsampler.junit4

Package Filter

Comma-separated list of packages to show in the class list.

junitsampler.pkg.filter

Class name

Fully qualified test class (required).

junitSampler.classname

Constructor String

String passed to the string constructor; when set, that constructor is used.

junitsampler.constructorstring

Test Method

The method to run (required).

junitsampler.method

Success Message / Success Code

Message and unique code for success (defaults Test successful, 1000).

junitsampler.success, junitsampler.success.code

Failure Message / Failure Code

Message and unique code for failure (defaults Test failed, 0001).

junitsampler.failure, junitsampler.failure.code

Error Message / Error Code

Message and code for errors (defaults An unexpected error occurred, 9999).

junitsampler.error, junitsampler.error.code

Do not call setUp and tearDown

Skip setUp and tearDown; tick it when the selected method is oneTimeSetUp or oneTimeTearDown.

junitsampler.exec.setup

Append assertion errors

Add assertion errors to the response message.

junitsampler.append.error

Append runtime exceptions

Add runtime exceptions to the response message (only if the previous box is unticked).

junitsampler.append.exception

Create a new instance per sample

New test-class instance for each sample (default false).

junitsampler.createinstancepersample

Example: reuse a Bookshelf smoke test

package com.example.bookshelf.smoke;

import static org.junit.Assert.assertEquals;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import org.junit.Before;
import org.junit.Test;

public class BookSearchSmokeTest {

    private HttpClient client;
    private String baseUrl;

    @Before
    public void setUp() {
        client = HttpClient.newHttpClient();
        baseUrl = System.getProperty("bookshelf.url", "http://localhost:8080");
    }

    @Test(timeout = 2000)
    public void searchReturnsOk() throws Exception {
        HttpResponse<String> response = client.send(
                HttpRequest.newBuilder(URI.create(baseUrl + "/api/books?query=java")).GET().build(),
                HttpResponse.BodyHandlers.ofString());
        assertEquals(200, response.statusCode());
    }
}

Package the compiled test classes as a jar, copy it to lib/junit, then Add → Sampler → JUnit Request: tick Search for JUnit 4 annotations, set Package Filter to com.example.bookshelf, pick com.example.bookshelf.smoke.BookSearchSmokeTest and the method searchReturnsOk. The setUp is public, as the documentation requires, and keeps no static state. Pass the URL as a system property with -Dbookshelf.url=... when JMeter starts.

<JUnitSampler guiclass="JUnitTestSamplerGui" testclass="JUnitSampler" testname="JUnit search smoke">
  <stringProp name="junitSampler.classname">com.example.bookshelf.smoke.BookSearchSmokeTest</stringProp>
  <stringProp name="junitsampler.constructorstring"></stringProp>
  <stringProp name="junitsampler.method">searchReturnsOk</stringProp>
  <stringProp name="junitsampler.pkg.filter">com.example.bookshelf</stringProp>
  <stringProp name="junitsampler.success">Test successful</stringProp>
  <stringProp name="junitsampler.success.code">1000</stringProp>
  <stringProp name="junitsampler.failure">Test failed</stringProp>
  <stringProp name="junitsampler.failure.code">0001</stringProp>
  <stringProp name="junitsampler.error">An unexpected error occurred</stringProp>
  <stringProp name="junitsampler.error.code">9999</stringProp>
  <stringProp name="junitsampler.exec.setup">false</stringProp>
  <stringProp name="junitsampler.append.error">true</stringProp>
  <stringProp name="junitsampler.append.exception">false</stringProp>
  <boolProp name="junitsampler.junit4">true</boolProp>
  <boolProp name="junitsampler.createinstancepersample">false</boolProp>
</JUnitSampler>
<hashTree/>

Cost and pitfalls

The documentation’s own guidelines for tests that run well under JMeter:

  • Make setUp and tearDown public and thread-safe; avoid static members.

  • Keep each test method a discrete unit of work, not a long sequence of actions.

  • Do not make test methods depend on each other: JMeter can run them in any order.

  • Read configurable values from the jar rather than from files that differ per machine.

  • Because one instance is reused per sampler, put expensive initialisation in oneTimeSetUp.

  • Define unique success and failure codes and use them consistently, so results can be filtered.

The sampler itself is cheap. The cost is the test code: a test that creates a new HTTP client in setUp creates one per sample, which is slower than production clients that reuse connections.

Bolt Request

What it does and when to use it

The Bolt Request runs Cypher queries against Neo4j over the Bolt protocol. It was added in JMeter 5.2; 5.5 added the database, access-mode and transaction-timeout options and the pool-size setting. Each request takes a connection from the pool of a Bolt Connection Configuration and returns it when the sample completes. The measured time is the full query execution: running the Cypher statement and consuming the results the database sends back.

For Neo4j itself (the property graph model, Cypher, drivers, transactions and clustering), see the Neo4j Reference, in particular Cypher fundamentals and Transactions and drivers. This section adds only what JMeter needs.

Fields

Bolt Connection Configuration (Add → Config Element → Bolt Connection Configuration):

GUI field Meaning JMX property Default

Bolt URI

Database URI: bolt://host:port for a direct connection, neo4j://host:port for a cluster.

boltUri

bolt://localhost:7687

Username

User account.

username

neo4j

Password

User credentials.

password

empty

Connection Pool Max Size

Size of the driver’s Bolt connection pool. Raise it with many threads so they do not wait for a connection.

maxConnectionPoolSize

100

Bolt Request (Add → Sampler → Bolt Request):

GUI field Meaning JMX property

Cypher Statement

The query to execute (required).

cypher

Params

Parameter values, JSON formatted.

params

Record Query Results

Add the result data to the response (default false). Memory overhead: debug only.

recordQueryResults

Access Mode

WRITE or READ. Use WRITE for a standalone Neo4j; in a cluster it routes to the leader, followers or read replicas.

accessMode

Database

Database to query. Required for Neo4j 4.0 and later unless querying the default database; must be empty for 3.5.

database

Transaction timeout

Timeout for the transaction. The documentation gives no unit; the GUI tooltip and the 5.6.3 source use seconds, and 0 means no timeout.

txTimeout

The documentation strongly advises query parameters, which let the database cache and reuse execution plans. Concatenating ${bookId} into the Cypher text produces a new query text per value and defeats that cache.

Example: Bookshelf recommendations

Suppose Bookshelf keeps "readers also borrowed" links in a local Neo4j as (:Book)-[:ALSO_BORROWED]->(:Book). The request below reads five recommendations for the book the user is viewing:

<BoltConnectionElement guiclass="TestBeanGUI" testclass="BoltConnectionElement" testname="Bolt Connection Configuration">
  <stringProp name="boltUri">bolt://${__P(host,localhost)}:7687</stringProp>
  <stringProp name="username">neo4j</stringProp>
  <stringProp name="password">${__P(neo4j_password,changeme)}</stringProp>
  <intProp name="maxConnectionPoolSize">100</intProp>
</BoltConnectionElement>
<hashTree/>
<BoltSampler guiclass="TestBeanGUI" testclass="BoltSampler" testname="Recommendations">
  <stringProp name="cypher">MATCH (b:Book {id: $bookId})-[:ALSO_BORROWED]->(r:Book) RETURN r.title LIMIT 5</stringProp>
  <stringProp name="params">{"bookId": "${bookId}"}</stringProp>
  <boolProp name="recordQueryResults">false</boolProp>
  <stringProp name="accessMode">READ</stringProp>
  <stringProp name="database">neo4j</stringProp>
  <intProp name="txTimeout">5</intProp>
</BoltSampler>
<hashTree/>

$bookId is a Cypher parameter resolved by Neo4j; ${bookId} is a JMeter variable resolved by JMeter inside the JSON of Params. The two are not the same thing, and only the JMeter one is substituted before the query is sent.

Worked numbers for the pool. The 5.6.3 source creates one driver, with the configured pool, when the test starts, and every Bolt Request borrows from it. With 150 threads and the default pool of 100, at most 100 queries can be in flight, and up to 50 threads wait for a connection; that wait is inside the measured time. If a query takes 20 ms and think time is 3 s, each thread holds a connection less than 1 % of the time and 100 connections are plenty; the pool only matters for short think times or long queries. Size it as at least the number of threads that can run a Bolt Request at the same moment.

Cost and pitfalls

  • Record Query Results. It iterates the whole result set into the response; leave it off for load runs.

  • Access mode on a cluster. A read query sent as WRITE all goes to the leader and overloads it; mark reads as READ.

  • Database on Neo4j 3.5. A database name makes the request fail there; leave the field empty.

  • Driver version. JMeter 5.6.3 bundles Neo4j Java driver 4.4.13; changes.xml on master plans the Neo4j Java driver 6.x for 6.0. Check the Neo4j driver compatibility notes for the server version under test.

Access Log Sampler

What it does and when to use it

The Access Log Sampler reads a web server access log and turns each entry into an HTTP request, so a test can replay real traffic instead of a guessed mix. The access-log tutorial lists its benefits: real traffic data, a record of how usage changes over time, and session information. It also lists the cases where access logs are inappropriate:

  • security-sensitive applications where the data is encrypted;

  • applications that do not allow fine-grained control of which request parameters are written to the log;

  • applications that need correlation between requests (a log cannot replay a JWT obtained at login);

  • web servers that cannot append the POST data to the log;

  • servers hosting several applications without a separate log per application.

A log that contains POST data can contain passwords in plain text, so the tutorial also suggests custom logging that keeps sensitive data out of the log.

The sampler understands the common log format:

127.0.0.1 - - [21/Oct/2003:05:37:21 -0500] "GET /index.jsp?%2Findex.jsp= HTTP/1.1" 200 8343

The parser only looks at the quoted text containing an HTTP method (GET, PUT, POST, DELETE and so on). Everything else, including the response code, is ignored. Internally the sampler creates an HTTP sampler through a generator, sets its server, port and image parsing, asks the parser for one entry and calls the HTTP sampler. So each sample replays exactly one log line. The component reference still labels the element (Beta Code).

Fields

GUI field Meaning JMX property Required

Server

Domain name or IP address of the web server.

domain

Yes

Protocol

Scheme, http or https.

protocol

No (default http)

Port

Port the web server listens on.

portString

No (default 80)

Parse Images

Download images and resources contained in each page.

imageParsing

No (default false)

Parser

Class that parses the log (default TCLogParser).

parserClassName

Yes (default provided)

Filter (Optional)

Class that filters out lines.

filterClassName

No

Log File

Location of the access log.

logFile

Yes

The parsers and filters differ in how threads share the log:

Class Behaviour

TCLogParser

Each thread processes the whole log independently.

SharedTCLogParser, OrderPreservingLogParser

Threads share the file: each thread gets the next entry.

SessionFilter

Filters nothing; it makes sure the cookies of one client IP are processed by one thread at a time. A second thread that wants an entry from the same IP waits until the first has finished.

LogFilter

Filters entries by file name and regex and can replace extensions, but it cannot be configured from the GUI, so it cannot really be used.

Example: replay a Bookshelf access log

  1. Add → Threads (Users) → Thread Group, then Add → Sampler → Access Log Sampler.

  2. Add → Listener → Aggregate Report on the Thread Group, with results.jtl as file name (in CLI mode use -l instead).

  3. In the Access Log Sampler set Server ${__P(host,localhost)}, Port ${__P(port,8080)}, leave Parse Images off for an API, and point Log File at the access log.

  4. Start the test (Run → Start, or Ctrl + R).

<AccessLogSampler guiclass="TestBeanGUI" testclass="AccessLogSampler" testname="Replay access log">
  <elementProp name="HTTPsampler.Arguments" elementType="Arguments">
    <collectionProp name="Arguments.arguments"/>
  </elementProp>
  <stringProp name="domain">${__P(host,localhost)}</stringProp>
  <stringProp name="portString">${__P(port,8080)}</stringProp>
  <boolProp name="imageParsing">false</boolProp>
  <stringProp name="logFile">logs/bookshelf-access.log</stringProp>
  <stringProp name="parserClassName">org.apache.jmeter.protocol.http.util.accesslog.SharedTCLogParser</stringProp>
  <stringProp name="filterClassName"></stringProp>
</AccessLogSampler>
<hashTree/>

Worked numbers. Take a one-hour Bookshelf log of 36,000 lines and a Thread Group of 10 threads, each with an iteration count large enough to reach the end of the log. With TCLogParser every thread replays the whole log, so the server receives 10 × 36,000 = 360,000 requests: ten copies of the same hour. With SharedTCLogParser the threads take turns, so the log is replayed once, 36,000 requests in total, at whatever speed 10 threads without think time can reach. Neither parser reproduces the timestamps of the log; add a timer if the original pacing matters. The behaviour at the end of the file is not described in the documentation, so set the iteration count from the line count rather than relying on it.

Cost and pitfalls

  • Only GET-style replay is reliable. The request line is all that is parsed; bodies are not in the common log format.

  • No correlation. Requests that need a token, a CSRF value or an ID created earlier fail on replay. Use access logs to derive the mix of a workload model (see Performance Testing Fundamentals) and build the journey with HTTP Requests.

  • Every line, including static files. The log contains every image, CSS and JavaScript request the server saw; filter the file beforehand if only API calls matter.

  • Privacy. Production logs contain client IPs and possibly personal data in query strings; anonymise them before they reach a load generator.

  • Extending it. Custom formats need a class implementing org.apache.jmeter.protocol.http.util.accesslog.LogParser (setGenerator(Generator), parse(int)) and possibly a Generator; TCLogParser and StandardGenerator are the reference implementations.

Debug Sampler

What it does and when to use it

The Debug Sampler generates a sample whose response data lists the values of all JMeter variables, JMeter properties and system properties, each section sorted by name. It is the quickest way to see what a CSV Data Set, an extractor or a __P call really produced while a plan is being built: put it after the step under suspicion and look at the Response Data pane of View Results Tree.

Fields

GUI field Meaning JMX property Default

JMeter Properties

Include JMeter properties.

displayJMeterProperties

false

JMeter Variables

Include JMeter variables.

displayJMeterVariables

true

System Properties

Include system properties.

displaySystemProperties

false

Example: check the Bookshelf login correlation

After the login request of bookshelf-load.jmx, Add → Sampler → Debug Sampler named DEBUG after login, with only JMeter Variables ticked:

<DebugSampler guiclass="TestBeanGUI" testclass="DebugSampler" testname="DEBUG after login">
  <boolProp name="displayJMeterProperties">false</boolProp>
  <boolProp name="displayJMeterVariables">true</boolProp>
  <boolProp name="displaySystemProperties">false</boolProp>
</DebugSampler>
<hashTree/>

Run one thread and one iteration; the response data reads like this (values shortened, placeholders only):

JMeterVariables:
JMeterThread.last_sample_ok=true
...
START.MS=...
...
password=placeholder
term=java
token=eyJhbGciOi...
username=reader01

If token is missing or holds the extractor’s default value, the problem is in the extractor, not in the next request. The neighbouring Debug PostProcessor does the same as a sub-sample of a chosen sampler and can also show the sampler’s properties; see Correlation & Extractors for the full debugging workflow.

Cost and pitfalls

  • Disable it for load runs. Every Debug Sampler is a sample in the results, so it skews counts, throughput and the dashboard, and JMeter Properties or System Properties add several kilobytes of text per sample.

  • Secrets in results. Variables include tokens and passwords read from CSV files; a results file saved with response data will contain them.

  • Ignore it in transactions. A Debug Sampler inside a Transaction Controller adds its (tiny) time to the transaction.

Flow Control Action

What it does and when to use it

The Flow Control Action is a sampler intended for use inside a conditional controller. Rather than generate a sample, it pauses, stops the selected target, or changes the loop flow. It was called Test Action before JMeter 5.0, and the older name still appears in old plans and in the .jmx class name, TestAction. JMeter 5.0 also added the loop actions Go to next iteration of Current Loop and Break Current Loop.

Typical uses:

  • stop a thread whose login failed, from inside an If Controller, so it does not send requests without a token;

  • add a pause inside a Transaction Controller without generating a sample, so think time can be part of a transaction when that is wanted;

  • carry a timer: set the duration to 0 and add a timer as a child for a variable pause;

  • carry a pre- or post-processor that must run once at a point of the flow without a sample of its own (the pattern used in Logic Controllers & Transactions).

Fields

GUI field Values JMX property

Name

Label shown in the tree.

testname

Target

Current Thread (0) or All Threads (2); ignored for Pause and the loop actions.

ActionProcessor.target

Logical Action on Thread/Test

Pause (1), Stop (0), Stop Now (2), Start Next Thread Loop (3), Go to next iteration of Current Loop (4), Break Current Loop (5).

ActionProcessor.action

Duration (milliseconds)

How long to pause; required for Pause, default 0.

ActionProcessor.duration

The component reference lists the actions as Pause, Stop, Stop Now and Go to next loop iteration; the 5.6.3 GUI shows the six radio buttons above, and the numbers in parentheses are the stored values from the 5.6.3 source.

Stop stops the thread or test after any samples in progress complete. Stop Now stops the test without waiting and interrupts active samples. If some threads do not stop within 5 seconds, GUI mode shows a message, and CLI mode exits JMeter. That limit is the jmeterengine.threadstop.wait property, in milliseconds (default 5000).

Example: stop the thread when login fails

<IfController guiclass="IfControllerPanel" testclass="IfController" testname="If login failed">
  <stringProp name="IfController.condition">${__jexl3("${token}" == "TOKEN_NOT_FOUND")}</stringProp>
  <boolProp name="IfController.evaluateAll">false</boolProp>
  <boolProp name="IfController.useExpression">true</boolProp>
</IfController>
<hashTree>
  <TestAction guiclass="TestActionGui" testclass="TestAction" testname="Stop this user">
    <intProp name="ActionProcessor.action">0</intProp>
    <intProp name="ActionProcessor.target">0</intProp>
    <stringProp name="ActionProcessor.duration">0</stringProp>
  </TestAction>
  <hashTree/>
</hashTree>

TOKEN_NOT_FOUND is the default value given to the JSON Extractor for token in the login step (see Correlation & Extractors); the If Controller and its Interpret Condition as Variable Expression? option are covered in Logic Controllers & Transactions. Only the threads whose login failed stop; the others carry on, instead of the failed ones sending unauthenticated requests, each counted as an error, for the rest of the run.

Cost and pitfalls

  • No sample means no assertion. Post-processors, assertions and listeners are skipped because the result is null; record the reason in a variable or a log line if it matters for analysis.

  • A fixed pause is not think time. The Pause duration is a fixed number of milliseconds; for think time with variation use timers (or a timer as child of a zero-duration Flow Control Action), and keep plain pauses for conditional waits.

  • Stop Now on All Threads. It interrupts samples in progress, so the last results of every thread are errors.

  • Old plans. A plan saved by JMeter 4 or earlier still says TestAction; that is the same element.

MongoDB Script (deprecated)

Status

The MongoDB Script sampler and its MongoDB Source Config element were deprecated in JMeter 3.0 (Bugzilla 58772). Since then they no longer appear in the menu: the default not_in_menu property in bin/jmeter.properties lists org.apache.jmeter.protocol.mongodb.sampler.MongoScriptSampler and org.apache.jmeter.protocol.mongodb.config.MongoSourceElement. The JMeter team advises not to use them. The changes.xml on master plans their removal in 6.0 (PR 6573), together with the bundled mongo-java-driver (2.14.3 in 5.6.3): plans that use them will no longer load, and the stated replacement is a JSR223 Sampler with the MongoDB Java driver of your choice.

The books still present this sampler as a normal element (Cookbook ch. 4; PTwJ ch. 7). Treat those recipes as history.

What it does

The sampler sends a script to MongoDB through com.mongodb.DB#eval, which takes a global write lock and so hurts the database’s performance. The documentation itself says it is better avoided for load testing and is more suitable for functional testing or test set-up in setUp and tearDown Thread Groups.

GUI field Meaning JMX property Required

MongoDB Source

Name of the JMeter variable the connection is bound to; must match the MongoDB Source of a MongoDB Source Config.

MongoScriptSampler.source

Yes

Database Name

Database used by the script.

MongoScriptSampler.database

Yes

Username / Password

Credentials.

MongoScriptSampler.username, MongoScriptSampler.password

No

Script

Mongo script as it would be used in the MongoDB shell.

MongoScriptSampler.script

Yes

The MongoDB Source Config takes a Server Address List, the MongoDB Source variable name (unique across the plan), and driver options: Keep Trying, Maximum connections per host, Connection timeout, Maximum retry time, Maximum wait time (default 120,000 ms), Socket timeout, Socket keep alive, ThreadsAllowedToBlockForConnectionMultiplier (default 5) and the write-concern settings (Safe, Fsync, Wait for Journal, Wait for servers, Wait timeout, Continue on error). Each thread gets its own connection.

Migration: a JSR223 Sampler with a current driver

The replacement that changes.xml names is a JSR223 Sampler with a MongoDB Java driver you install yourself. Copy the synchronous driver jars (mongodb-driver-sync, mongodb-driver-core and bson, all the same version) into lib, restart JMeter, and share one MongoClient per test through a property, created once in a setUp Thread Group:

// setUp Thread Group, JSR223 Sampler "Create MongoClient" (Groovy, cache compiled script ticked)
import com.mongodb.client.MongoClients

def uri = 'mongodb://' + (props.get('host') ?: 'localhost') + ':27017'
props.put('mongoClient', MongoClients.create(uri))
SampleResult.setIgnore()
// main Thread Group, JSR223 Sampler "Find book" (Groovy, cache compiled script ticked)
import com.mongodb.client.model.Filters

def books = props.get('mongoClient').getDatabase('bookshelf').getCollection('books')
def doc = books.find(Filters.eq('_id', vars.get('bookId'))).first()
SampleResult.setResponseData((doc?.toJson() ?: 'null'), 'UTF-8')
SampleResult.setSuccessful(doc != null)

The scripts follow the rules of Scripting with JSR223 & Groovy: no ${...} inside a cached script (values come from vars and props), one shared client because the MongoDB driver manages its own connection pool, and a MongoClient.close() in a tearDown Thread Group. The JSR223 Sampler times the whole script, so keep it to the database call.

Changes from the books to 5.6 and 6.0

Element JMeter 2.x / 3.0 (books) JMeter 5.6.3 Planned for 6.0 (changes.xml on master)

Flow Control Action

Test Action, with Pause, Stop, Stop Now and Go to next loop iteration.

Renamed in 5.0; Go to next iteration of Current Loop and Break Current Loop added in 5.0.

No change listed.

MongoDB Script, MongoDB Source Config

Presented as normal elements (Cookbook ch. 4, PTwJ ch. 7); deprecated in 3.0.

Deprecated, hidden by not_in_menu, mongo-java-driver 2.14.3 bundled.

Removed with the driver; plans using them no longer load.

Bolt Request

Did not exist.

Added in 5.2; database, access mode, transaction timeout and pool size added in 5.5; Neo4j Java driver 4.4.13.

Neo4j Java driver 6.x.

Java Request

Classes found by classpath scanning.

ServiceLoader plus legacy scanning (5.6, PR 5885).

Requires Java 17 or later to run; no Java Request change listed.

JUnit Request

JUnit 3 and 4.

JUnit 3 and 4, JUnit 4.13.2 bundled.

No change listed.

FTP, LDAP, LDAP Extended, OS Process, Access Log, Debug Sampler

Same elements.

Same elements and fields.

No change listed; 6.0 updates bundled libraries such as Commons Net (3.13.0).

References