Testing Soap 1.2 service in RobotFramework using suds library - soap

I am trying to test soap 1.2 services using RobotFramework. So far, we have only tested soap 1.1 services using suds library for RobotFramework, and suds is not compatible with soap 1.2.
Backwards compatibility is an option for the new services, but it would be better to have a more long-term solution. I am not an experienced programmer, though I can edit code if told what to edit and where.
What happens in the test we have for soap 1.2 services using suds is: suds is unable to interpret the response it gets from the webservice and gives this error: SAXParseException: :159:229: mismatched tag
The soap message is fine, there is no problem using it in SoapUI.
I have found some snippets online that suggest I could get suds library to work with soap 1.2 for my RobotFramework tests. But I have little programming experience and no idea how to incorporate those snippets in suds.
Someone commented on this snippet that this fixed his issue with RobotFramework and suds.
Is there someone out there willing to explain how I could make this work? I can't seem to figure it out on my own. Any suggestions would be greatly appreciated.
from suds.client import Client
from suds.bindings import binding
import logging
USERNAME = 'username'
PASSWORD = 'password'
# Just for debugging purposes.
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.DEBUG)
# Telnic's SOAP server expects a SOAP 1.2 envelope, not a SOAP 1.1 envelope
# and will complain if this hack isn't done.
binding.envns = ('SOAP-ENV', 'http://www.w3.org/2003/05/soap-envelope')
client = Client('client.wsdl',
username=USERNAME,
password=PASSWORD,
headers={'Content-Type': 'application/soap+xml'})
# This will now work just fine.
client.service.someRandomMethod()
snippet from: https://gist.github.com/kgaughan/858851

In short Suds does not support SOAP 1.2 bindings. Development has ceased quite some time ago. For this reason the SudsLibrary does not support it either.
Some of the differences I observed using an example service SOAP 1.1/1.2 are:
HTTP header Content-Type:
1.2 = "application/soap+xml"
1.1 = "text/xml".
HTTP header
1.2 = Action
1.1 = SOAPAction
Envelope Namespace
1.2 = "http://www.w3.org/2003/05/soap-envelope"
1.1 = "http://schemas.xmlsoap.org/soap/envelope/"
For each of these a seperate solution was implemented in the example below. The content type could be overwritten. The Action can be added but the SOAPAction can not be removed. The namespace can also be overwritten using the extension library. This should work for you if your service ignores the SOAPaction header attribute.
Test Case.robot
*** Settings ***
Library SudsLibrary
Library SudsLibraryExtension
Library Collections
*** Test Cases ***
TC
${BASE_URL} Set Variable http://www.holidaywebservice.com
${SERVICE} Create Dictionary
... name=HolidayService_v2
... wsdl=HolidayService2.asmx?WSDL
${PORT} Set variable HolidayService2Soap12
${METHOD} Set variable GetCountriesAvailable
Set Binding SOAP-ENV http://www.w3.org/2003/05/soap-envelope
Create Soap Client ${BASE_URL}/${SERVICE.name}/${SERVICE.wsdl}
Set Port ${PORT}
Set Headers Content-Type application/soap+xml
Set Headers Soapaction ${EMPTY}
Set Headers Action "${BASE_URL}/${SERVICE.name}/${METHOD}"
${result} Call Soap Method ${METHOD}
SudsLibraryExtension.py
import suds.bindings
from robot.libraries.BuiltIn import BuiltIn, RobotNotRunningError
class SudsLibraryExtension(object):
"""
Extension on the SudsLibrary
"""
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
ROBOT_LIBRARY_VERSION = 1.0
def __init__(self, LibraryName='SudsLibrary'):
"""SudsLibraryExtension can be imported with an optional argument.
- ``LibraryName``:
Default value for `LibraryName` is SudsLibrary if not given.
The name can by any Library Name that implements or extends the
SudsLibraryExtension.
"""
try:
self.SudsLibrary = BuiltIn().get_library_instance(LibraryName)
# This is useful for when you run Robot in Validation mode or load
# the library in an IDE that automatically retrieves the documen-
# tation from the library.
except RobotNotRunningError:
pass
def set_binding(self, binding, url):
"""Set Binding can be used to add a binding to the message.
Example Set Binding SOAP-ENV http://www.w3.org/2003/05/soap-envelope
"""
suds.bindings.binding.envns = (binding, url)

Related

How can Python's zeep module work against an API manager?

I've used zeep against a SOAP-service, and it works perfectly. However, when this service is placed behind Gravitee API Manager, I'm unable to get it to work any longer, just get a 404 response.
Here's my code :
from zeep import Client, Settings
import base64,sys, logging, traceback
from requests import Session
from zeep.transports import Transport
import requests
from lxml import etree
wsdl= 'https://link_to_service_on_gravitee'
session = Session()
session.verify = False
session.headers['Api-Key']= 'xxxxx'
transport = Transport(session=session)
settings = Settings(raw_response=True, strict=False, xml_huge_tree=True)
client = Client(wsdl, transport=transport, settings=settings)
data = []
data.append(
{'ServerProcessId': 'GL07',
'OrderNumber': 1}
)
cdata = []
cdata.append(
{'Username': 'xxx',
'Client': 'yyy',
'Password': 'zzz'}
)
node = client.create_message(client.service, 'GetResult',input=data, credentials=cdata)
print('*** SOAP Message')
print(etree.tostring(node))
print('*** End SOAP Message')
response = requests.Response()
try:
response = client.service.GetResult(input=data, credentials=cdata)
print(response)
except Exception as e:
print(response.headers)
logging.error(traceback.format_exc())
When I test the message generated by Python (etree.tostring(node)) in SOAPUI, it works correctly. Also, if I alter the api-key, I get an error about authentication problems, so Gravitee seems to accept the key from my code.
But the response I get, with correct api-key, is always [404].
Got it to work when I downloaded the wsdl to a local file, but don't want to do this for every wsdl.
Any ideas ?
There are multiple reasons for getting a 404 from Gravitee:
* Did you create an API
* Did you create a simple plan for this API
* Did you deploy the API to the gateway.
Once all those steps are done, you should be able to consume your API.
Hope it helps,
Regards,

How can I add WS-A adressing to a SOAP webservice-request via Robot Framework?

I am new with Robot Framework and I run into a problem.
I try to call a web service that requires WSA (Web Service Addressing).
I tried sending a request while using SoapUI.
Sending a request via SoapUI provides a <wsa:Action>, a <wsa:RelatesTo> and a <wsa:MessageID> tag in the header when WSA is enabled.
Now I want to do the same with RobotFramework.
How can I inject these same tags via Robot Framework?
Here is my test
*** Settings ***
Library SudsLibrary
Library Collections
Library String
*** Test Cases ***
test
[Tags] blah
Create Soap Client C:${/}Robot WS${/}WS${/}wsdl${/}C60W30A.wsdl
Set Http Authentication MyUID MyPWD
${C60W30A}= Create Wsdl Object ns0:Invoer
${taimen}= Set Soap Headers "wsa:Action" GenBetKenmOperation
Set Wsdl Object Attribute ${C60W30A} Functie 04
Set Wsdl Object Attribute ${C60W30A} Bronsysteem COA
Set Wsdl Object Attribute ${C60W30A} Gebruiker WILLT10
${result}= Call Soap Method GenBetKenmOperation ${C60W30A}
Where the resulting XML is:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.MyCompany.nl/inning/coa/GenererenBetKenmerk" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns0:Body>
<ns1:GenererenBetKenm>
<Invoer>
<Functie>04</Functie>
<Bronsysteem>COA</Bronsysteem>
<Gebruiker>GeBrID</Gebruiker>
</Invoer>
</ns1:GenererenBetKenm>
</ns0:Body>
</SOAP-ENV:Envelope>
And the error:
FAIL : WebFault: Server raised fault: 'A required header representing a Message Addressing Property is not present'
As you can see the <wsa:Action> tag is missing. As wel are the other SOAP-header tags when I add them.

How can i get failed http request details in jmeter via mail?

I am trying to send the mail through jmeter for failed http request, I want to know the sampler details like name of http request?
I have added if controller to check the assertion of previously running request sand send a mail if it fails.It gives me error message
"Message from Jmeter thread # Test failed: code expected to match /200/"
But I want to know the name of http request which has been failed so i can know specifically which request is failing?
You can use JSR223 PreProcessor to get the previous sampler details using the following code:
def sampler = ctx.getPreviousSampler()
Example usage:
def previousSamplerName = ctx.getPreviousSampler().getName()
log.info("Failed sampler name: " + previousSamplerName)
vars.put("SamplerName", previousSamplerName)
Demo:
If everything goes fine you will be able to access previous sampler name as ${SamplerName} in the SMTP Request sampler
ctx is a shorthand to JMeterContext class instance, see the JavaDoc for available methods and fields
vars is a shorthand to JMeterVariables class instance, it provides read/write access to all JMeter Variables in scope.
Also check out Groovy Is the New Black guide to get familiarized with using Groovy in JMeter tests.

GWTTestCase - HTMLUnit - No permitted "Access-Control-Allow-Origin"

When running GWTTestCase that call an external Restful service with GWT (Using Restlet-GWT) the app throws the error below.
Error:
Jan 05, 2015 1:24:41 PM com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJobManagerImpl runSingleJob
SEVERE: Job run failed with unexpected RuntimeException: Wrapped java.lang.RuntimeException: No permitted "Access-Control-Allow-Origin" header.
net.sourceforge.htmlunit.corejs.javascript.WrappedException: Wrapped java.lang.RuntimeException: No permitted "Access-Control-Allow-Origin" header.
at net.sourceforge.htmlunit.corejs.javascript.Context.throwAsScriptRuntimeEx(Context.java:1889)
at com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest.doSend(XMLHttpRequest.java:681)
at com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest.access$000(XMLHttpRequest.java:94)
at com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest$1.run(XMLHttpRequest.java:603)
at net.sourceforge.htmlunit.corejs.javascript.Context.call(Context.java:602)
at net.sourceforge.htmlunit.corejs.javascript.ContextFactory.call(ContextFactory.java:507)
at com.gargoylesoftware.htmlunit.javascript.background.JavascriptXMLHttpRequestJob.run(JavascriptXMLHttpRequestJob.java:36)
at com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJobManagerImpl.runSingleJob(JavaScriptJobManagerImpl.java:328)
at com.gargoylesoftware.htmlunit.javascript.background.DefaultJavaScriptExecutor.run(DefaultJavaScriptExecutor.java:162)
at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.RuntimeException: No permitted "Access-Control-Allow-Origin" header.
... 9 more
From my research this seems to be an issue that HTMLUnit would not allow to access Cross-domain, is there a work around with this?
You can add the support of CORS to your application.
A support has been provided in 2.3 release of the Restlet framework (cf http://restlet.com/technical-resources/restlet-framework/guide/2.3/introduction/whats-new/2.3).
If you are using the 2.2 release, and because we won't add this feature to 2.2, you can add the required classes in your own code manually (cf https://github.com/restlet/restlet-framework-java/blob/2.3/modules/org.restlet/src/org/restlet/service/CorsService.java, https://github.com/restlet/restlet-framework-java/blob/2.3/modules/org.restlet/src/org/restlet/engine/application/CorsFilter.java, and https://github.com/restlet/restlet-framework-java/blob/2.3/modules/org.restlet/src/org/restlet/engine/application/CorsResponseHelper.java).
I was stumped by this very same error response but I am not able to refactor the Restlet framework into my client & server codebases.
A couple of tips for handling diagnosis of the problem.
use a proxy or inspect dev tool to record the exact headers within the request and response for both the OPTIONS and GET/POST pairs.
OPTIONS request header "Origin" must match response header "Access-Control-Allow-Origin" exactly. No wildcards. Perhaps write your response to just echo the request like:
response.addHeader("Access-control-allow-origin", request.getHeader("Origin"));
Your request header names must be fully enumerated within the OPTIONS "Access-control-request-headers" header value AND match the "Access-control-Allow-Headers" response header.
Note: that a mismatch in #3 will trigger the same error message as a mismatch in #2.

Camel ReST Proxy route in ServiceMix fails for Base64 uploads

I have deployed on SMX the following route that proxies all ReST request to the real ReST service provider (Tomcat). All ReST calls to SMX routed successfully however a saveDocument service that uploads PDF files fail.
public void configure() throws Exception {
from("jetty:http://{{smx.host}}:{{smx.rest-proxy-port}}/{{smx.context}}matchOnUriPrefix=true")
.log("ReST call received (Java DSL)")
.to("jetty:http://{{real-server-address}}:{{real-ws-port}}/{{context}}?bridgeEndpoint=true&throwExceptionOnFailure=false")
.log("Rest call proxied (Java DSL)");
}
The following exception is logged in servicemix.log.
19:53:57,065 | WARN | HttpClient-137 | HttpExchange | 111 - org.eclipse.jetty.util - 7.5.4.v20111024 | EXCEPTION JettyContentExchange#188af650=POST//real-server-address...:8080/contextpath.../saveDocument#SENDING(3ms)->
EXCEPTED(0ms)sent=3ms java.lang.IndexOutOfBoundsException
Do I have to perform some additional processing on the base64 before redirect the call to the real ReST service?
UPDATE on my previous post.
This seems to work when I use txt file but fails for pdf or doc.
UPDATE 2: It also fails when txt size exceeds 7KB.
Is it possible to set camel jetty to accept big size files?
This can be solved if Multipart WS is used.
I have implemented a Multipart CXF ReST file upload service for testing the route in case of a multipart WS.
The following route works OK for multipart:
from("jetty:http://.../?matchOnUriPrefix=true&enableMultipartFilter=false")
.noStreamCaching()
.log("Service Proxied")
.to("jetty:http://...:../?bridgeEndpoint=true&throwExceptionOnFailure=false");
Still cannot find what is going wrong with the first WS.
The issue is tracked here also.