Passing same value to multiple tasks in locust - locust

We have a requirement where we need to send a post request and then send a delete request for the same end point(REST API).
Need to generate a unique id for each post request, for each user in each iteration.
generated unique string is put inside on_start() method of task class (SequentialTaskSet).
Problem is, it runs for one iteration, but generates same id for consecutive iterations for each user.
To get unique id for each user in each iteration, generating the unique string within the task itself works, but issue here is, I could not pass the same Id to next task where I need to send delete request.
This is what code looks like now:
class StudentClass(SequentialTaskSet):
rndString = None
def on_start(self):
self.rndString = str(uuid.uuid4())
#task
def postRequest(self):
endpoint = "/students"
headers = {
'Authorization': 'Bearer token',
'content-type': 'application/json', 'accept': 'application/json'
}
data = {
"Id": f'std-{self.rndString}',
}
with self.client.post(endpoint, name="Post request", headers=headers, data=json.dumps(data),
catch_response=True) as response:
........
Appreciate any help in achieving this.

I think if you don't need to call post and delete requests with different weights you can do both calls in same task. Is there something I am missing that requires you to separate tasks for post and delete calls? If yo do need to separate them you can update the self.rndString in post task and it will use the updated one in delete.

#task(1)
def hello_world(self):
response = self.client.get("/listing")
print(response.text)
#task
def fill_crud(self):
response = self.client.post('/api/fill_post/', {"number_1": 76, "number_2": 897, "number_3": 564, "text_4": "Sneha"})
print(response.status_code)
res = json.loads(response.text)
response_id = (res['id'])
response_put = self.client.put(f'/api/fill_post/{response_id}/', {"number_1": 76576, "number_2": 89657, "number_3": 5654, "text_4": "Sneha"})
response_patch = self.client.patch(f'/api/fill_post/{response_id}/', {"text_4": "Suveksha"})
response_delete = self.client.delete(f'/api/fill_post/{response_id}/')
You can try it in this way, I hope it will helps anyone.

Related

In Shopify, using REST API's or GraphQL, can I simultaneously open and work with two stores

I need to duplicate some information between two stores ( one being the source store and the other the destination store ) .. can I open access to both stores, do a fetch data query on the source store and then mutate to the destination store, rather than having to use an intermediate storage file or memory, as the data size is large.
Yes, you can. In the most simple case you need a private app for each of the two stores. Then your calls to the REST or GraphQL API are constructed in such a way that they address the respectiv store. In Python this might look like the follwing
import base64
import requests
API_VERSION = '2022-01'
API_KEY1 = "API_KEY for private app of store 1")
PASSWORD1 = "PASSWORD for private app of store 1")
CREDENTIAL1 = f'{API_KEY1}:{PASSWORD1}'
auth = base64.b64encode(CREDENTIAL1.encode('ascii')).decode('ascii')
headers1 = {"Accept": "application/json", "Content-Type": "application/json", 'Authorization': 'Basic '+auth}
SHOP1 = 'name of store1 i.g. example1.myshopify.com'
base1 = f'https://{SHOP1}/admin/api/{API_VERSION}/'
API_KEY2 = "API_KEY for private app of store 2")
PASSWORD2 = "PASSWORD for private app of store 2")
CREDENTIAL2 = f'{API_KEY2}:{PASSWORD2}'
auth = base64.b64encode(CREDENTIAL2.encode('ascii')).decode('ascii')
headers2 = {"Accept": "application/json", "Content-Type": "application/json", 'Authorization': 'Basic '+auth}
SHOP2 = 'name of store2 i.g. example2.myshopify.com'
base2 = f'https://{SHOP2}/admin/api/{API_VERSION}/'
# example call to the first store
r1 = requests.get(base1+'products/count.json',headers=headers1)
# example call to the second store
r2 = requests.get(base2+'products/count.json',headers=headers2)

Locust- how to pass different host address

We have two tasks under the same class, both are pointing to different hosts.
Example:
First task (Create a new token) pointing to host - HTTP://xyz.abc.new
Second task (Create a new token-old) pointing to host- HTTP://xyz.abc.old
import time
from locust import User, HttpUser, task, between, SequentialTaskSet
class LoginTaskSet(SequentialTaskSet):
#task
def generate_token(self):
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
launch_response_new = self.client.post("/oauth2/access?grant_type=password&username=abcd#xyz.com&password=SWr5q3ghhhSd", headers=headers,name = "Create a new token")
print("Launch - Response body: {}".format(launch_response_new.text))
#task
def generate_old_token(self):
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
launch_response_old = self.client.post("/oauth/access?grant_type=password&username=abcd#xyz.com&password=SWr5q3ghhhSd", headers=headers,name = "Create a new token- old")
print("Launch - Response body old: {}".format(launch_response_old.text))
class Login(HttpUser):
tasks = [LoginTaskSet]
wait_time = between(1, 2)
How to send host value's as part of each request ? How to run the locust without passing host value?
You can give it the full URL in your client calls. It should only use the host you give it when your endpoints start with /. So instead of just "/oauth2/…" you’d do "http://xyz.abc.new/oauth2/...".

How to use REST in python to delete multiple IDs in interation?

I am trying to create a script that will do a GET request to retrieve data and then output it so that it can be referenced in the DELETE request URL to run through and delete all the data.
Code:
url = "https://192.168.0.1/api/3/asset_groups/443/assets"
payload = {}
headers = {
'Authorization': 'Basic',
"Accept": "application/json"
}
data = requests.get(url, headers=headers, data = payload, verify=False).text
output = json.loads(data)
#Attempting to delete assets by resource field
for resources in output['resources']:
print(resources)
Would I be able to somehow get the resources to be referenced as the id part in the DELETE request
URL:
"https://192.168.0.1/api/3/asset_groups/443/assets/{assetId}"
The resources field just outputs the IDs of the assets I retrieved as such:
102695
105759
105761
The list is much longer than just these 3 and is never a set amount. Will always vary hence why I would like it to iterate until all are deleted.

Getting name of previous test step of type Rest Request in SoapUI groovy script

I'm using groovy script to transfer a certain property from the response of a REST request like this:
def setCookie = testRunner.testCase.testSteps["SubmitCompleteDeviceRegistration"].testRequest.response.responseHeaders["Set-Cookie"]
def global = com.eviware.soapui.SoapUI.globalProperties
re = /(SESSION_AUTHENTICATION_TOKEN=[A-Za-z0-9_-]+;)/
matcher = ( setCookie =~ re )
def cookie = matcher[0][0]
global.setPropertyValue("SESSION_AUTHENTICATION_TOKEN","$cookie")
return cookie
Now what I want to do is make the name of the above teststep, "SubmitCompleteDeviceRegistration", variable, so I can use the transfer for various REST-Requests.
The name of this variable TestStep should equal the name of the previous TestStep of the RestRequest type.
How can I go about defining the TestStep that equals this condition?
I'm trying to use something like
def prevGroovyTestStep =
testRunner.testCase.findPreviousStepOfType(testRunner.testCase.getTestStepByName
("SubmitCompleteDeviceRegistration"),RestRequest)
log.info(prevGroovyTestStep.getName())
But I'm not sure how to implement this.
Any help would be really appreciated!
Getting the previous step name
def previousStepName = context.testCase.testStepList[context.currentStepIndex - 1].name
log.info "Previous step name is : ${previousStepName}"
Getting the previous step name if its type is Rest Request
def testStep = context.testCase.testStepList[context.currentStepIndex - 1]
def previousStepName
if (testStep instanceof com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep) {
previousStepName = testStep.name
} else {
log.error "Previous step is not of Rest Request Type"
}
if (previousStepName) {
log.info "Previous step name is : ${previousStepName}"
}
If type does not match in the above case, it will log the error message.
UPDATE - updating as per the latest comments from the author of this question. The below one helps all your need and the above may not needed any more.
Add a custom property for the test case, whose name is STEP_NAME and its value is the test step name to which http header needs to be added. As you commented, the last test step name in this case.
Go the request test step where you are getting the Cookie as response header.
Add an assertion of type Script Assertion and have the below code. Note that, you need to modify the test step name to which you want to add the request header Cookie. Using the place holder for now.
/**Below script should be used as script assertion for first test request step
* Assumes below
* a. test response contains http header called 'Set-Cookie'
* b. other request needs to send http header called 'Cookie'
* In case if there is any change in the two header names you may need to
* change its references below
**/
def responseCookieKey = 'Set-Cookie'
def requestCookieKey = 'Cookie'
def setHttpHeaders(String nextStepName, def headers) {
def nextRequest = context.testCase.testSteps[nextStepName].httpRequest
def existingHeaders = nextRequest.requestHeaders
headers.each {
existingHeaders[it.key] = it.value
}
nextRequest.requestHeaders = existingHeaders
}
if (messageExchange.responseHeaders.containsKey(responseCookieKey)) {
log.info "Found Cookie in the response headers"
def cookiez = messageExchange.responseHeaders[responseCookieKey]
assert null != cookiez, "Response does not contain Cookie"
def headers = [(requestCookieKey) : (cookiez)]
setHttpHeaders(context.testCase.getProvertyValue('STEP_NAME'), headers)
} else {
log.error "Not Found Cookie in the response headers"
}

How to pass parameter using Ext.Ajax.request when method type is DELETE

I am trying to send use Ext.Ajax.request method to delete some data on server. My request method looks as below :
Ext.Ajax.request({
url: '/myserver/restful/service/delete',
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
params: {
userId: 12345
}
});
On my jersey server I have written which looks like as below :
#Path("/delete")
#DELETE
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response deleteUser(final String userId) {
System.out.println("user id = " + userId);
return Response.ok().entity("success").build();
}
This method prints out user id in following format :
user id = userId=12345
So my expected value for userId is 12345 but it is giving me userId=12345. As I am newbie to jersey thing, I am not able to decide what to do now.
Can anyone please tell what is going wrong?
Not sure about what's going wrong in Jersey, but... if you are trying to use DELETE with a request body you're on the wrong track anyway. Don't. The only relevant parameter for DELETE should be the request URI it's being applied to.
#Julian is correct you really shouldn't have params with an HTTP DELETE verb.
Try this:
#Path("/delete/{userId}
Then inside of your method:
#PathParam("userId") String userId
And then when you call your service change your url to : delete/(userId) (without the parens) and remove the params.