The goal is to do soft assertion on each JSON field.
* def KAFKA_TOPIC = "topic1"
* def kafkaExpected = {field1:"value1",field2:"value2",field3:"value3"}
* def kafkaActual = {"topic1":[{field1:"value1",field2:"x",field3:"y"}]}
* configure continueOnStepFailure = { enabled: true, continueAfter: false, keywords: ['match'] }
* match (kafkaActual[KAFKA_TOPIC]) == ['#(kafkaExpected)'] <-- do we have one-liner like this to do soft assertions on all fields?
* configure continueOnStepFailure = false
Output:
$[0].field2 | not equal (STRING:STRING)
'x'
'value2'
Instead of doing it 1 by 1.
* match (kafkaActual[KAFKA_TOPIC])[0].field1 == kafkaExpected.field1
* match (kafkaActual[KAFKA_TOPIC])[0].field2 == kafkaExpected.field2
* match (kafkaActual[KAFKA_TOPIC])[0].field3 == kafkaExpected.field3
Output:
match failed: EQUALS
$ | not equal (STRING:STRING)
'x'
'value2'
match failed: EQUALS
$ | not equal (STRING:STRING)
'y'
'value3'
And whats weird is that on terminal logs it only printed one assertion, either on both approach.
$ | not equal (STRING:STRING)
'y'
'value3'
Trying to use Karate.forEach but seems like not the right path.
Found a solution from this link provided by Peter. I just need to transform the JSON to list of key, value format and use it as data source.
From:
{field1:"value1",field2:"value2",field3:"value3"}
Transformed To:
[{key:"field1",value:"value1"},{key:"field2",value:"value2"},{key:"field3",value:"value3"}]
Function used and usage:
* def input = INPUT
* def func =
"""
function(obj){
var output = [];
for (var i in obj) {
output.push({key: i, value: obj[i]});
}
return output
}
"""
* json kafkaAttributes = func(input)
* configure continueOnStepFailure = { enabled: true, continueAfter: false, keywords: ['match'] }
* karate.call('kafka.feature#validateFieldsAndValues',kafkaAttributes)
* configure continueOnStepFailure = false
#validateFieldsAndValues
Scenario:
* match (response[KAFKA_TOPIC][0][key]) contains value
Related
When i am passing the value of a string json filter is working fine. But when I am passing embedded expression in the JSONPATH it is not replacing actual value.
Given url appServer +'/integration/rest/user'+'?page=0'+'&pageSize=10'+'&fieldList=first_name,last_name,id,username,last_login,active,date_created'+'&filter=user_type%20equals%20%27P%27%20'+'&getTotalRecordCount=true'
And header X-CSRF-TOKEN = csrfToken
* cookie JSESSIONID = jsessionid
* print routevalue
* cookie route = routevalue
* string searchUser = 'anupama'
* callonce sleep 10
Given request ' '
When method get
Then status 200
* def usernames = get response.integration.serviceData.record[*].username
* print usernames
* print searchUser
* def userNode = get[0] response.integration.serviceData.record[?(#.username== '#(searchUser)')]
* print userNode
Embedded expressions are only for JSONPath and XML: https://github.com/intuit/karate#embedded-expressions
Please use the karate API for dynamic JsonPath: https://github.com/intuit/karate#jsonpath-filters
* def userNode = karate.jsonPath(response, "$.integration.serviceData.record[?(#.username=='" + searchUser + "')]")
I'm trying to get information from Wikidata. For example, to access to "cobalt-70" I use the API.
API_ENDPOINT = "https://www.wikidata.org/w/api.php"
query = "cobalt-70"
params = {
'action': 'wbsearchentities',
'format': 'json',
'language': 'en',
'search': query
}
r = requests.get(API_ENDPOINT, params = params)
print(r.json())
So there is a "claims" which gives access to the statements. Is there a best way to check if a value exists in the statement? For example, "cobalt-70" have the value 0.5 inside the property P2114. So how can I check if a value exists in the statement of the entity? As this example.
Is there an approach to access it. Thank you!
I'm not sure this is exactly what you are looking for, but if it's close enough, you can probably modify it as necessary:
import requests
import json
url = 'https://www.wikidata.org/wiki/Special:EntityData/Q18844865.json'
req = requests.get(url)
targets = j_dat['entities']['Q18844865']['claims']['P2114']
for target in targets:
values = target['mainsnak']['datavalue']['value'].items()
for value in values:
print(value[0],value[1])
Output:
amount +0.5
unit http://www.wikidata.org/entity/Q11574
upperBound +0.6799999999999999
lowerBound +0.32
amount +108.0
unit http://www.wikidata.org/entity/Q723733
upperBound +115.0
lowerBound +101.0
EDIT:
To find property id by value, try:
targets = j_dat['entities']['Q18844865']['claims'].items()
for target in targets:
line = target[1][0]['mainsnak']['datavalue']['value']
if isinstance(line,dict):
for v in line.values():
if v == "+0.5":
print('property: ',target[0])
Output:
property: P2114
I try a solution which consists to search inside the json object as the solution proposed here : https://stackoverflow.com/a/55549654/8374738. I hope it can help. Let's give you the idea.
import pprint
def search(d, search_pattern, prev_datapoint_path=''):
output = []
current_datapoint = d
current_datapoint_path = prev_datapoint_path
if type(current_datapoint) is dict:
for dkey in current_datapoint:
if search_pattern in str(dkey):
c = current_datapoint_path
c+="['"+dkey+"']"
output.append(c)
c = current_datapoint_path
c+="['"+dkey+"']"
for i in search(current_datapoint[dkey], search_pattern, c):
output.append(i)
elif type(current_datapoint) is list:
for i in range(0, len(current_datapoint)):
if search_pattern in str(i):
c = current_datapoint_path
c += "[" + str(i) + "]"
output.append(i)
c = current_datapoint_path
c+="["+ str(i) +"]"
for i in search(current_datapoint[i], search_pattern, c):
output.append(i)
elif search_pattern in str(current_datapoint):
c = current_datapoint_path
output.append(c)
output = filter(None, output)
return list(output)
And you just need to use:
pprint.pprint(search(res.json(),'0.5','res.json()'))
Output:
["res.json()['claims']['P2114'][0]['mainsnak']['datavalue']['value']['amount']"]
I'm having some difficulty with delete.many and update.many using the new builders whilst trying to convert my previous version's (working) code into reactivemongo 0.16.5 ("org.reactivemongo" %% "play2-reactivemongo" % "0.16.5-play26", "org.reactivemongo" %% "reactivemongo-akkastream" % "0.16.5". As you'll see; I'm using this within the Play plugin so dealing with JSON (rather than BSON)
I'm going from the official documentation here. My errors are similar for both update & delete so I'll just post for update here to keep it trim.
Update command
def updateMany(collName: String)(quJsa: JsArray)(orderedBool: Boolean = false): Future[MultiBulkWriteResult] = {
lazy val updateBuilder = getCollection(collName).map(_.update(orderedBool))
quJsa.asOpt[Seq[JsObject]].map(
_.map(
x => x.as[MongoUpdateBuilder]
)
).map(
_.map(
x => updateBuilder.flatMap(
_.element(q = x.q, u = x.getSetUpdate, upsert = x.upsertBool, multi = x.multiBool)
)
)
).map(
x => Future.sequence(x)
).map(
_.flatMap(
x => updateBuilder.flatMap(
_.many(x)
)
)
).getOrElse(getMultiBulkWriteResultErrorF("input not recognised as jsarr"))
}
Custom update builder model
case class MongoUpdateBuilder(q: JsObject, u: JsObject, upsertBool: Boolean, multiBool: Boolean) {
def getSetUpdate = Json.obj("$set" -> u)
}
object MongoUpdateBuilder {
implicit val mongoUpdateBuilderFormat = Json.format[MongoUpdateBuilder]
}
Error container
def getMultiBulkWriteResultErrorF(errStr: String): Future[MultiBulkWriteResult] = {
val mbwr = MultiBulkWriteResult(
ok = false,
n = 0,
nModified = 0,
upserted = Seq(),
writeErrors = Seq(WriteError(index = 0, code = 404, errmsg = errStr)),
writeConcernError = None,
code = Some(404),
errmsg = Some(errStr),
totalN = 0
)
Future.successful(mbwr)
}
And the main issue:
no type parameters for method flatMap: (f: reactivemongo.play.json.collection
.JSONCollection#UpdateBuilder => scala.concurrent.Future[S])(implicit executor: scala.concurrent.ExecutionContext)scala.concurrent.Future[S] exist so that it can be applied to arguments (reactivemongo.play.json.collection.JSONCollection#UpdateBuilder => scala.concurrent.Future[_1.UpdateCommand.UpdateElement] forSome { val _1: reactivemongo.play.json.collection.J
SONCollection }) [error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : reactivemongo.play.json.collection.JSONCollection#UpdateBuilder => scala.concurrent.Future[_1.UpdateCommand.UpdateElement] forSome { val _1: reactivemongo.play.jso
n.collection.JSONCollection }
[error] required: reactivemongo.play.json.collection.JSONCollection#UpdateBuilder => scala.concurrent.Future[?S]
[error] x => updateBuilder.flatMap(
So the issue seems to be this line - updateBuilder.flatMap. The Future cannot be flattened with these types (JSONCollection#UpdateBuilder & JSONCollection#UpdateCommand.UpdateElement). So I'm struggling with this one. Please reach out if you can see the issue here. Many thanks!
How do I delete JSON object properties dynamically? I tried this:
* def delKey =
"""
function(json, key) {
delete json[key];
return json;
}
"""
* def aJson = { row: null, age: 35 , city: 'na'}
* print "Before: "
* print aJson
* def called = delKey(aJson, 'age')
* print "After: "
* print aJson
The result:
I think you have not seen the remove and set keywords. Here is the right approach. Also note how the print statement supports a comma-delimited style so that it will pretty-print:
* def aJson = { row: null, age: 35 , city: 'na' }
* print 'Before: ', aJson
* remove aJson.age
* print 'After: ', aJson
If you need to remove keys dynamically, the JS API karate.remove(name, path) can be used. Refer to the docs !
I have the following code chunk:
def response = '[{"id": "121","startTime": "2013-11-10T20:48:54Z", "reqId": 123456, "endTime": null, "numFiles" :null},
{"id": "123","startTime": "2013-11-29T21:45:00Z","reqId": 123458,"endTime": "2013-11-30T21:45:00Z", "numFiles" :null },
{"id": "121","startTime": "2013-11-8T20:48:54Z", "reqId": 123111, "endTime": null, "numFiles" :null}]'
def sortedResponse = response.sort { a,b -> b.reqId <=> a.reqId}
def reqRespAPI = new JsonSlurper().parseText(sortedResponse )
def id = reqRespAPI.id
def stTime = reqRespAPI.startTime
def eTime = reqRespAPI.endTime
def rqId = reqRespAPI.reqId
def numRec = reqRespAPI.numFiles
...some other stuff here....
I am trying to sort by reqId (rqId) descending. Do I have to use a for loop? The current sortedResponse is throwing an exception:
groovy.lang.MissingMethodException: No signature of method: java.lang.String.sort() is applicable for argument types: (...Controller$_closure2_closure8) values: [....Controller$_closure2_closure8#5976ac5b]
I have also tried sort (new OrderBy(...)) but that also did not work...
Any help would be appreciated.
The issue seems to be that you're trying to sort the response String, rather than the collection of JSONObjects.
Try this?
def reqRespJSON = new JsonSlurper().parseText( response )
def sortedJSON = reqRespJSON.sort { a,b -> b.reqId <=> a.reqId}
def id = sortedJSON[0].id
Note that the sortedJSON is an List of Maps, so you have to specify which one you want the id from (using [0]).