Permalink
Browse files

Merge pull request #542 from ashrocket/default_form_value

Savon 3 sets the correct value for 'form' attribute 'qualified' 'unqualified'

This fixes a regression in Savon v3
  • Loading branch information...
tjarratt committed Jan 28, 2014
2 parents 3fa5293 + 0fdaeda commit f47b5c6346bb05ce5ae3ea9d738d9987bcc5c517
Showing with 306 additions and 2 deletions.
  1. +1 −0 CHANGELOG.md
  2. +7 −2 lib/savon/xs/types.rb
  3. +156 −0 spec/fixtures/wsdl/jetairways.wsdl
  4. +142 −0 spec/integration/jetairways_spec.rb
View
@@ -1,4 +1,5 @@
## 3.0.0 (branch)
+* Fix: [#539] (https://github.com/savonrb/savon/issues/539) Implement element form 'qualified' or 'unqualified' correctly
* This version requires Ruby 1.9.2 or higher. Ruby 1.8 is no longer supported!
View
@@ -66,15 +66,20 @@ def initialize(node, schemas, schema = {})
@element_form_default = schema[:element_form_default]
@name = node['name']
- @form = node['form'] || 'unqualified'
+ # Because you've overriden the form method, you don't need to set
+ # unqualified as the default when no form is specified.
+ #@form = node['form'] || 'unqualified'
+ @form = node['form']
@namespaces = node.namespaces
end
attr_reader :name, :form, :namespace, :namespaces
def form
- if @form == 'qualified' || @element_form_default == 'qualified'
+ if @form
+ @form
+ elsif @element_form_default == 'qualified'
'qualified'
else
'unqualified'
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://www.vedaleon.com/webservices" xmlns:s1="http://www.ebxml.org/namespaces/messageHeader" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:s2="http://schemas.xmlsoap.org/ws/2002/12/secext" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://www.vedaleon.com/webservices" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
+ <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Vedaleon Web Services</wsdl:documentation>
+ <wsdl:types>
+ <s:schema elementFormDefault="qualified" targetNamespace="http://www.vedaleon.com/webservices">
+ <s:element name="Logon">
+ <s:complexType />
+ </s:element>
+ <s:element name="LogonResponse">
+ <s:complexType>
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="LogonResult" type="s:string" />
+ </s:sequence>
+ </s:complexType>
+ </s:element>
+ </s:schema>
+ <s:schema elementFormDefault="qualified" targetNamespace="http://www.ebxml.org/namespaces/messageHeader">
+ <s:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <s:element name="MessageHeader" type="s1:MessageHeader" />
+ <s:complexType name="MessageHeader">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="From" type="s1:From" />
+ <s:element minOccurs="0" maxOccurs="1" name="To" type="s1:To" />
+ <s:element minOccurs="0" maxOccurs="1" name="CPAId" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="ConversationId" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Service" type="s1:Service" />
+ <s:element minOccurs="0" maxOccurs="1" name="Action" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="MessageData" type="s1:MessageData" />
+ <s:element minOccurs="0" maxOccurs="1" name="DuplicateElimination" />
+ <s:element minOccurs="0" maxOccurs="unbounded" name="Description" type="s1:Description" />
+ </s:sequence>
+ <s:attribute form="qualified" name="id" type="s:ID" />
+ <s:attribute form="qualified" name="version" type="s:string" />
+ <s:anyAttribute />
+ </s:complexType>
+ <s:complexType name="From">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="unbounded" name="PartyId" type="s1:PartyId" />
+ <s:element minOccurs="0" maxOccurs="1" name="Role" type="s:string" />
+ </s:sequence>
+ </s:complexType>
+ <s:complexType name="PartyId">
+ <s:simpleContent>
+ <s:extension base="s:string">
+ <s:attribute form="qualified" name="type" type="s:string" />
+ </s:extension>
+ </s:simpleContent>
+ </s:complexType>
+ <s:complexType name="To">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="unbounded" name="PartyId" type="s1:PartyId" />
+ <s:element minOccurs="0" maxOccurs="1" name="Role" type="s:string" />
+ </s:sequence>
+ </s:complexType>
+ <s:complexType name="Service">
+ <s:simpleContent>
+ <s:extension base="s:string">
+ <s:attribute form="qualified" name="type" type="s:string" />
+ </s:extension>
+ </s:simpleContent>
+ </s:complexType>
+ <s:complexType name="MessageData">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="MessageId" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Timestamp" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="RefToMessageId" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="TimeToLive" type="s:dateTime" />
+ </s:sequence>
+ </s:complexType>
+ <s:complexType name="Description">
+ <s:simpleContent>
+ <s:extension base="s:string">
+ <s:attribute ref="xml:lang" use="optional" />
+ </s:extension>
+ </s:simpleContent>
+ </s:complexType>
+ </s:schema>
+ <s:schema elementFormDefault="qualified" targetNamespace="http://schemas.xmlsoap.org/ws/2002/12/secext">
+ <s:element name="Security" type="s2:Security" />
+ <s:complexType name="Security">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="UsernameToken" type="s2:SecurityUsernameToken" />
+ <s:element minOccurs="0" maxOccurs="1" name="BinarySecurityToken" type="s:string" />
+ </s:sequence>
+ <s:anyAttribute />
+ </s:complexType>
+ <s:complexType name="SecurityUsernameToken">
+ <s:sequence>
+ <s:element minOccurs="0" maxOccurs="1" name="Username" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" name="Password" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" form="unqualified" name="Organization" type="s:string" />
+ <s:element minOccurs="0" maxOccurs="1" form="unqualified" name="Domain" type="s:string" />
+ </s:sequence>
+ </s:complexType>
+ </s:schema>
+ </wsdl:types>
+ <wsdl:message name="LogonSoapIn">
+ <wsdl:part name="parameters" element="tns:Logon" />
+ </wsdl:message>
+ <wsdl:message name="LogonSoapOut">
+ <wsdl:part name="parameters" element="tns:LogonResponse" />
+ </wsdl:message>
+ <wsdl:message name="LogonMessageHeader">
+ <wsdl:part name="MessageHeader" element="s1:MessageHeader" />
+ </wsdl:message>
+ <wsdl:message name="LogonSecurity">
+ <wsdl:part name="Security" element="s2:Security" />
+ </wsdl:message>
+ <wsdl:portType name="SessionCreateSoap">
+ <wsdl:operation name="Logon">
+ <wsdl:input message="tns:LogonSoapIn" />
+ <wsdl:output message="tns:LogonSoapOut" />
+ </wsdl:operation>
+ </wsdl:portType>
+ <wsdl:binding name="SessionCreateSoap" type="tns:SessionCreateSoap">
+ <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="Logon">
+ <soap:operation soapAction="http://www.vedaleon.com/webservices/Logon" style="document" />
+ <wsdl:input>
+ <soap:body use="literal" />
+ <soap:header message="tns:LogonMessageHeader" part="MessageHeader" use="literal" />
+ <soap:header message="tns:LogonSecurity" part="Security" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap:body use="literal" />
+ <soap:header message="tns:LogonMessageHeader" part="MessageHeader" use="literal" />
+ <soap:header message="tns:LogonSecurity" part="Security" use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:binding name="SessionCreateSoap12" type="tns:SessionCreateSoap">
+ <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
+ <wsdl:operation name="Logon">
+ <soap12:operation soapAction="http://www.vedaleon.com/webservices/Logon" style="document" />
+ <wsdl:input>
+ <soap12:body use="literal" />
+ <soap12:header message="tns:LogonMessageHeader" part="MessageHeader" use="literal" />
+ <soap12:header message="tns:LogonSecurity" part="Security" use="literal" />
+ </wsdl:input>
+ <wsdl:output>
+ <soap12:body use="literal" />
+ <soap12:header message="tns:LogonMessageHeader" part="MessageHeader" use="literal" />
+ <soap12:header message="tns:LogonSecurity" part="Security" use="literal" />
+ </wsdl:output>
+ </wsdl:operation>
+ </wsdl:binding>
+ <wsdl:service name="SessionCreate">
+ <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Vedaleon Web Services</wsdl:documentation>
+ <wsdl:port name="SessionCreateSoap" binding="tns:SessionCreateSoap">
+ <soap:address location="http://USE_ADDRESS_RETURNED_BY_LOCATION_SERVICE/jettaobeapi/SessionCreate.asmx" />
+ </wsdl:port>
+ <wsdl:port name="SessionCreateSoap12" binding="tns:SessionCreateSoap12">
+ <soap12:address location="http://USE_ADDRESS_RETURNED_BY_LOCATION_SERVICE/jettaobeapi/SessionCreate.asmx" />
+ </wsdl:port>
+ </wsdl:service>
+</wsdl:definitions>
@@ -0,0 +1,142 @@
+require 'spec_helper'
+
+describe 'Integration with Jetairways\'s SessionCreate Service' do
+
+ subject(:client) { Savon.new fixture('wsdl/jetairways') }
+
+
+
+ let(:service_name) { :SessionCreate }
+ let(:port_name) { :SessionCreateSoap }
+
+ it 'returns a map of services and ports' do
+ expect(client.services).to eq(
+ 'SessionCreate'=> {
+ :ports=> {
+ 'SessionCreateSoap'=> {
+ :type=>'http://schemas.xmlsoap.org/wsdl/soap/',
+ # symbolic endpoint
+ :location=>'http://USE_ADDRESS_RETURNED_BY_LOCATION_SERVICE/jettaobeapi/SessionCreate.asmx'
+ },
+ 'SessionCreateSoap12'=>{
+ :type=>'http://schemas.xmlsoap.org/wsdl/soap12/',
+ # symbolic endpoint
+ :location=>'http://USE_ADDRESS_RETURNED_BY_LOCATION_SERVICE/jettaobeapi/SessionCreate.asmx'
+ }
+ }
+ }
+ )
+ end
+
+ it 'knows the operations' do
+ operation = client.operation(service_name, port_name, :Logon)
+
+ expect(operation.soap_action).to eq('http://www.vedaleon.com/webservices/Logon')
+ expect(operation.endpoint).to eq('http://USE_ADDRESS_RETURNED_BY_LOCATION_SERVICE/jettaobeapi/SessionCreate.asmx')
+
+ namespace = 'http://www.vedaleon.com/webservices'
+
+ expect(operation.body_parts).to eq([
+ [['Logon'], { namespace: namespace, form: 'qualified', singular: true }]
+ ])
+ end
+
+ # multiple implicit headers. reference: http://www.ibm.com/developerworks/library/ws-tip-headers/index.html
+ it 'creates an example header' do
+ operation = client.operation(service_name, port_name, :Logon)
+
+ expect(operation.example_header).to eq(
+ MessageHeader:
+ {From: {PartyId: [{}], Role: 'string'},
+ To: {PartyId: [{}], Role: 'string'},
+ CPAId: 'string',
+ ConversationId: 'string',
+ Service: {},
+ Action: 'string',
+ MessageData:
+ {MessageId: 'string',
+ Timestamp: 'string',
+ RefToMessageId: 'string',
+ TimeToLive: 'dateTime'},
+ DuplicateElimination: {},
+ Description: [{}],
+ _id: 's:ID',
+ _version: 's:string'},
+ Security:
+ {UsernameToken:
+ {Username: 'string',
+ Password: 'string',
+ Organization: 'string',
+ Domain: 'string'},
+ BinarySecurityToken: 'string'}
+ )
+ end
+
+ it 'creates an example body' do
+ operation = client.operation(service_name, port_name, :Logon)
+
+ expect(operation.example_body).to eq(
+ Logon:{}
+ )
+ end
+
+ it 'creates a request with multiple headers' do
+ operation = client.operation(service_name, port_name, :Logon)
+
+ operation.header =
+ {
+ MessageHeader:
+ {CPAId:"9W",
+ ConversationId:"1",
+ Service:{Service:"Create"},
+ Action:"CreateSession",
+ MessageData:
+ {MessageId:"0",
+ Timestamp:"2014-02-01T12:57:12.000Z"}
+ },
+ Security:
+ { UsernameToken: {
+ Username: 'example_user',
+ Password: 'my_secret',
+ Organization: 'example_organization'}
+
+ }
+ }
+ operation.body =
+ {Logon:{}}
+
+ expected = Nokogiri.XML('
+ <env:Envelope
+ xmlns:lol0="http://www.ebxml.org/namespaces/messageHeader"
+ xmlns:lol1="http://schemas.xmlsoap.org/ws/2002/12/secext"
+ xmlns:lol2="http://www.vedaleon.com/webservices"
+ xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
+ <env:Header>
+ <lol0:MessageHeader>
+ <lol0:CPAId>9W</lol0:CPAId>
+ <lol0:ConversationId>1</lol0:ConversationId>
+ <lol0:Service>Create</lol0:Service>
+ <lol0:Action>CreateSession</lol0:Action>
+ <lol0:MessageData>
+ <lol0:MessageId>0</lol0:MessageId>
+ <lol0:Timestamp>2014-02-01T12:57:12.000Z</lol0:Timestamp>
+ </lol0:MessageData>
+ </lol0:MessageHeader>
+ <lol1:Security>
+ <lol1:UsernameToken>
+ <lol1:Username>example_user</lol1:Username>
+ <lol1:Password>my_secret</lol1:Password>
+ <Organization>example_organization</Organization>
+ </lol1:UsernameToken>
+ </lol1:Security>
+ </env:Header>
+ <env:Body>
+ <lol2:Logon/>
+ </env:Body>
+ ')
+
+ expect(Nokogiri.XML operation.build).
+ to be_equivalent_to(expected).respecting_element_order
+ end
+
+end

0 comments on commit f47b5c6

Please sign in to comment.