How to Poll a request for certain interval and determine Pass or Failure - cucumber

I've the API request as below :
* def reqCreate = read('classpath:integration/create-request.json')
* def resCreate = read('classpath:integration/create-response.json')
* def personId = 12
Given path '/person/' + personId
And header Authorization = 'Bearer ' + accessToken
When method get
Then status 200
Then match response == resCreate
I need to check the response after every 5 seconds till one minute.During one minute or till one minutes any any moment, if response assertion gives true then final result is true else should return false after specified duration.

This is explained clearly in the documentation : https://github.com/intuit/karate#retry-until
* configure retry = { count: 12, interval: 5000 }
Given url demoBaseUrl
And path 'greeting'
And retry until response.id > 3
When method get
Then status 200
In your case :
Given path '/person/' + personId
And configure retry = { count: 12, interval: 5000 }
And header Authorization = 'Bearer ' + accessToken
And retry until response == resCreate
When method get
Then status 200
Please don't forget to mark your previous questions as answered, you have a few that you left open.

Related

Karate api test: TestRunner.testParallel:15 Multi threaded access requested by thread Thread[pool-1-thread-1,3] but is not allowed for language(s) js

Testing api with Karate: mocks and queue implementation: Error TestRunner.testParallel:15 Multi threaded access requested by thread Thread[pool-1-thread-1,3,main] but is not allowed for language(s) js. is produced when try to consume a queue with multiple messages.
Flow:
Call a messageMock.feature :
Background:
* def QueueUtils = Java.type('mocks.QueueUtils')
* configure cors = true
* configure responseHeaders = { 'Content-Type': 'application/json' }
Scenario: pathMatches('/message') && methodIs('post')
* def response = read('../../responses/message/message.json')
* def responseStatus = 200
* QueueUtils.send(response.data, JSON.stringify(read('test.json')), 25)
* QueueUtils.send(response.data, JSON.stringify(read('test1.json')), 25)
* QueueUtils.send(response.data, JSON.stringify(read('test2.json')), 25)
From feature:
Scenario: Send message
* def QueueConsumer = Java.type('mocks.QueueConsumer')
* def port = karate.start('messageMock.feature').port
* url baseUrl + port
Given path '/message';
And request read('req.json')
When method post
Then status 200
* def queue = new QueueConsumer(response.data)
* def handler = function(msg){ karate.signal(msg) }
* queue.listen(karate.toJava(handler))
* listen 2000
* json response = listenResult
* print '### received:', listenResult
And match response == read('test.json')
* listen 2000
* json response1 = listenResult
* print '### received1:', listenResult
And match response1 == read('test1.json')
* listen 2000
* json response2 = listenResult
* print '### received2:', listenResult
And match response2 == read('test2.json')
The error message is given on line:
* json response = listenResult
is it a bug or incorrectly created test?
What I am trying to test is a queue that have several enqueued messages before consumption. Is this possible to do with Karate?
It is possible we have some work left for multiple threads with the new JS engine.
It would be very helpful if you can provide a sample project that replicates this problem. Kindly follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue
Some work-arounds are given here, but not ideal: https://github.com/intuit/karate/issues/1633#issuecomment-874854857
Which is why it is important that you help us replicate - so that we can figure out a better solution.

Python3 how to resume at item in for loop when an exception was triggered

I'm somehow unable to came up with a solution after spending already few days on this. What I need to do:
Iterate trough a large list of hosts in a .txt file to perform a request to the devices/queries/devices/v1 API endpoint for CrowdStrike to get a so called aid (agent id).
Once I have the aid (there can be multiple aid's for a single host) I need to again iterate but this time over the aid's to the devices/entities/devices/v1 API endpoint to retrieve information such as hostname, last seen plus need to make another call, this time to the policy/combined/reveal-uninstall-token/v1 API endpoint, to get the uninstall token for each of the aid's.
The problem is that the bearer token that I'm generating initially is only valid for 30 minutes, and it needs to by provided with each subsequent request. My idea was to use the try except construct + I'm raising exceptions with Response raise for status as described in correct-way-to-try-except-using-python-requests-module. So I'm hoping that at any point I'm making a request, if it fails due to an HTTP error like 401 Client Error: Unauthorized for url: it would indicate that the token has expired and would call the login() function token = login() within except to make a call to request new a new token and assign it to the token variable and that would allow my to proceed with my for loop since the new token would be provided. The problem I now see, is that for the given host that I'm iterating over, when the token expires, it get's skipped right after the new token is generated (the loop basically continues for the next item within the list). How could I workaround this ?
PS. I know the code is far from perfect, but it's my first steps and would be really nice I someone could lead me here. Was looking and continue and break but continue seams to actually be doing exactly what I'm seeing as behavior with my code and break is not applicable for what I want to do.
for host in host_list:
try:
'''
1.Get agent id (aid) for each host (NOTE:can return multiple aid's for single host).
If the returned list is empty, that means the host is not in CS and skip the
processing of the remaining code.
'''
query_aid = requests.get(base_url+ 'devices/queries/devices/v1?limit=5000&filter=hostname:' + "'" + host + "'", headers = {"accept": "application/json", "authorization": "Bearer " + token} )
query_aid.raise_for_status()
aux = json.loads(query_aid.text)
aux2 = aux["resources"]
if len(aux2) == 0:
print(host + ' ; ' + 'not in CS')
else:
'''
for whatever count of aid's returned iterate through each and make a call to the
devices/entities/devices/v1 endpoint to pull hostname and last_seen information,
and make for each aid a call to the policy/combined/reveal-uninstall-token/v1
endpoint to pull the uninstall token for each
'''
for aid in aux2:
host_details_request = requests.get(base_url + 'devices/entities/devices/v1?ids=' + aid , headers = {"accept": "application/json", "authorization": "Bearer " + token})
host_details_request.raise_for_status()
aux = json.loads(host_details_request.text)
last_seen = re.search(r'\d{4}-\d{2}-\d{2}', aux["resources"][0]["last_seen"])
request_uninstall_token = requests.post(base_url + 'policy/combined/reveal-uninstall-token/v1', headers = {'Content-type': 'application/json', "authorization": "Bearer " + token }, json = { "audit_message": "test api ", "device_id": aid })
request_uninstall_token.raise_for_status()
aux3 = json.loads(request_uninstall_token.text)
print(aux["resources"][0]["hostname"] + 'uninstall token: ' + aux3["resources"][0]["uninstall_token"] + ';' + last_seen.group(0))
except requests.exceptions.HTTPError as err:
print(err)
token = login()
Create a function that handles your try code. Then call this function within your expect after the login call
for host in host_list:
try:
handle_host(host)
except requests.exceptions.HTTPError as err:
print(err)
token = login()
handle_host(host)

How to create a random string everytime a test runs in karate dsl

The json request I am sending is:
Given url applicationURL
And path 'applications'
And header Authorization = subscribeToken
And request:
{
"throttlingTier": "Unlimited",
"description": "sample app description",
"name": "TestbyKarate",
"callbackUrl": "https:/apistore-dev-dev-a878-14-ams10-nonp.qcpaws.qantas.com.au/callback"
}
When method post
Then status 201
* def applicationId = response.applicationId
* print 'applicationId is ', applicationId
I am sending the name in my request as TestbyKarate but I want to send a unique value every time my test runs.
Is there any way to do it?
Can you please read the docs once. It will really benefit you.
https://github.com/intuit/karate#commonly-needed-utilities
So in the Background or common feature, you have:
* def now = function(){ return java.lang.System.currentTimeMillis() }
Then you can do this:
* def name = 'Test-' + now()
* request { name: '#(name)' }
check below example
Feature: Create User Name
Scenario: UserName with unique Name
def getDate =
"""
function(){ return java.lang.System.nanoTime() }
"""
def time = getDate()
def userName = 'createUser' + time + '_Test'

How to skip next steps if a condition is fulfilled in a feature file using karate

My feature file looks somthing like this :
#Subscribe to an API
Given url applicationURL
And path 'subscriptions'
And header Authorization = subscribeToken
And request {'tier': 'Gold','apiIdentifier': '#(APIIDStr)','applicationId': '#(applicationId)'}
When method post
Then status 201
* def subscriptionId = response.subscriptionId
* print 'subscriptionID is ', subscriptionId
* def status = response.status
* print 'subscribed with status ', status , ' and subscriptionID ' , subscriptionId
#* eval if (response.status == 'ON_HOLD') karate.call('BPSWorkflow.feature')
Given url applicationURL + '/applications/generate-keys?'
And param applicationId = applicationId
And header Authorization = subscribeToken
And request {"validityTime": "3600","keyType": "PRODUCTION","accessAllowDomains": ["ALL"]}
When method post
Then status 200
* def accessTokenforInvokation = 'Bearer '+ response.token.accessToken
* print 'accessTokenforInvokation is ', accessTokenforInvokation
I want to skip every step after "#* eval if (response.status == 'ON_HOLD') karate.call('BPSWorkflow.feature')" status is 'ON_HOLD'.
Can someone help?
There is an experimental API you can use karate.abort() - here is the documentation: https://github.com/intuit/karate/tree/master/karate-netty#karateabort
This will be made more obvious and documented better in the next release.
* eval if (response.status == 'ON_HOLD') { karate.call('BPSWorkflow.feature'); karate.abort() }

How to get total time spend in Gitlab?

Is there a way to get the total time spend on all issues that a user have spend with the time tracking /spend slash command?
Time tracking stats with the API gets just a small amount of data: https://docs.gitlab.com/ce/api/issues.html#get-time-tracking-stats
Gitlab CE 9.1.4
As I see it is possible to parse comments from API v3 and calculate total.
For example,
https://gitlab.com/api/v3/projects/:id/issues/:issue_id/notes?private_token=your_token
{
id: 73113225,
body: "added 1h of time spent at 2018-05-15",
attachment: null,
author: {
...
username: "mnvxxx",
},
...
}
More info:
https://docs.gitlab.com/ee/api/notes.html
UPDATE
Currently I has created instrument for calculating spent time by every contributor. I hope it will be helpful:
https://github.com/zubroide/gitpab
Here is a very simple Python script that works with API v4:
import requests
API_KEY = "" # Enter your API key here
BASE_URL = "https://{{enter gitlab url here}}/api/v4/"
item_counter = 0
total_seconds = 0
for i in range(1, 57): # manually set range of issues here. All issues doesn't work well.
issue = requests.get(BASE_URL + 'projects/2/issues/' + str(i) + '/time_stats')
total_seconds += issue.json()['total_time_spent']
item_counter += 1
print("Hours on all issues: %.2f" % float((total_seconds / 60) / 60))
print("Total issues: " + str(item_counter))
I'm posting to this thread because this is the first answer that comes up on Google, and there isn't really any other ready-made solutions to be found.
Building on top of what #josh-harkema has provided, this is a version that lists all closed issues that were assigned to a specific username that have been updated in a given time period (and do not have the label 'paid' set):
import requests
import os
username = os.environ.get('GITLAB_REPORTING_USERNAME')
project_id = os.environ.get('GITLAB_REPORTING_PROJECTID') # in the top of your project page
access_token = os.environ.get('GITLAB_REPORTING_TOKEN') # https://gitlab.com/profile/personal_access_tokens
base_url = "https://gitlab.com/api/v4"
updated_after = "2019-06-01T00:00:00.00Z"
updated_before = "2019-07-01T00:00:00.00Z"
item_counter = 0
total_seconds = 0
headers = { 'Private-Token': access_token }
url_template = "{base_url}/projects/{project_id}/issues?" \
"state=closed&assignee_username={username}&updated_after={updated_after}&updated_before={updated_before}"
url = url_template.format(base_url=base_url, project_id=project_id, username=username,
updated_after=updated_after, updated_before=updated_before)
# call API
issues = requests.get(url, headers = headers)
total_seconds = 0
issues_to_pay = []
line_template = "id: {id} closed: {closed_at} time spent: {time}\ttitle: {title}\turl: {url}"
print("Issue statistics for {u} from {f} to {t}:\n".format(u=username,f=updated_after, t=updated_before))
for issue in issues.json():
time_val = issue['time_stats']['human_total_time_spent']
already_paid = u'paid' in issue['labels'] # you can put a label 'paid' to exclude an issue
if already_paid:
time_val = time_val + " *"
else:
# if the issue has been paid, already, don't add the time, and don't list as to be paid
total_seconds += issue['time_stats']['total_time_spent']
issues_to_pay.append(str(issue['id']))
line = line_template.format(
id=issue['id'],
closed_at=issue['closed_at'],
title=issue['title'],
time=time_val,
url=issue['web_url']
)
print(line)
print("")
print("Hours to pay on all issues: %.2f" % float((float(total_seconds) / 60) / 60))
print("")
print("* = issue has been paid for, already")
print("All issue to pay: {issues}".format(issues=",".join(issues_to_pay)))
Note: You need to have environment variables set for the GITLAB_REPORTING_USERNAME, the GITLAB_REPORTING_PROJECTID, as well as the GITLAB_REPORTING_TOKEN.
We use this to pay contractors. Hope this helps!
I was myself looking for the same and after more searching, I found this excellent CLI tool called gitlab-time-tracker. It generates comprehensive reports of tracked-time that you can customise by multiple options and can print them even as PDFs!
For keeping this answer relevant to OP's question, you can print (in your terminal) total time spent by a user using following command**:
gtt report "namespace/project" --user username --closed --from="2017-03-01" --to="2017-04-01"
** This assumes that you've installed this tool (gtt) and setup your Gitlab PAT (with "api" scope activated) in its config file.
You'll have to use both the Gitlab Commits API and the GraphQL API to achieve it. Below is some code that's been shorted for brevity.
You'll need to specify a Gitlab instance flag and your personal token.
Say you have a function used to capture all users in your Gitlab instance called "GetUsers":
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/sirupsen/logrus"
"github.com/xanzy/go-gitlab"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
address = kingpin.Flag("address", "The Gitlab URL to use").Required().String()
token = kingpin.Flag("token", "Project token").String()
)
func main () {
timeTracker()
}
func timeTracker(git *gitlab.Client) {
names := GetUsers(git)
for _, name := range names {
jsonData := map[string]interface{}{
"query": `
query($user: String!) {
timelogs(username: $user ) {
edges {
node {
id
user {
id
username
}
timeSpent
issue{
labels{
nodes{
title
}
}
}
}
}
}
}
`, "variables": fmt.Sprintf(`{"user":"%s"}`, name),
}
jsonValue, _ := json.Marshal(jsonData)
request, err := http.NewRequest("POST", "https://" +*address + "/api/graphql", bytes.NewBuffer(jsonValue))
if err != nil {
logrus.Error(err)
}
request.Header.Set("Authorization", "Bearer "+*token)
request.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: time.Second * 10}
response, err := client.Do(request)
response.Body.Close()
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
}
logrus.Print(ioutil.ReadAll(response.Body))
Result (when decode with JSONDecoder):
INFO[0000] User: user1, Time spent: 300 (s)
INFO[0000] User: user2, Time spent: 120 (s)
You can then take this data and decode it into a struct (I would copy and paste the post request to an autogenerator for sanity's sake), then do what you want with it. Or change the POST request to capture users by Project if you're more interested in something granular.
Source: https://docs.gitlab.com/ee/api/graphql/getting_started.html

Resources