I want to benchmark some remote API calls via code. I've been using JMH for it so far, but it doesnt quite fit my need as a stress test tool (JMH works well for micro benchmarking, where the snippet being benchmarks rusn really really fast). My remote APIs respond in tens of seconds, so I really need to run the tests with:
Multiple parameterized inputs
Multiple client threads (controlling the load)
I'm able achieve a lot via manual tests in JMeter UI, but I would like to write some java tests/benchmarks that use JMeter and does the same. Is there a way to do that?
You can either kick off an existing JMeter test or create a new one using JMeter API
Run existing test example code:
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;
import java.io.File;
public class RunExistingJMeterTest {
public static void main(String[] args) throws Exception {
// Initialize properties
JMeterUtils.loadJMeterProperties("/path/to/your/jmeter/bin/jmeter.properties");
// JMeter Engine
StandardJMeterEngine jmeter = new StandardJMeterEngine();
// Initialize logging, locale, etc.
JMeterUtils.setJMeterHome("/path/to/your/jmeter");
JMeterUtils.initLocale();
// Initialize JMeter SaveService
SaveService.loadProperties();
// Load existing .jmx Test Plan
HashTree testPlanTree = SaveService.loadTree(new File("/path/to/your/jmeter/extras/Test.jmx"));
Summariser summer = null;
String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
if (summariserName.length() > 0) {
summer = new Summariser(summariserName);
}
// Store execution results into a .jtl file
String logFile = "/path/to/results/file.jtl";
ResultCollector logger = new ResultCollector(summer);
logger.setFilename(logFile);
testPlanTree.add(testPlanTree.getArray()[0], logger);
// Run JMeter Test
jmeter.configure(testPlanTree);
jmeter.run();
}
}
Create JMeter script programmatically:
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.gui.ArgumentsPanel;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.control.gui.LoopControlPanel;
import org.apache.jmeter.control.gui.TestPlanGui;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
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;
import java.io.FileOutputStream;
public class CreateNewJMeterTest {
public static void main(String[] args) throws Exception {
StandardJMeterEngine jmeter = new StandardJMeterEngine();
//JMeter initialization (properties, log levels, locale, etc)
JMeterUtils.setJMeterHome("/path/to/your/jmeter/installation");
JMeterUtils.loadJMeterProperties("/path/to/your/jmeter/bin/jmeter.properties");
JMeterUtils.initLocale();
// JMeter Test Plan, basically JOrphan HashTree
HashTree testPlanTree = new HashTree();
// First HTTP Sampler - open example.com
HTTPSamplerProxy examplecomSampler = new HTTPSamplerProxy();
examplecomSampler.setDomain("example.com");
examplecomSampler.setPort(80);
examplecomSampler.setPath("/");
examplecomSampler.setMethod("GET");
examplecomSampler.setName("Open example.com");
examplecomSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
examplecomSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
// Loop Controller
LoopController loopController = new LoopController();
loopController.setLoops(1);
loopController.setFirst(true);
loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
loopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.class.getName());
loopController.initialize();
// Thread Group
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setName("Example Thread Group");
threadGroup.setNumThreads(1);
threadGroup.setRampUp(1);
threadGroup.setSamplerController(loopController);
threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
// Test Plan
TestPlan testPlan = new TestPlan("Create JMeter Script From Java Code");
testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
testPlan.setUserDefinedVariables((Arguments) new ArgumentsPanel().createTestElement());
// Construct Test Plan from previously initialized elements
testPlanTree.add(testPlan);
HashTree threadGroupHashTree = testPlanTree.add(testPlan, threadGroup);
threadGroupHashTree.add(examplecomSampler);
// save generated test plan to JMeter's .jmx file format
SaveService.saveTree(testPlanTree, new FileOutputStream("/path/to/test.jmx"));
//add Summarizer output to get test progress in stdout like:
// summary = 2 in 1.3s = 1.5/s Avg: 631 Min: 290 Max: 973 Err: 0 (0.00%)
Summariser summer = null;
String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
if (summariserName.length() > 0) {
summer = new Summariser(summariserName);
}
// Store execution results into a .jtl file
String logFile = "/path/to/test/results.jtl";
ResultCollector logger = new ResultCollector(summer);
logger.setFilename(logFile);
testPlanTree.add(testPlanTree.getArray()[0], logger);
// Run Test Plan
jmeter.configure(testPlanTree);
jmeter.run();
System.exit(0);
}
}
Check out Five Ways To Launch a JMeter Test without Using the JMeter GUI article for more information.
Related
I'm using Spring Boot version 2.1.8.RELEASE, and I have this problem:
Have you a solution please ?
[Thread-2] ERROR o.a.k.t.TestUtils - Error deleting C:\Users\usr\AppData\Local\Temp\kafka-255644115154741962
java.nio.file.FileSystemException: C:\Users\usr\AppData\Local\Temp\kafka-255644115154741962\version-2\log.1:
The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
at java.nio.file.Files.delete(Files.java:1126)
at org.apache.kafka.common.utils.Utils$2.visitFile(Utils.java:734)
at org.apache.kafka.common.utils.Utils$2.visitFile(Utils.java:723)
at java.nio.file.Files.walkFileTree(Files.java:2670)
at java.nio.file.Files.walkFileTree(Files.java:2742)
at org.apache.kafka.common.utils.Utils.delete(Utils.java:723)
at org.apache.kafka.test.TestUtils$1.run(TestUtils.java:184)
This is my test, i use a windows 10 like OS,
This is my test,
import org.I0Itec.zkclient.ZkClient;
import org.junit.Test;
import kafka.utils.ZKStringSerializer$;
import kafka.utils.ZkUtils;
import kafka.zk.EmbeddedZookeeper;
public class BaseTest {
private static final String ZKHOST = "127.0.0.1";
#Test
public void producerTest(){
// setup Zookeeper
EmbeddedZookeeper zkServer = new EmbeddedZookeeper();
String zkConnect = ZKHOST + ":" + zkServer.port();
ZkClient zkClient = new ZkClient(zkConnect, 30000, 30000, ZKStringSerializer$.MODULE$);
ZkUtils zkUtils = ZkUtils.apply(zkClient, false);
zkClient.close();
zkServer.shutdown();
}
}
I'm new to JMeter. I've a Java code which I've imported as JAR file. There is a variable called output, in which the result is in which the output is received and is printed. I want to access that variable from Jmeter Beanshell. Can anyone help me out with that?
My Java code is as follows:
package co.in;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class RestClientGet_Validate {
// http://localhost:8080/RESTfulExample/json/product/get
public static void main(String[] args) {
try {
URL url = new URL("http://172.16.2.192:8080/pivot_service_1.0/service/validate");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
response = output;
}
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
First of all, be informed that you can execute the request using JMeter's HTTP Request sampler and obtain the output using Regular Expression Extractor
If you're looking for a way to re-use your existing Java code in JMeter scripting test elements:
You need to change return type of your function to String, to wit replace
public static void main(String[] args)
with
public static String main()
You need to add return statement at the end of your function like:
return output;
Once done place the .jar to JMeter Classpath and restart JMeter to pick it up
If everything goes well you should be able to access the value in Beanshell like:
String output = co.in.RestClientGet_Validate.main();
Also be aware that starting from JMeter 3.1 it is recommended to switch to JSR223 Test Elements and Groovy language for scripting so consider migrating from Beanshell ASAP.
I am working on Jmeter Scripts from sometime now, there is a need to secure the Jmeter script and majorly make it unreadable for external stakeholders. My expectation is to obfuscate or deliver the script as some kind of JAR or executable. I need some ideas or workaround to start with.
Thanks
Senz79
It is possible to run existing JMeter script from Java code or create a JMeter test purely in Java using JMeter API so it is not a problem to create an executable binary which will run your test and obfuscate it.
Example Java code to run a JMeter test:
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;
import java.io.File;
public class JMeterFromCode {
public static void main(String[] argv) throws Exception {
// JMeter Engine
StandardJMeterEngine jmeter = new StandardJMeterEngine();
// Initialize Properties, logging, locale, etc.
JMeterUtils.loadJMeterProperties("/tmp/jmeter/bin/jmeter.properties");
JMeterUtils.setJMeterHome("/tmp/jmeter");
JMeterUtils.initLogging();// you can comment this line out to see extra log messages of i.e. DEBUG level
JMeterUtils.initLocale();
// Initialize JMeter SaveService
SaveService.loadProperties();
// Load existing .jmx Test Plan
HashTree testPlanTree = SaveService.loadTree(new File("/tmp/jmeter/test.jmx"));
Summariser summer = null;
String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");
if (summariserName.length() > 0) {
summer = new Summariser(summariserName);
}
ResultCollector logger = new ResultCollector(summer);
logger.setFilename("/tmp/jmeter/test.jtl");
testPlanTree.add(testPlanTree.getArray()[0], logger);
// Run JMeter Test
jmeter.configure(testPlanTree);
jmeter.run();
}
}
See the following reference material to get started:
Five Ways To Launch a JMeter Test without Using the JMeter GUI
Bytecode obfuscation
How can we trigger concurrent requests in JMeter...
I am not talking about the non -html elements (where we have a provision in jmeter to download them concurrently).
I have few AJAX calls to be downloaded concurrently...
As per JMeter 3.0 there is no suitable Test Elements, you will need to:
go for JSR223 Sampler + Groovy language and Apache HTTP Components (which are parts of JMeter anyway)
or develop your custom sampler to overcome JMeter thread group limitation and kick off extra threads to execute AJAX calls.
Example JSR223 Sampler Code:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; // necessary imports
List<String> urls = new ArrayList<String>(); // initialize array of URLs
Collections.addAll(urls,args); // read URLs from "Parameters" input and add them to array
ExecutorService pool = Executors.newFixedThreadPool(urls.size()); // initialize pool of Future Tasks with number of threads equal to size of URLs provided
for (String url : urls) { // for each URL from list
final String currentURL = url;
pool.submit(new Runnable() { // Sumbit a new thread which will execute GET request
#Override
public void run() {
try {
HttpClient client = new DefaultHttpClient(); // Use Apache Commons HTTPClient to perform GET request
HttpGet get = new HttpGet(currentURL);
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
pool.shutdown(); // shut down thread pool
More details: How to Load Test AJAX/XHR Enabled Sites With JMeter
I created a jmx file using java code. But when i tried to execute the jmx file using java, it throws the exception. Pls help me.. I have added all the jars.
(Error in NonGUIDriver java.lang.IllegalArgumentException: Problem loading XML from:'/home/ksahu/MyScreenshots/k.jmx', conversion error com.thoughtworks.xstream.converters.ConversionException: null : null)
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;
import java.io.FileInputStream;
public class RunJMXfile {
public static void main(String[] argv) throws Exception {
// JMeter Engine
StandardJMeterEngine jmeter = new StandardJMeterEngine();
// Initialize Properties, logging, locale, etc.
JMeterUtils.loadJMeterProperties("/home/ksahu/apache-jmeter-2.13/bin/jmeter.properties");
JMeterUtils.setJMeterHome("/home/ksahu/apache-jmeter-2.13");
JMeterUtils.initLogging();// you can comment this line out to see extra log messages of i.e. DEBUG level
JMeterUtils.initLocale();
// Initialize JMeter SaveService
SaveService.loadProperties();
// Load existing .jmx Test Plan
FileInputStream in = new FileInputStream("/home/ksahu/MyScreenshots/k.jmx");
HashTree testPlanTree = SaveService.loadTree(in);
in.close();
// Run JMeter Test
jmeter.configure(testPlanTree);
jmeter.run();
}
}
This is the code that i have used to generate the jmx file
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.SetupThreadGroup;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.HashTree;
public class jmeterTesting {
public static void main(String[] args) throws FileNotFoundException, IOException{
// Engine
StandardJMeterEngine jm = new StandardJMeterEngine();
JMeterUtils.setJMeterHome("/home/ksahu/apache-jmeter-2.13");
// jmeter.properties
JMeterUtils.loadJMeterProperties("/home/ksahu/apache-jmeter-2.13/bin/jmeter.properties");
HashTree hashTree = new HashTree();
// HTTP Sampler
HTTPSampler httpSampler = new HTTPSampler();
httpSampler.setDomain("www.google.com");
httpSampler.setPort(80);
httpSampler.setPath("/");
httpSampler.setMethod("GET");
// Loop Controller
TestElement loopCtrl = new LoopController();
((LoopController)loopCtrl).setLoops(1);
((LoopController)loopCtrl).addTestElement(httpSampler);
((LoopController)loopCtrl).setFirst(true);
// Thread Group
SetupThreadGroup threadGroup = new SetupThreadGroup();
threadGroup.setNumThreads(1);
threadGroup.setRampUp(1);
threadGroup.setSamplerController((LoopController)loopCtrl);
// Test plan
TestPlan testPlan = new TestPlan("MY TEST PLAN");
hashTree.add("testPlan", testPlan);
hashTree.add("loopCtrl", loopCtrl);
hashTree.add("threadGroup", threadGroup);
hashTree.add("httpSampler", httpSampler);
jm.configure(hashTree);
jm.run();
System.out.println(hashTree);
SaveService.saveTree(hashTree,new FileOutputStream("/home/ksahu/MyScreenshots/k.jmx"));
}
}
Try to open your /home/ksahu/MyScreenshots/k.jmx in JMeter GUI. If it does not open - there is a problem with the code, you generated the JMX file with. In that case update your question with the code, you used to create the k.jmx file.
See Chapter 4. RUN A JMETER TEST THROUGH A PROGRAM (FROM JAVA CODE) of the Five Ways To Launch a JMeter Test without Using the JMeter GUI for details.
Also there is a sample project which you can use as a reference: https://bitbucket.org/blazemeter/jmeter-from-code/
You need to change the text "org.apache.jorphan.collections.HashTree" in the JMX generated using java to "hashTree". Open the JMX in any text editor and do the replace as mentioned. If that doesn't suffice, include the below step.
You need to set TestElement.ENABLED, TestElement.TEST_CLASS and TestElement.GUI_CLASS explicitly for each element. For example a sampler can be defined as below.
HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
httpSampler.setDomain(DOMAIN);
httpSampler.setPort(PORT);
httpSampler.setPath(PATH);
httpSampler.setMethod(METHOD);
httpSampler.addArgument("", "${domain}");
httpSampler.setProperty(TestElement.ENABLED, true);
httpSampler.setResponseTimeout("20000");
httpSampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
httpSampler .setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());