Problem in JSR223 script, JSR223 PostProcessor : javax.script.ScriptException - jmeter

I am using Jmeter 5.0 where i have piece of java code written inside a JSR223 PostProcessor. The code is as follows -
import java.util.Map;
import java.util.HashMap;
Map gamePlayHistoryMap = new HashMap();
gamePlayHistoryMap.put(${playerId}, ${GameplayHistoryId});
props.put("GamePlayHistoryMap", gamePlayHistoryMap);
Map payLevelDetailsMap = new HashMap();
payLevelDetailsMap.put(${playerId}, ${PayLevelDetails});
props.put("PayLevelDetailsMap", payLevelDetailsMap);
However when i execute the test plan, in the console i get the following error -
javax.script.ScriptException: In file: inline evaluation of: import java.util.Map; import java.util.HashMap; Map gamePlayHistoryMap = new H . . . '' Encountered "( 107 , )" at line 6, column 23.
in inline evaluation of:import java.util.Map; import java.util.HashMap; Map gamePlayHistoryMap = new H . . . '' at line number 6
Can someone help me in pointing where i might have gone wrong ?

Don't use ${} in JSR223 scripts, use instead vars.get("") to get varibles
gamePlayHistoryMap.put(vars.get("playerId"), vars.get("GameplayHistoryId"));
It seems that GameplayHistoryId is empty, in such case add default value in JSONExtractor or fail test
See JMeter's best practices for JSR223 scripting:
In this case, ensure the script does not use any variable using ${varName} as caching would take only first value of ${varName}. Instead use :
vars.get("varName")

Since JMeter 3.1 you should be using groovy language for scripting, looking into your exception details it appears you're using java which is not real Java, it's Beanshell interpreter which has worse performance comparing to Groovy and you have to stick to Java 5 syntax.
Don't inline JMeter Functions and/or Variables into scripts as they might be resolved into something causing script failures and in case of Groovy they conflict with GString templates and compilation caching feature. Use vars shorthand for JMeterVariables class to read existing variables values and create new ones, i.e. replace this line:
gamePlayHistoryMap.put(${playerId}, ${GameplayHistoryId});
with this one:
gamePlayHistoryMap.put(vars.get('playerId'), vars.get('GameplayHistoryId'));

You are missing the Map key/value definition.
Map <String, String> gamePlayHistoryMap = new HashMap<>();
gamePlayHistoryMap.put(${playerId}, ${GameplayHistoryId});
Not sure about the answer of:
Don't use ${} in JSR223 scripts, use instead vars.get("")
not sure it has anything to do with it.

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

JMeter with gRPC Java Client and BeanShell Sampler

why it's not possible to run this native Java gRPC Client out of the BeanShell Sampler of JMeter:
package at.fhj.swd.grpc.client;
import at.fhj.swd.grpc.CalcRequest;
import at.fhj.swd.grpc.CalcResponse;
import at.fhj.swd.grpc.CalcServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class GrpcClient {
public static void calc() {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9090)
.usePlaintext()
.build();
CalcServiceGrpc.CalcServiceBlockingStub stub
= CalcServiceGrpc.newBlockingStub(channel);
CalcResponse calcResponse = stub.calc(CalcRequest.newBuilder()
.setNumber(7)
.build());
channel.shutdown();
System.out.println(calcResponse.getResultList());
}
}
The BeanShell Sampler Script can't create an instance of GrpcCient. (method invocation quoted)
import at.fhj.swd.grpc.client.GrpcClient;
GrpcClient grpcClient = new GrpcClient();
//grpcClient.calc();
The error:
Response code:500
Response message:org.apache.jorphan.util.JMeterException: Error invoking bsh method: eval io/grpc/Channel
seems that there was something wrong with an import, but why? The Client runs if its executed without JMeter.
Beanshell is not 100% compatible with Java so if there are overloaded functions/constructors you need to explicitly specify which one you want via reflection
Since JMeter 3.1 it's recommended to use JSR223 Test Elements and Groovy so it would be sufficient just to choose groovy from the Language dropdown and your code will start working as expected. Moreover Groovy has much better performance comparing to Beanshell, see Apache Groovy - Why and How You Should Use It article for more details

How to fetch Map from jmeter global properties in different thread

I am using Jmeter 5.0 where i have piece of java code written inside a JSR223 PostProcessor in a single thread group. The values are getting stored inside the maps and i can view it in the Debug Sampler. The code is as follows -
import java.util.Map;
import java.util.HashMap;
Map gamePlayHistoryMap = new HashMap();
gamePlayHistoryMap.put(vars.get("playerId"), vars.get("GameplayHistoryId"));
props.put("GamePlayHistoryMap", gamePlayHistoryMap);
Map payLevelDetailsMap = new HashMap();
payLevelDetailsMap.put(vars.get("playerId"), vars.get("PayLevelDetails"));
props.put("PayLevelDetailsMap", payLevelDetailsMap);
Now i want to access the values of these 2 maps in different thread group. How to do that ? I have tried using JSR223 PreProcessor where i have written code as follows -
import java.util.Map;
import java.util.HashMap;
Map gameTemplateIdMap = props.get("GamePlayHistoryMap");
Map payLevelDetailsMap = props.get("PayLevelDetailsMap");
I am unable to get the values as stored in previous thread.Can someone help me in pointing where i might have gone wrong ?
1st Thread Debug Sampler -
GamePlayHistoryMap={107=3387} HTTPResponse.parsers=htmlParser
wmlParser cssParser
PayLevelDetailsMap={107={"prizeQuantity":0,"prizeType":{"prizeTypeId":2,"prizeName":"Cash","description":"Promotional
Cash","listofErrors":[],"isValid":true},"isValid":true,"description":"$0.3","externalPrizeID":null,"prizeTypeID":2,"gameTemplateID":0,"isNotifySocial":false,"prizeValue":0.3,"payMethodID":1,"winProbability":17.5,"celebrationLevel":null,"payMethod":{"payMethodID":1,"name":"CMS","description":"Account","listofErrors":[],"isValid":true},"listofErrors":[],"payLevelTemplateID":41170,"isNotifySignage":true,"position":3,"celebrationLevelID":1}}
2nd Thread Debug Sampler -
GamePlayHistoryMap={107=} HTTPResponse.parsers=htmlParser wmlParser
cssParser PayLevelDetailsMap={107=}
Are you sure that your 2nd Thread Group is being executed after 1st Thread Group? The only failure reason I can think of is that you're trying to read the value from map at the time when it has not yet been defined.
Check out jmeter.log file for any suspicious entries. If I'm right and this is the case you can:
Tick Run Thread Groups consecutively at Test Plan level
Or use Inter-Thread Communication Plugin in order to block 2nd Thread Group until the value of map is set in the 1st Thread Group
I did this using the bsh.shared property of BeanShell Sampler. 1st Thread group code which populates the map is as follows -
import java.util.Map;
import java.util.HashMap;
Map gamePlayHistoryMap = new HashMap();
Map payLevelDetailsMap = new HashMap();
gamePlayHistoryMap.put(vars.get("playerId"), vars.get("GameplayHistoryId"));
bsh.shared.gphMap = gamePlayHistoryMap;
payLevelDetailsMap.put(vars.get("playerId"), vars.get("PayLevelDetails"));
bsh.shared.pldMap = payLevelDetailsMap;
2nd Thread Group code which fetches the map is as follows -
import java.util.Map;
import java.util.HashMap;
Map myMap1 = bsh.shared.gphMap;
vars.put("GamePlayHistoryId", myMap1.get(vars.get("playerId")));
log.info(myMap1.get(vars.get("playerId")));
Map myMap2 = bsh.shared.pldMap;
vars.put("PayLevelDetails", myMap2.get(vars.get("playerId")));
log.info(myMap2.get(vars.get("playerId")));
Of course i think this can also be done using JSR223 elements, just need to figure out how. I also need to figure out how to declare the map in the 1st thread group globally so that each time the thread runs the values of the map gets appended. As of now each time the map gets newly initialized whenever the thread runs more than once. Any pointers how to achieve this would be greatly appreciated.
Thank You

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

How to capture thread specific different data form drop down list in jmeter?

My application consist the Select Title drop down list contains values as Mr, Miss, Dr & Mrs.
I want to capture the different title (Random but from above 4) for different thread. please suggest how it is possible.
This is my script i have pass the title parameter as ${randomTitle}
Value pass to database as,
Post request as,
Out of interest, is it vital to use enum there?
Try amending your code as follows:
import java.util.Random;
String[] frm_titles = {"Mr", "Miss", "Dr", "Mrs"};
Random randGenerator = new Random();
int randInt = randGenerator.nextInt(frm_titles.length);
vars.put("randomTitle",frm_titles[randInt]);
It should work this way. Enum must not be local to Beanshell interpreter, if you need to use enum structure - compile it as .jar and place it to JMeter classpath.
See How to use BeanShell: JMeter's favorite built-in component guide for more details on Beanshell scripting in Apache JMeter.
You can use Beanshell Preprocessor:
import java.util.Random;
public enum frm_titles {"Mr", "Miss", "Dr", "Mrs"};
Random randGenerator = new Random();
int randInt = randGenerator.nextInt(frm_titles.values().length);
vars.put("randomTitle",frm_titles.values()[randInt].toString());
Then, in your test plan change the post params and add ${randomTitle} instead your title param.
Check this links for more info:
http://www.beanshell.org/manual/quickstart.html
http://jmeter.apache.org/usermanual/component_reference.html#BeanShell_Sampler
http://jmeter.apache.org/usermanual/functions.html
http://testeverythingqtp.blogspot.com.es/2013/01/jmeter-bean-shell-script-create-file.html
http://jmeter-kh.blogspot.com.es/2009/07/how-to-make-beanshell-work-in-jmeter.html
I think 2 ways are possible,
you can try beanshell processor
you can try regular expression extractor and counter
first approach is best explained above, for 2nd approach you can try,
Random product selection using Jmeter

Resources