SoapUI. Add multipart body part using groovy - groovy

I need to add json as multipart body part to "multipart/form-data" request using groovy.
I can do this using file attachments:
testRunner.testCase
.testSteps["/job/result"]
.getHttpRequest()
.attachBinaryData(json.toString().getBytes(), "application/json").contentID = "info"
My problem is "attachBinaryData" creates a temp file per request. It is not good for load tests :)
Is there other possibility to add body parts, without file attachments?
something like :
testRunner.testCase
.testSteps["/job/result"]
.getHttpRequest()
.addBodyPart("application/json", json.toString())
P.S. it must be the "add", because request has also one static attachment.

If you want to add a json to your request as a multipart/form-data using groovy script testStep you can use the follow code:
def jsonStr = "{'id':'test','someValue':'3'}"
def testStep = context.testCase.testSteps["/job/result"]
// set the content for the request
testStep.getHttpRequest().setRequestContent(jsonStr)
// and set the media type
testStep.testRequest.setMediaType('application/json')
// if you want to send as a multipart/form-data then use follow line instead
// testStep.testRequest.setMediaType('multipart/form-data')
This results in a request configured as follows:
Hope it helps,

Have found a solution using https://github.com/jgritman/httpbuilder
def http = new HTTPBuilder(serviceEndPoint)
def scanResultFile = new File(testRunner.testCase.getPropertyValue("ScanResultFile"))
http.request( POST ){ req ->
headers.'Connection' = 'Keep-Alive'
headers.'User-Agent' = 'SoapUI 4.5.1'
requestContentType = 'multipart/form-data'
ByteArrayBody bin = new ByteArrayBody(scanResultFile.readBytes(), "application/octet-stream", "jobResult");
StringBody info = new StringBody(testRunner.testCase.getPropertyValue("JsonScanResult"), "application/json", java.nio.charset.StandardCharsets.UTF_8);
MultipartEntity entity = new MultipartEntity()
entity.addPart("info", info);
entity.addPart("jobResult", bin)
req.entity = entity
}

Related

HTTPBuilder & Session ID

I have the following code to connect to a REST API service, authenticate, retrieve a session ID then make further requests passing the session ID to authenticate. The initial request works and I get a HTTP 200 OK plus the session ID in the response, however when I try to make a second request passing the session ID in the header, I get
Caught: groovyx.net.http.HttpResponseException: Bad Request
I know the script can be written much better with the use of classes and try / catch etc. I am still learning both java and groovy so I start by just trying to do everything within the same class.
Any help much appreciated.
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.URIBuilder
import static groovyx.net.http.Method.POST
import static groovyx.net.http.ContentType.*
def url = 'https://1.1.1.1/web_api/'
def uri = new URIBuilder(url)
String CHKPsid
uri.path = 'login'
def http = new HTTPBuilder(uri)
http.ignoreSSLIssues()
http.request(POST,JSON ) { req ->
headers.'Content-Type' = 'application/json'
body = [
"user":"username",
"password":"password"
]
response.success = { resp, json ->
println (json)
CHKPsid = (json.sid)
println "POST Success: ${resp.statusLine}"
}
}
uri.path = 'show-changes'
http.request(POST,JSON ) { req ->
headers.'Content-Type' = 'application/json'
headers.'X-chkp-sid' = '${CHKPsid}'
body = [
"from-date" : "2017-02-01T08:20:50",
"to-date" : "2017-10-21"
]
response.success = { resp, json ->
println (json)
println "POST Success: ${resp.statusLine}"
}
}
String interpolation does not work with single (or triple single quotes). When groovy will evaluate '${CHKPsid}' (single quotes), its value will be ${CHKPsid} (this string). In order to use the value of the variable, you should use double quotes: "${CHKPsid}" or simply just the variable: headers.'X-chkp-sid' = CHKPsid.
So the output of this:
String CHKPsid = "abc123"
println '${CHKPsid}'
println "${CHKPsid}"
will be:
${CHKPsid}
abc123
In order to quickly test what the server receives, you can use httpbin.org or requestb.in
So as well as the correct assignment of the value of the session ID, I found that calling the same HTTPbuilder - http.request the second time even with a change of uri, header and body was the problem. The listening server still saw this as part of the same login API call. My workaround / resolution was to define a 2nd HTTPbuilder with a different name and this now works. I'm interested to know if this is normal behaviour and how others approach this. Thanks.

Is it safe to reuse Groovy HTTPBuilder objects for multiple requests?

I have some HTTPBuilder code that behaves differently depending on whether or not I reuse the same HTTPBuilder object to perform two different requests to the same REST service:
def http = new HTTPBuilder( 'https://myBaseURI/' )
http.auth.basic username, password.getPlainText()
http.ignoreSSLIssues()
http.request(GET,JSON) { req ->
uri.path = 'some/api/path/'
headers.'User-Agent' = 'Mozilla/5.0'
} // this request always behaves as expected
http.request(POST, JSON) { req ->
uri.path = 'some/other/api/path'
headers.'User-Agent' = 'Mozilla/5.0'
body = {
// Request body elided for brevity
}
}
The 'correct' behavior is for the POST to return a 201 - Created, but the response comes back as 200 OK unless I create a new HTTPBuilder to handle issuing the second request, in which case, the API call behaves as expected.
Certainly, the cause of the different results could be elsewhere, but I first wanted to make sure I wasn't misusing this object. Are there problems to be aware of when reusing the HTTPBuilder to issue multiple HTTP requests?
Try removing that forward slash at the end when you set uri.path in the GET request.
Looking at the documentation for setPath in URIBuilder you get:
//Set the path component of this URI. The value may be absolute or relative to the current path. e.g.
def uri = new URIBuilder( 'http://localhost/p1/p2?a=1' )
uri.path = '/p3/p2'
assert uri.toString() == 'http://localhost/p3/p2?a=1'
uri.path = 'p2a'
assert uri.toString() == 'http://localhost/p3/p2a?a=1'
uri.path = '../p4'
assert uri.toString() == 'http://localhost/p4?a=1&b=2&c=3#frag'
I understand this to mean that if you set the uri.path of an httpbuilder object with a slash at the end, you have essentially updated the working path so any subsequent relative path updates to uri.path will result in a concatenation of the path. Therefore, your POST in that example ends up pointing at https://myBaseURI/some/api/path/some/other/api/path

ServiceStack - Switch off Snapshot

I've followed instructions on how creating a ServiceStack here at:
https://github.com/ServiceStack/ServiceStack/wiki/Create-your-first-webservice
I'm sure I have followed it to the letter, but as soon as I run the web application. I get a 'Snapshot' view of my response. I understand this happens when I don't have a default view/webpage. I set up the project as a ASP.net website, not a ASP.net MVC website. Could that be the problem?
I also wrote a test console application with the following C# code. It got the response as a HTML webpage rather than as a plain string e.g. "Hello, John".
static void sendHello()
{
string contents = "john";
string url = "http://localhost:51450/hello/";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentLength = contents.Length;
request.ContentType = "application/x-www-form-urlencoded";
// SEND TO WEBSERVICE
using (StreamWriter writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(contents);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string result = string.Empty;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
Console.WriteLine(result);
}
How can I switch off the 'snapshot' view? What am I doing wrong?
The browser is requesting html so ServiceStack is returning the html snapshot.
There are a couple of ways to stop the snapshot view:
First is to use the ServiceClient classes provided by servicestack. These also have the advantage of doing automatic routing and strongly typing the response DTOs.
Next way would be to set the Accept header of the request to something like application/json or application/xml which would serialize the response into json or xml respectively. This is what the ServiceClients do internally
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
...
Another method would be to add a query string parameter called format and set it to json or xml
string url = "http://localhost:51450/hello/?format=json";
Putting the specific format requesting is the practical way to do this
string url = "http://localhost:51450/hello/?format=json";
I suggest simply deleting this feature.
public override void Configure(Container container)
{
//...
this.Plugins.RemoveAll(p => p is ServiceStack.Formats.HtmlFormat);
//...
}
Now all requests with the Content-Type=text/html will be ignored.

how to pass in paramters to a post request using the servicestack json client

I'm having trouble getting my servicestack json client to format a REST Post request.
I'm trying to post to my login service with a raw json body of
{"Uname":"joe", "Password":"test"}
but the post methods is actually mistakenly sending this
{"login":""}
Here's the code I'm using.
JsonServiceClient.HttpWebRequestFilter = filter =>
{
filter.Headers.Add(string.Format("X-API-Key: {0}", "test"));
};
var client = new JsonServiceClient(url);
var url = "/login";
var login = new LoginModel { Uname = uname, Password = pwd };
return client.Post<UserCredentials>(url, login);
How should I structure the parameter object so that it serializes to the correctly to the intended raw value in the post request? Additionally, can I just pass in a dictionary or a more generic object so that I don't have to create a LoginModel class or struct?
It turns out the issue was that I was using public fields instead of public properties in my LoginModel. Changing it to properties fixed it.

Using Artifactory's REST API to deploy jar file

Given this api documentation, how would I use HTTPBuilder and Groovy to construct my query? I've tried multiple things but I'm not getting it right.
def http = new HTTPBuilder()
http.request('http://artifactory:8888/libs-snapshot-local/my/jar/1.0/test-jar-1.0.jar', PUT, JSON ) { req ->
body = [
uri: "http://artifactory:8888/libs-snapshot-local/my/jar/1.0/test-jar-1.0.jar",
downloadUri: "http://artifactory:8888/libs-snapshot-local/my/jar/1.0/test-jar-1.0.jar",
repo: "libs-snapshot-local",
path: "c:\\pathtojarfile\\test.jar",
created: "2012-02-03T08:37:12.599-0800",
createdBy: "someuser",
size: "1024",
mimeType: "application/java-archive"
]
response.success = { resp, json ->
}
}
This seems to get me part way there, but it uploads an empty jar file. Seems like the body is completely ignored. Removing it produces the same result. I can't seem to find a good reference on how this is done.
The JSON in the mentioned documentation is actually Artifactory's response to the deployment request.
For deployment, Artifactroy requires only a simple PUT request, for example:
def restClient = new RESTClient('http://localhost:8080/artifactory/libs-release-local/')
restClient.auth.basic 'username', 'password'
restClient.encoder.'application/zip' = this.&encodeZipFile
def encodeZipFile(Object data) throws UnsupportedEncodingException {
def entity = new FileEntity((File) data, 'application/zip');
entity.setContentType('application/zip');
return entity
}
def response = restClient.put(path: 'org/artifact/1.0/artifact-1.0.jar',
body: new File('/path/to/local/artifact.jar'),
requestContentType: 'application/zip'
)

Resources