tictoc-savon 0.7.9
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +5 -0
- data/CHANGELOG +176 -0
- data/LICENSE +20 -0
- data/README.rdoc +64 -0
- data/Rakefile +50 -0
- data/lib/savon.rb +35 -0
- data/lib/savon/client.rb +131 -0
- data/lib/savon/core_ext.rb +8 -0
- data/lib/savon/core_ext/array.rb +31 -0
- data/lib/savon/core_ext/datetime.rb +10 -0
- data/lib/savon/core_ext/hash.rb +107 -0
- data/lib/savon/core_ext/net_http.rb +19 -0
- data/lib/savon/core_ext/object.rb +16 -0
- data/lib/savon/core_ext/string.rb +69 -0
- data/lib/savon/core_ext/symbol.rb +8 -0
- data/lib/savon/core_ext/uri.rb +10 -0
- data/lib/savon/logger.rb +56 -0
- data/lib/savon/request.rb +138 -0
- data/lib/savon/response.rb +174 -0
- data/lib/savon/soap.rb +302 -0
- data/lib/savon/version.rb +5 -0
- data/lib/savon/wsdl.rb +137 -0
- data/lib/savon/wsdl_stream.rb +85 -0
- data/lib/savon/wsse.rb +163 -0
- data/spec/basic_spec_helper.rb +11 -0
- data/spec/endpoint_helper.rb +23 -0
- data/spec/fixtures/gzip/gzip_response_fixture.rb +7 -0
- data/spec/fixtures/gzip/message.gz +0 -0
- data/spec/fixtures/response/response_fixture.rb +36 -0
- data/spec/fixtures/response/xml/authentication.xml +14 -0
- data/spec/fixtures/response/xml/multi_ref.xml +39 -0
- data/spec/fixtures/response/xml/soap_fault.xml +8 -0
- data/spec/fixtures/response/xml/soap_fault12.xml +18 -0
- data/spec/fixtures/wsdl/wsdl_fixture.rb +37 -0
- data/spec/fixtures/wsdl/wsdl_fixture.yml +42 -0
- data/spec/fixtures/wsdl/xml/authentication.xml +63 -0
- data/spec/fixtures/wsdl/xml/geotrust.xml +156 -0
- data/spec/fixtures/wsdl/xml/namespaced_actions.xml +307 -0
- data/spec/fixtures/wsdl/xml/no_namespace.xml +115 -0
- data/spec/http_stubs.rb +26 -0
- data/spec/integration/http_basic_auth_spec.rb +16 -0
- data/spec/integration/server.rb +51 -0
- data/spec/savon/client_spec.rb +86 -0
- data/spec/savon/core_ext/array_spec.rb +49 -0
- data/spec/savon/core_ext/datetime_spec.rb +21 -0
- data/spec/savon/core_ext/hash_spec.rb +190 -0
- data/spec/savon/core_ext/net_http_spec.rb +38 -0
- data/spec/savon/core_ext/object_spec.rb +34 -0
- data/spec/savon/core_ext/string_spec.rb +99 -0
- data/spec/savon/core_ext/symbol_spec.rb +12 -0
- data/spec/savon/core_ext/uri_spec.rb +19 -0
- data/spec/savon/request_spec.rb +117 -0
- data/spec/savon/response_spec.rb +179 -0
- data/spec/savon/soap_spec.rb +202 -0
- data/spec/savon/wsdl_spec.rb +107 -0
- data/spec/savon/wsse_spec.rb +132 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +5 -0
- metadata +229 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<definitions name="Api" xmlns:typens="urn:ActionWebService" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="urn:ActionWebService" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns="http://schemas.xmlsoap.org/wsdl/">
|
3
|
+
<types>
|
4
|
+
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:ActionWebService">
|
5
|
+
<xsd:complexType name="MpUser">
|
6
|
+
<xsd:all>
|
7
|
+
<xsd:element name="avatar_thumb_url" type="xsd:string"/>
|
8
|
+
<xsd:element name="speciality" type="xsd:string"/>
|
9
|
+
<xsd:element name="avatar_icon_url" type="xsd:string"/>
|
10
|
+
<xsd:element name="firstname" type="xsd:string"/>
|
11
|
+
<xsd:element name="city" type="xsd:string"/>
|
12
|
+
<xsd:element name="mp_id" type="xsd:int"/>
|
13
|
+
<xsd:element name="lastname" type="xsd:string"/>
|
14
|
+
<xsd:element name="login" type="xsd:string"/>
|
15
|
+
</xsd:all>
|
16
|
+
</xsd:complexType>
|
17
|
+
<xsd:complexType name="MpUserArray">
|
18
|
+
<xsd:complexContent>
|
19
|
+
<xsd:restriction base="soapenc:Array">
|
20
|
+
<xsd:attribute wsdl:arrayType="typens:MpUser[]" ref="soapenc:arrayType"/>
|
21
|
+
</xsd:restriction>
|
22
|
+
</xsd:complexContent>
|
23
|
+
</xsd:complexType>
|
24
|
+
<xsd:complexType name="McContact">
|
25
|
+
<xsd:all>
|
26
|
+
<xsd:element name="last_name" type="xsd:string"/>
|
27
|
+
<xsd:element name="email" type="xsd:string"/>
|
28
|
+
<xsd:element name="mp_id" type="xsd:int"/>
|
29
|
+
<xsd:element name="role" type="xsd:int"/>
|
30
|
+
<xsd:element name="login" type="xsd:string"/>
|
31
|
+
<xsd:element name="first_name" type="xsd:string"/>
|
32
|
+
</xsd:all>
|
33
|
+
</xsd:complexType>
|
34
|
+
<xsd:complexType name="McContactArray">
|
35
|
+
<xsd:complexContent>
|
36
|
+
<xsd:restriction base="soapenc:Array">
|
37
|
+
<xsd:attribute wsdl:arrayType="typens:McContact[]" ref="soapenc:arrayType"/>
|
38
|
+
</xsd:restriction>
|
39
|
+
</xsd:complexContent>
|
40
|
+
</xsd:complexType>
|
41
|
+
</xsd:schema>
|
42
|
+
</types>
|
43
|
+
<message name="GetUserLoginById">
|
44
|
+
<part name="api_key" type="xsd:string"/>
|
45
|
+
<part name="id" type="xsd:int"/>
|
46
|
+
</message>
|
47
|
+
<message name="GetUserLoginByIdResponse">
|
48
|
+
<part name="return" type="xsd:string"/>
|
49
|
+
</message>
|
50
|
+
<message name="GetAllContacts">
|
51
|
+
<part name="api_key" type="xsd:string"/>
|
52
|
+
<part name="login" type="xsd:string"/>
|
53
|
+
</message>
|
54
|
+
<message name="GetAllContactsResponse">
|
55
|
+
<part name="return" type="typens:McContactArray"/>
|
56
|
+
</message>
|
57
|
+
<message name="SearchUser">
|
58
|
+
<part name="api_key" type="xsd:string"/>
|
59
|
+
<part name="phrase" type="xsd:string"/>
|
60
|
+
<part name="page" type="xsd:string"/>
|
61
|
+
<part name="per_page" type="xsd:string"/>
|
62
|
+
</message>
|
63
|
+
<message name="SearchUserResponse">
|
64
|
+
<part name="return" type="typens:MpUserArray"/>
|
65
|
+
</message>
|
66
|
+
<portType name="ApiApiPort">
|
67
|
+
<operation name="GetUserLoginById">
|
68
|
+
<input message="typens:GetUserLoginById"/>
|
69
|
+
<output message="typens:GetUserLoginByIdResponse"/>
|
70
|
+
</operation>
|
71
|
+
<operation name="GetAllContacts">
|
72
|
+
<input message="typens:GetAllContacts"/>
|
73
|
+
<output message="typens:GetAllContactsResponse"/>
|
74
|
+
</operation>
|
75
|
+
<operation name="SearchUser">
|
76
|
+
<input message="typens:SearchUser"/>
|
77
|
+
<output message="typens:SearchUserResponse"/>
|
78
|
+
</operation>
|
79
|
+
</portType>
|
80
|
+
<binding name="ApiApiBinding" type="typens:ApiApiPort">
|
81
|
+
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
|
82
|
+
<operation name="GetUserLoginById">
|
83
|
+
<soap:operation soapAction="/api/api/GetUserLoginById"/>
|
84
|
+
<input>
|
85
|
+
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
|
86
|
+
</input>
|
87
|
+
<output>
|
88
|
+
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
|
89
|
+
</output>
|
90
|
+
</operation>
|
91
|
+
<operation name="GetAllContacts">
|
92
|
+
<soap:operation soapAction="/api/api/GetAllContacts"/>
|
93
|
+
<input>
|
94
|
+
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
|
95
|
+
</input>
|
96
|
+
<output>
|
97
|
+
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
|
98
|
+
</output>
|
99
|
+
</operation>
|
100
|
+
<operation name="SearchUser">
|
101
|
+
<soap:operation soapAction="/api/api/SearchUser"/>
|
102
|
+
<input>
|
103
|
+
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
|
104
|
+
</input>
|
105
|
+
<output>
|
106
|
+
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:ActionWebService" use="encoded"/>
|
107
|
+
</output>
|
108
|
+
</operation>
|
109
|
+
</binding>
|
110
|
+
<service name="ApiService">
|
111
|
+
<port name="ApiApiPort" binding="typens:ApiApiBinding">
|
112
|
+
<soap:address location="http://example.com/api/api"/>
|
113
|
+
</port>
|
114
|
+
</service>
|
115
|
+
</definitions>
|
data/spec/http_stubs.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
FakeWeb.allow_net_connect = false
|
2
|
+
|
3
|
+
# Some WSDL and SOAP request.
|
4
|
+
FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint, :body => WSDLFixture.authentication
|
5
|
+
FakeWeb.register_uri :post, EndpointHelper.soap_endpoint, :body => ResponseFixture.authentication
|
6
|
+
|
7
|
+
# WSDL and SOAP request with a Savon::SOAPFault.
|
8
|
+
FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:soap_fault), :body => WSDLFixture.authentication
|
9
|
+
FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:soap_fault), :body => ResponseFixture.soap_fault
|
10
|
+
|
11
|
+
# WSDL and SOAP request with a Savon::HTTPError.
|
12
|
+
FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:http_error), :body => WSDLFixture.authentication
|
13
|
+
FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:http_error), :body => "", :status => ["404", "Not Found"]
|
14
|
+
|
15
|
+
# WSDL and SOAP request with an invalid endpoint.
|
16
|
+
FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:invalid), :body => ""
|
17
|
+
FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:invalid), :body => "", :status => ["404", "Not Found"]
|
18
|
+
|
19
|
+
# WSDL request returning a WSDL document where the main sections are not namespaced.
|
20
|
+
FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:no_namespace), :body => WSDLFixture.no_namespace
|
21
|
+
|
22
|
+
# WSDL request returning a WSDL document with namespaced SOAP actions.
|
23
|
+
FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:namespaced_actions), :body => WSDLFixture.namespaced_actions
|
24
|
+
|
25
|
+
# WSDL request returning a WSDL document with geotrust SOAP actions.
|
26
|
+
FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:geotrust), :body => WSDLFixture.geotrust
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "basic_spec_helper"
|
2
|
+
|
3
|
+
describe Savon do
|
4
|
+
before { @client = Savon::Client.new "http://localhost:8080/http-basic-auth" }
|
5
|
+
|
6
|
+
it "should be able to handle HTTP basic authentication" do
|
7
|
+
@client.request.basic_auth "user", "password"
|
8
|
+
response = @client.do_something!
|
9
|
+
response.to_hash[:authenticate_response][:return][:success].should == true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should raise a Savon::HTTPError in case authentication failed" do
|
13
|
+
lambda { @client.do_something! }.should raise_error(Savon::HTTPError)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "webrick"
|
2
|
+
|
3
|
+
include WEBrick
|
4
|
+
|
5
|
+
# Run WEBrick. Yields the server to a given block.
|
6
|
+
def run_webrick(config = {})
|
7
|
+
config.update :Port => 8080
|
8
|
+
server = HTTPServer.new config
|
9
|
+
yield server if block_given?
|
10
|
+
["INT", "TERM"].each { |signal| trap(signal) { server.shutdown } }
|
11
|
+
server.start
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the SOAP response fixture for a given +file+.
|
15
|
+
def respond_with(file)
|
16
|
+
response_path = File.dirname(__FILE__) + "/../fixtures/response/xml"
|
17
|
+
File.read "#{response_path}/#{file}.xml"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns HTML links for a given Hash of link URI's and names.
|
21
|
+
def link_to(links)
|
22
|
+
links.map { |link| "<a href='#{link[:uri]}'>#{link[:name]}</a>" }.join("<br>")
|
23
|
+
end
|
24
|
+
|
25
|
+
run_webrick do |server|
|
26
|
+
user, password, realm = "user", "password", "realm"
|
27
|
+
|
28
|
+
htdigest = HTTPAuth::Htdigest.new "/tmp/webrick-htdigest"
|
29
|
+
htdigest.set_passwd realm, user, password
|
30
|
+
authenticator = HTTPAuth::DigestAuth.new :UserDB => htdigest, :Realm => realm
|
31
|
+
|
32
|
+
# Homepage including links to subpages.
|
33
|
+
server.mount_proc("/") do |request, response|
|
34
|
+
response.body = link_to [
|
35
|
+
{ :uri => "http-basic-auth", :name => "HTTP basic auth" },
|
36
|
+
{ :uri => "http-digest-auth", :name => "HTTP digest auth" }
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
# HTTP basic authentication.
|
41
|
+
server.mount_proc("/http-basic-auth") do |request, response|
|
42
|
+
HTTPAuth.basic_auth(request, response, realm) { |u, p| u == user && p == password }
|
43
|
+
response.body = respond_with :authentication
|
44
|
+
end
|
45
|
+
|
46
|
+
# HTTP digest authentication.
|
47
|
+
server.mount_proc("/http-digest-auth") do |request, response|
|
48
|
+
authenticator.authenticate request, response
|
49
|
+
response.body = "HTTP digest authentication successfull"
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Savon::Client do
|
4
|
+
before { @client = Savon::Client.new EndpointHelper.wsdl_endpoint }
|
5
|
+
|
6
|
+
it "should be initialized with an endpoint String" do
|
7
|
+
client = Savon::Client.new EndpointHelper.wsdl_endpoint
|
8
|
+
client.request.http.proxy?.should be_false
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should accept a proxy URI via an optional Hash of options" do
|
12
|
+
client = Savon::Client.new EndpointHelper.wsdl_endpoint, :proxy => "http://proxy"
|
13
|
+
client.request.http.proxy?.should be_true
|
14
|
+
client.request.http.proxy_address == "http://proxy"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should accept a SOAP endpoint via an optional Hash of options" do
|
18
|
+
client = Savon::Client.new EndpointHelper.wsdl_endpoint, :soap_endpoint => "http://localhost"
|
19
|
+
client.wsdl.soap_endpoint.should == "http://localhost"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have a method that returns the Savon::WSDL" do
|
23
|
+
@client.wsdl.should be_a(Savon::WSDL)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have a method that returns the Savon::Request" do
|
27
|
+
@client.request.should be_a(Savon::Request)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should respond to available SOAP actions while behaving as expected otherwise" do
|
31
|
+
WSDLFixture.authentication(:operations).keys.each do |soap_action|
|
32
|
+
@client.respond_to?(soap_action).should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
@client.respond_to?(:object_id).should be_true
|
36
|
+
@client.respond_to?(:some_undefined_method).should be_false
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should dispatch available SOAP calls via method_missing and return the Savon::Response" do
|
40
|
+
@client.authenticate.should be_a(Savon::Response)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should disable the Savon::WSDL when passed a method with an exclamation mark" do
|
44
|
+
@client.wsdl.enabled?.should be_true
|
45
|
+
[:operations, :namespace_uri, :soap_endpoint].each do |method|
|
46
|
+
Savon::WSDL.any_instance.expects(method).never
|
47
|
+
end
|
48
|
+
|
49
|
+
response = @client.authenticate! do |soap|
|
50
|
+
soap.input.should == "authenticate"
|
51
|
+
soap.input.should == "authenticate"
|
52
|
+
end
|
53
|
+
response.should be_a(Savon::Response)
|
54
|
+
@client.wsdl.enabled?.should be_false
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should raise a Savon::SOAPFault in case of a SOAP fault" do
|
58
|
+
client = Savon::Client.new EndpointHelper.wsdl_endpoint(:soap_fault)
|
59
|
+
lambda { client.authenticate! }.should raise_error(Savon::SOAPFault)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should raise a Savon::HTTPError in case of an HTTP error" do
|
63
|
+
client = Savon::Client.new EndpointHelper.wsdl_endpoint(:http_error)
|
64
|
+
lambda { client.authenticate! }.should raise_error(Savon::HTTPError)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should yield an instance of Savon::SOAP to a given block expecting one argument" do
|
68
|
+
@client.authenticate { |soap| soap.should be_a(Savon::SOAP) }
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should yield an instance of Savon::SOAP and Savon::WSSE to a gven block expecting two arguments" do
|
72
|
+
@client.authenticate do |soap, wsse|
|
73
|
+
soap.should be_a(Savon::SOAP)
|
74
|
+
wsse.should be_a(Savon::WSSE)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should have a call method that forwards to method_missing for SOAP actions named after existing methods" do
|
79
|
+
@client.call(:authenticate) { |soap| soap.should be_a(Savon::SOAP) }
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should raise a NoMethodError when the method does not match an available SOAP action or method" do
|
83
|
+
lambda { @client.some_undefined_method }.should raise_error(NoMethodError)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Array do
|
4
|
+
|
5
|
+
describe "to_soap_xml" do
|
6
|
+
it "should return the XML for an Array of Hashes" do
|
7
|
+
array = [{ :name => "adam" }, { :name => "eve" }]
|
8
|
+
result = "<user><name>adam</name></user><user><name>eve</name></user>"
|
9
|
+
|
10
|
+
array.to_soap_xml("user").should == result
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return the XML for an Array of different Objects" do
|
14
|
+
array = [:symbol, "string", 123]
|
15
|
+
result = "<value>symbol</value><value>string</value><value>123</value>"
|
16
|
+
|
17
|
+
array.to_soap_xml("value").should == result
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should default to escape special characters" do
|
21
|
+
array = ["<tag />", "adam & eve"]
|
22
|
+
result = "<value><tag /></value><value>adam & eve</value>"
|
23
|
+
|
24
|
+
array.to_soap_xml("value").should == result
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not escape special characters when told to" do
|
28
|
+
array = ["<tag />", "adam & eve"]
|
29
|
+
result = "<value><tag /></value><value>adam & eve</value>"
|
30
|
+
|
31
|
+
array.to_soap_xml("value", false).should == result
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should add attributes to a given tag" do
|
35
|
+
array = ["adam", "eve"]
|
36
|
+
result = '<value active="true">adam</value><value active="true">eve</value>'
|
37
|
+
|
38
|
+
array.to_soap_xml("value", :escape_xml, :active => true).should == result
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should add attributes to duplicate tags" do
|
42
|
+
array = ["adam", "eve"]
|
43
|
+
result = '<value id="1">adam</value><value id="2">eve</value>'
|
44
|
+
|
45
|
+
array.to_soap_xml("value", :escape_xml, :id => [1, 2]).should == result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe DateTime do
|
4
|
+
before do
|
5
|
+
@datetime = DateTime.new 2012, 03, 22, 16, 22, 33
|
6
|
+
@datetime_string = "2012-03-22T16:22:33Z"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "to_soap_value" do
|
10
|
+
it "should return an xs:dateTime compliant String" do
|
11
|
+
@datetime.to_soap_value.should == @datetime_string
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "to_soap_value!" do
|
16
|
+
it "should act like :to_soap_value" do
|
17
|
+
@datetime.to_soap_value.should == @datetime_string
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
|
5
|
+
describe "find_soap_body" do
|
6
|
+
it "should return the content from the 'soap:Body' element" do
|
7
|
+
soap_body = { "soap:Envelope" => { "soap:Body" => "content" } }
|
8
|
+
soap_body.find_soap_body.should == "content"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return an empty Hash in case the 'soap:Body' element could not be found" do
|
12
|
+
soap_body = { "some_hash" => "content" }
|
13
|
+
soap_body.find_soap_body.should == {}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "to_soap_xml" do
|
18
|
+
describe "should return SOAP request compatible XML" do
|
19
|
+
it "for a simple Hash" do
|
20
|
+
hash, result = { :some => "user" }, "<some>user</some>"
|
21
|
+
hash.to_soap_xml.should == result
|
22
|
+
end
|
23
|
+
|
24
|
+
it "for a nested Hash" do
|
25
|
+
hash, result = { :some => { :new => "user" } }, "<some><new>user</new></some>"
|
26
|
+
hash.to_soap_xml.should == result
|
27
|
+
end
|
28
|
+
|
29
|
+
it "for a Hash with multiple keys" do
|
30
|
+
hash = { :all => "users", :before => "whatever" }
|
31
|
+
hash.to_soap_xml.should include("<all>users</all>", "<before>whatever</before>")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "for a Hash containing an Array" do
|
35
|
+
hash, result = { :some => ["user", "gorilla"] }, "<some>user</some><some>gorilla</some>"
|
36
|
+
hash.to_soap_xml.should == result
|
37
|
+
end
|
38
|
+
|
39
|
+
it "for a Hash containing an Array of Hashes" do
|
40
|
+
hash = { :some => [{ :new => "user" }, { :old => "gorilla" }] }
|
41
|
+
result = "<some><new>user</new></some><some><old>gorilla</old></some>"
|
42
|
+
|
43
|
+
hash.to_soap_xml.should == result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should convert Hash key Symbols to lowerCamelCase" do
|
48
|
+
hash, result = { :find_or_create => "user" }, "<findOrCreate>user</findOrCreate>"
|
49
|
+
hash.to_soap_xml.should == result
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should not convert Hash key Strings" do
|
53
|
+
hash, result = { "find_or_create" => "user" }, "<find_or_create>user</find_or_create>"
|
54
|
+
hash.to_soap_xml.should == result
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should convert DateTime objects to xs:dateTime compliant Strings" do
|
58
|
+
hash = { :before => DateTime.new(2012, 03, 22, 16, 22, 33) }
|
59
|
+
result = "<before>2012-03-22T16:22:33Z</before>"
|
60
|
+
|
61
|
+
hash.to_soap_xml.should == result
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should convert Objects responding to to_datetime to xs:dateTime compliant Strings" do
|
65
|
+
singleton = Object.new
|
66
|
+
def singleton.to_datetime
|
67
|
+
DateTime.new(2012, 03, 22, 16, 22, 33)
|
68
|
+
end
|
69
|
+
|
70
|
+
hash, result = { :before => singleton }, "<before>2012-03-22T16:22:33Z</before>"
|
71
|
+
hash.to_soap_xml.should == result
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should call to_s on Strings even if they respond to to_datetime" do
|
75
|
+
object = "gorilla"
|
76
|
+
object.expects(:to_datetime).never
|
77
|
+
|
78
|
+
hash, result = { :name => object }, "<name>gorilla</name>"
|
79
|
+
hash.to_soap_xml.should == result
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should call to_s on any other Object" do
|
83
|
+
[666, true, false, nil].each do |object|
|
84
|
+
{ :some => object }.to_soap_xml.should == "<some>#{object}</some>"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should default to escape special characters" do
|
89
|
+
result = { :some => { :nested => "<tag />" }, :tag => "<tag />" }.to_soap_xml
|
90
|
+
result.should include("<tag><tag /></tag>")
|
91
|
+
result.should include("<some><nested><tag /></nested></some>")
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should not escape special characters for keys marked with an exclamation mark" do
|
95
|
+
result = { :some => { :nested! => "<tag />" }, :tag! => "<tag />" }.to_soap_xml
|
96
|
+
result.should include("<tag><tag /></tag>")
|
97
|
+
result.should include("<some><nested><tag /></nested></some>")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should preserve the order of Hash keys and values specified through :order!" do
|
101
|
+
hash = { :find_user => { :name => "Lucy", :id => 666, :order! => [:id, :name] } }
|
102
|
+
result = "<findUser><id>666</id><name>Lucy</name></findUser>"
|
103
|
+
hash.to_soap_xml.should == result
|
104
|
+
|
105
|
+
hash = { :find_user => { :mname => "in the", :lname => "Sky", :fname => "Lucy", :order! => [:fname, :mname, :lname] } }
|
106
|
+
result = "<findUser><fname>Lucy</fname><mname>in the</mname><lname>Sky</lname></findUser>"
|
107
|
+
hash.to_soap_xml.should == result
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should raise an error if the :order! Array does not match the Hash keys" do
|
111
|
+
hash = { :name => "Lucy", :id => 666, :order! => [:name] }
|
112
|
+
lambda { hash.to_soap_xml }.should raise_error(ArgumentError)
|
113
|
+
|
114
|
+
hash = { :by_name => { :name => "Lucy", :lname => "Sky", :order! => [:mname, :name] } }
|
115
|
+
lambda { hash.to_soap_xml }.should raise_error(ArgumentError)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should add attributes to Hash keys specified through :attributes!" do
|
119
|
+
hash = { :find_user => { :person => "Lucy", :attributes! => { :person => { :id => 666 } } } }
|
120
|
+
result = '<findUser><person id="666">Lucy</person></findUser>'
|
121
|
+
hash.to_soap_xml.should == result
|
122
|
+
|
123
|
+
hash = { :find_user => { :person => "Lucy", :attributes! => { :person => { :id => 666, :city => "Hamburg" } } } }
|
124
|
+
soap_xml = hash.to_soap_xml
|
125
|
+
soap_xml.should include('id="666"', 'city="Hamburg"')
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should add attributes to duplicate Hash keys specified through :attributes!" do
|
129
|
+
hash = { :find_user => { :person => ["Lucy", "Anna"], :attributes! => { :person => { :id => [1, 3] } } } }
|
130
|
+
result = '<findUser><person id="1">Lucy</person><person id="3">Anna</person></findUser>'
|
131
|
+
hash.to_soap_xml.should == result
|
132
|
+
|
133
|
+
hash = { :find_user => { :person => ["Lucy", "Anna"], :attributes! => { :person => { :active => "true" } } } }
|
134
|
+
result = '<findUser><person active="true">Lucy</person><person active="true">Anna</person></findUser>'
|
135
|
+
hash.to_soap_xml.should == result
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "map_soap_response" do
|
140
|
+
it "should convert Hash key Strings to snake_case Symbols" do
|
141
|
+
soap_response = { "userResponse" => { "accountStatus" => "active" } }
|
142
|
+
result = { :user_response => { :account_status => "active" } }
|
143
|
+
|
144
|
+
soap_response.map_soap_response.should == result
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should strip namespaces from Hash keys" do
|
148
|
+
soap_response = { "ns:userResponse" => { "ns2:id" => "666" } }
|
149
|
+
result = { :user_response => { :id => "666" } }
|
150
|
+
|
151
|
+
soap_response.map_soap_response.should == result
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should convert Hash keys and values in Arrays" do
|
155
|
+
soap_response = { "response" => [{ "name" => "dude" }, { "name" => "gorilla" }] }
|
156
|
+
result = { :response=> [{ :name => "dude" }, { :name => "gorilla" }] }
|
157
|
+
|
158
|
+
soap_response.map_soap_response.should == result
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should convert xsi:nil values to nil Objects" do
|
162
|
+
soap_response = { "userResponse" => { "xsi:nil" => "true" } }
|
163
|
+
result = { :user_response => nil }
|
164
|
+
|
165
|
+
soap_response.map_soap_response.should == result
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should convert Hash values matching the xs:dateTime format into DateTime Objects" do
|
169
|
+
soap_response = { "response" => { "at" => "2012-03-22T16:22:33" } }
|
170
|
+
result = { :response => { :at => DateTime.new(2012, 03, 22, 16, 22, 33) } }
|
171
|
+
|
172
|
+
soap_response.map_soap_response.should == result
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should convert Hash values matching 'true' to TrueClass" do
|
176
|
+
soap_response = { "response" => { "active" => "false" } }
|
177
|
+
result = { :response => { :active => false } }
|
178
|
+
|
179
|
+
soap_response.map_soap_response.should == result
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should convert Hash values matching 'false' to FalseClass" do
|
183
|
+
soap_response = { "response" => { "active" => "true" } }
|
184
|
+
result = { :response => { :active => true } }
|
185
|
+
|
186
|
+
soap_response.map_soap_response.should == result
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|