savon 0.7.9 → 0.8.0.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/.gitignore +9 -0
  2. data/.rspec +1 -0
  3. data/.yardopts +2 -0
  4. data/CHANGELOG.md +332 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +37 -0
  8. data/Rakefile +28 -39
  9. data/autotest/discover.rb +1 -0
  10. data/lib/savon.rb +10 -31
  11. data/lib/savon/client.rb +116 -98
  12. data/lib/savon/core_ext/array.rb +36 -22
  13. data/lib/savon/core_ext/datetime.rb +15 -6
  14. data/lib/savon/core_ext/hash.rb +122 -94
  15. data/lib/savon/core_ext/object.rb +19 -11
  16. data/lib/savon/core_ext/string.rb +62 -57
  17. data/lib/savon/core_ext/symbol.rb +13 -5
  18. data/lib/savon/error.rb +6 -0
  19. data/lib/savon/global.rb +75 -0
  20. data/lib/savon/http/error.rb +42 -0
  21. data/lib/savon/soap.rb +8 -283
  22. data/lib/savon/soap/fault.rb +48 -0
  23. data/lib/savon/soap/request.rb +61 -0
  24. data/lib/savon/soap/response.rb +65 -0
  25. data/lib/savon/soap/xml.rb +132 -0
  26. data/lib/savon/version.rb +2 -2
  27. data/lib/savon/wsdl/document.rb +107 -0
  28. data/lib/savon/wsdl/parser.rb +90 -0
  29. data/lib/savon/wsdl/request.rb +35 -0
  30. data/lib/savon/wsse.rb +42 -104
  31. data/savon.gemspec +26 -0
  32. data/spec/fixtures/response/response_fixture.rb +26 -26
  33. data/spec/fixtures/response/xml/list.xml +18 -0
  34. data/spec/fixtures/wsdl/wsdl_fixture.rb +6 -0
  35. data/spec/fixtures/wsdl/wsdl_fixture.yml +4 -4
  36. data/spec/savon/client_spec.rb +274 -51
  37. data/spec/savon/core_ext/datetime_spec.rb +1 -1
  38. data/spec/savon/core_ext/hash_spec.rb +40 -4
  39. data/spec/savon/core_ext/object_spec.rb +1 -1
  40. data/spec/savon/core_ext/string_spec.rb +0 -12
  41. data/spec/savon/http/error_spec.rb +52 -0
  42. data/spec/savon/savon_spec.rb +90 -0
  43. data/spec/savon/soap/fault_spec.rb +80 -0
  44. data/spec/savon/soap/request_spec.rb +45 -0
  45. data/spec/savon/soap/response_spec.rb +153 -0
  46. data/spec/savon/soap/xml_spec.rb +249 -0
  47. data/spec/savon/soap_spec.rb +4 -177
  48. data/spec/savon/{wsdl_spec.rb → wsdl/document_spec.rb} +54 -17
  49. data/spec/savon/wsdl/request_spec.rb +15 -0
  50. data/spec/savon/wsse_spec.rb +123 -92
  51. data/spec/spec_helper.rb +19 -4
  52. data/spec/support/endpoint.rb +25 -0
  53. metadata +97 -97
  54. data/.autotest +0 -5
  55. data/CHANGELOG +0 -176
  56. data/README.rdoc +0 -64
  57. data/lib/savon/core_ext.rb +0 -8
  58. data/lib/savon/core_ext/net_http.rb +0 -19
  59. data/lib/savon/core_ext/uri.rb +0 -10
  60. data/lib/savon/logger.rb +0 -56
  61. data/lib/savon/request.rb +0 -138
  62. data/lib/savon/response.rb +0 -174
  63. data/lib/savon/wsdl.rb +0 -137
  64. data/lib/savon/wsdl_stream.rb +0 -85
  65. data/spec/basic_spec_helper.rb +0 -11
  66. data/spec/endpoint_helper.rb +0 -23
  67. data/spec/http_stubs.rb +0 -26
  68. data/spec/integration/http_basic_auth_spec.rb +0 -16
  69. data/spec/integration/server.rb +0 -51
  70. data/spec/savon/core_ext/net_http_spec.rb +0 -38
  71. data/spec/savon/core_ext/uri_spec.rb +0 -19
  72. data/spec/savon/request_spec.rb +0 -117
  73. data/spec/savon/response_spec.rb +0 -179
  74. data/spec/spec.opts +0 -4
@@ -3,7 +3,7 @@ require "spec_helper"
3
3
  describe DateTime do
4
4
  before do
5
5
  @datetime = DateTime.new 2012, 03, 22, 16, 22, 33
6
- @datetime_string = "2012-03-22T16:22:33Z"
6
+ @datetime_string = "2012-03-22T16:22:33+00:00"
7
7
  end
8
8
 
9
9
  describe "to_soap_value" do
@@ -56,7 +56,7 @@ describe Hash do
56
56
 
57
57
  it "should convert DateTime objects to xs:dateTime compliant Strings" do
58
58
  hash = { :before => DateTime.new(2012, 03, 22, 16, 22, 33) }
59
- result = "<before>2012-03-22T16:22:33Z</before>"
59
+ result = "<before>2012-03-22T16:22:33+00:00</before>"
60
60
 
61
61
  hash.to_soap_xml.should == result
62
62
  end
@@ -67,7 +67,7 @@ describe Hash do
67
67
  DateTime.new(2012, 03, 22, 16, 22, 33)
68
68
  end
69
69
 
70
- hash, result = { :before => singleton }, "<before>2012-03-22T16:22:33Z</before>"
70
+ hash, result = { :before => singleton }, "<before>2012-03-22T16:22:33+00:00</before>"
71
71
  hash.to_soap_xml.should == result
72
72
  end
73
73
 
@@ -79,8 +79,12 @@ describe Hash do
79
79
  hash.to_soap_xml.should == result
80
80
  end
81
81
 
82
+ it "should properly serialize nil values" do
83
+ { :some => nil }.to_soap_xml.should == '<some xsi:nil="true"/>'
84
+ end
85
+
82
86
  it "should call to_s on any other Object" do
83
- [666, true, false, nil].each do |object|
87
+ [666, true, false].each do |object|
84
88
  { :some => object }.to_soap_xml.should == "<some>#{object}</some>"
85
89
  end
86
90
  end
@@ -151,6 +155,21 @@ describe Hash do
151
155
  soap_response.map_soap_response.should == result
152
156
  end
153
157
 
158
+ context "with Savon.strip_namespaces set to false" do
159
+ around do |example|
160
+ Savon.strip_namespaces = false
161
+ example.run
162
+ Savon.strip_namespaces = true
163
+ end
164
+
165
+ it "should not strip namespaces from Hash keys" do
166
+ soap_response = { "ns:userResponse" => { "ns2:id" => "666" } }
167
+ result = { "ns:user_response" => { "ns2:id" => "666" } }
168
+
169
+ soap_response.map_soap_response.should == result
170
+ end
171
+ end
172
+
154
173
  it "should convert Hash keys and values in Arrays" do
155
174
  soap_response = { "response" => [{ "name" => "dude" }, { "name" => "gorilla" }] }
156
175
  result = { :response=> [{ :name => "dude" }, { :name => "gorilla" }] }
@@ -166,7 +185,7 @@ describe Hash do
166
185
  end
167
186
 
168
187
  it "should convert Hash values matching the xs:dateTime format into DateTime Objects" do
169
- soap_response = { "response" => { "at" => "2012-03-22T16:22:33" } }
188
+ soap_response = { "response" => { "at" => "2012-03-22T16:22:33+00:00" } }
170
189
  result = { :response => { :at => DateTime.new(2012, 03, 22, 16, 22, 33) } }
171
190
 
172
191
  soap_response.map_soap_response.should == result
@@ -185,6 +204,23 @@ describe Hash do
185
204
 
186
205
  soap_response.map_soap_response.should == result
187
206
  end
207
+
208
+ it "should convert namespaced entries to array elements" do
209
+ soap_response = {
210
+ "history" => {
211
+ "ns10:case" => { "ns10:name" => "a_name" },
212
+ "ns11:case" => { "ns11:name" => "another_name" }
213
+ }
214
+ }
215
+
216
+ result = {
217
+ :history => {
218
+ :case => [{ :name => "a_name" }, { :name => "another_name" }]
219
+ }
220
+ }
221
+
222
+ soap_response.map_soap_response.should == result
223
+ end
188
224
  end
189
225
 
190
226
  end
@@ -23,7 +23,7 @@ describe Object do
23
23
  DateTime.new(2012, 03, 22, 16, 22, 33)
24
24
  end
25
25
 
26
- singleton.to_soap_value.should == "2012-03-22T16:22:33Z"
26
+ singleton.to_soap_value.should == "2012-03-22T16:22:33+00:00"
27
27
  end
28
28
 
29
29
  it "calls to_s unless the Object responds to to_datetime" do
@@ -2,18 +2,6 @@ require "spec_helper"
2
2
 
3
3
  describe String do
4
4
 
5
- describe "self.random" do
6
- it "returns a random 100-character String" do
7
- String.random.should be_a(String)
8
- String.random.length.should == 100
9
- end
10
-
11
- it "returns a random String of a given length" do
12
- String.random(50).should be_a(String)
13
- String.random(50).length.should == 50
14
- end
15
- end
16
-
17
5
  describe "snakecase" do
18
6
  it "converts a lowerCamelCase String to snakecase" do
19
7
  "lowerCamelCase".snakecase.should == "lower_camel_case"
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::HTTP::Error do
4
+ let(:http_error) { Savon::HTTP::Error.new new_response(:code => 404, :body => "Not Found") }
5
+ let(:no_error) { Savon::HTTP::Error.new new_response }
6
+
7
+ it "should be a Savon::Error" do
8
+ Savon::HTTP::Error.should < Savon::Error
9
+ end
10
+
11
+ describe "#http" do
12
+ it "should return the HTTPI::Response" do
13
+ http_error.http.should be_an(HTTPI::Response)
14
+ end
15
+ end
16
+
17
+ describe "#present?" do
18
+ it "should return true if there was an HTTP error" do
19
+ http_error.should be_present
20
+ end
21
+
22
+ it "should return false unless there was an HTTP error" do
23
+ no_error.should_not be_present
24
+ end
25
+ end
26
+
27
+ [:message, :to_s].each do |method|
28
+ describe "##{method}" do
29
+ it "should return an empty String unless an HTTP error is present" do
30
+ no_error.send(method).should == ""
31
+ end
32
+
33
+ it "should return the HTTP error message" do
34
+ http_error.send(method).should == "HTTP error (404): Not Found"
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "#to_hash" do
40
+ it "should return the HTTP response details as a Hash" do
41
+ http_error.to_hash.should == { :code => 404, :headers => {}, :body => "Not Found" }
42
+ end
43
+ end
44
+
45
+ def new_response(options = {})
46
+ defaults = { :code => 200, :headers => {}, :body => ResponseFixture.authentication }
47
+ response = defaults.merge options
48
+
49
+ HTTPI::Response.new response[:code], response[:headers], response[:body]
50
+ end
51
+
52
+ end
@@ -0,0 +1,90 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon do
4
+
5
+ describe ".configure" do
6
+ around do |example|
7
+ Savon.reset_config!
8
+ example.run
9
+ Savon.reset_config!
10
+ end
11
+
12
+ describe "log" do
13
+ it "should default to true" do
14
+ Savon.log?.should be_true
15
+ end
16
+
17
+ it "should set whether to log HTTP requests" do
18
+ Savon.configure { |config| config.log = false }
19
+ Savon.log?.should be_false
20
+ end
21
+ end
22
+
23
+ describe "logger" do
24
+ it "should set the logger to use" do
25
+ MyLogger = Class.new
26
+ Savon.configure { |config| config.logger = MyLogger }
27
+ Savon.logger.should == MyLogger
28
+ end
29
+
30
+ it "should default to Logger writing to STDOUT" do
31
+ Savon.logger.should be_a(Logger)
32
+ end
33
+ end
34
+
35
+ describe "log_level" do
36
+ it "should default to :debug" do
37
+ Savon.log_level.should == :debug
38
+ end
39
+
40
+ it "should set the log level to use" do
41
+ Savon.configure { |config| config.log_level = :info }
42
+ Savon.log_level.should == :info
43
+ end
44
+ end
45
+
46
+ describe "raise_errors" do
47
+ it "should default to true" do
48
+ Savon.raise_errors?.should be_true
49
+ end
50
+
51
+ it "should not raise errors when disabled" do
52
+ Savon.raise_errors = false
53
+ Savon.raise_errors?.should be_false
54
+
55
+ Savon.raise_errors = true # reset to default
56
+ end
57
+ end
58
+
59
+ describe "soap_version" do
60
+ it "should default to SOAP 1.1" do
61
+ Savon.soap_version.should == 1
62
+ end
63
+
64
+ it "should return 2 if set to SOAP 1.2" do
65
+ Savon.soap_version = 2
66
+ Savon.soap_version.should == 2
67
+
68
+ Savon.soap_version = 1 # reset to default
69
+ end
70
+
71
+ it "should raise an ArgumentError in case of an invalid version" do
72
+ lambda { Savon.soap_version = 3 }.should raise_error(ArgumentError)
73
+ end
74
+ end
75
+
76
+ describe "strip_namespaces" do
77
+ it "should default to true" do
78
+ Savon.strip_namespaces?.should == true
79
+ end
80
+
81
+ it "should not strip namespaces when set to false" do
82
+ Savon.strip_namespaces = false
83
+ Savon.strip_namespaces?.should == false
84
+
85
+ Savon.strip_namespaces = true # reset to default
86
+ end
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,80 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::SOAP::Fault do
4
+ let(:soap_fault) { Savon::SOAP::Fault.new new_response(:body => ResponseFixture.soap_fault) }
5
+ let(:soap_fault2) { Savon::SOAP::Fault.new new_response(:body => ResponseFixture.soap_fault12) }
6
+ let(:no_fault) { Savon::SOAP::Fault.new new_response }
7
+
8
+ it "should be a Savon::Error" do
9
+ Savon::SOAP::Fault.should < Savon::Error
10
+ end
11
+
12
+ describe "#http" do
13
+ it "should return the HTTPI::Response" do
14
+ soap_fault.http.should be_an(HTTPI::Response)
15
+ end
16
+ end
17
+
18
+ describe "#present?" do
19
+ it "should return true if the HTTP response contains a SOAP 1.1 fault" do
20
+ soap_fault.should be_present
21
+ end
22
+
23
+ it "should return true if the HTTP response contains a SOAP 1.2 fault" do
24
+ soap_fault2.should be_present
25
+ end
26
+
27
+ it "should return false unless the HTTP response contains a SOAP fault" do
28
+ no_fault.should_not be_present
29
+ end
30
+ end
31
+
32
+ [:message, :to_s].each do |method|
33
+ describe "##{method}" do
34
+ it "should return an empty String unless a SOAP fault is present" do
35
+ no_fault.send(method).should == ""
36
+ end
37
+
38
+ it "should return a SOAP 1.1 fault message" do
39
+ soap_fault.send(method).should == "(soap:Server) Fault occurred while processing."
40
+ end
41
+
42
+ it "should return a SOAP 1.2 fault message" do
43
+ soap_fault2.send(method).should == "(soap:Sender) Sender Timeout"
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "#to_hash" do
49
+ it "should return the SOAP response as a Hash unless a SOAP fault is present" do
50
+ no_fault.to_hash[:authenticate_response][:return][:success].should be_true
51
+ end
52
+
53
+ it "should return a SOAP 1.1 fault as a Hash" do
54
+ soap_fault.to_hash.should == {
55
+ :fault => {
56
+ :faultstring => "Fault occurred while processing.",
57
+ :faultcode => "soap:Server"
58
+ }
59
+ }
60
+ end
61
+
62
+ it "should return a SOAP 1.2 fault as a Hash" do
63
+ soap_fault2.to_hash.should == {
64
+ :fault => {
65
+ :detail => { :max_time => "P5M" },
66
+ :reason => { :text => "Sender Timeout" },
67
+ :code => { :value => "soap:Sender", :subcode => { :value => "m:MessageTimeout" } }
68
+ }
69
+ }
70
+ end
71
+ end
72
+
73
+ def new_response(options = {})
74
+ defaults = { :code => 200, :headers => {}, :body => ResponseFixture.authentication }
75
+ response = defaults.merge options
76
+
77
+ HTTPI::Response.new response[:code], response[:headers], response[:body]
78
+ end
79
+
80
+ end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::SOAP::Request do
4
+ let(:request) { Savon::SOAP::Request.new HTTPI::Request.new, soap }
5
+ let(:soap) { Savon::SOAP::XML.new Endpoint.soap, :get_user, :id => 1 }
6
+
7
+ it "contains the content type for each supported SOAP version" do
8
+ content_type = Savon::SOAP::Request::ContentType
9
+ content_type[1].should == "text/xml;charset=UTF-8"
10
+ content_type[2].should == "application/soap+xml;charset=UTF-8"
11
+ end
12
+
13
+ describe ".new" do
14
+ it "should use the SOAP endpoint for the request" do
15
+ request.request.url.should == URI(soap.endpoint)
16
+ end
17
+
18
+ it "should set the SOAP body for the request" do
19
+ request.request.body.should == soap.to_xml
20
+ end
21
+
22
+ it "should set the 'Content-Type' header for SOAP 1.1" do
23
+ request.request.headers["Content-Type"].should == Savon::SOAP::Request::ContentType[1]
24
+ end
25
+
26
+ it "should set the 'Content-Type' header for SOAP 1.2" do
27
+ soap.version = 2
28
+ request.request.headers["Content-Type"].should == Savon::SOAP::Request::ContentType[2]
29
+ end
30
+
31
+ it "should not set the 'Content-Type' header if it's already specified" do
32
+ headers = { "Content-Type" => "text/plain" }
33
+ request = Savon::SOAP::Request.new HTTPI::Request.new(:headers => headers), soap
34
+ request.request.headers["Content-Type"].should == headers["Content-Type"]
35
+ end
36
+ end
37
+
38
+ describe "#response" do
39
+ it "should execute an HTTP POST request and return a Savon::SOAP::Response" do
40
+ HTTPI.expects(:post).returns(HTTPI::Response.new 200, {}, ResponseFixture.authentication)
41
+ request.response.should be_a(Savon::SOAP::Response)
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,153 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::SOAP::Response do
4
+
5
+ describe ".new" do
6
+ it "should raise a Savon::SOAP::Fault in case of a SOAP fault" do
7
+ lambda { soap_fault_response }.should raise_error(Savon::SOAP::Fault)
8
+ end
9
+
10
+ it "should not raise a Savon::SOAP::Fault in case the default is turned off" do
11
+ Savon.raise_errors = false
12
+ lambda { soap_fault_response }.should_not raise_error(Savon::SOAP::Fault)
13
+ Savon.raise_errors = true
14
+ end
15
+
16
+ it "should raise a Savon::HTTP::Error in case of an HTTP error" do
17
+ lambda { soap_response :code => 500 }.should raise_error(Savon::HTTP::Error)
18
+ end
19
+
20
+ it "should not raise a Savon::HTTP::Error in case the default is turned off" do
21
+ Savon.raise_errors = false
22
+ soap_response :code => 500
23
+ Savon.raise_errors = true
24
+ end
25
+ end
26
+
27
+ describe "#success?" do
28
+ around do |example|
29
+ Savon.raise_errors = false
30
+ example.run
31
+ Savon.raise_errors = true
32
+ end
33
+
34
+ it "should return true if the request was successful" do
35
+ soap_response.should be_a_success
36
+ end
37
+
38
+ it "should return false if there was a SOAP fault" do
39
+ soap_fault_response.should_not be_a_success
40
+ end
41
+
42
+ it "should return false if there was an HTTP error" do
43
+ http_error_response.should_not be_a_success
44
+ end
45
+ end
46
+
47
+ describe "#soap_fault?" do
48
+ around do |example|
49
+ Savon.raise_errors = false
50
+ example.run
51
+ Savon.raise_errors = true
52
+ end
53
+
54
+ it "should not return true in case the response seems to be ok" do
55
+ soap_response.soap_fault?.should be_false
56
+ end
57
+
58
+ it "should return true in case of a SOAP fault" do
59
+ soap_fault_response.soap_fault?.should be_true
60
+ end
61
+ end
62
+
63
+ describe "#soap_fault" do
64
+ around do |example|
65
+ Savon.raise_errors = false
66
+ example.run
67
+ Savon.raise_errors = true
68
+ end
69
+
70
+ it "should return a Savon::SOAP::Fault" do
71
+ soap_fault_response.soap_fault.should be_a(Savon::SOAP::Fault)
72
+ end
73
+
74
+ it "should return a Savon::SOAP::Fault containing the HTTPI::Response" do
75
+ soap_fault_response.soap_fault.http.should be_an(HTTPI::Response)
76
+ end
77
+
78
+ it "should return a Savon::SOAP::Fault even if the SOAP response seems to be ok" do
79
+ soap_response.soap_fault.should be_a(Savon::SOAP::Fault)
80
+ end
81
+ end
82
+
83
+ describe "#http_error?" do
84
+ around do |example|
85
+ Savon.raise_errors = false
86
+ example.run
87
+ Savon.raise_errors = true
88
+ end
89
+
90
+ it "should not return true in case the response seems to be ok" do
91
+ soap_response.http_error?.should_not be_true
92
+ end
93
+
94
+ it "should return true in case of an HTTP error" do
95
+ soap_response(:code => 500).http_error?.should be_true
96
+ end
97
+ end
98
+
99
+ describe "#http_error" do
100
+ around do |example|
101
+ Savon.raise_errors = false
102
+ example.run
103
+ Savon.raise_errors = true
104
+ end
105
+
106
+ it "should return a Savon::HTTP::Error" do
107
+ http_error_response.http_error.should be_a(Savon::HTTP::Error)
108
+ end
109
+
110
+ it "should return a Savon::HTTP::Error containing the HTTPI::Response" do
111
+ http_error_response.http_error.http.should be_an(HTTPI::Response)
112
+ end
113
+
114
+ it "should return a Savon::HTTP::Error even if the HTTP response seems to be ok" do
115
+ soap_response.http_error.should be_a(Savon::HTTP::Error)
116
+ end
117
+ end
118
+
119
+ describe "#to_hash" do
120
+ it "should return the SOAP response body as a Hash" do
121
+ soap_response.to_hash[:authenticate_response][:return].should ==
122
+ ResponseFixture.authentication(:to_hash)
123
+ end
124
+ end
125
+
126
+ describe "#to_xml" do
127
+ it "should return the raw SOAP response body" do
128
+ soap_response.to_xml.should == ResponseFixture.authentication
129
+ end
130
+ end
131
+
132
+ describe "#http" do
133
+ it "should return the HTTPI::Response" do
134
+ soap_response.http.should be_an(HTTPI::Response)
135
+ end
136
+ end
137
+
138
+ def soap_response(options = {})
139
+ defaults = { :code => 200, :headers => {}, :body => ResponseFixture.authentication }
140
+ response = defaults.merge options
141
+
142
+ Savon::SOAP::Response.new HTTPI::Response.new(response[:code], response[:headers], response[:body])
143
+ end
144
+
145
+ def soap_fault_response
146
+ soap_response :body => ResponseFixture.soap_fault
147
+ end
148
+
149
+ def http_error_response
150
+ soap_response :code => 404, :body => "Not found"
151
+ end
152
+
153
+ end