How to modify the image in the JMeter script? - image

I'm uploading the image with the following JMeter script. But we have the requirement to modify the image for every request so that virus scanner scans it every time. Can anyone please suggest how to modify the image? Thanks.
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true">
<elementProp name="HTTPsampler.Files" elementType="HTTPFileArgs">
<collectionProp name="HTTPFileArgs.files">
<elementProp name="Sample.JPG" elementType="HTTPFileArg">
<stringProp name="File.path">Sample.JPG</stringProp>
<stringProp name="File.paramname">File</stringProp>
<stringProp name="File.mimetype">image/jpeg</stringProp>
</elementProp>
</collectionProp>
</elementProp>

You can use ImageIO class in order to add something to the original image
Add JSR223 PreProcessor as a child of the HTTP Request sampler which performs the image upload
Put the following code into "Script" area:
def image = javax.imageio.ImageIO.read(new File('Sample.jpg'))
def graphics = image.getGraphics()
graphics.setFont(graphics.getFont().deriveFont(16f))
graphics.drawString('User ' + ctx.getThreadNum() + '; iteration: ' + ctx.getVariables().getIteration(), 50, 50)
graphics.dispose()
javax.imageio.ImageIO.write(image, "jpg", new File("Sample.jpg"))
That's it, when you run your test the above code will add current user and iteration text to the upper-left corner of the image (the font color is white so if your image is white you won't be able to see it using your eyes)
More information on Groovy scripting in JMeter: Apache Groovy - Why and How You Should Use It
If any concurrency is assumed - consider making the copy of the image and updating the filename in the HTTP Request sampler otherwise you will run into race condition when multiple threads will be simultaneously writing into the same file so the image will get corrupt.

Related

Jmeter JSR223 Unable to read data from CSV file

Requirement is ItemID should be read from external CSV file and passed in the JSR223 preprocessor script. This is the groovy code in JSR223 and it is working as expected in the grrovy executer.
def items = []
List<String> lines = new File("C:\\Users\\854986\\itemid.csv").readLines()
def itemNo = RandomUtils.nextInt(5, 10)
1.upto(itemNo) { index ->
def item = [:]
def lineFromCsv = lines.get(index as int)
item.put('itemId', lineFromCsv)
But it jmeter it is throwing error and below is the error message.
"2022-11-15 12:34:14,398 ERROR o.a.j.m.JSR223PreProcessor: Problem in JSR223 script, JSR223 PreProcessor 3
javax.script.ScriptException: org.apache.commons.jexl2.JexlException$Parsing: JsonBuilder#1:20 parsing error near '... ment, miss ...'
at org.apache.commons.jexl2.scripting.JexlScriptEngine.compile(JexlScriptEngine.java:237)"./
I have java 19.0.1, Jmeter 5.4.3 and groovy 4.0.2.
You're talking about "groovy code". Any reason to use jexl2 language in the JSR223 PreProcessor?
Make sure to choose groovy as the language and at least this error should go away. Groovy is the recommended scripting option since JMeter 3.1 mainly because Groovy provides maximum performance comparing to other engines

JMeter User Defined Variable for enabling Test Duration

I am trying to parameterize the JMeter test so that I can run Load Test, Stress Test as well as Soak Load Test using the same test plan.
In order to do this, I defined the following as User Defined variables (Test Plan -> Add -> Config Element -> User Defined Variables)
numberOfThreads=${__P(numberOfThreads,1)}
rampUp=${__P(rampUp,1)}
loopCount=${__P(loopCount,1)}
schedulerEnabled=${__P(schedulerEnabled,false)}
schedulerDuration=${__P(schedulerDuration,120)}
Now, in the ThreadGroup definition, I am using these variables as
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Test123" enabled="true">
<stringProp name="TestPlan.comments">Test for the endpoint GET /test123</stringProp>
<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">${loopCount}</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">${numberOfThreads}</stringProp>
<stringProp name="ThreadGroup.ramp_time">${rampUp}</stringProp>
<boolProp name="ThreadGroup.scheduler">{schedulerEnabled}</boolProp>
<stringProp name="ThreadGroup.duration">${schedulerDuration}</stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
<boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
</ThreadGroup>
But when I run the same and pass in values
numberOfThreads=50
rampUp=10
loopCount=-1
schedulerEnabled=true
schedulerDuration=30
(using jmeter-maven-plugin)
the first ThreadGroup keeps creating infinite number of threads instead of shutting down the thread groups after 30 seconds.
PS: 30 is an example. When executing Soak Load Test, I will be setting a higher value to the same.
PS: I noticed that LoopController.continue_forever is set to 'false' immaterial whether for Loop Count I check "Infinite" or provide the value 1. When in UI, I check "Infinite", the value of LoopController.loops is set to -1.
jmeter-maven-plugin: 2.7.0
JMeter Version: 5.1.1
I don't think this is the correct way to enable/disable the thread lifetime setting:
<boolProp name="ThreadGroup.scheduler">{schedulerEnabled}</boolProp>
Instead of trying to enable/disable the thread lifetime setting you could rather play with this schedulerDuration setting itself, for example if you plan to run fixed amount of loops - set the duration to something very big, the maximum value is 9223372036854775807
Also it should be possible to use Runtime Controller
If ability to enable/disable the scheduler is something you really need, you will need to amend it in the .jmx script beforehand somehow, i.e. using sed editor. Also Taurus framework has possibility to amend all the properties of all the test elements using simple YAML syntax

how can we know, by what user the sql is executed in jmeter

I'm executing the sqls with different jdbc-connection strings. Each sql will run on respective database-user. Sqls are executing fine. But, I need confirmation like, the sql is executed with the user mentioned in connection-string. Is there any option which will emit the user involved to execute the sql to jtl ?
We can make it possible by . Parse the username using regex and read the variable through BeanShellPostprocessor and put same to the jtl.
<hashTree /><RegexExtractor enabled="true" guiclass="RegexExtractorGui" testclass="RegexExtractor" testname="Regular Expression Extractor">
<stringProp name="RegexExtractor.useHeaders">true</stringProp>
<stringProp name="RegexExtractor.refname">UserName</stringProp>
<stringProp name="RegexExtractor.regex">UserName=(\w+), </stringProp>
<stringProp name="RegexExtractor.template">$1$</stringProp>
<stringProp name="RegexExtractor.default" />
<stringProp name="RegexExtractor.match_number" />
</RegexExtractor><hashTree />
In Beanshell postprocessor read it:
String db_user = vars.get("UserName");
vars.put("db_user", db_user);
Note: Also, need to mention the variable name used here at jmeter/bin/jmeter.properties file.
sample_variables=db_user
By above way, we can achieve this.

How can I navigate the JMeter test element tree from within a sampler script

From a JSR223 Sampler, I can get access to the current test element using the sampler variable.
From there, how can I navigate the tree of TestElement objects? For example, how can I get access to the parent test element (and then it’s parent, etc) or how can I get access to the TestPlan test element?
Background:
I want to dynamically create a JDBC Connection Configuration element from a JSR223 Sampler using Groovy.
From other questions (e.g., here) and web searches (e.g., here), I know how to create test plan elements from the top down (e.g., how to create a test plan and build the tree down from there). So I know how to do the new DataSourceElement() which is a TestElement but I don’t know how to add that new element to the test plan. In the sampler script I have access to the sampler (Sampler) and the ctx (JMeterContext) variables but I don’t know how to navigate the test element tree.
I tried just using sampler.addTestElement but a config element isn’t really valid under a sampler element. Still, I did try but the config element was not found when I tried to use it in a JDBC Request (error: "No pool found named: 'myDatabaseThreadPool', ensure Variable Name matches Variable Name of JDBC Connection Configuration").
I’m hoping that if I can get the TestPlan element and add the config element to that, then it would work.
FWIW, my test plan looks like this:
Test Plan
Thread Group 1 (could be a setup thread group)
JSR223 Sampler (this is where I want to create the dynamic config)
Thread Group 2 (multiple threads)
JDBC Request (uses the pool variable name specified in the dynamic config)
View Results Tree
I can go into further detail about why I want to dynamically create the JDBC Connection Configuration, but if there’s an easy answer about how to navigate the test element tree from inside my sampler script I’d like to know that anyway.
As you have mentioned you have access to JMeterContext via ctx shorthand. Hence you have access to StandardJMeterEngine class instance via ctx.getEngine(); method.
Looking into StandardJMeterEngine source you can see that test plan is being stored as HashTree structure:
private HashTree test;
So the choices are in:
change access modifier to public and recompile JMeter from sources
use Trail - Java Reflection API in order to access test value
Reference code:
import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.SearchByClass;
import java.lang.reflect.Field;
import java.util.Collection;
StandardJMeterEngine engine = ctx.getEngine();
Field test = engine.getClass().getDeclaredField("test");
test.setAccessible(true);
HashTree testPlanTree = (HashTree) test.get(engine);
SearchByClass testPlans = new SearchByClass(TestPlan.class);
testPlanTree.traverse(testPlans);
Collection testPlansRes = testPlans.getSearchResults();
TestPlan testPlan = (TestPlan)testPlansRes.toArray()[0];
//do what you need with "testPlanTree" and/or "testPlan"
Check out How to Use BeanShell: JMeter's Favorite Built-in Component guide for more information using JMeter and Java API from scripting test elements.

Trying to generate JMeter Test Plan (jmx) With JMeter API : Not able to save CSVDataSet element

I am creating a JMeter jmx file dynamically by using JMeter APIs. I am able to add a ThreadGroup within a TestPlan and a JavaSampler within the ThreadGroup. But when I add a CSVDataSet element within the Java Sampler, it does not get saved properly.
The following code is used to create a new CSVDataSet element
CSVDataSet csvDataSet = new CSVDataSet();
csvDataSet.setName("CSV Data Set");
csvDataSet.setComment("Sample CSV Data Set");
csvDataSet.setDelimiter(",");
csvDataSet.setFileEncoding("");
csvDataSet.setFilename("d:\\jmeter\\data.csv"); // variable
csvDataSet.setQuotedData(true);
csvDataSet.setRecycle(true);
csvDataSet.setShareMode(shareMode.all);
csvDataSet.setStopThread(false);
csvDataSet.setVariableNames("firstname, lastname, email"); // variable
csvDataSet.setEnabled(true);
When this is saved using SaveService.saveTree, the final jmx does not contain all the values which were set.
<org.apache.jorphan.collections.HashTree>
<CSVDataSet testname="CSV Data Set Config" enabled="true">
<stringProp name="TestPlan.comments">Sample CSV Data Set Config</stringProp>
</CSVDataSet>
<org.apache.jorphan.collections.HashTree/>
As seen above, only the test name, enabled, and comments are added. The rest of the variables are completely ignored.
Is there something that needs to be set in order to get all the values as expected?
or is this a bug in JMeter? I am using version 2.11
The basic code is as per section 4.3 from following link
http://blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui
To that I add the code shown above. The way it is added is,
testPlanTree.add("testPlan", testPlan);
testPlanTree.add("loopController", loopController);
testPlanTree.add("threadGroup", threadGroup);
testPlanTree.add("httpSampler", httpSampler);
testPlanTree.add("csvDataSet", csvDataSet);
SaveService
.saveTree(testPlanTree, new FileOutputStream("d:\\test.jmx"));
output of CSVDataSet block is as shown above.
After looking into the JMeter source code, it seems all the properties are set using the setProperty function rather than the individual setter functions. So putting the following code does the job of creating the CSVDataSet element properly.
csvDataSet.setProperty("delimiter", ",");
csvDataSet.setProperty("fileEncoding", "");
csvDataSet.setProperty("filename", "d:\\data.csv");
csvDataSet.setProperty("quotedData", true);
csvDataSet.setProperty("recycle", true);
csvDataSet.setProperty("shareMode", "shareMode.all");
csvDataSet.setProperty("stopThread", false);
csvDataSet.setProperty("variableNames", "var1, var2, var3");
Not sure why setters are not used in the code, but this seems to be the way to go for now
It is clearly not a bug in JMeter otherwise CSV Data Set could not be saved.
It is probably an issue in the way you build the HashTree, but unless you show the full code, you cannot get help.
By the way, as I said in a previous answer, what you are trying to do to build different tests based on input parameter is not good idea IMHO, the approach will be very fragile towards upcoming versions of JMeter.
JMeter provides ways to do it that you should follow.

Resources