Mutex in WRK lua script - concurrency

I have the following script in Lua (custom.lua):
local data = loadFile()
local count = -1
request = function()
url_path = "/resource"
-- lock count
count += 1
local arrayIndex = count
-- unlock count
local headers = { ["Content-Type"] = "application/json;charset=UTF-8" }
return wrk.format("POST", url_path, headers, json.stringify(data[arrayIndex]))
end
This script reads a file and parses this into an array, then sets up the requests for my test. My problem is that I need some sort of mutex to make sure each request will use a different array index.
The idea would be to block the count, update its value, copy to a local variable and use it to define the request body. However, I could not find it in Lua nor in wrk.
wrk -t250 -c250 -d5m -s ./custom.lua --timeout 5s -H 'Host: localhost' http://localhost:8080

Related

Postman accessing the stored results in the database leveldb

So I have a set of results in Postman from a runner on a collection using some data file for iterations - I have the stored data from the runner in the Postman app on Linux, but I want to know how I can get hold of the data. There seems to be a database hidden away in the ~/.config directory (/Desktop/file__0.indexeddb.leveldb) - that looks like it has the data from the results there.
Is there anyway that I can get hold of the raw data - I want to be able to save the results from the database and not faff around with running newman or hacking a server to post the results and then save, I already have 20000 results in a collection. I want to be able to get the responseData from each post and save it to a file - I will not execute the posts again, I need to just work out a way
I've tried KeyLord, FastNoSQL (this crashes), levelDBViewer(Jar), but not having any luck here.
Any suggestions?
inline 25024 of runner.js a simple yet hack for small numbers of results I can do the following
RunnerResultsRequestListItem = __WEBPACK_IMPORTED_MODULE_2_pure_render_decorator___default()(_class = class RunnerResultsRequestListItem extends __WEBPACK_IMPORTED_MODULE_0_react__["Component"] {
constructor(props) {
super(props);
var text = props.request.response.body,
blob = new Blob([text], { type: 'text/plain' }),
anchor = document.createElement('a');
anchor.download = props.request.ref + ".txt";
anchor.href = (window.webkitURL || window.URL).createObjectURL(blob);
anchor.dataset.downloadurl = ['text/plain', anchor.download, anchor.href].join(':');
anchor.click();
it allows me to save but obviously I have to click save for now, anyone know how to automate the saving part - please add something here!

How to read dynamic request parameter value in postman?

I pass some a random integer in the value of a parameter in the request body -
"trans_id":"7q498992029699{{$randomInt}}"
What is the best way to get the final value of trans_id param in the Tests tab?
As per my observation, using {{$randomInt}} again in the request body gives a different random integer.
A way around is to store it to environment variable while sending the request, using Pre-request-script. And later get same environment variable in your test.
Body:
{
"trans_id": "{{transId}}"
}
Pre-request-script:
var randomNumber = '7q498992029699' + _.random(0, 1000);
pm.environment.set("transId", randomNumner);
Test:
var tarnsId = pm.environment.get("transId");
Note: {{$randomInt}} and _.random(0, 1000) both are doing the same thing, it provides random number from 0-1000.
You could create your random int as a variable in the Pre-Request script of your request like this:
pm.globals.set('myRandomInt', Math.floor(Math.random() * 1000))
Or
// Using the built-in Lodash module
pm.globals.set("myRandomInt", _.random(0, 1000))
(I am using a global variable in this example but you can of course use an environment variable if you want to.)
Now you can re-use the variable {{myRandomInt}} in your request body and in your Tests tab.

How to build a Postman url query with Pre-request Scripts

I'm trying to use a pre-request script to build out a request object based on data pulled from a CSV file. The problem is that the request seems to be set in stone prior to the pre-request script being run. That would seem to make this a mid-request script almost rather than a pre-request.
My code is as follows:
if(ipList === undefined) ipList = "1.2.3.4,2.3.4.5,123.234.345.465";
let ips = ipList.split(',');
let queryArray = [];
for( i=0; i<ips.length; i++){
queryArray.push({ "key": "ip", "value": ips[i] });
}
console.log(queryArray);
pm.request.url.query = queryArray;
console.log(pm.request);
When I hardcode a url query variable in the request to equal 4.3.2.1, the pm.response.url object like this:
pm.request.url.query[0] = {key:"ip", value:"4.3.2.1"}
Note that the url.query[0] part of the object matches the parameter in the actual get request.
When I change the value of pm.request.url.query to equal the new query array, however as you can see here, the query array is set correctly, but the parameters are not appended to the request URL.
So unless I'm doing something wrong, it appears that the request is immutable even to the pre-request scripts.
So my question is this:
Is there a way to modify the url params of a request prior to making the request?
BTW: I know that is might seem odd to have multiple params with the same key in a query, but that's the way this API works and hard coding multiple ip addresses in the query works just fine.
You could just assign a new value to pm.request.url.
Here I had some query params already in the URL, which I had to edit:
const urlSplit = request.url.split('?');
const paramsString = urlSplit[1]; // the second part actually represents the query string we need to modify
const eachParamArray = paramsString.split('&');
let params = {};
eachParamArray.forEach((param) => {
const key = param.split('=')[0];
const value = param.split('=')[1];
Object.assign(params, {[key]: value});
});
params.bla = params.bla + 'foobar';
newQueryString = Object.keys(params).map(key => key + '=' + params[key]).join('&');
pm.request.url = urlSplit[0] + '?' + newQueryString;
In the end, I just constructed a new URL, using the first part of the previous one & the query string with the edited bla parameter.
This seemed to work for me--it didn't change what the UI shows the query string is, but it changed what the actual request was (looking at the console log)
pm.request.url.addQueryParams(["a=1", "b=2"])
pm.request.url.query.remove("b")
I have some parameters called "script_loginAs" etc... named such that people on my team know the parameter is evaluated and not sent.

Read request body without deleting it

So I have a MyHandler which has to know what's inside the request body:
class MyHandler
include HTTP::Handler
def call(context)
p "MyHandler got body: " + context.request.body.not_nil!.gets_to_end
call_next(context)
end
end
server = HTTP::Server.new(42, [MyHandler.new]) do |context|
p "Server got body: " + context.request.body.not_nil!.gets_to_end
end
As expected, after MyHandler has read, server receives a empty body. How can copy the body without modifying original context?
Crystal supports streaming request bodies, which means that once you stream in the request, the IO is EOF and the second handler can't read any data.
A simple way to solve this would be to retrieve the entire content using body_string = context.request.body.try(&.gets_to_end), then set the request body to the returned string using context.request.body = body_string. This buffers the entire body to memory then sets the body to the buffer stored in memory. The downside to this approach is that an attacker can send an infinitely sized request body and eat all the memory on your server, causing a DOS attack. Another disadvantage is that if you're working with binary data, you would then need to convert the string into a slice using #to_slice to work with it.
One way to solve the DOS attack problem - if you have a maximum body size in mind - is to fail the request if the body is too large:
if body = context.request.body
body_io = IO::Memory.new
bytes_read = IO.copy(body, body_io, limit: 1_048_576) # 1GiB limit
body_io.rewind
if bytes_read == 1_048_576
# Fail request
end
# use body_io
body_io.rewind # Reset body_io to start
context.request.body = body_io
end
If you need to accept an infinitely sized body, and not buffer it to memory, you should create a custom IO implementation which wraps the existing body IO and runs the required transform inside IO#read(Bytes). This method is quite complex, and the previous method covers almost all situations, so I won't provide a code sample for this option.

jmeter - counting cookie values

I'm playing around with jmeter to validate a bug fix.
Server logic sets the cookie "mygroup" it can be either "groupa" or "groupb". I want to be able fire a series of requests and be able to see there is a proper balanced distribution between the values of this cookie. Ie make 100 requests and 50 times the cookie will be set to "groupa" and "groupb".
I'm a bit stuck on this. I currently have the following. I can see the cookies being set in the results tree but I'd like to be able to display the a table with the version and the number of requests of each.
Thread Group
HTTP Cookie Manager
HTTP Request
View Results Tree
Within the results tree I can see Set-Cookie: mygroup="groupa" and also sometimes mygroup="groupb" how do I tabulize this ??
You can have cookies values exported as JMeter variables by setting:
CookieManager.save.cookies=true
in user.properties.
Add a Cookie Manager to your Test Plan.
In this case you will have the var COOKIE_mygroup set by JMeter.
You can then count it like this using a JSR223 Sampler + Groovy (add groovy-all-version.jar in jmeter/lib folder:
String value = vars.get("COOKIE_mygroup");
Integer counterB = vars.getObject("counterB");
Integer counterA = vars.getObject("counterA");
if(counterA == null) {
counterA = new Integer(0);
vars.putObject("counterA", counterA);
}
if(counterB == null) {
counterB = new Integer(0);
vars.putObject("counterB", counterB);
}
if(value.equals("groupa")) {
counterA = counterA+1;
vars.putObject("counterA", counterA);
} else {
counterB = counterB+1;
vars.putObject("counterB", counterB);
}
Asyou have only one thread, at end of loop you can then compare the 2 values or just display the value:
add a debug sampler
add a view tree result
Run test plan, in view result tree click on debug sampler , select response tab and you should have your values