How to take value of a variable in Gatling script - gatling

I have extracted token value from the login api call.but i am not able to use that variable value into next api call.My code is given below
val scn = scenario("test login")
.exec(http("login call")
.post("https://api.k6.io/v3/account/login")
.headers(headers_1)
.body(RawFileBody("data/login.json"))
.check(status.is(200))
.check(jsonPath("$.token.key").saveAs("tokenId")))
.pause(21)
.exec(http("edit profile call")
.post("https://api.k6.io/v3/users/3187878")
.headers(headers_1)
.header("Authorization", "Token ${tokenId}")
.body(RawFileBody("data/editprofile.json"))
.check(status.is(200)))
but the call get failed. I am not getting the value of that variable in the second call.
{"key":"4c713e3f5d362f0002f6eef737401e249c154bed"}
i need to use the value of 'key' in the header for next api call as in the format of
.header("Authorization", "Token 4c713e3f5d362f0002f6eef737401e249c154bed")
but it is not getting in this format.where i am going wrong?Can anyone help me.Thanks in advance

Your way of capturing data with a check and re-injecting it with Gatling Expression Language is correct.
Possible reasons your scenario doesn't work:
the "login call" request fails and is not able to capture the data
you use RawFileBody but maybe some data in there needs to be dynamic, just like your Authorization header
If you want to check what's been captured, you can add an extra action before your pause:
.exec { session =>
println(session("tokenId").as[String])
session
}

Related

Discord JS v12: How do you get a message's content by it's ID?

I'm relatively new to discord.js, and I've started building a bot project that allows a user to create a message via command, have that message stored in a hidden channel on my private server, and then said message can be extracted through the message ID.
I have the write working and it returns the message ID of the message sent in the hidden channel, but I'm completely stumped on the get command. I've tried searching around online but every method I tried would return errors like "Cannot read property 'fetch' of undefined" or "'channel' is not defined". Here are some examples of what I tried, any help would be appreciated. Note that my args is already accurate, and "args[0]" is the first argument after the command. "COMMAND_CHANNEL" is the channel where the command is being executed while "MESSAGE_DATABASE" is the channel where the targeted message is stored.
let msgValue = channel.messages.cache.get(args[0])
client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content)
let msgValue = msg.channel.message.fetch(args[0])
.then(message => client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content))
.catch(console.error);
I even tried using node-fetch to call the discord API itself
const api = require("node-fetch")
let msgValue = api(`https://discordapp.com/api/v8/channels/${MESSAGE_DATABASE}/messages/${args[0]}`)
.then(message => client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content))
.catch(console.error);
Am I missing something or am I making some sort of mistake?
Edit: Thanks for the help! I finished my bot, it's just a little experimental bot that allows you to create secret messages that can only be viewed through their ID upon executing the command :get_secret_message <message_id>. I posted it on top.gg but it hasn't been approved yet, so in the meantime if anyone wants to mess around with it here is the link: https://discord.com/api/oauth2/authorize?client_id=800368784484466698&permissions=76800&scope=bot
List of commands:
:write_secret_message - Write a secret message, upon execution the bot will DM you the message ID.
:get_secret_message <message_id> - Get a secret message by its ID, upon execution the bot will DM you the message content.
:invite - Get the bot invite link.
NOTE: Your DMs must be turned on or the bot won't be able to DM any of the info.
My test message ID: 800372849155637290
fetch returns the result as promise so you need to use the then to access that value instead of assigning it to a variable (msgValue). Also you made a typo (channel.message -> channel.messages).
I would recommend using something like this:
msg.channel.messages
.fetch(args[0])
.then(message => {
client.channels
.fetch(COMMAND_CHANNEL)
.then(channel => channel.send(message.content))
.catch(console.error)
})
.catch(console.error)
I think you were quite close with the second attempt you posted, but you made one typo and the way you store the fetched message is off.
The typo is you wrote msg.channel.message.fetch(args[0]) but it should be msg.channel.messages.fetch(args[0]) (the typo being the missing s after message). See the messages property of a TextChannel.
Secondly, but this is only a guess really as I can't be sure since you didn't provide much of your code, when you try to fetch the message, you are doing so from the wrong channel. You are trying to fetch the message with a given ID from in the channel the command was executed from (the msg.channel). Unless this command was executed from the "MESSAGE_DATABASE" channel, you would need to fetch the message by ID from the "MESSAGE_DATABASE" channel instead of the msg.channel.
Thirdly, if you fetch a message, the response from the Promise can be used in the .then method. You tried to assign the response to a variable msgValue with let msgValue = msg.channel.message.fetch(args[0]) but that won't do what you'll expect it to do. This will actual assign the entire Promise to the variable. What I think you want to do is just use the respone from the Promise directly in the .then method.
So taking all that, please look at the snippet of code below, with inspiration taken from the MessageManager .fetch examples. Give it a try and see if it works.
// We no longer need to store the value of the fetch in a variable since that won't work as you expect it would.
// Also we're now fetching the message from the MESSAGE_DATABASE channel.
client.channels.cache.get(MESSAGE_DATABASE).fetch(args[0])
// The fetched message will be given as a parameter to the .then method.
.then(fetchedMessage => client.channels.cache.get(COMMAND_CHANNEL).send(fetchedMessage.content))
.catch(console.error);

Gatling overrides `Cookie` header with the `Set-Cookie` header of previous response

I have an http request in Gatling that gets executed 10 times:
val scnProxy = scenario("Access proxy")
.exec(session => session.set("connect.sid", sessionId))
.repeat(10) {
exec(
http("Access endpoint")
.get("/my-api")
.header(
"Cookie",
session => "connect.sid=" + session("connect.sid").as[String]
)
.check(status is 200)
)
}
For some reason, I get the intended response only on the first iteration. On every other iteration, I keep getting 401. So, I changed log level to TRACE to see what the problem is and found a weird behavior. For the first iteration, I get the header Cookie: connect.sid=... but for some reason, on second and other iterations, the cookie parameter gets overridden by the set-cookie of the previous request. Since Cookie header value is a string, it does not merge these cookies.
Is there a way that I can add a cookie instead of my cookie getting overriden?
Use the proper Gatling components for manipulating cookies.

Gatling not storing value in session

I am using sessions in gatling to store values, as shown below
exec(session => {
val id = Instant.now.toEpochMilli.toString + scala.util.Random.nextInt(1000).toString
session.set("STARTED_PROCESS_ID",id)
//Store the id somewhere for processing later
session
})
.exec(
http("scenario")
.post(url)
.header("Content-Type", "application/json")
.header("id", session => session("STARTED_PROCESS_ID").as[String])
.body(StringBody(body)
.check(status.is(200))
According to the documentation, the value should be stored in session & the header "id" should be populated as expected. But when running the simuation I get the following error
java.util.NoSuchElementException: No attribute named 'STARTED_PROCESS_ID' is defined
at io.gatling.core.session.SessionAttribute.as(Session.scala:46)
at common.HttpUtil$.$anonfun$sendPostRequestForWasStartDefLoad$1(HttpUtil.scala:557)
at io.gatling.core.action.SessionHook.execute(SessionHook.scala:32)
at io.gatling.core.action.Action.$bang(Action.scala:38)
at io.gatling.core.action.Action.$bang$(Action.scala:38)
Can someone please help explain why is this happening ?
You're not using the Session API correctly. Please properly read the documentation.
Session is immutable and set returns a new instance.
exec { session =>
val id = Instant.now.toEpochMilli.toString + scala.util.Random.nextInt(1000).toString
session.set("STARTED_PROCESS_ID",id)
}
gatling sessions are immutable, so where you return session as the final line of your session function, you're actually returning the initial, unedited session.
session.set returns a new, updated session, so you can just leave that as the last line of the session function and it should work.

Cannot get Username / given_name when using angular-oauth2-oidc and Identity Server 4

I am following the Implicit Workflow example from the angular-oauth2-oidc documentation.
Everything works well in my Angular app, and I can login (during which I am redirected to Identity Server), get my token and use this token to access my Web Api.
However, I have noticed that the "given_name" claim is null, and therefore, the username is not displayed on the login page. Specifically, the following method from the sample code appears to return null:
public get name() {
let claims = this.oauthService.getIdentityClaims();
if (!claims) return null;
return claims.given_name;
}
I thought perhaps this was a problem with permissions, but my scope is set to:
scope: 'openid profile email api1',
Any idea what I need to change to get this "given_name" claim?
For those who encountered the same issue. You can fix it by adding this line AlwaysIncludeuserClaimsInIdToken=true in the client settings on identity provider side.
OauthService.getIdentityClaims() is a Promise and holds UserInfo you can extract the name field with braces, so your function should be:
public get name() {
let claims = this.oauthService.getIdentityClaims();
if (!claims) return null;
return claims['name'];
}
The answer marked as "Best answer" is not correct. Get the user claims in the 'idtoken' will cause that the 'idtoken' be very big and then you may exceed the size limit.
The correct implementation is to use the 'UserInfo' Endpoint and then use the method 'loadUserProfile':
Example:
getUserClaims() {
const user = this.oauthService.loadUserProfile();
console.log(user, user);
}
I had the same issue, in my case with an error displayed on the browser console, saying that Request was blocked by Security Policy.
even having the AllowAnyOrigin() method called in startup, I lacked to get the header allowed. So when in my angular aap i call the loadUserProfile method via the
token_received event, it sends some headers that were not allowed.
Finaly this fix my issue:
app.UseCors(options => options.AllowAnyOrigin().AllowAnyHeader());
Don't forget calling that before usemvc

Get auth token in Gatling

I'm trying to use Gatling to test my API but I've got a problem. I'm testing for now the login/logout. At the login, the user got a token, that is used for logout.
When I use the recorder, it keep a fix token, and of course, it doesn't work when I run the test. But I don't find in the doc or google how I can get dynamically the token.
Does anyone know ?
Thanks !
EDIT:
after recording here what I got
val headers_13 = Map(
"Accept" -> """*/*""",
"Origin" -> """http://site.com""",
"token" -> """token"""
)
val scn = scenario("Scenario Name")
.exec(http("request_1")
.post("http://site.com/login")
.headers(headers_1)
.param("""player[email]""", """email#address.com""")
.param("""player[password]""", """password""")
)
.pause(757 milliseconds)
…
.exec(http("request_13")
.get("http://site.com/logout")
.headers(headers_13)
)
.pause(202 milliseconds)
I try to put the two pieces of code after .post("http://site.com/login") and .get("http://site.com/logout") but that didn't works
Where is your token? Is it a HTTP header?
Generally speaking, the way to save data from responses in order to reuse it for further requests is the Check API.
.check(header("tokenName").saveAs("token")
...
.header("tokenName", "${token}")

Resources