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

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.

Related

Jmeter Mongo Db insert script is not adding iterations from csv data set

CSV set as below
enter image description here
Jmeter insert mongo DB script is as below
import com.mongodb.*
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.MongoClientSettings;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import java.util.Arrays;
try {
MongoCollection<Document> collection = vars.getObject("collection");
Document document = new Document("_id", "${_id}")
.append("has_mortgages",false)
.append("data", new Document ("etag":"${_etag}")
.append("links", new Document ("charges","/company/${_id}/charges"))
);
collection.insertOne(document);
}
catch (Exception e) {
SampleResult.setSuccessful(false);
SampleResult.setResponseCode("500");
SampleResult.setResponseMessage("Exception: " + e);
}
Thread group - no.of threads is 1 and loop count is 3
While running the script the first iteration is picking the value of _id as PT000001 and inserting the record. While
second iteration is picking up the _id correctly from the csv which is PT000002 but the
collection.insertOne(document); is still adding the _id PT000001
Can some one please tell me what is wrong with my script??
Take a look at JSR223 Sampler documentation:
The JSR223 test elements have a feature (compilation) that can significantly increase performance. To benefit from this feature:
Use Script files instead of inlining them. This will make JMeter compile them if this feature is available on ScriptEngine and cache them.
Or Use Script Text and check Cache compiled script if available property.
When using this feature, ensure your script code does not use JMeter variables or JMeter function calls directly in script code as caching would only cache first replacement. Instead use script parameters.
so you need to change "${_id}" to vars.get('_id') and "${_etag}" to vars.get('_etag') and your script will start working as expected.
vars stands for JMeterVariables class instance, see the JavaDoc for all available functions and Top 8 JMeter Java Classes You Should Be Using with Groovy for more information on this and other JMeter API shorthands available for the JSR223 Test Elements.
Resolved after unchecking the below check from sampler
Cache compiled script if available

Can we control Jmeter's components through Beanshell? I want to disable all assertions through one flag. how can I do it?

Can we control Jmeter's components through Beanshell? I want to disable all assertions through one flag. How can I do it?
If any other solution than beanShell then let me know.
The easiest way is running your JMeter test using Taurus tool as a wrapper, it naturally supports JMeter tests, moreover it provides some nice extensions.
Particular in your case you can use Modifications for Existing Scripts functionality which allows enabling or disabling Test Elements
---
scenarios:
modification_example:
script: /your/jmeter/testplan.jmx
modifications:
disable: # Names of the tree elements to disable
- Response Assertion
- Duration Assertion
I see two ways in addition to previous answers:
1) Wrap assertions into If controllers, then - yes, set a flag var & check at the If block.
2) Run JMeter programmatically through JMeter API - here you'd have programmatic access to each and every element in the TestPlan.
Although that way is documented quite poorly while the API model is far from being clear itself.
UPD: some clues for the way of doing the latter
1) Here's the main reference: http://jmeter.apache.org/api/index.html
2) Instantiate engine and load properties:
StandardJMeterEngine jmeter = new StandardJMeterEngine();
JMeterUtils.loadJMeterProperties("/path/to/jmeter.properties");
3) Instantiate SaveService and load your plan (yes, save service is what resposible for that)
SaveService.loadProperties();
File yourplan = new File("/path/to/yourplan.jmx");
HashTree planTree = SaveService.loadTree(yourplan);
4) Here's the point where you can access & work your plan elements, going through the HashTree, retrieving test elements in sub-hashtrees (for elements, see the reference mentioned in p.1) & changing them and/or the test structure (cast to TestElement must be good enough for enabling/disabling).
5) As you got done with it, the rest is straightforward:
jmeter.configure(planTree);
jmeter.run();
That should be pretty much it.
From my knowledge, you can not disable all Assertions in the Test Plan by using BeanShell
The work around is as follows:
Create a variable as processAssertions in User Defined Variable config element.
Keep All Assertions inside If Controllers.
Add condition as ${processAssertions}==true, so Assertions will be evaluated ONLY when you set the processAssertions value to true. Set any value other than true, to make JMeter to ignore Assertions.
Using Bean Shell Assertion:
Pre-condition: create processAssertions (Set to TRUE) in User Defined Variables
import org.apache.jmeter.assertions.ResponseAssertion;
log.info("hello");
try{
ResponseAssertion obj = new ResponseAssertion();
if(${processAssertions}==TRUE) { // value accessed from UDV
log.info("inside if");
obj.Enabled=false;
SampleResult.setSuccessful(true); // set sample result to PASS, set to false to mark it failure.
}
} catch(Exception e) {
}
If Controller - with assertions:
If Controller - without assertions:
References:
https://www.blazemeter.com/blog/how-use-jmeter-assertions-3-easy-steps
http://jmeter.apache.org/usermanual/component_reference.html#assertions

How to get the name given to transaction controller using beanshell preprocesssor in jmeter

I want to get the name given to transaction controller using BeanShell preprocessor in JMeter.
Which I want to use to connect and display in dynaTrace later using header manager.
I tried something like this using BeanShell listener
String test = sampleResult.getSampleLabel();
log.info(test);
but I want to use the preprocessor.
log.info(sampler.getName());
This is used to get the name of sampler, in the similar way I want to get the name of transaction controller.
Specifically, I want to use BeanShell preprocessor .
Can somebody help me in this?
You cannot walk further than Previous Result or Previous Sampler so I would state that it is not something you can implement easily. Looks like your test is not very well designed as normally people do not require knowing the name of the parent sampler controller.
Nevertheless you can get access to JMeter Test Plan Tree and figure out information from there. The example code will look something like:
import org.apache.jmeter.control.TransactionController;
import org.apache.jmeter.engine.StandardJMeterEngine;
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 txnCtrlSearch = new SearchByClass(TransactionController.class);
testPlanTree.traverse(txnCtrlSearch);
Collection txnControllers = txnCtrlSearch.getSearchResults();
for (Object txnController : txnControllers) {
log.info(((TransactionController) txnController).getName());
}
Demo:
Some information on using JMeter API from Beanshell scripts: How to Use BeanShell: JMeter's Favorite Built-in Component

What is different between props and vars object in JMeter

Im new in load and performance testing so could anyone explain me, what is difference between vars object and props object in JMeter beanshell script.
Im also bit confuse about JMeter variable and properties.
Thanks.
The most simplest explanation would be that variables(vars) are not shared between threads, and properties(props) ARE shared.
Usage:
vars - ( JMeterVariables) - gives read/write access to variables:
vars.get(key);
vars.put(key,val);
vars.putObject("OBJ1",new Object());
vars.getObject("OBJ2");
props - (JMeterProperties - class java.util.Properties):
props.get("START.HMS");
props.put("PROP1","1234");
You can refer to this link to get more info on vars and props.
As per Blazemeter Blog
vars
vars (JMeter variables) is the most frequently used component. It’s an
instance of the org.apache.jmeter.threads.JMeterVariables class and
provides read/write access to current variables, is capable of
enumerating/changing existing variables, creating new ones, and
obtaining nested properties. All JMeter variables are Java strings.
If you need to put something else to a JMeter variable, you’ll need to
cast it to the string first. The following code snippet demonstrates
how to save previous sampler response data into a JMeter variable.
byte [] samplerdata = ctx.getPreviousResult().getResponseData();
String samplerdatastring = new String(samplerdata);
vars.put("samplerdata",samplerdatastring);
props
Basically, this is the same as “vars,” but it exposes JMeter
properties instead. See JavaDoc on java.util.Properties and JMeter
documentation on JMeter properties for more information. The primary
distinction between props and vars is that props have a “global”
scope, whereas the scope of “vars” is limited to the current thread
group.
Refer to this link.

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