├── .gitignore
├── README.md
├── pom.xml
└── src
├── it
├── java
│ └── com
│ │ └── example
│ │ └── jmeter
│ │ └── JmeterTestPlanIT.java
├── resources
│ └── Names.csv
├── resources1.html
├── resources2.html
├── resources3.html
├── resources4.html
└── resources5.html
└── main
├── java
└── com
│ └── example
│ └── jmeter
│ └── JmeterTestPlan.java
└── resources
├── Results.csv
└── jmxFile.jmx
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | #IntelliJ files
11 | *.iml
12 | *.idea
13 |
14 | #Target
15 | target/
16 |
17 | # Mobile Tools for Java (J2ME)
18 | .mtj.tmp/
19 |
20 | # Package Files #
21 | *.jar
22 | *.war
23 | *.nar
24 | *.ear
25 | *.zip
26 | *.tar.gz
27 | *.rar
28 |
29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
30 | hs_err_pid*
31 | .idea
32 | my-app.iml
33 |
34 |
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This is an example of how to create an Apache JMeter testplan in the Java SDK. Essentially creating all of the UI components necessary as well so it can be loaded into the JMeter program itself as a custom script.
2 |
3 | Although an example, this repo exists to explain how a custom testplan is made, you would likely do this in cases of automation, paramaterization, source control of JMX plans, but most noteworthy would be the creation and use of a custom sampler. i.e. : https://jmeter.apache.org/api/org/apache/jmeter/protocol/java/sampler/JavaSampler.html
4 |
5 | Instead of using the default HTTP Sampler (which does not support special or dynamic auth) you can create your own Sampler, with your own Client which then enables the use of special auth such as OAuth, AWS4, etc. using regular Java code with implementation of your choice.
6 |
7 | Again because this is your code in the language of choice you have more liberty for design and implementation choices, as well as the luxury to create unit tests for your components, thus eliminating manual testing of code components in JMeter's UI tool.
8 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 |
5 | UTF-8
6 | UTF-8
7 | 1.8
8 |
9 |
10 | jmeter-example-project
11 | example-jmeter-with-sdk
12 | 1.0-SNAPSHOT
13 |
14 |
15 |
16 |
17 | org.apache.jmeter
18 | ApacheJMeter_core
19 | 5.1.1
20 |
21 |
22 |
23 |
24 | org.apache.jmeter
25 | ApacheJMeter_components
26 | 5.1.1
27 |
28 |
29 |
30 |
31 | org.apache.jmeter
32 | ApacheJMeter_http
33 | 5.1.1
34 |
35 |
36 |
37 |
38 |
39 | org.apache.httpcomponents
40 | httpclient
41 | 4.5.4
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | com.lazerycode.jmeter
51 | jmeter-maven-plugin
52 | 2.9.0
53 |
54 |
55 |
56 | jmeter-tests
57 |
58 | jmeter
59 |
60 |
61 |
62 |
63 | jmeter-check-results
64 |
65 | results
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/it/java/com/example/jmeter/JmeterTestPlanIT.java:
--------------------------------------------------------------------------------
1 | package com.example.jmeter;
2 |
3 | import org.apache.jorphan.collections.HashTree;
4 | import org.junit.Test;
5 |
6 | import java.io.IOException;
7 |
8 | public class JmeterTestPlanIT {
9 | String domainName = "google.com";
10 | String path = "/search?q=" + "${" + JmeterTestPlan.QUERY_PARAMETER_VAR_NAME + "}";
11 | String inputCSVFile = "src/it/resources/names.csv";
12 |
13 | @Test
14 | public void sendQueriesToGoogle() throws IOException {
15 |
16 | System.out.println("hello world");
17 |
18 | JmeterTestPlan testPlanClient = new JmeterTestPlan();
19 |
20 | HashTree createdTree = testPlanClient.createTestPLan(
21 | inputCSVFile,
22 | domainName,
23 | path,
24 | "GET",
25 | 1);
26 |
27 | testPlanClient.engineRunner(createdTree);
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/it/resources/Names.csv:
--------------------------------------------------------------------------------
1 | James
2 | Josephine
3 | Art
4 | Lenna
5 | Donette
6 | Simona
7 | Mitsue
8 | Leota
9 | Sage
10 | Kris
11 | Minna
12 | Abel
13 | Kiley
14 | Graciela
15 | Cammy
16 | Mattie
17 | Meaghan
18 | Gladys
19 | Yuki
20 | Fletche
--------------------------------------------------------------------------------
/src/it/resources1.html:
--------------------------------------------------------------------------------
1 |
2 | 301 Moved
3 | 301 Moved
4 | The document has moved
5 | here.
6 |
7 |
--------------------------------------------------------------------------------
/src/it/resources2.html:
--------------------------------------------------------------------------------
1 |
2 | 301 Moved
3 | 301 Moved
4 | The document has moved
5 | here.
6 |
7 |
--------------------------------------------------------------------------------
/src/it/resources3.html:
--------------------------------------------------------------------------------
1 |
2 | 301 Moved
3 | 301 Moved
4 | The document has moved
5 | here.
6 |
7 |
--------------------------------------------------------------------------------
/src/it/resources4.html:
--------------------------------------------------------------------------------
1 |
2 | 301 Moved
3 | 301 Moved
4 | The document has moved
5 | here.
6 |
7 |
--------------------------------------------------------------------------------
/src/it/resources5.html:
--------------------------------------------------------------------------------
1 |
2 | 301 Moved
3 | 301 Moved
4 | The document has moved
5 | here.
6 |
7 |
--------------------------------------------------------------------------------
/src/main/java/com/example/jmeter/JmeterTestPlan.java:
--------------------------------------------------------------------------------
1 | package com.example.jmeter;
2 |
3 | import org.apache.jmeter.config.Arguments;
4 | import org.apache.jmeter.config.CSVDataSet;
5 | import org.apache.jmeter.config.gui.ArgumentsPanel;
6 | import org.apache.jmeter.control.LoopController;
7 | import org.apache.jmeter.control.gui.TestPlanGui;
8 | import org.apache.jmeter.engine.StandardJMeterEngine;
9 | import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
10 | import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
11 | import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
12 | import org.apache.jmeter.reporters.ResultCollector;
13 | import org.apache.jmeter.reporters.Summariser;
14 | import org.apache.jmeter.save.SaveService;
15 | import org.apache.jmeter.testbeans.gui.TestBeanGUI;
16 | import org.apache.jmeter.testelement.TestElement;
17 | import org.apache.jmeter.testelement.TestPlan;
18 | import org.apache.jmeter.threads.SetupThreadGroup;
19 | import org.apache.jmeter.threads.gui.ThreadGroupGui;
20 | import org.apache.jmeter.util.JMeterUtils;
21 | import org.apache.jorphan.collections.HashTree;
22 |
23 | import java.io.File;
24 |
25 | import java.io.FileOutputStream;
26 | import java.io.IOException;
27 |
28 | public class JmeterTestPlan {
29 | public static final String QUERY_PARAMETER_VAR_NAME = "queryParams";
30 |
31 | /**
32 | * Used to create Jmeter test plan, also saves testplan as a .jmx file
33 | * in resource folder
34 | */
35 | public HashTree createTestPLan(String inputCSVFile, String domainName, String path, String httpMethod, int threadCount) throws IOException {
36 | JMeterUtils.setJMeterHome("target/jmeter");
37 |
38 | //import the jmeter properties, as is provided
39 | JMeterUtils.loadJMeterProperties("target/jmeter/bin/jmeter.properties");
40 | //Set locale
41 | JMeterUtils.initLocale();
42 |
43 | //Will be used to compose the testPlan, acts as container
44 | HashTree hashTree = new HashTree();
45 |
46 | //Going to use google.com/search?q='queryParam', load in params from CSV
47 | CSVDataSet csvConfig = new CSVDataSet();
48 | csvConfig.setProperty("filename", inputCSVFile);
49 | csvConfig.setComment("List of query params");
50 | csvConfig.setName("MarshalQueryParams");
51 |
52 | csvConfig.setProperty("delimiter", "\\n");
53 |
54 | csvConfig.setProperty("variableNames", QUERY_PARAMETER_VAR_NAME);
55 | csvConfig.setProperty("recycle", "false");//Recycle input on end of file (set to false)
56 | csvConfig.setProperty("ignoreFirstLine", "false");//Ignore first line of file
57 | csvConfig.setProperty("stopThread", true);//Stops thread on EOF
58 | csvConfig.setProperty("shareMode", "shareMode.thread");
59 |
60 | csvConfig.setProperty(TestElement.TEST_CLASS, CSVDataSet.class.getName());
61 | csvConfig.setProperty(TestElement.GUI_CLASS, TestBeanGUI.class.getName());
62 |
63 | //HTTPSampler acts as the container for the HTTP request to the site.
64 | HTTPSampler httpHandler = new HTTPSampler();
65 | httpHandler.setDomain(domainName);
66 | httpHandler.setProtocol("https");
67 | httpHandler.setPath(path);
68 | httpHandler.setMethod(httpMethod);
69 | httpHandler.setName("GoogleSearch");
70 |
71 | //Adding pieces to enable this to be exported to a .jmx and loaded
72 | //into Jmeter
73 | httpHandler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
74 | httpHandler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
75 |
76 | //LoopController, handles iteration settings
77 | LoopController loopController = new LoopController();
78 | loopController.setLoops(LoopController.INFINITE_LOOP_COUNT);
79 | loopController.setFirst(true);
80 | loopController.initialize();
81 |
82 | //Thread groups/user count
83 | SetupThreadGroup setupThreadGroup = new SetupThreadGroup();
84 | setupThreadGroup.setName("GoogleTG");
85 | setupThreadGroup.setNumThreads(threadCount);
86 | setupThreadGroup.setRampUp(1);
87 | setupThreadGroup.setSamplerController(loopController);
88 |
89 | //Adding GUI pieces for Jmeter
90 | setupThreadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
91 | setupThreadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
92 |
93 | //Create the tesPlan item
94 | TestPlan testPlan = new TestPlan("GoogleQueryTestPlan");
95 | //Adding GUI pieces for Jmeter gui
96 | testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
97 | testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
98 | testPlan.setUserDefinedVariables((Arguments) new ArgumentsPanel().createTestElement());
99 |
100 | hashTree.add(testPlan);
101 |
102 | HashTree groupTree = hashTree.add(testPlan, setupThreadGroup);
103 | groupTree.add(httpHandler);
104 | groupTree.add(csvConfig);
105 |
106 | //Save this tes plan as a .jmx for future reference
107 | SaveService.saveTree(hashTree, new FileOutputStream("src/main/resources/jmxFile.jmx"));
108 |
109 | //Added summarizer for logging meta info
110 | Summariser summariser = new Summariser("summaryOfResults");
111 |
112 | //Collect results
113 |
114 | ResultCollector resultCollector = new ResultCollector(summariser);
115 |
116 | resultCollector.setFilename("src/main/resources/Results.csv");
117 |
118 | hashTree.add(hashTree.getArray()[0], resultCollector);
119 |
120 | return hashTree;
121 | }
122 |
123 | public void engineRunner(HashTree hashTree) {
124 | //Create the Jmeter engine to be used (Similar to Android's GUI engine)
125 | StandardJMeterEngine jEngine = new StandardJMeterEngine();
126 |
127 | jEngine.configure(hashTree);
128 |
129 | jEngine.run();
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/main/resources/Results.csv:
--------------------------------------------------------------------------------
1 | timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,failureMessage,bytes,sentBytes,grpThreads,allThreads,URL,Latency,IdleTime,Connect
2 | 1558305694001,618,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,628,0,1,1,https://google.com/search?q=James,618,0,0
3 | 1558305694623,57,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,636,0,1,1,https://google.com/search?q=Josephine,57,0,0
4 | 1558305694680,51,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,624,0,1,1,https://google.com/search?q=Art,51,0,0
5 | 1558305694732,52,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,628,0,1,1,https://google.com/search?q=Lenna,52,0,0
6 | 1558305694785,47,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,632,0,1,1,https://google.com/search?q=Donette,47,0,0
7 | 1558305694832,52,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,630,0,1,1,https://google.com/search?q=Simona,52,0,0
8 | 1558305694885,49,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,630,0,1,1,https://google.com/search?q=Mitsue,49,0,0
9 | 1558305694935,49,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,628,0,1,1,https://google.com/search?q=Leota,48,0,0
10 | 1558305694984,59,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,626,0,1,1,https://google.com/search?q=Sage,59,0,0
11 | 1558305695043,51,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,626,0,1,1,https://google.com/search?q=Kris,51,0,0
12 | 1558305695095,47,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,628,0,1,1,https://google.com/search?q=Minna,47,0,0
13 | 1558305695142,52,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,626,0,1,1,https://google.com/search?q=Abel,52,0,0
14 | 1558305695194,43,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,628,0,1,1,https://google.com/search?q=Kiley,43,0,0
15 | 1558305695237,55,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,634,0,1,1,https://google.com/search?q=Graciela,55,0,0
16 | 1558305695293,50,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,628,0,1,1,https://google.com/search?q=Cammy,50,0,0
17 | 1558305695343,51,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,630,0,1,1,https://google.com/search?q=Mattie,51,0,0
18 | 1558305695395,46,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,632,0,1,1,https://google.com/search?q=Meaghan,46,0,0
19 | 1558305695441,43,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,630,0,1,1,https://google.com/search?q=Gladys,43,0,0
20 | 1558305695485,44,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,626,0,1,1,https://google.com/search?q=Yuki,44,0,0
21 | 1558305695530,49,GoogleSearch,301,Moved Permanently,GoogleTG 1-1,text,true,,632,0,1,1,https://google.com/search?q=Fletche,49,0,0
22 |
--------------------------------------------------------------------------------
/src/main/resources/jmxFile.jmx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 1
12 | 1
13 |
14 | false
15 | -1
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | google.com
24 | https
25 | /search?q=${queryParams}
26 | GET
27 |
28 |
29 |
30 | src/it/resources/names.csv
31 | List of query params
32 | \n
33 | queryParams
34 | false
35 | false
36 | true
37 | shareMode.thread
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------