I'm attempting to create a test plan when a certain value is reached, then some functionality happens. The test plan consists of multiple threads running with a loop, and when some condition is reached I'd like to fire an HTTP request .
I'll drill down to the guts of it:
In my test I have logic in a looping way with multiple threads, and when a condition is met (the condition is met every 10 seconds) then I need to iterate through a value that it's value should be saved from the previous iteration - that value which I defined is a property (inside user.properties) - startIndex = 0 (initialized to 0).
So I've made a While Controller which it's condition is like this:
${__javaScript(${__P(startIndex,)}<=${currBulk},)}
And I expect the HTTP request, which depends on startIndex value inside the while to be executed when startIndex<=currBulk variable.
Inside the While Controller the HTTP request should to be fired until all indexes are covered, and I've written it like this inside BeanShell PostProcessor:
int startIndexIncInt = Integer.parseInt(props.getProperty("startIndex")); //get the initiated index of the loop
startIndexIncInt = startIndexIncInt + 1; //increment it and see if needed to fire the request again, by the original While condition
vars.put("startIndexIncIntVar", String.valueOf(startIndexIncInt));
props.put("startIndex",vars.get("startIndexIncIntVar")); //the property incremental and update
So, I designed it like in order that in the next time (after 10 more seconds) I'll have an updated startIndex that will be compared to the new currBulk (which is always updated by my test plan).
And I just cant have it done . I keep receiving errors like:
startIndexIncInt = Integer.parseInt(props.ge . . . '' : Typed variable declaration : Method Invocation Integer.parseInt
Needless to say that also the var startIndexIncIntVar I defined isn't setted (I checked via debug sampler).
Also, my problem isn't with the time entering the while, my problems are basically with the variable that I should increment and use inside my HTTP request (the while condition, and beanshell post processor script)
Just for more info on it, if I'd written it as pseudo code it would look like this:
startInc = 0
----Test plan loop----
------ test logic, currBulk incremented through the test-----
if(time condition to enter while){
while (startIndex <= currBulk){
Send HTTP request (the request depends on startIndex value)
startIndex++
}
}
Please assist
It appears to be a problem with your startIndex property as I fail to see any Beanshell script error, the code is good so my expectation is that startIndex property is unset or cannot be cast to the integer. You can get a way more information regarding the problem in your Beanshell script in 2 ways:
Add debug() command to the beginning of your script - you will see a lot of debugging output in the console window.
Put your code inside try block like:
try {
int startIndexIncInt = Integer.parseInt(props.getProperty("startIndex")); //get the initiated index of the loop
startIndexIncInt = startIndexIncInt + 1; //increment it and see if needed to fire the request again, by the original While condition
vars.put("startIndexIncIntVar", String.valueOf(startIndexIncInt));
props.put("startIndex", vars.get("startIndexIncIntVar")); //the property incremental and update
} catch (Throwable ex) {
log.error("Beanshell script failure", ex);
throw ex;
}
this way you will be able to see the cause of the problem in jmeter.log file
Actually it appears that you are overscripting as incrementing a variable can be done using built-in components like Counter test element or __counter() function. See How to Use a Counter in a JMeter Test article for more information on the domain.
Related
Background:
I want to perform a test where I need to check time taken to transfer data from one api to another api.
for ex:
/API_1 is sending data
/API_2 gets the data from API_1. here not all data is received at once it is coming in chunks and taking time.
So i want to record this delay.
I am trying this
val ExeScn= scenario("CheckDelay")
.exec(http("XX-Post")
.post("src/v1/req")
.header("Authorization", "ABCD")
.body(StringBody(postBody))
.asJSON
.check(jsonPath("$.data.name[*].address[*].property").findAll.is("Completed")
)
How do I apply a loop here?
I want to run scenario("CheckDelay") till below condition
.check(jsonPath("$.data.name.address.property").find.is("Completed")
loop: asAlongAs
condition for the loop: : isUndefined()
check: simple find with a notExists
I am using this simple google app script to parse through all available Google Sites and dump the html content of individual pages. There are quite many pages so the script will eventually run into 6 minute time limit.
Is it possible to somehow use the PropertiesService to save the current progress (especially in the array loops) and continue where left off later on?
var sites = SitesApp.getAllSites("somedomain.com");
var exportFolder = DriveApp.getFolderById("a4342asd1242424folderid-");
// Cycle through all sites
for (var i in sites){
var SiteName = sites[i].getName();
var pages = sites[i].getAllDescendants();
// Create folder in Drive for each site name
var siteFolder = exportFolder.createFolder(SiteName)
for (var p in pages){
// Get page name and url
var PageUrl = pages[p].getUrl();
//Dump the raw html content in the text file
var htmlDump = pages[p].getHtmlContent();
siteFolder.createFile(PageUrl+".html", htmlDump)
}
}
I can image how one can use the Properties Service to store current line number in the Spreadsheet, and continute where left off. But how can this be done with array containing objects like Sites or Pages?
Using Objects with Properties Service
According to the quotas the maximum size of something you can store in the properties service is 9kb. With a total of 500kb. So if your object is less than this size, it should be no problem. That said, you will need to convert the object to a string with JSON.stringify() and when you retrieve it, use JSON.parse.
Working around the run time limit
What is commonly done to work around the limit is to structure a process around the properties service and triggers. Essentially you make the script keep track of time, and if it starts to take a long time, you get it to save its position and then create a trigger so that the script runs again in 10 seconds (or however long you want), for example:
function mainJob(x) {
let timeStart = new Date()
console.log("Starting at ", timeStart)
for (let i = x; i < 500000000; i++){ // NOTE THE i = x
// MAIN JOB INSTRUCTIONS
let j = i
// ...
// Check Time
let timeCheck = new Date()
if (timeCheck.getTime() - timeStart.getTime() > 30000) {
console.log("Time limit reached, i = ", i)
// Store iteration number
PropertiesService
.getScriptProperties()
.setProperty('PROGRESS', i)
console.log("stored value of i")
// Create trigger to run in 10 seconds.
ScriptApp.newTrigger("jobContinue")
.timeBased()
.after(10000)
.create()
console.log("Trigger created for 10 seconds from now")
return 0
}
}
// Reset progress counter
PropertiesService
.getScriptProperties()
.setProperty('PROGRESS', 0)
console.log("job complete")
}
function jobContinue() {
console.log("Restarting job")
previousTrigger = ScriptApp.getProjectTriggers()[0]
ScriptApp.deleteTrigger(previousTrigger)
console.log("Previous trigger deleted")
triggersRemain = ScriptApp.getProjectTriggers()
console.log("project triggers", triggersRemain)
let progress = PropertiesService
.getScriptProperties()
.getProperty('PROGRESS')
console.log("about to start main job again at i = ", progress)
mainJob(progress)
}
function startJob() {
mainJob(0)
}
Explanation
This script only has a for loop with 500 million iterations in which it assigns i to j, it is just an example of a long job that potentially goes over the run time limit.
The script is started by calling function startJob which calls mainJob(0).
Within mainJob
It starts by creating a Date object to get the start time of the mainJob.
It takes the argument 0 and uses it to initialize the for loop to 0 as you would normally initialise a for loop.
At the end of every iteration, it creates a new Date object to compare with the one created at the beginning of mainJob. In the example, it is set to see if the script has been running for 30 seconds, this can obviously be extended but keep it well below the limit.
If it has taken more than 30 seconds, it stores the value of i in the properties service and then creates a trigger to run jobContinue in 10 seconds.
After 10 seconds, the function jobContinue calls the properties service for the value for i, and calls mainJob with the value returned from the properties service.
jobContinue also deletes the trigger it just created to keep things clean.
This script should run as-is in a new project, try it out! When I run it, it takes around 80 seconds, so it runs the first time, creates a trigger, runs again, creates a trigger, runs again and then finally finishes the for loop.
References
quotas
JSON.stringify()
JSON.parse.
ScriptApp
Triggers
If you are able to process all pages of 1 site under 6 minutes then you could try saving the site names first in a sheet or props depending on the number again. And keep processing n-sites per run. Can also try SitesApp.getAllSites(domain, start, max) and save start value in props after incrementing.
Can do something similar for pages if you cannot process them under 6 minutes.
SitesApp.getAllDescendants(options)
I have a MEAN stack, when the frontend calls for a url like /movies/KN3MJQR.mp4,
the get block in the routes.js looks like this
app.get('/movie/:url', function(req, res) {
try {
var url = req.url.split('/')[2]
res.sendfile(moviesFolder + url);
#i want to add my logic for incrementing view count here.
} catch (e) {
console.log(e);
}
});
I want to add logic to increment the view count of each of the movie whenever a request is raised for the .mp4 . I tried adding the increment view count logic at the place commented in the code as shown above only to find that the whole get method gets called n number of times as the streaming happens. How do I handle this logic?
Update : Code to check the same as answered by #rsp
if(req.get('Range')===('bytes=0-')){
console.log('first call');
}else{
console.log('further call');
}
The endpoint can be hit many times because res.sendfile() supports ranges and the client can do multiple downloads of partial data.
You can inspect the relevant header with req.get('Range') and see if it's the first or last part (depending on whether you want to count every started download or only the finished ones).
For more info on the header, see:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35
My requirement was that whenever there was an error in the Jmeter execution, there should be a delay before starting the next iteration.
"Start Next Thread Loop" is selected at the Thread Group level for Sampler error. Due to this Jmeter will start a new Iteration if there is any error during the execution.
For this purpose I have used Beanshell Timer at the start of the Iteration. Following code is added for delay if the response code is anything other than "200"
String code = prev.getResponseCode();
if(code!="200"){
log.info("::::::::::::::::::::::::::::Response Code = "+code);
log.info("sleep for 10sec");
return 10000;
}
else
return 0;
Please let me know if there are any better ways of doing this.
I believe the prev.getResponseCode() can also be used to do any kind of cleanup task, in case there is any error.
Like for example, if a user logs into the application and got an error before doing logout. We can test at the start of the iteration if the previous response code is in error, if so, we can make the user logout of the application.
You can do this using:
If Controller that will check if last response was in error or not using
${__jexl2("${JMeterThread.last_sample_ok}" == "false",)}
Test Action that will be used to Start Next Thread Loop
Test plan would have the following layout:
I am using services for my AngularJS project and trying to call a service.method using a for loop, like this :
for( key in URLs) {
Service.fetchXML(key);
}
Service description:
[..]
fetchXML : function(resource) {
var prop = SomeVar[resource]; //SomeVar is declared within the service
$.get('xmlURL.xml?resource='+prop, function(data) {
//adds data to the IndexedDB after properly parsing it.
console.log(resource)
dbAdd();
})
Problem is when I try resource inside fetchXML() method; its set permanently, means if the loop runs for five times, only one instance of fetchXML() is created and console.log(resource) returns the same for all five iterations.
Please tell me what am I doing wrong here.
for( key in URLs) {
Service.fetchXML();
}
Should be passing parameter to function since it is used as resource to create prop.
for( key in URLs) {
Service.fetchXML(key);
}
This should have been fairly easy to troubleshoot. First it would be apparent in the request url inspected in browser console/dev tools.
Also using some simple degugger or console.log() statements in function would have helped. Or setting breakpoint on the function and stepping through it to see variable values