7

I am trying to create a jmeter jmx file using the jmeter java api. This is what I have done,

  1. gui.jmx

Use the jmeter gui application to create a reference jmx file against which I can compare. To the test plan, I only add a thread group and a java sampler within the thread group. All values are default.

  1. code.jmx

Using the jmeter java api, I create a jmx file containing a test plan, thread group and java sampler. All values are set as per the case 1.

After creating the jmx file from code, I note the following differences,

1) The nodes in gui.jmx is replaced by the following in code.jmx

    <org.apache.jorphan.collections.HashTree>

Though this is not an issue, is it possible to somehow generate the following tag as the GUI saves it

    <hashTree>

2) Test element nodes contain the attributes 'guiClass' and 'testClass' in gui.jmx e.g. These attributes are not generated in code.jmx and neither did I find any API to explicitly set them -> Due to this the generated code.jmx does not open in the jmeter gui console. Which probably means that the generated jmx can be used in no console mode only. Is this by design? Is there some way by which these attributes can be added via code using the jmeter apis? (not using DOM as a hack)

3) The xml structure of gui.jmx is as follows,

    <hashTree>
    <TestPlan ...>
    ...
    </TestPlan>
    <hashTree>
    <ThreadGroup ...>
    ...
    </ThreadGroup>
    **<hashTree/>**
    </hashTree>
</hashTree>

Note the nesting of the HashTree elements. When this opens up in the JMeter GUI, the elements are nested within each other.

The xml structure of code.jmx is as follows,

<org.apache.jorphan.collections.HashTree>
    <TestPlan ...>
    ...
    </TestPlan>
    **<org.apache.jorphan.collections.HashTree/>**
    <ThreadGroup ...>
    ...
    </ThreadGroup>
    **<org.apache.jorphan.collections.HashTree/>**
</org.apache.jorphan.collections.HashTree>

Note the difference in placement of tags. There is no nesting. They are all at the same level. Why does this happen. What is the proper way to add test elements using jmx api so that the hash tree elements are nested within each other as in the first case?

UBIK LOAD PACK
  • 33,980
  • 5
  • 71
  • 116
Avi
  • 1,070
  • 1
  • 15
  • 28
  • Can you show how you create jmx using jmeter java api ? – UBIK LOAD PACK Aug 26 '14 at 18:26
  • If you are asking in general how this is done, you may check the sample code provided by the Blazemeter folks, http://blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui – Avi Aug 27 '14 at 06:41
  • Issue 1) is not much of a problem. While running the jmx, it works fine. Issue 3) is now resolved. I was adding the test elements incorrectly to the HashTree. The structure is now same as the one generated by gui.jmx. Issue 2) is not resolved. It seems unless the attributes guiClass and testClass are not present in the test element tags, the jmx script does not run even from the command line. I found no way to add these attributes while saving the test elements using SaveService.saveTree. Has anyone successfully generated a jmx file using code and then run it from the command line? – Avi Aug 29 '14 at 13:01
  • Finally after looking into the jmeter source code, I figured that in addition to what I was doing, I needed to explicitly set the guiClass and testClass parameters
    testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName()); testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
    – Avi Aug 30 '14 at 10:47
  • you should write this in a new answer and accept it – UBIK LOAD PACK Aug 30 '14 at 11:14
  • see also http://stackoverflow.com/questions/17020274/api-for-generating-jmeter-test-plans – Korny Oct 08 '14 at 17:57

3 Answers3

18

Finally after looking into the jmeter source code, I figured that in addition to what I was doing, I needed to explicitly set the guiClass and testClass parameters

testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName()); testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());

similarly for other test elements like ThreadGroup, JavaSampler etc.

The full code is as follows,

package com.test;

import java.io.FileOutputStream;

import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.control.gui.LoopControlPanel;
import org.apache.jmeter.control.gui.TestPlanGui;
import org.apache.jmeter.protocol.java.control.gui.JavaTestSamplerGui;
import org.apache.jmeter.protocol.java.sampler.JavaSampler;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.threads.gui.ThreadGroupGui;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;

public class JMXCreator {
    public static void main(String[] argv) throws Exception {
        // Initialize the configuration variables
        String jmeterHome = "D:\\apache-jmeter-2.11";
        JMeterUtils.setJMeterHome(jmeterHome);
        JMeterUtils.loadJMeterProperties(JMeterUtils.getJMeterBinDir()
                + "\\jmeter.properties");
        JMeterUtils.initLogging();
        JMeterUtils.initLocale();

        // TestPlan
        TestPlan testPlan = new TestPlan();
        testPlan.setName("Test Plan");
        testPlan.setEnabled(true);
        testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
        testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());

        // ThreadGroup controller
        LoopController loopController = new LoopController();
        loopController.setEnabled(true);
        loopController.setLoops(5);
        loopController.setProperty(TestElement.TEST_CLASS,
                LoopController.class.getName());
        loopController.setProperty(TestElement.GUI_CLASS,
                LoopControlPanel.class.getName());

        // ThreadGroup
        ThreadGroup threadGroup = new ThreadGroup();
        threadGroup.setName("Thread Group");
        threadGroup.setEnabled(true);
        threadGroup.setSamplerController(loopController);
        threadGroup.setNumThreads(5);
        threadGroup.setRampUp(10);
        threadGroup.setProperty(TestElement.TEST_CLASS,
                ThreadGroup.class.getName());
        threadGroup.setProperty(TestElement.GUI_CLASS,
                ThreadGroupGui.class.getName());

        // JavaSampler
        JavaSampler javaSampler = new JavaSampler();
        javaSampler.setClassname("my.example.sampler");
        javaSampler.setEnabled(true);
        javaSampler.setProperty(TestElement.TEST_CLASS,
                JavaSampler.class.getName());
        javaSampler.setProperty(TestElement.GUI_CLASS,
                JavaTestSamplerGui.class.getName());

        // Create TestPlan hash tree
        HashTree testPlanHashTree = new HashTree();
        testPlanHashTree.add(testPlan);

        // Add ThreadGroup to TestPlan hash tree
        HashTree threadGroupHashTree = new HashTree();
        threadGroupHashTree = testPlanHashTree.add(testPlan, threadGroup);

        // Add Java Sampler to ThreadGroup hash tree
        HashTree javaSamplerHashTree = new HashTree();
        javaSamplerHashTree = threadGroupHashTree.add(javaSampler);

        // Save to jmx file
        SaveService.saveTree(testPlanHashTree, new FileOutputStream(
                "d:\\test.jmx"));
    }
}
Avi
  • 1,070
  • 1
  • 15
  • 28
  • Could you post your full code from that example that is now working? I can't seem to get it to work with your changes still. – James Armstead Sep 06 '14 at 05:42
  • And/Or what objects did you set those Properties on? I set them for every TestElement I could and changed the "TestPlan" to match whatever element I was setting them on, but it still doesn't seem to execute my HttpSampler. – James Armstead Sep 06 '14 at 05:53
  • Added the code. The only difference is that I am using a JavaSampler instead of HTTPSampler. – Avi Sep 06 '14 at 15:44
2

Just a comment regarding

<org.apache.jorphan.collections.HashTree>

if you set in saveservice.properties file:

hashTree=org.apache.jorphan.collections.HashTree

instead of:

hashTree=org.apache.jorphan.collections.ListedHashTree

you will get

  <hashTree>
Piotr Boho
  • 2,650
  • 2
  • 13
  • 20
0

Creating JMeter test from Java Api is not really supported method and you expose your test plan to changes in JMeter.

I would not do it.

I seems you are doing this to dynamically create test scripts based on some chosen variables, this is not the right way to do it.

I JMeter to do what you want you use:

Also have a look at Jenkins and Maven for examples :

UBIK LOAD PACK
  • 33,980
  • 5
  • 71
  • 116
  • We are automating our performance tests and want the ability to dynamically create test scripts based on some chosen variables – Avi Aug 28 '14 at 03:54
  • I updated my answer, if ok you should accept and upvote – UBIK LOAD PACK Aug 29 '14 at 14:59
  • I checked this. It gives way to add parameters dynamically. What I am trying to do is add samplers dynamically. Based on the chosen test configuration, I may have 2 java samplers or more than two. Also parameters for each sampler may be different. Samplers may also involve passing data between them. I need to create the jmx file on the fly for this. – Avi Aug 29 '14 at 16:18
  • You can do the first thing with If Controller, and the rest with Post Processor or CSV Dataset, believe me your approach is wrong and won't be maintanable – UBIK LOAD PACK Aug 29 '14 at 17:51
  • PMD, I will definitely look into the method you are suggesting. Thanks. – Avi Aug 30 '14 at 10:45
  • I checked out controllers. Using a logic controller of any kind we can customize the logic to decide when a request is sent. However I dont believe we can add a sampler to the jmx dynamically (which is what I want to do by creating the jmx itself based on dynamically chosen tests). The jmx will need all the required samplers added before we run the test and using the controller we can decide when to call which. This is fine, but not exactly what I am trying to do. I understand your point about maintainability and my implementation might break with the next version of JMeter. – Avi Aug 31 '14 at 16:02