My current environment: JMeter v2.11, remote Oracle 12, JDK 7
There is a system (A) that will send 2000 SOAP/XML submissions (per hour) into a receiving system (B). System B will insert a new row to the database table (for each new submission) setting the application.status column value to numeric value of 1. System (B) processes the requests and updates the application.status column from numeric value of 1 to numeric value of 6 once the processing is complete and the submissions are 'approved'.
I have a requirement that states these A to B submissions need to be 'approved' within 60 seconds - I am trying to setup my thread to verify this.
My current workings (after some start up help from Dmitri T) are as follows:
Thread Group
-Beanshell Sampler (to create an XML message)
-Beanshell Sampler (to submit XML to a web service)
-While Controller-->${__javaScript("${status_1}" != "6")}
--Duration Assertion-->60000 milliseconds (Duration)
--JDBC Request-->select status from application where applicationID = (select max(application_id) from application); VarName = status
Currently, my Thread Group will run and I will get multiple JDBC Requests executed until either the JDBC Request takes longer than the Duration Assertion value OR until the status value in the application table is updated to 6 (which equates to 'Approved' status).
This is NOT what I need.
I don't want to verify whether the JDBC request takes longer than the Duration value, it will never take longer than the Duration value, what I need the Duration Assertion for is to fail if the change from application.status=1 to application.status=6 takes longer than 60 seconds
As I state above - it won't prove my requirement to verify if the JDBC request takes longer than the Duration Assertion value (it never will), I need the Duration Assertion to check the application.status change takes less than 60 seconds.
I've tried the following:
Thread Group
-While Controller-->${__javaScript("${status_1}" != "6")}
--Duration Assertion-->60000 milliseconds (Duration)
--JDBC Request-->select status from application where applicationID = (select max(application_id) from application); VarName = status
Thread Group
-While Controller-->${__javaScript("${status_1}" != "6")}
--JDBC Request-->select status from application where applicationID = (select max(application_id) from application); VarName = status
--Duration Assertion-->60000 milliseconds (Duration)
Thread Group
-While Controller-->${__javaScript("${status_1}" != "6")}
--JDBC Request-->select status from application where applicationID = (select max(application_id) from application); VarName = status
---Duration Assertion-->60000 milliseconds (Duration)
I'm running out of ideas! - As with my previous requests, I appreciate any help anyone can provide.
Cheers!
Just move your Duration Assertion one level up (the same level as JDBC Request, not as a child of JDBC Request) - in that case it will be applied to While Controller duration, not the single request.
To learn more regarding assertions scope, cost and interoperability see How to Use JMeter Assertions in 3 Easy Steps guide.
Related
I am uploading a file via API for which I do a ‘polling’ and have the following 2 steps / transactions:
HTTP request to upload it for which I get a temporary status response ‘uploading’
While loop with a counter until the response status changes to ‘success’ but not more than 10 times.
${__javaScript("${STATUS}" != "success" && ${counter} < 10,)}
Question-1: How do I measure the response time for step-2 as it varies (sometimes, file will be uploaded in 2 times and sometime in 8 times)?
Question-2: How to make step-2 fail when the status has not changed to success even after all 10 iterations/ attempts?
Please could someone help?
Thanks,
N
Put everything under Transaction Controller, it will measure duration of all the iterations.
You can go for JSR223 Assertion, example code would be something like:
if (vars.get('counter') == '9' && vars.get('STATUS') != 'success') {
AssertionResult.setFailureMessage(true)
AssertionResult.setFailureMessage('Status is ' + vars.get('STATUS') + ' after ' + vars.get('counter') + ' iterations')
}
put it as a child of the 2nd request and if after 10 iterations the status won't be success it will mark the sampler as failed.
I was using JMeter properties for storing the threadLocalCachedConnection object. I made sure to use unique property names as properties.
In thread group 1, I had a JSR223 PostProcessor to scrape session per thread(VU), and then store it in a property called sessionID.
And I added another JSR223 PostProcessor as a child of the last sampler in the Thread Group1.
def connection = sampler.threadLocalCachedConnection
props.put("presenterConnection" + ctx.getThreadNum(), connection.get())
In Thread Group 2, I added a JSR223 PreProcessor as a child of the first sampler.
def presenterConnection = props.get('presenterConnection' + ctx.getThreadNum())
sampler.threadLocalCachedConnection.set(presenterConnection)
String sendCommand = "SEND\n" +
"content-type:application/json;charset=UTF-8\n" +
"destination:/v1/session/${__property(sessionId)}/command\n" +
"id:perftest01-presenter-${__property(sessionId)}\n" +
"\n" +
"{\"type\": \"go-to-slide\", \"data\": {\"index\": 0}}\n" +
'\0' // note: NULL char at end
;
vars.put("wsStompSendCommand", sendCommand);
I tested with 2 threads (VUs). Why both threads were using the last sessionId instead of using one sessionId per thread??
As per JMeter Documentation:
Properties are not the same as variables. Variables are local to a thread; properties are common to all threads
so your line
props.put('sessionId', vars.get('sessionUUID'))
creates a global sessionId propety which is:
common for all Threads no matter in which Thread Group they are
exists until you shut down JMeter/JVM
You need to play the same trick as with the presenterConnection to wit:
props.put('sessionId_'+ ctx.getThreadNum(), vars.get('sessionUUID'))
and then read it where required:
def sessionId = props.get('sessionId_'+ ctx.getThreadNum())
More information: Apache Groovy: What Is Groovy Used For?
I'm programming a contacts export from our database to Google Contacts using the Google People API. I'm programming the requests over URL via Google Apps Script.
The code below - using https://people.googleapis.com/v1/people:batchCreateContacts - works for 13 to about 15 single requests, but then Google returns this error message:
Quota exceeded for quota metric 'Critical read requests (Contact and Profile Reads)' and limit 'Critical read requests (Contact and Profile Reads) per minute per user' of service 'people.googleapis.com' for consumer 'project_number:***'.
For speed I send the request with batches of 10 parallel requests.
I have the following two questions regarding this problem:
Why, for creating contacts, I would hit a quotum regarding read requests?
Given the picture link below, why would sending 2 batches of 10 simultaneous requests (more precise: 13 to 15 single requests) hit that quotum limit anyway?
quotum limit of 90 read requests per user per minute as displayed on console.cloud.google.com
Thank you for any clarification!
Further reading: https://developers.google.com/people/api/rest/v1/people/batchCreateContacts
let payloads = [];
let lengthPayloads;
let limitPayload = 200;
/*Break up contacts in payload limits*/
contacts.forEach(function (contact, index) /*contacts is an array of objects for the API*/
{
if(!(index%limitPayload))
{
lengthPayloads = payloads.push(
{
'readMask': "userDefined",
'sources': ["READ_SOURCE_TYPE_CONTACT"],
'contacts': []
}
);
}
payloads[lengthPayloads-1]['contacts'].push(contact);
}
);
Logger.log("which makes "+payloads.length+" payloads");
let parallelRequests = [];
let lengthParallelRequests;
let limitParallelRequest = 10;
/*Break up payloads in parallel request limits*/
payloads.forEach(function (payload, index)
{
if(!(index%limitParallelRequest))
lengthParallelRequests = parallelRequests.push([]);
parallelRequests[lengthParallelRequests-1].push(
{
'url': "https://people.googleapis.com/v1/people:batchCreateContacts",
'method': "post",
'contentType': "application/json",
'payload': JSON.stringify(payload),
'headers': { 'Authorization': "Bearer " + token }, /*token is a token of a single user*/
'muteHttpExceptions': true
}
);
}
);
Logger.log("which makes "+parallelRequests.length+" parallelrequests");
let responses;
parallelRequests.forEach(function (parallelRequest)
{
responses = UrlFetchApp.fetchAll(parallelRequest); /* error occurs here*/
responses = responses.map(function (response) { return JSON.parse(response.getContentText()); });
responses.forEach(function (response)
{
if(response.error)
{
Logger.log(JSON.stringify(response));
throw response;
}
else Logger.log("ok");
}
);
Output of logs:
which makes 22 payloads
which makes 3 parallelrequests
ok (15 times)
(the error message)
I had raised the same issue in Google's issue tracker.
Seems that the single BatchCreateContacts or BatchUpdateContacts call consumes six (6) "Critical Read Request" quota per request. Still did not get an answer why for creating/updating contacts, we are hitting the limit of critical read requests.
Quota exceeded for quota metric 'Critical read requests (Contact and Profile Reads)' and limit 'Critical read requests (Contact and Profile Reads) per minute per user' of service 'people.googleapis.com' for consumer 'project_number:***'.
There are two types of quotas: project based quotas and user based quotas. Project based quotas are limits placed upon your project itself. User based quotes are more like flood protection they limit the number of requests a single user can make over a period of time.
When you send a batch request with 10 requests in it it counts as ten requests not as a single batch request. If you are trying to run this parallel then you are defiantly going to be overflowing the request per minute per user quota.
Slow down this is not a race.
Why, for creating contacts, I would hit a quota regarding read requests?
I would chock it up to a bad error message.
Given the picture link below, why would sending 13 to 15 requests hit that quota limit anyway? ((there are 3 read requests before this code)) quota limit of 90 read requests per user per minute as displayed on console.cloud.google.com
Well you are sending 13 * 10 = 130 per minute that would exceed the request per minute. There is also no way of knowing how fast your system is running it could be going faster as it will depend upon what else the server is doing at the time it gets your requests what minute they are actually being recorded in.
My advice is to just respect the quota limits and not try to understand why there are to many variables on Googles servers to be able to tack down what exactly a minute is. You could send 100 requests in 10 seconds and then try to send another 100 in 55 seconds and you will get the error you could also get the error after 65 seconds depend upon when they hit the server and when the server finished processing your initial 100 requests.
Again slow down.
I am using JMeter Webdriver sampler for the application UI response time measurement. I am facing issue with the wait function. For example the login page loads between 10 to 120 secs. So I have the following code for the login page in Webdriver sampler for the page load check.
var ui=JavaImporter(org.openqa.selenium.support.ui)
var wait=new support_ui.WebDriverWait(WDS.browser,120)
wait.until(ui.ExpectedConditions.visibilityOfElementLocated(pkg.By.className('logout-btn-hover')))
The issue is even after the page load completely, JMeter is still waiting to perform the next action. This waiting time will reduce if I reduce the 120 secs.But sometimes the application will take 120 secs to load also so I need to keep 120 secs.
I am writing the time to a log file once the sampler completes its action. Because of the wait time issue I am not able to calculate time properly.
There are at least 2 errors in your script, it should look something like:
var ui=JavaImporter(org.openqa.selenium.support.ui)
var wait=new ui.WebDriverWait(WDS.browser,120)
wait.until(ui.ExpectedConditions.visibilityOfElementLocated(org.openqa.selenium.By.className('logout-btn-hover')))
Check out jmeter.log file for any suspicious entries, in particular for something like:
ERROR c.g.j.p.w.s.WebDriverSampler: Expected condition failed: waiting for visibility of element located by By.className: logout-btn-hover (tried for 120 second(s) with 500 milliseconds interval)
Double check your CSS selector
Consider refactoring your code to look for the logout button(?) in a loop with verbose logging for each step. Sample code:
var pkg = JavaImporter(org.openqa.selenium)
WDS.sampleResult.sampleStart()
WDS.browser.get('http://example.com')
var start = new Date().getTime()
var attempt = 1
while (new Date().getTime() - start < 5000) {
try {
var logout = WDS.browser.findElement(pkg.By.className('logout-btn-hover'))
WDS.log.info('Element found')
break
}
catch (err) {
WDS.log.info('Attempt # ' + attempt + ', Element not found')
java.lang.Thread.sleep(1000)
attempt++
}
}
WDS.sampleResult.sampleEnd()
Example output when the element is not found:
Example output when the element is found:
Check out The WebDriver Sampler: Your Top 10 Questions Answered article for more information on using WebDriver sampler in JMeter scripts.
How can I get an overall PASS/FAIL result for a JMeter thread group without using a post processor on every sampler?
I've tried using a beanshell listener, but it doesn't work for instances where there are multiple samplers inside a transaction controller with "Generate Parent Sample" enabled. In that case, the listener only gets called once per transaction controller and I'm only able to access the result of the last sampler inside the transaction controller.
Edit:
I would like to be able to save a pass/fail value as Jmeter variable or property for the thread group. If one or more components of the thread group fail or return an error, then that would be an overall fail. This variable will then be used for reporting purposes.
My current beanshell listener code:
SampleResult sr = ctx.getPreviousResult();
log.info(Boolean.toString(sr.isSuccessful()));
if (!sr.isSuccessful()){
props.put("testPlanResult", "FAIL");
testPlanResultComment = props.get("testPlanResultComment");
if(testPlanResultComment == ""){
testPlanResultComment = sr.getSampleLabel();
}else {
testPlanResultComment = testPlanResultComment + ", " + sr.getSampleLabel();
}
props.put("testPlanResultComment", testPlanResultComment);
log.info(testPlanResultComment);
}
If you call prev.getParent() you will be able to fetch individual sub-samples via getSubResults() function, something like:
prev.getParent().getSubResults().each {result ->
log.info('Sampler: ' + result.getSampleLabel() + ' Elapsed time: ' + result.getTime() )
}
log.info('Total: ' + prev.getParent().getTime())
Demo:
More information: Apache Groovy - Why and How You Should Use It