Home > Schuberg Philis > stress/load testing a Java-enabled web site with jMeter

stress/load testing a Java-enabled web site with jMeter

jMeter is a great tool to perform several load and stress tests on websites, ftp servers, database servers and more. I use it to see how much end-users can log in to their banking environment and check their current account details, to validate how much inserts/sec can be handled by a database, the maximum amount of ldap lookups, etc.

During testing, the most interesting things usually happen during the load test. It’s funny to see how a site behaves (or dies) when the system is running out of resources. My ultimate goal is not to find the moment where the site breaks, but to tune the site to a level where it actually never breaks, but only becoming slow, without collapsing via some snowball effect on system resources. I’d rather have a slow web site where 8 web servers are running at 95% cpu, than a collapsed farm because end-users hit the F5 button after receiving a system error.

In one of my last assignments to benchmark a site, the site turned out to use java classes, with browser-based functions to create an encrypted password which in turn was sent to the web site for authentication.

There I was, with a need for executing a custom java class, and a clear FAQ on the jMeter site telling me explicitely “Does JMeter process dynamic pages (e.g. Javascript and applets): No. JMeter does not process Javascript or applets embedded in HTML pages.”.

But jMeter does support a way to execute JavaScript functions, via the “BSF assertion”. And here’s the trick: JavaScript provides a bridging function towards java libraries, via the Packages method. If you have a custom class in a JAR file provided by the website, the regular path to that class would be com.Company.Custom.Classname, and the function can be called “FunctionName”. Using this function from within JavaScript is can be done by calling the function with it’s full path, and by adding “Packages.” in front of it.

Example java class function use within jMeter, e.g. by using a class file to encrypt a username/password combination by using a custom java function:

  • download the website’s JAR file, and put it in the jMeter java classpath
  • Create your regular jMeter test
  • Add a “user definded variable” test component, and add a field called “PASSWORD” with variable “secret”, and an empty field “HASHEDPASSWORD”.
  • Add the “BSF sampler” to the HTTP request sampler containing the username/password login page
  • Put “javascript” in the “script language” field of the BSF assertion

This is how the JavaScript code within the BSF assertion could look like:

//Get the jMeter variable and put it in a Javascript variable

var password = vars.get(‘PASSWORD’);

//the actual magic: the calling of a Java class function from within JavaScript
//This is not an actual password encryption, only an example by help of a jMeter class available
//You can find this class in ~jmeter/lib/soap.jar
var hashedpassword = Packages.org.apache.soap.Utils.cleanString(password);

//Put the result back into a jMeter variable for further processing
vars.put(‘HASHEDPASSWORD’,hashedpassword);

//and since we’re not testing anything in this “BSF assertion”, we will always call it a success:
AssertionResult.setFailure(false);

And that’s it!

Full example, tested with Jmeter 2.3.2  (copy this into a test.jmx text file):

<?xml version=”1.0″ encoding=”UTF-8″?>
<jmeterTestPlan version=”1.2″ properties=”2.1″>
  <hashTree>
    <TestPlan guiclass=”TestPlanGui” testclass=”TestPlan” testname=”Test Plan” enabled=”true”>
      <stringProp name=”TestPlan.comments”></stringProp>
      <boolProp name=”TestPlan.functional_mode”>false</boolProp>
      <boolProp name=”TestPlan.serialize_threadgroups”>false</boolProp>
      <elementProp name=”TestPlan.user_defined_variables” elementType=”Arguments” guiclass=”ArgumentsPanel” testclass=”Arguments” testname=”User Defined Variables” enabled=”true”>
        <collectionProp name=”Arguments.arguments”/>
      </elementProp>
      <stringProp name=”TestPlan.user_define_classpath”></stringProp>
    </TestPlan>
    <hashTree>
      <ThreadGroup guiclass=”ThreadGroupGui” testclass=”ThreadGroup” testname=”Thread group” enabled=”true”>
        <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”>1</stringProp>
        </elementProp>
        <stringProp name=”ThreadGroup.num_threads”>1</stringProp>
        <stringProp name=”ThreadGroup.ramp_time”>0</stringProp>
        <longProp name=”ThreadGroup.start_time”>1230116483000</longProp>
        <longProp name=”ThreadGroup.end_time”>1230116483000</longProp>
        <boolProp name=”ThreadGroup.scheduler”>false</boolProp>
        <stringProp name=”ThreadGroup.on_sample_error”>stoptest</stringProp>
        <stringProp name=”ThreadGroup.duration”></stringProp>
        <stringProp name=”ThreadGroup.delay”></stringProp>
      </ThreadGroup>
      <hashTree>
        <Arguments guiclass=”ArgumentsPanel” testclass=”Arguments” testname=”User Defined Variables” enabled=”true”>
          <collectionProp name=”Arguments.arguments”>
            <elementProp name=”PASSWORD” elementType=”Argument”>
              <stringProp name=”Argument.name”>PASSWORD</stringProp>
              <stringProp name=”Argument.value”>&lt;secret&gt;</stringProp>
              <stringProp name=”Argument.metadata”>=</stringProp>
            </elementProp>
            <elementProp name=”HASHEDPASSWORD” elementType=”Argument”>
              <stringProp name=”Argument.name”>HASHEDPASSWORD</stringProp>
              <stringProp name=”Argument.value”>ThisShouldBeGoneWIthTheSecondHTTPRequest</stringProp>
              <stringProp name=”Argument.metadata”>=</stringProp>
            </elementProp>
          </collectionProp>
        </Arguments>
        <hashTree/>
        <HTTPSampler guiclass=”HttpTestSampleGui” testclass=”HTTPSampler” testname=”HTTP Request (initial)” enabled=”true”>
          <elementProp name=”HTTPsampler.Arguments” elementType=”Arguments” guiclass=”HTTPArgumentsPanel” testclass=”Arguments” testname=”User Defined Variables” enabled=”true”>
            <collectionProp name=”Arguments.arguments”/>
          </elementProp>
          <stringProp name=”HTTPSampler.domain”>www.cupfighter.net</stringProp>
          <stringProp name=”HTTPSampler.port”></stringProp>
          <stringProp name=”HTTPSampler.protocol”>http</stringProp>
          <stringProp name=”HTTPSampler.contentEncoding”></stringProp>
          <stringProp name=”HTTPSampler.path”>/</stringProp>
          <stringProp name=”HTTPSampler.method”>GET</stringProp>
          <boolProp name=”HTTPSampler.follow_redirects”>false</boolProp>
          <boolProp name=”HTTPSampler.auto_redirects”>true</boolProp>
          <boolProp name=”HTTPSampler.use_keepalive”>true</boolProp>
          <boolProp name=”HTTPSampler.DO_MULTIPART_POST”>false</boolProp>
          <stringProp name=”HTTPSampler.FILE_NAME”></stringProp>
          <stringProp name=”HTTPSampler.FILE_FIELD”></stringProp>
          <stringProp name=”HTTPSampler.mimetype”></stringProp>
          <stringProp name=”HTTPSampler.monitor”>false</stringProp>
          <stringProp name=”HTTPSampler.embedded_url_re”></stringProp>
        </HTTPSampler>
        <hashTree>
          <BSFAssertion guiclass=”TestBeanGUI” testclass=”BSFAssertion” testname=”BSF Assertion” enabled=”true”>
            <stringProp name=”filename”></stringProp>
            <stringProp name=”parameters”></stringProp>
            <stringProp name=”script”> //Get the jMeter variable and put it in a Javascript variable
        var password = vars.get(&apos;PASSWORD&apos;);

 //the actual magic: the calling of a Java class function from within JavaScript
        //This is not an actual password encryption, only an example by help of a jMeter class available
        //You can find this class in ~jmeter/lib/soap.jar
        var hashedpassword = Packages.org.apache.soap.Utils.cleanString(password);

 //Put the result back into a jMeter variable for further processing
 vars.put(&apos;HASHEDPASSWORD&apos;,hashedpassword);

 //and since we&apos;re not testing anything in this &quot;BSF assertion&quot;, we will always call it a success:
 AssertionResult.setFailure(false);
</stringProp>
            <stringProp name=”scriptLanguage”>javascript</stringProp>
          </BSFAssertion>
          <hashTree/>
        </hashTree>
        <HTTPSampler guiclass=”HttpTestSampleGui” testclass=”HTTPSampler” testname=”HTTP Request 2″ enabled=”true”>
          <elementProp name=”HTTPsampler.Arguments” elementType=”Arguments” guiclass=”HTTPArgumentsPanel” testclass=”Arguments” testname=”User Defined Variables” enabled=”true”>
            <collectionProp name=”Arguments.arguments”>
              <elementProp name=”Password” elementType=”HTTPArgument”>
                <boolProp name=”HTTPArgument.always_encode”>false</boolProp>
                <stringProp name=”Argument.value”>${HASHEDPASSWORD}</stringProp>
                <stringProp name=”Argument.metadata”>=</stringProp>
                <boolProp name=”HTTPArgument.use_equals”>true</boolProp>
                <stringProp name=”Argument.name”>Password</stringProp>
              </elementProp>
              <elementProp name=”Username” elementType=”HTTPArgument”>
                <boolProp name=”HTTPArgument.always_encode”>false</boolProp>
                <stringProp name=”Argument.value”>Cupfighter</stringProp>
                <stringProp name=”Argument.metadata”>=</stringProp>
                <boolProp name=”HTTPArgument.use_equals”>true</boolProp>
                <stringProp name=”Argument.name”>Username</stringProp>
              </elementProp>
            </collectionProp>
          </elementProp>
          <stringProp name=”HTTPSampler.domain”>www.cupfighter.net</stringProp>
          <stringProp name=”HTTPSampler.port”></stringProp>
          <stringProp name=”HTTPSampler.protocol”>http</stringProp>
          <stringProp name=”HTTPSampler.contentEncoding”></stringProp>
          <stringProp name=”HTTPSampler.path”>/</stringProp>
          <stringProp name=”HTTPSampler.method”>POST</stringProp>
          <boolProp name=”HTTPSampler.follow_redirects”>false</boolProp>
          <boolProp name=”HTTPSampler.auto_redirects”>true</boolProp>
          <boolProp name=”HTTPSampler.use_keepalive”>true</boolProp>
          <boolProp name=”HTTPSampler.DO_MULTIPART_POST”>false</boolProp>
          <stringProp name=”HTTPSampler.FILE_NAME”></stringProp>
          <stringProp name=”HTTPSampler.FILE_FIELD”></stringProp>
          <stringProp name=”HTTPSampler.mimetype”></stringProp>
          <stringProp name=”HTTPSampler.monitor”>false</stringProp>
          <stringProp name=”HTTPSampler.embedded_url_re”></stringProp>
          <stringProp name=”TestPlan.comments”>using variable processed by Java&apos;s cleanString function in BSF assertion</stringProp>
        </HTTPSampler>
        <hashTree/>
      </hashTree>
      <ResultCollector guiclass=”ViewResultsFullVisualizer” testclass=”ResultCollector” testname=”View Results Tree” enabled=”true”>
        <boolProp name=”ResultCollector.error_logging”>false</boolProp>
        <objProp>
          <name>saveConfig</name>
          <value>
            <time>true</time>
            <latency>true</latency>
            <timestamp>true</timestamp>
            <success>true</success>
            <label>true</label>
            <code>true</code>
            <message>true</message>
            <threadName>true</threadName>
            <dataType>true</dataType>
            <encoding>false</encoding>
            <assertions>true</assertions>
            <subresults>true</subresults>
            <responseData>false</responseData>
            <samplerData>false</samplerData>
            <xml>true</xml>
            <fieldNames>false</fieldNames>
            <responseHeaders>false</responseHeaders>
            <requestHeaders>false</requestHeaders>
            <responseDataOnError>false</responseDataOnError>
            <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
            <assertionsResultsToSave>0</assertionsResultsToSave>
            <bytes>true</bytes>
          </value>
        </objProp>
        <stringProp name=”filename”></stringProp>
        <stringProp name=”TestPlan.comments”>Check the request tab, on the POST data to see if the &lt;secret&gt; was changed to &amp;lt;secret&amp;gt</stringProp>
      </ResultCollector>
      <hashTree/>
    </hashTree>
  </hashTree>
</jmeterTestPlan>

Categories: Schuberg Philis Tags:
  1. January 30th, 2010 at 18:51 | #1

    Hi – Thanks for your post, it’s one of many I found when researching a problem I had with JMeter. I wanted to offer a different approach to invoking custom Java from inside JMeter, which is to implement the JMeter ‘Function’ interface in Java. This allows you to directly invoke your own Java classes from JMeter. For those interested I have instructions and a skeleton implementation:

    http://gabenell.blogspot.com/2010/01/custom-functions-for-jmeter.html

  2. December 1st, 2010 at 08:38 | #2

    Hi

    I am trying to run the Jmeter.bat file from BIN folder but unable to run which is saying
    “java.lang.ClassNotFoundException: org.apache.jmeter.JMeter” , as per this i have understood that Jmeter.class is not found in “Apache” folder, but after so many searches I am unable to find any jmeter.class file.

    Can you please help?

    Thanks
    Gunjan

  3. December 7th, 2010 at 12:29 | #3

    Hi,
    the class is in the jmeter.jar file.
    Regards Anton

  1. No trackbacks yet.