Friday, June 22, 2012

How to run Jmeter tests in non-GUI mode, automated with a shell script

Apache Jmeter is a great versatile tool for performance testing of web servers, DBMS servers etc. It's a pure Java application where you can use even your own Java code to customize and randomize your tests. My intention of this post is not to tell you about all of those features, but one such cool feature of Jmeter which is running Jmeter tests in non-GUI mode.

If you have worked with Jmeter you surely should have experienced that sometimes it get stuck or crashes while you are doing high concurrency (> 300) load testing. One solution for this is to create your test using the GUI and save it as a '.jmx' file and later run that in non-GUI mode and save the test results to a '.jtl' file. In that way you will be able to carry out your load test without crashing or maybe with more concurrency.

OKEY..... This is how to do it.

1. First prepare your test plan with Jmeter and save it, let's say the file name is 'mytest.jmx'. (It gets saved as a xml configuration file with the .jmx extention).

2. Then go to Apache JMETER_HOME/bin folder using command shell. And then run Jmeter with the following parameters, to execute the test.
./jmeter -n -t \absolute_path\mytest.jmx -l \absolute_path\mytest_results.jtl

3. While the test is running the results will be saved in the 'mytest_results.jtl'. When your test is complete you can open this jtl file in Jmeter and summarize the results or create graphs using it.
To do that open Jmeter and add a Summary Report to the test plan (Add --> Listener --> Summary Report). And then go to the Summary Report UI and 'Browse' and open your mytest_results.jtl file.


OK.....next comes the real headache :-). Let's say you have to repeat the above test several times with small changes to the test. I actually had a requirement at my work to repeat the same Jmeter test with different concurrency levels and number of loops.
The hard way to do this is create separate test scripts for different concurrency levels using the GUI and run them separately as above.
A less hard way to do this is open the test file (.jmx) using a text editor and change the values every time you repeat the test, in the ThreadGroup element in the test configuration(as below), and run the same file.

<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">1000</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">300</stringProp>
        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
        <longProp name="ThreadGroup.start_time">1339414812000</longProp>
        <longProp name="ThreadGroup.end_time">1339414812000</longProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>


OK.... But why not automate the above 'less hard way' and make your life easy..
If you are a shell scripting master this is a "few lines" work, but since I'm not, this is how I did it.

#!/bin/bash

i=0

conc[0]=50
conc[1]=100
conc[2]=250
conc[3]=500
conc[4]=750
conc[5]=1000
conc[6]=1250

loop[0]=5000
loop[1]=2500
loop[2]=1000
loop[3]=500
loop[4]=334
loop[5]=250
loop[6]=200

cd ./jmx
while test $i != 7
do
sed 's/_loop_/'${loop[$i]}'/g' mytest.jmx > ./jmtest.jmx
sed 's/_con_/'${conc[$i]}'/g' jmtest.jmx > jmtest_${conc[$i]}.jmx
rm jmtest.jmx
cd ../apache-jmeter-2.6/bin/
./jmeter -n -t ../../jmx/jmtest_${conc[$i]}.jmx -l ../../jtl/results_${conc[$i]}.jtl
i=`expr $i + 1`
cd ../../jmx
done


For newbies like me, I will explain the script briefly.

For this script to work first you should do a small change to your Jmeter test configuration. You have to give a variable string for num_threads and loop instead of actual values, as below.
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
        <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
        <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
          <boolProp name="LoopController.continue_forever">false</boolProp>
          <stringProp name="LoopController.loops">_loop_</stringProp>
        </elementProp>
        <stringProp name="ThreadGroup.num_threads">_con_</stringProp>
        <stringProp name="ThreadGroup.ramp_time">1</stringProp>
        <longProp name="ThreadGroup.start_time">1339414812000</longProp>
        <longProp name="ThreadGroup.end_time">1339414812000</longProp>
        <boolProp name="ThreadGroup.scheduler">false</boolProp>
        <stringProp name="ThreadGroup.duration"></stringProp>
        <stringProp name="ThreadGroup.delay"></stringProp>
      </ThreadGroup>

In the shell script, first I put the concurrency values and loop values in to 2 different arrays.
And then using a while loop I edit the concurrency and loop values in Jmeter test script for each time I have to repeat the test. I have used sed command for that. It searches for the _loop_ and _con_ strings in the Jmeter script and will replace it with the corresponding values in above two arrays.
Then inside the loop, changed Jmeter script is executed (for the number of times the while loop is run) in non GUI mode and results are saved in different jtl files.



25 comments:

  1. Hi ,

    This is really helpful,, can u pls guide me with one my doubt that ,
    if I have 3 thread group in my script and i want to run any one of them through CMD , what should be the suntax ..

    Waiting for ur reply .

    ReplyDelete
    Replies
    1. Hi Anukrosh,

      I don't think it is possible to start a selected thread group separately when you have multiple thread groups in one script. There is no command line parameter to support such functionality. Refer "2.4 Running JMeter" section in http://jmeter.apache.org/usermanual/get-started.html

      Delete
  2. Thanks for the great post. There are some more options on running JMeter without GUI, if anyone is interested check 5 Ways To Launch a JMeter Test without Using the JMeter GUI guide which covers Ant, Maven and programmatic execution/creation of JMeter tests.

    ReplyDelete
  3. can anyone help to do performance testing of 500 websites using jmeter in non-gui mode?

    ReplyDelete
  4. "./" this is the way to execute the *.sh or *.pl scripts in backend on solaris or unix boxes. In order to run JMeter in non-GUI mode we can simply type from command line --> jmeter -n -t \absolute_path\mytest.jmx -l \absolute_path\mytest_results.jtl

    ReplyDelete
  5. Hi,
    I am running the Jmeter in Linux but I have to increase the Jmeter Heap size in linux

    please suggest to me
    Thanks in advance

    ReplyDelete
  6. i want to create a java application that automatically generates test scripts for jmeter. We pass the url, GET or POST method, expected result like 200 OK or 404 not found, and specify the number of users. The values are passed to jmeter, which is then tested and the status result is passed back to my application.
    Can anyone please help ?

    ReplyDelete
  7. Great article..thanks for sharing

    ReplyDelete
  8. Well, I think your blog is pretty good and have lots of useful information about Jmeter. Keep it up!

    ReplyDelete
  9. Hi Niro,
    Is there a way to use Jmeter completely through Java API's.

    ReplyDelete
    Replies
    1. Sorry for the late reply.

      Please have a look at https://jmeter.apache.org/api/

      Delete
  10. HI Niro,
    I have a requirment where the jmx itself has to be created with shell script .Can this be done.

    ReplyDelete
    Replies
    1. Hi Sailaja,

      I'm not sure about that. However you can use Ant Jmeter plugin to keep parameterized jmeter test templates and use And scripts to pass values and execute the jmeter script. Please check
      http://www.programmerplanet.org/projects/jmeter-ant-task/

      Delete
    2. In your script are you manually running the jmeter-server.bat coz i dont see it invoked in your script.

      Delete
  11. Hi Niro,
    while running Jmeter script in Non GUI mode it is pulling Error,Could not open .jmx file,I tried different paths

    ReplyDelete
  12. Hi Niro, As a part of prep to trigger through jenkins i was trying to run .jmx script locally in non-gui mode. I get few errors as below but later the script ran and got the output in .csv file. Can someone help me resolve the errors:-
    Command:-./jmeter -n -t ./examples/Dec21Test.jmx -l ./examples/resultsJan19.csv
    Errors:-
    main ERROR Null object returned for File in Appenders.
    2019-01-20 15:11:46,020 main ERROR Unable to locate appender “jmeter-log” for logger config “root”
    Creating summariser
    Created the tree successfully using ./examples/Dec21Test.jmx
    Starting the test @ Sun Jan 20 15:11:46 CST 2019 (1548018706536)
    Waiting for possible Shutdown/StopTestNow/Heapdump message on port 4446
    summary + 5 in 00:00:48 = 0.1/s Avg: 1286 Min: 0 Max: 3673 Err: 0 (0.00%) Active: 1 Started: 1 Finished: 0
    summary + 2 in 00:00:30 = 0.1/s Avg: 1035 Min: 404 Max: 1667 Err: 0 (0.00%) Active: 1 Started: 1 Finished: 0
    summary = 7 in 00:01:18 = 0.1/s Avg: 1214 Min: 0 Max: 3673 Err: 0 (0.00%)
    summary + 3 in 00:00:30 = 0.1/s Avg: 473 Min: 1 Max: 1211 Err: 0 (0.00%) Active: 1 Started: 1 Finished: 0
    summary = 10 in 00:01:48 = 0.1/s Avg: 992 Min: 0 Max: 3673 Err: 0 (0.00%)
    summary + 1 in 00:00:12 = 0.1/s Avg: 426 Min: 426 Max: 426 Err: 0 (0.00%) Active: 0 Started: 1 Finished: 1
    summary = 11 in 00:02:00 = 0.1/s Avg: 941 Min: 0 Max: 3673 Err: 0 (0.00%)
    Tidying up ... @ Sun Jan 20 15:13:47 CST 2019 (1548018827241)
    ... end of run

    ReplyDelete
  13. It is really helpful article please read it too my blog AVG UI failed to load

    ReplyDelete
  14. I am using ubuntu system, so my command is like ./jmeter...., have kept my files in bin folder with name plan [plan.jmx and plan.csv], and tried command with path and direct file name.

    but always getting 'Could not open plan.jmx'

    ReplyDelete
    Replies
    1. I made a silly mistake, I did not follow strict capital-small structure for file name in my command. like PLAN, plan, Plan difference.
      ./jmeter -n -t plan.jmx -l plan.csv
      ./jmeter -n -t Plan.jmx -l Plan.csv

      give commands as per file name exactly.

      Delete
  15. This is realy a Nice blog post read on of my blogs It is really helpful article please read it too my blog AVG UI Failed To Load. you can visits our websites or toll free no +1-866-558-4555. solve your problem fastly.

    ReplyDelete