Groovy RestClient POST request sends invalid JSON - groovy

I found, that sending JSON, which has entry which starts with "function" produces invalid JSON.
Example:
#Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.1')
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import groovyx.net.http.RESTClient
import static groovyx.net.http.ContentType.JSON
def jsonSlurper = new JsonSlurper()
// if you replace `function` on next line to any other word - it will work correctly
String baseContextJSON = '{ "afterResponse": "function (getParam, setParam, genInfo) { }" }'
def baseContext = jsonSlurper.parseText(baseContextJSON)
println JsonOutput.prettyPrint(JsonOutput.toJson(baseContext))
RESTClient http = new RESTClient('https://requestinspector.com')
http.post(
path: "/inspect/01dh7rs82be884ke89jcny061e",
body: baseContext, // if I use baseContextJSON here - correct JSON would be sent
query: null,
requestContentType: JSON
)
This code sends this payload:
{"afterResponse":function(getParam,setParam,genInfo){}}
That's invalid JSON - note missing quote around function.
You can see actual received payloads at https://requestinspector.com/p/01dh7rs82be884ke89jcny061e (until it expires, or you can generate you own)
I can't even figure out:
- is it bug in HTTPBuilder?
- is it bug in how Groovy handles and convert Map to JSON?
Any idea what can I do to pin root cause?

Related

How deserialize protocol buffers from http response use python

I want to deserialize an API response to a python object whose content-type is protobuf, I use the ParseFromString method to parse the HTTP response, but only get a number 23, print the response content directly is b'\n\x08Hi,py-pb'. So, how do I deserialize the HTTP response to the python object?
proto file content:
syntax = "proto3";
package greet;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}
python code:
# _*_ coding: utf8 _*_
from google.protobuf.json_format import ParseDict, MessageToJson
from protos.greet_pb2 import HelloRequest, HelloReply
import httpx
import asyncio
async def send_req():
req = {'name': 'py-pb'}
msg = ParseDict(req, HelloRequest())
print(msg)
print(type(msg))
print(msg.SerializeToString())
async with httpx.AsyncClient() as client:
resp = await client.post('http://localhost:5044/greet/Greeter/SayHello', data=msg.SerializeToString(),
headers={'Accept': 'application/protobuf', 'Content-Type': 'application/protobuf'})
print('=========response=========')
# print(resp.stream)
# print(resp.content)
# print(resp.text)
resp_msg = HelloReply().ParseFromString(resp.content)
# resp_msg = HelloReply().SerializeToString(resp.content)
print(resp_msg)
asyncio.run(send_req())
Versions:
Python - 3.10.5
google.protobuf - 4.21.2
Related answer:
ParseFromString is a method -- it does not return anything, but rather fills in self with the parsed content.
Reference:
Google Protocol Buffers (protobuf) in Python3 - trouble with ParseFromString (encoding?)
ParseFromString is an instance method. So you want, e.g.:
hello_reply = HelloReply()
hello_reply.ParseFromString(resp.content)
The docs include an example using ParseFromString.
Here's a repro:
from google.protobuf.json_format import ParseDict, MessageToJson
from greet_pb2 import HelloRequest, HelloReply
rqst = {'name': 'py-pb'}
msg = ParseDict(rqst, HelloRequest())
tx = msg.SerializeToString()
print(tx)
print(tx.hex())
resp = HelloReply()
resp.ParseFromString(tx)
print(resp)
Yields:
b'\n\x05py-pb'
0a0570792d7062
message: "py-pb"
You can take the binary as hex and plug it into protogen to decode it.
Field #1: 0A String Length = 5, Hex = 05, UTF8 = "py-pb"

Passing token from get request to a header in SoapUI

I have a getToken request in a test case get_Admin_Token in PassToken test suite, where I have as a response following JSON:
{
"access_token": "5701f536-0bd5-441f-a490-21aafeasdasdd",
"token_type": "bearer",
"refresh_token": "c53af657-8292-4aff-xxxx-xxxf0ffed310",
"expires_in": 80208,
"scope": "read write trust"
}
I need to use access_token value in uploadFile method, but I need to pass it in a header. I have a field Authorization with Bearer: $(access_token) value.
Using some google I found:
https://community.smartbear.com/t5/SoapUI-Open-Source/How-do-I-do-a-property-transfer-with-multiple-source-responses/td-p/106456 question, which was looking similar. I started to create a GroovyScript test step, where I used code to pass it to the Properties table, but no success. I was also trying to put it to assertions for the get_Admin_Token, but I got a message about incorrect object types. I also tried to use def accessToken = jsonSlurper.access_token.toString() to use strings, but now I got an error `
No signature of method:
com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase.setProperty() is
applicable for argument types: (java.lang.String, java.lang.String) values:
[AUTH_KEY, Bearer 5701f536-0bd5-441f-a490-21aafeasdasdd] Possible solutions:
getProperty(java.lang.String), addProperty(java.lang.String),
hasProperty(java.lang.String), hasProperty(java.lang.String), getProject(),
getProperties()
My groovy code:
import groovy.json.JsonSlurper
def response = messageExchange.response.responseContent
def jsonSlurper = new JsonSlurper().parseText(response)
assert !(jsonSlurper.isEmpty())
def accessToken = jsonSlurper.access_token.toString()
assert null != accessToken, "access_token does not have a value"
def authorizationKey = "${accessToken}"
context.testCase.setProperty('AUTH_KEY',"Bearer " + authorizationKey)
Is this code valid? I'm not sure what to put in next method as authorization value in header, I tried with ${#get_Admin_Token#AUTH_KEY}, but it doesn't work
EDIT: Easier way
Just pass Token to properties using transfer action and set in header Bearer ${Properties#AdminToken}. That's all
===================
Old version:
The following answer is correct if anyone is looking for the Groovy script:
Ok, I think I spotted a workaround.
Groovy code is as following:
import groovy.json.JsonSlurper
def response = messageExchange.response.responseContent
def jsonSlurper = new JsonSlurper().parseText(response)
assert !(jsonSlurper.isEmpty())
def accessToken = jsonSlurper.access_token.toString()
assert null != accessToken, "access_token does not have a value"
def authorizationKey = "${accessToken}"
context.testCase.testSuite.setPropertyValue("AUTH_KEY","Bearer " + authorizationKey)
log.info context.testCase.testSuite.getPropertyValue( "AUTH_KEY" )
And using answer presented here: How to transfer dynamic auth value in all requests instead of changing the value in every request's header in SOAPUI I created a new GroovyScript Test Case:
testRunner.testCase.testSteps.each{ name, testStep ->
log.info name
if(testStep.metaClass.getMetaMethod("getTestRequest")){
if(name=="UploadScreenshot"){
def request = testStep.getTestRequest()
def headers = request.getRequestHeaders()
headers.add('Authoritzation',context.testCase.testSuite.getPropertyValue( "AUTH_KEY" ))
request.setRequestHeaders(headers)
log.info "Added header to $name"
}
}
}
I know it's not a very good idea, to put an if to the loop instead if delete a loop, but I don't know yet how to do it and I need to proceed with work

Can't extract data from RESTClient response

I am writing my first Groovy script, where I am calling a REST API.
I have the following call:
def client = new RESTClient( 'http://myServer:9000/api/resources/?format=json' )
That returns:
[[msr:[[data:{"level":"OK"}]], creationDate:2017-02-14T16:44:11+0000, date:2017-02-14T16:46:39+0000, id:136]]
I am trying to get the field level, like this:
def level_value = client.get( path : 'msr/data/level' )
However, when I print the value of the variable obtained:
println level_value.getData()
I get the whole JSON object instead of the field:
[[msr:[[data:{"level":"OK"}]], creationDate:2017-02-14T16:44:11+0000, date:2017-02-14T16:46:39+0000, id:136]]
So, what am I doing wrong?
Haven't looked at the docs for RESTClient but like Tim notes you seem to have a bit of a confusion around the rest client instance vs the respons object vs the json data. Something along the lines of:
def client = new RESTClient('http://myServer:9000/api/resources/?format=json')
def response = client.get(path: 'msr/data/level')
def level = response.data[0].msr[0].data.level
might get you your value. The main point here is that client is an instance of RESTClient, response is a response object representing the http response from the server, and response.data contains the parsed json payload in the response.
You would need to experiment with the expression on the last line to pull out the 'level' value.

Assert response starts with

I am trying to assert the response, to check if the response value starts with a certain text. I tried using the function startsWith but it seems like it does not work in SOPAUI script assertion.
This is what I have tried:
import groovy.json.JsonSlurper
//grab the response
def ResponseMessage = messageExchange.response.responseContent.records
//define a JsonSlurper
def jsonSlurper = new JsonSlurper().parseText(ResponseMessage)
//log.info jsonSlurper
assert jsonSlurper.startsWith("Text")
Here is the json response
{
"Name": "Natalie",
"message": "What are you doing"
}
I want to check if the Name starts with "Nat"
From documentation JsonSlurper().parseText(String text) returns:
data structure of lists and maps
so you can not use startsWith directly. To achieve what you want you have to go to the desired object in the path and use startsWith there. Something like must works for your case:
import groovy.json.JsonSlurper
def jsonStr = '{ "Name": "Natalie", "message": "What are you doing" }'
def jsonSlurper = new JsonSlurper().parseText(jsonStr)
assert jsonSlurper.Name.startsWith("Nat")

How do I set a value in JSON response in Groovy script in SOAP UI

I have two REST request which I am trying to run in SOAP UI. I want to feed response from one REST request to the other REST request. I am using property transfer for this. I first want to modify a Value in Response from 1st request and then feed it . I am trying this
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
// request
def request = '''{"data":{
"supplementaryMessages" : [ ],
"requisitionHeaders" : [ {
"dataOperation" : "UPDATE"
} ]
}}'''
// parse the request
def jsonReq = new JsonSlurper().parseText(request);
// get the response where you've the values you want to get
// using the name of your test step
responseContent = testRunner.testCase.getTestStepByName("Fetch1").getPropertyValue("response")
// parse response
def jsonResp = new JsonSlurper().parseText(responseContent)
// get the values from your first test response
// and set it in the request of the second test
jsonResp.data.requisitionHeaders.dataOperation = jsonReq.data.requisitionHeaders.dataOperation
When I run this I am getting the Type Mismatch error .It could be very simple issue but I am new to Groovy .

Resources