Gatling2 Failing to use user session properly - gatling

I hope someone can point me into the right direction!
I try to run one scenario which has several steps that have to be executed in order and each with the same user session to work properly. The below code works fine with one user but fails if I use 2 or more users...
What am I doing wrong?
val headers = Map(
Constants.TENANT_HEADER -> tenant
)
val httpConf = http
.baseURL(baseUrl)
.headers(headers)
val scen = scenario("Default Order Process Perf Test")
.exec(OAuth.getOAuthToken(clientId))
.exec(session => OAuth.createAuthHHeader(session, clientId))
.exec(RegisterCustomer.registerCustomer(customerMail, customerPassword,
tenant))
.exec(SSO.doLogin(clientId, customerMail, customerPassword, tenant))
.exec(session => OAuth.upDateAuthToken(session, clientId))
.exec(session =>
UpdateCustomerBillingAddr.prepareBillingAddrRequestBody(session))
.exec(UpdateCustomerBillingAddr.updateCustomerBillingAddr(tenant))
.exec(RegisterSepa.startRegisterProcess(tenant))
.exec(session => RegisterSepa.prepareRegisterRequestBody(session))
.exec(RegisterSepa.doRegisterSepa(tenant))
setUp(
scen
.inject(atOnceUsers(2))
.protocols(httpConf))
object OAuth {
private val OBJECT_MAPPER = new ObjectMapper()
def getOAuthToken(clientId: String) = {
val authCode = PropertyUtil.getAuthCode
val encryptedAuthCode = new
Crypto().rsaServerKeyEncrypt(authCode)
http("oauthTokenRequest")
.post("/oauth/token")
.formParam("refresh_token", "")
.formParam("code", encryptedAuthCode)
.formParam("grant_type", "authorization_code")
.formParam("client_id", clientId)
.check(jsonPath("$").saveAs("oauthToken"))
.check(status.is(200))
}
def createAuthHHeader(session: Session, clientId: String) = {
val tokenString = session.get("oauthToken").as[String]
val tokenDto = OBJECT_MAPPER.readValue(tokenString,
classOf[TokenDto])
val session2 = session.set(Constants.TOKEN_DTO_KEY, tokenDto)
val authHeader = AuthCommons.createAuthHeader(tokenDto,
clientId, new util.HashMap[String, String]())
session2.set(Constants.AUTH_HEADER_KEY, authHeader)
}
def upDateAuthToken(session: Session, clientId: String) = {
val ssoToken = session.get(Constants.SSO_TOKEN_KEY).as[String]
val oAuthDto = session.get(Constants.TOKEN_DTO_KEY).as[TokenDto]
val params = new util.HashMap[String, String]
params.put("sso_token", ssoToken)
val updatedAuthHeader = AuthCommons.createAuthHeader(oAuthDto,
clientId, params)
session.set(Constants.AUTH_HEADER_KEY, updatedAuthHeader)
}
}
def createAuthHHeader(session: Session, clientId: String) = {
val tokenString = session.get("oauthToken").as[String]
val tokenDto = OBJECT_MAPPER.readValue(tokenString,
classOf[TokenDto])
val session2 = session.set(Constants.TOKEN_DTO_KEY, tokenDto)
val authHeader = AuthCommons.createAuthHeader(tokenDto,
clientId, new util.HashMap[String, String]())
session2.set(Constants.AUTH_HEADER_KEY, authHeader)
}
So I did add the two methods that dont work along as expected. In the first part I try to fetch a token and store in the session via check(jsonPath("$").saveAs("oauthToken")) and in the second call I try to read that token with val tokenString = session.get("oauthToken").as[String] which fails with the exception saying that there is no entry for that key in the session...

I've copied it and removed/mocked any missing code references, switched to one of my apps auth url and it seems to work - at least 2 firsts steps.
One thing that seems weird is jsonPath("$").saveAs("oauthToken") which saves whole json (not single field) as attribute, is it really what you want to do? And are you sure that getOAuthToken is working properly?
You said that it works for 1 user but fails for 2. Aren't there any more errors? For debug I suggest changing logging level to TRACE or add exec(session => {println(session); session}) before second step to verify if token is properly saved to session. I think that something is wrong with authorization request (or building that request) and somehow it fails or throws some exception. I would comment out all steps except 1st and focus on checking if that first request is properly executed and if it adds proper attribute to session.

I think your brackets are not set correctly. Change them to this:
setUp(
scn.inject(atOnceUsers(2))
).protocols(httpConf)

Related

Access JSON Array without array name

I have a JSON object:
{
"login_name":"hello#gmail.com",
"login_pass":"abc123",
"created_on":"2021-01-17 19:20:07",
"user_id":"1",
"active":"1"
}
I don't know how to access it because it doesn't have a name.
This is using Volley:
val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
{ response ->
val obj = JSONObject(response.toString()) // this works and outputs the JSON object
val test: JSONObject = obj.getJSONObject("login_name") // this doesn't work
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
},
{ error ->
Toast.makeText(this#Login, "Error!", Toast.LENGTH_LONG).show()
}
)
I also tried converting the Json object to an array but that didn't work either...
Looked at:
Get JSONArray without array name, How can i write Android Json parsing without array name
EDIT:
val obj = JSONObject(response)
That didn't work for me because:
None of the following functions can be called with the arguments supplied.
(String!) defined in org.json.JSONObject
((MutableMap<Any?, Any?>..Map<*, *>?)) defined in org.json.JSONObject
(JSONTokener!) defined in org.json.JSONObject
But after 2 days of trying, this worked... Didn't think I could just do that
val test = response.getString("login_name")
response is indeed a jsonObject, you could use it without know its name:
String login_name= response.getString("login_name");
You are all most doing it right. Ass i see you convert the object to a string, and thats why you cant access the data afterwards.
val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
{ response ->
val obj = JSONObject(response) // this works and outputs the JSON object
val test: JSONObject = obj.getJSONObject("login_name") // this doesn't work
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
},
{ error ->
Toast.makeText(this#Login, "Error!", Toast.LENGTH_LONG).show()
}
)
Try this, without the toString() function on response.

Helping me understand session api Gatling

I am new to gatling
I am trying to loop on json response, find the country code that I am looking for and take the id coressponding the that coutry code.
Sample algorithm:
list.foreach( value => { if (value.coutrycode == "PL") then store value.id })
on Gatling:
def getOffer() = {
exec(
http("GET /offer")
.get("/offer")
.check(status.is(Constant.httpOk))
.check((bodyString.exists),
jsonPath("$[*]").ofType[Map[String,Any]].findAll.saveAs("offerList")))
.foreach("${offerList}", "item"){
exec(session => {
val itemMap = session("item").as[Map[String,Any]]
val countryCodeId = itemMap("countryCode")
println("****" + countryCodeId)
// => print all the country code on the list
if (countryCodeId =="PL"){ // if statement condition
println("*************"+ itemMap("offerd")); // print the id eg : "23"
session.set("offerId", itemMap("offerId")); // set the id on the session
}
println("$$$$$$$$$$$$$$" + session("offerId")) // verify that th session contains the offerId but is not
session
})
}
}
When I try to print the session("offerId"), it's print "item" and not the offerId.
I looked on the documentation but I didn't understand the behaviour. Could you please explain it to me ?
It's all in the documentation.
Session instances are immutable!
Why is that so? Because Sessions are messages that are dealt with in a
multi-threaded concurrent way, so immutability is the best way to deal
with state without relying on synchronization and blocking.
A very common pitfall is to forget that set and setAll actually return
new instances.
val session: Session = ???
// wrong usage
session.set("foo", "FOO") // wrong: the result of this set call is just discarded
session.set("bar", "BAR")
// proper usage
session.set("foo", "FOO").set("bar", "BAR")
So what you want is:
val newSession =
if (countryCodeId =="PL"){ // if statement condition
println("*************"+ itemMap("offerd")); // print the id eg : "23"
session.set("offerId", itemMap("offerId")); // set the id on the session
} else {
session
}
// verify that the session contains the offerId
println("$$$$$$$$$$$$$$" + newSession("offerId").as[String])
newSession

Gatling how to store and load a value for a later request

I'd like to build a load test where the second request is fed from first response. The data extraction is done in a method because it is not only one line of code. My problem is storing the value (id) and load it later. How should the value be stored and loaded? I tried some different approaches, and I come up with this code. The documentation has not helped me.
object First {
val first = {
exec(http("first request")
.post("/graphql")
.headers(headers_0)
.body(RawFileBody("computerdatabase/recordedsimulation/first.json"))
.check(bodyString.saveAs("bodyResponse"))
)
.exec {
session =>
val response = session("bodyResponse").as[String]
session.set("Id", getRandomValueForKey("id", response))
session}
.pause(1)
}
}
object Second {
val second = {
exec(http("Second ${Id}")
.post("/graphql")
.headers(headers_0)
.body(RawFileBody("computerdatabase/recordedsimulation/second.json"))
)
.pause(1)
}
}
val user = scenario("User")
.exec(
First.first,
Second.second
)
setUp(user.inject(
atOnceUsers(1),
)).protocols(httpProtocol)
Your issue is that you're not using the Session properly.
From the documentation:
Warning
Session instances are immutable!
Why is that so? Because Sessions are messages that are dealt with in a multi-threaded concurrent way, so immutability is the best way to deal with state without relying on synchronization and blocking.
A very common pitfall is to forget that set and setAll actually return new instances.
This is exactly what you're doing:
exec { session =>
val response = session("bodyResponse").as[String]
session.set("Id", getRandomValueForKey("id", response))
session
}
It should be:
exec { session =>
val response = session("bodyResponse").as[String]
session.set("Id", getRandomValueForKey("id", response))
}

Inject user index into body file in Gatling scenario

I want to use ELFileBody and put a variable in a txt file.
This file contains a soap request.
The request (scenario) is executed only one time but as many times as users.
I want to put into file variable, the user index (position in execution).
Something like this :
.set("myVar", userIndex) //myVar is the variable declared in the body file ( ${myVar} )
Here is my code for now :
val users = 1500
val baseUrl = "http://127.0.0.1:7001"
val httpProtocol = http
.baseURL(baseUrl)
.inferHtmlResources()
.acceptEncodingHeader("gzip,deflate")
.contentTypeHeader("text/xml;charset=UTF-8")
.userAgentHeader("Apache-HttpClient/4.1.1 (java 1.5)")
val headers_0 = Map("SOAPAction" -> """""""")
val uri1 = "http://127.0.0.1:7001/myProject-ws/myProjectWebService"
val scn = scenario("Scenario1Name")
.exec(http("scn.Scenario1Name")
.post("/myProject-ws/myProjectWebService")
.headers(headers_0)
.body(RawFileBody("File_0000_request.txt")))
setUp(scn.inject(atOnceUsers(users))).protocols(httpProtocol)
How can I inject the user index into myVar variable in the request body ?
finally, i used a function that return a dynamic reference (id) and I call it from my scenario.
def getDynamicId(): String = {
val formatter = new SimpleDateFormat("yyyyMMddHHmmss.SSS")
val result = "PM".concat(formatter.format(Calendar.getInstance().getTime()))
result
}
//[...]
scenario("ScenarioName")
.exec(session => session.set("myVar", getDynamicId))
// [...]
.body(ElFileBody("BodyFile_0000_request.txt")))
And in the body file, I have the variable ${myVar}
You need read file like e.g.
val customSeparatorFeeder = separatedValues(pathToFile, separator).queue circular
after scenario("Scenario1Name") you need to add .feed(customSeparatorFeeder)
you can read more about it here https://gatling.io/docs/2.3/session/feeder/

Using OAuth2 with service account on gdata in python

I want to use data.photos.service.PhotosService to push and pull photos from Picasa. I got a service key file XXXXXXXX-privatekey.p12 from Google console and am now trying to authenticate using said key with google.
The documentation for OAUTH2 using appengine has led me to believe that using the following would be of use:
f = file(settings.SITE_ROOT + '/aurora/' + settings.PRIVATE_KEY, 'rb')
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(settings.SERVICE_ACCOUNT_NAME, key, scope = 'http://picasaweb.google.com/data https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile')
http = httplib2.Http()
http = credentials.authorize(http)
service = build("oauth2", "v2", http=http)
user_info = None
try:
user_info = service.userinfo().get().execute()
# neither of these two methods work
#gd_client.SetOAuthInputParameters(signature_method = gdata.auth.OAuthSignatureMethod.RSA_SHA1, consumer_key = "asdfasdfasdf.apps.googleusercontent.com", rsa_key = key, two_legged_oauth = True, requestor_id = user_info.get('email'))
#gd_client.auth_token = gdata.gauth.TwoLeggedOAuthRsaToken(consumer_key = user_info.get('email'), rsa_private_key = key, requestor_id = user_info.get('email'))
except errors.HttpError, e:
logging.error('An error occurred: %s', e)
user_inf0 = {u'verified_email': True, u'id': u'1234', u'name': u'asdfasdfasdf#developer.gserviceaccount.com', u'email': u'asdfasdfasdf#developer.gserviceaccount.com'}
The issue is that either method 1 using SetOAuthInputParameters returns a invalid token, or method 2 returns a 403 restricted.
I am at my wits' end reading through mountains of code that all do regular 3 legged oauth when I really and truly do not want to do it that way. Any ideas/articles I haven't seen yet?
Use gdata.gauth.OAuth2TokenFromCredentials.
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
gd_client = auth2token.authorize(gd_client)
OAuth2TokenFromCredentials is designed to help you use apiclient and gdata at the same time. Under the covers, it uses the credentials for making sure it has the auth information it needs to perform gdata calls.
Note, if you still get 403, it may be something else entirely. I was using a service account to access a user's data and was getting 403 because I hadn't spec'd the user properly in the SignedJwtAssertionCredentials call.
UPDATE: Here's the basic pattern I used:
from oauth2client.client import SignedJwtAssertionCredentials
credentials = SignedJwtAssertionCredentials(
    "XXXXXXXXXXX#developer.gserviceaccount.com",
    open("keyfile").read(),
    scope=(
    "https://www.googleapis.com/auth/drive",
    "https://spreadsheets.google.com/feeds",
    "https://docs.google.com/feeds"
), # For example.
    sub="user#gmail.com"
)
http = httplib2.Http()
http = credentials.authorize(http) # Not needed? See comment below.
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
gd_client = gdata.photos.service.PhotosService() # For example.
gd_client = auth2token.authorize(gd_client)
If you are using MFA on your google account, you need to use the consent screen authentication method. With Picassa API, it does not work as is, as the request API is slightly different.
import gdata.gauth
import os
import pickle
import gdata.photos.service
clientid='xxx' # https://console.developers.google.com/apis/credentials
clientsecret='xxx'
Scope='https://picasaweb.google.com/data/'
User_agent='myself'
def GetAuthToken():
if os.path.exists(".token"):
with open(".token") as f:
token = pickle.load(f)
else:
token = gdata.gauth.OAuth2Token(client_id=clientid,client_secret=clientsecret,scope=Scope,user_agent=User_agent)
print token.generate_authorize_url(redirect_uri='urn:ietf:wg:oauth:2.0:oob')
code = raw_input('What is the verification code? ').strip()
token.get_access_token(code)
with open(".token", 'w') as f:
pickle.dump(token, f)
return token
token = GetAuthToken()
gd_client = gdata.photos.service.PhotosService()
old_request = gd_client.request
def request(operation, url, data=None, headers=None):
headers = headers or {}
headers['Authorization'] = 'Bearer ' + token.access_token
return old_request(operation, url, data=data, headers=headers)
gd_client.request = request
photos = gd_client.GetUserFeed(kind='photo', limit='10')
for photo in photos.entry:
print 'Recently added photo title:', photo.title.text

Resources