I need to grab a data from XML-RPC web-service.
new XmlSlurper().parse("http://host/service") works fine, but now I have a particular service that requires basic HTTP authentication.
How can I set username and password for parse() method, or modify HTTP headers of the request?
Using http://username:password#host/service doesn't help - I still get java.io.IOException: Server returned HTTP response code: 401 for URL exception.
Thanks
I found this code over here which might help?
Editing this code to your situation, we get:
def addr = "http://host/service"
def authString = "username:password".getBytes().encodeBase64().toString()
def conn = addr.toURL().openConnection()
conn.setRequestProperty( "Authorization", "Basic ${authString}" )
if( conn.responseCode == 200 ) {
def feed = new XmlSlurper().parseText( conn.content.text )
// Work with the xml document
} else {
println "Something bad happened."
println "${conn.responseCode}: ${conn.responseMessage}"
}
This will work for you
Please remember to use this instead of the 'def authString' mentioned above:
def authString = "${usr}:${pwd}".getBytes().encodeBase64().toString()
Related
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
I am very new to use SoapUI. Writing test cases for my project APIs.
My requirement is to run a groovy script after an API call and if the response text of this API is "true", another API should call.
I found myself stuck to do this. Can anyone guide me to do this.
Thanks in advance!!!
I found answer but forgot to inform over here. I did asserted an script like this in TestStep:
def slurper = new groovy.json.JsonSlurper()
def responseJson = slurper.parseText(messageExchange.getResponseContent())
assert responseJson instanceof Map
assert responseJson.containsKey('authToken')
def id = "Bearer "+responseJson['authToken']
log.info(id.toString())
testRunner = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner(context.testCase.testSuite.project.getTestSuiteByName("TestSuite").getTestCaseByName("TestCas"), null)
def tcase = testRunner.testCase
def tstep = tcase.getTestStepByName("TestStep")
testContext = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext(tstep)
runner = tstep.run(testRunner, testContext)
Little idea for this :
def response = context.expand( '${TestRequest1#Response}' )
if ( response == 'true' )
{
testRunner.runTestStepByName( "TestRequest2")
}
Disable your first test Step(TestRequest1).
I wonder how to call REST API from a (groovy) Jenkins workflow script. I can execute "sh 'curl -X POST ...'" - it works, but building the request as a curl command is cumbersome and processing the response gets complicated. I'd prefer a native Groovy HTTP Client to program in groovy - which one should I start with? As the script is run in Jenkins, there is the step of copying all needed dependency jars to the groovy installation on Jenkins, so something light-weight would be appreciated.
Native Groovy Code without importing any packages:
// GET
def get = new URL("https://httpbin.org/get").openConnection();
def getRC = get.getResponseCode();
println(getRC);
if(getRC.equals(200)) {
println(get.getInputStream().getText());
}
// POST
def post = new URL("https://httpbin.org/post").openConnection();
def message = '{"message":"this is a message"}'
post.setRequestMethod("POST")
post.setDoOutput(true)
post.setRequestProperty("Content-Type", "application/json")
post.getOutputStream().write(message.getBytes("UTF-8"));
def postRC = post.getResponseCode();
println(postRC);
if(postRC.equals(200)) {
println(post.getInputStream().getText());
}
There is a built in step available that is using Jenkins HTTP Request Plugin to make http requests.
Plugin: https://wiki.jenkins-ci.org/display/JENKINS/HTTP+Request+Plugin
Step documentation: https://jenkins.io/doc/pipeline/steps/http_request/#httprequest-perform-an-http-request-and-return-a-response-object
Example from the plugin github page:
def response = httpRequest "http://httpbin.org/response-headers?param1=${param1}"
println('Status: '+response.status)
println('Response: '+response.content)
I had trouble installing the HTTPBuilder library, so I ended up using the more basic URL class to create an HttpUrlConnection.
HttpResponse doGetHttpRequest(String requestUrl){
URL url = new URL(requestUrl);
HttpURLConnection connection = url.openConnection();
connection.setRequestMethod("GET");
//get the request
connection.connect();
//parse the response
HttpResponse resp = new HttpResponse(connection);
if(resp.isFailure()){
error("\nGET from URL: $requestUrl\n HTTP Status: $resp.statusCode\n Message: $resp.message\n Response Body: $resp.body");
}
this.printDebug("Request (GET):\n URL: $requestUrl");
this.printDebug("Response:\n HTTP Status: $resp.statusCode\n Message: $resp.message\n Response Body: $resp.body");
return resp;
}
/**
* Posts the json content to the given url and ensures a 200 or 201 status on the response.
* If a negative status is returned, an error will be raised and the pipeline will fail.
*/
HttpResponse doPostHttpRequestWithJson(String json, String requestUrl){
return doHttpRequestWithJson(json, requestUrl, "POST");
}
/**
* Posts the json content to the given url and ensures a 200 or 201 status on the response.
* If a negative status is returned, an error will be raised and the pipeline will fail.
*/
HttpResponse doPutHttpRequestWithJson(String json, String requestUrl){
return doHttpRequestWithJson(json, requestUrl, "PUT");
}
/**
* Post/Put the json content to the given url and ensures a 200 or 201 status on the response.
* If a negative status is returned, an error will be raised and the pipeline will fail.
* verb - PUT or POST
*/
HttpResponse doHttpRequestWithJson(String json, String requestUrl, String verb){
URL url = new URL(requestUrl);
HttpURLConnection connection = url.openConnection();
connection.setRequestMethod(verb);
connection.setRequestProperty("Content-Type", "application/json");
connection.doOutput = true;
//write the payload to the body of the request
def writer = new OutputStreamWriter(connection.outputStream);
writer.write(json);
writer.flush();
writer.close();
//post the request
connection.connect();
//parse the response
HttpResponse resp = new HttpResponse(connection);
if(resp.isFailure()){
error("\n$verb to URL: $requestUrl\n JSON: $json\n HTTP Status: $resp.statusCode\n Message: $resp.message\n Response Body: $resp.body");
}
this.printDebug("Request ($verb):\n URL: $requestUrl\n JSON: $json");
this.printDebug("Response:\n HTTP Status: $resp.statusCode\n Message: $resp.message\n Response Body: $resp.body");
return resp;
}
class HttpResponse {
String body;
String message;
Integer statusCode;
boolean failure = false;
public HttpResponse(HttpURLConnection connection){
this.statusCode = connection.responseCode;
this.message = connection.responseMessage;
if(statusCode == 200 || statusCode == 201){
this.body = connection.content.text;//this would fail the pipeline if there was a 400
}else{
this.failure = true;
this.body = connection.getErrorStream().text;
}
connection = null; //set connection to null for good measure, since we are done with it
}
}
And then I can do a GET with something like:
HttpResponse resp = doGetHttpRequest("http://some.url");
And a PUT with JSON data using something like:
HttpResponse resp = this.doPutHttpRequestWithJson("{\"propA\":\"foo\"}", "http://some.url");
Have you tried Groovy's HTTPBuilder Class?
For example:
#Grapes(
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7.1')
)
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
def http = new HTTPBuilder("http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo")
http.request(POST, JSON ) { req ->
body = []
response.success = { resp, reader ->
println "$resp.statusLine Respond rec"
}
}
Blocking the main thread on I/O calls is not a good idea.
Delegating the I/O operation to a shell step is the recommended way currently.
The other way, which requires development, is to add a new step. By the way, there is an initiative to add a common set of steps to be used securely inside the pipeline script, although a full REST client owes its own plugin.
Do a GET with the Basic Auth header.
def accessToken = "ACCESS_TOKEN".bytes.encodeBase64().toString()
def req = new URL("https://raw.githubusercontent.com/xxxx/something/hosts").openConnection();
req.setRequestProperty("Authorization", "Basic " + accessToken)
def content = req.getInputStream().getText()
I have the following code in groovy:
def http = new HTTPBuilder( 'http://localhost:8080' )
http.post( path: '/this/is/my/path/'+variable) { resp ->
println "POST Success: ${resp.statusLine}"
assert resp.statusLine.statusCode == 200
}
I only want to execute that request. I have a method in another application that when there is a request in that url, I see a result. Problem is that I see nothing.
What might be the problem?
Most likely, your application only responds to GET request and not to POST requests. Try GET instead:
def http = new HTTPBuilder( 'http://localhost:8080' )
http.get( path: '/this/is/my/path/'+variable) { resp ->
println "GET Success: ${resp.statusLine}"
assert resp.statusLine.statusCode == 200
}
Also, are you sure that you expect a HTTP status 201 (Created) at this URL?
Could try just opening a simple HttpURLConnection like this:
URL url = new URL("http://localhost:8080/this/is/my/path/${variable}")
HttpURLConnection connection = url.openConnection()
println "responseCode: ${connection.responseCode}"
assert connection.responseCode == 200
I am using groovy RESTClient 0.6 to make a POST request. I expect an XML payload in the response. I have the following code:
def restclient = new RESTClient('<some URL>')
def headers= ["Content-Type": "application/xml"]
def body= getClass().getResource("/new_resource.xml").text
/*
If I omit the closure from the following line of code
RESTClient blows up with an NPE..BUG?
*/
def response = restclient.post(
path:'/myresource', headers:headers, body:body){it}
println response.status //prints correct response code
println response.headers['Content-Length']//prints 225
println response.data //Always null?!
The response.data is always null, even though when I try the same request using Google chrome's postman client, I get back the expected response body. Is this a known issue with RESTClient?
The HTTP Builder documentation says that data is supposed to contain the parsed response content but, as you've discovered, it just doesn't. You can, however, get the parsed response content from the reader object. The easiest, most consistent way I've found of doing this is to set the default success and failure closures on your RESTClient object like so:
def restClient = new RESTClient()
restClient.handler.failure = { resp, reader ->
[response:resp, reader:reader]
}
restClient.handler.success = { resp, reader ->
[response:resp, reader:reader]
}
You'll get the same thing on success and failure: a Map containing the response (which is an instance of HttpResponseDecorator) and the reader (the type of which will be determined by the content of the response body).
You can then access the response and reader thusly:
def map = restClient.get([:]) // or POST, OPTIONS, etc.
def response = map['response']
def reader = map['reader']
assert response.status == 200
I faced a similar issue and I took the cue from Sams solution but used closures to address it (similar solution but coded using closures instead of the returned object).
resp.data is always null when using the RESTClient, however the reader contains the data, so it would look something like this:
def restclient = new RESTClient('<some URL>')
def headers= ["Content-Type": "application/xml"]
def body= getClass().getResource("/new_resource.xml").text
try {
restclient.post(path:'/myresource', headers:headers, body:body) { resp, reader ->
resp.status // Status Integer
resp.contentType // Content type String
resp.headers // Map of headers
resp.data // <-- ALWAYS null (the bug you faced)
reader // <-- Data you're looking for
}
} catch (Exception e) {
e.response.status // Get HTTP error status Integer
}