s-savon 0.8.6

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 (61) hide show
  1. data/.gitignore +9 -0
  2. data/.rspec +1 -0
  3. data/.yardopts +2 -0
  4. data/CHANGELOG.md +461 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +37 -0
  8. data/Rakefile +40 -0
  9. data/lib/savon.rb +14 -0
  10. data/lib/savon/client.rb +157 -0
  11. data/lib/savon/core_ext/hash.rb +70 -0
  12. data/lib/savon/core_ext/object.rb +14 -0
  13. data/lib/savon/core_ext/string.rb +51 -0
  14. data/lib/savon/core_ext/time.rb +14 -0
  15. data/lib/savon/error.rb +6 -0
  16. data/lib/savon/global.rb +75 -0
  17. data/lib/savon/http/error.rb +42 -0
  18. data/lib/savon/soap.rb +24 -0
  19. data/lib/savon/soap/fault.rb +59 -0
  20. data/lib/savon/soap/request.rb +61 -0
  21. data/lib/savon/soap/response.rb +80 -0
  22. data/lib/savon/soap/xml.rb +187 -0
  23. data/lib/savon/version.rb +5 -0
  24. data/lib/savon/wsdl/document.rb +112 -0
  25. data/lib/savon/wsdl/parser.rb +102 -0
  26. data/lib/savon/wsdl/request.rb +35 -0
  27. data/lib/savon/wsse.rb +150 -0
  28. data/savon.gemspec +29 -0
  29. data/spec/fixtures/gzip/message.gz +0 -0
  30. data/spec/fixtures/response/another_soap_fault.xml +14 -0
  31. data/spec/fixtures/response/authentication.xml +14 -0
  32. data/spec/fixtures/response/header.xml +13 -0
  33. data/spec/fixtures/response/list.xml +18 -0
  34. data/spec/fixtures/response/multi_ref.xml +39 -0
  35. data/spec/fixtures/response/soap_fault.xml +8 -0
  36. data/spec/fixtures/response/soap_fault12.xml +18 -0
  37. data/spec/fixtures/wsdl/authentication.xml +63 -0
  38. data/spec/fixtures/wsdl/geotrust.xml +156 -0
  39. data/spec/fixtures/wsdl/namespaced_actions.xml +307 -0
  40. data/spec/fixtures/wsdl/no_namespace.xml +115 -0
  41. data/spec/fixtures/wsdl/two_bindings.xml +25 -0
  42. data/spec/savon/client_spec.rb +346 -0
  43. data/spec/savon/core_ext/hash_spec.rb +121 -0
  44. data/spec/savon/core_ext/object_spec.rb +19 -0
  45. data/spec/savon/core_ext/string_spec.rb +57 -0
  46. data/spec/savon/core_ext/time_spec.rb +13 -0
  47. data/spec/savon/http/error_spec.rb +52 -0
  48. data/spec/savon/savon_spec.rb +85 -0
  49. data/spec/savon/soap/fault_spec.rb +89 -0
  50. data/spec/savon/soap/request_spec.rb +45 -0
  51. data/spec/savon/soap/response_spec.rb +174 -0
  52. data/spec/savon/soap/xml_spec.rb +335 -0
  53. data/spec/savon/soap_spec.rb +21 -0
  54. data/spec/savon/wsdl/document_spec.rb +132 -0
  55. data/spec/savon/wsdl/parser_spec.rb +99 -0
  56. data/spec/savon/wsdl/request_spec.rb +15 -0
  57. data/spec/savon/wsse_spec.rb +213 -0
  58. data/spec/spec_helper.rb +14 -0
  59. data/spec/support/endpoint.rb +25 -0
  60. data/spec/support/fixture.rb +37 -0
  61. metadata +251 -0
@@ -0,0 +1,121 @@
1
+ require "spec_helper"
2
+
3
+ describe Hash do
4
+
5
+ describe "#deep_merge!" do
6
+ it "should recursively merge two Hashes" do
7
+ hash = { :one => 1, "two" => { "three" => 3 } }
8
+ other_hash = { :four => 4, "two" => { "three" => "merge", :five => 5 } }
9
+
10
+ hash.merge!(other_hash).should == { :one => 1, :four => 4, "two" => { "three" => "merge", :five => 5 } }
11
+ end
12
+ end
13
+
14
+ describe "#find_soap_header" do
15
+ it "should return the content from the 'soap:Header' element" do
16
+ soap_header = { "soap:Envelope" => { "soap:Header" => "content" } }
17
+ soap_header.find_soap_header.should == "content"
18
+ end
19
+
20
+ it "should return an empty Hash in case the 'soap:Header' element could not be found" do
21
+ soap_header = { "some_hash" => "content" }
22
+ soap_header.find_soap_header.should == {}
23
+ end
24
+ end
25
+
26
+ describe "#find_soap_body" do
27
+ it "should return the content from the 'soap:Body' element" do
28
+ soap_body = { "soap:Envelope" => { "soap:Body" => "content" } }
29
+ soap_body.find_soap_body.should == "content"
30
+ end
31
+
32
+ it "should return an empty Hash in case the 'soap:Body' element could not be found" do
33
+ soap_body = { "some_hash" => "content" }
34
+ soap_body.find_soap_body.should == {}
35
+ end
36
+ end
37
+
38
+ describe "#map_soap_response" do
39
+ it "should convert Hash key Strings to snake_case Symbols" do
40
+ soap_response = { "userResponse" => { "accountStatus" => "active" } }
41
+ result = { :user_response => { :account_status => "active" } }
42
+
43
+ soap_response.map_soap_response.should == result
44
+ end
45
+
46
+ it "should strip namespaces from Hash keys" do
47
+ soap_response = { "ns:userResponse" => { "ns2:id" => "666" } }
48
+ result = { :user_response => { :id => "666" } }
49
+
50
+ soap_response.map_soap_response.should == result
51
+ end
52
+
53
+ context "with Savon.strip_namespaces set to false" do
54
+ around do |example|
55
+ Savon.strip_namespaces = false
56
+ example.run
57
+ Savon.strip_namespaces = true
58
+ end
59
+
60
+ it "should not strip namespaces from Hash keys" do
61
+ soap_response = { "ns:userResponse" => { "ns2:id" => "666" } }
62
+ result = { "ns:user_response" => { "ns2:id" => "666" } }
63
+
64
+ soap_response.map_soap_response.should == result
65
+ end
66
+ end
67
+
68
+ it "should convert Hash keys and values in Arrays" do
69
+ soap_response = { "response" => [{ "name" => "dude" }, { "name" => "gorilla" }] }
70
+ result = { :response=> [{ :name => "dude" }, { :name => "gorilla" }] }
71
+
72
+ soap_response.map_soap_response.should == result
73
+ end
74
+
75
+ it "should convert xsi:nil values to nil Objects" do
76
+ soap_response = { "userResponse" => { "xsi:nil" => "true" } }
77
+ result = { :user_response => nil }
78
+
79
+ soap_response.map_soap_response.should == result
80
+ end
81
+
82
+ it "should convert Hash values matching the xs:dateTime format into DateTime Objects" do
83
+ soap_response = { "response" => { "at" => "2012-03-22T16:22:33+00:00" } }
84
+ result = { :response => { :at => DateTime.new(2012, 03, 22, 16, 22, 33) } }
85
+
86
+ soap_response.map_soap_response.should == result
87
+ end
88
+
89
+ it "should convert Hash values matching 'true' to TrueClass" do
90
+ soap_response = { "response" => { "active" => "false" } }
91
+ result = { :response => { :active => false } }
92
+
93
+ soap_response.map_soap_response.should == result
94
+ end
95
+
96
+ it "should convert Hash values matching 'false' to FalseClass" do
97
+ soap_response = { "response" => { "active" => "true" } }
98
+ result = { :response => { :active => true } }
99
+
100
+ soap_response.map_soap_response.should == result
101
+ end
102
+
103
+ it "should convert namespaced entries to array elements" do
104
+ soap_response = {
105
+ "history" => {
106
+ "ns10:case" => { "ns10:name" => "a_name" },
107
+ "ns11:case" => { "ns11:name" => "another_name" }
108
+ }
109
+ }
110
+
111
+ result = {
112
+ :history => {
113
+ :case => [{ :name => "a_name" }, { :name => "another_name" }]
114
+ }
115
+ }
116
+
117
+ soap_response.map_soap_response.should == result
118
+ end
119
+ end
120
+
121
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ describe Object do
4
+
5
+ describe "blank?" do
6
+ it "returns true for Objects perceived to be blank" do
7
+ ["", false, nil, [], {}].each do |object|
8
+ object.should be_blank
9
+ end
10
+ end
11
+
12
+ it "returns false for every other Object" do
13
+ ["!blank", true, [:a], {:a => "b"}].each do |object|
14
+ object.should_not be_blank
15
+ end
16
+ end
17
+ end
18
+
19
+ end
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe String do
4
+
5
+ describe "snakecase" do
6
+ it "converts a lowerCamelCase String to snakecase" do
7
+ "lowerCamelCase".snakecase.should == "lower_camel_case"
8
+ end
9
+
10
+ it "converts period characters to underscores" do
11
+ "User.GetEmail".snakecase.should == "user_get_email"
12
+ end
13
+ end
14
+
15
+ describe "lower_camelcase" do
16
+ it "converts a snakecase String to lowerCamelCase" do
17
+ "lower_camel_case".lower_camelcase.should == "lowerCamelCase"
18
+ end
19
+ end
20
+
21
+ describe "starts_with?" do
22
+ it "should return whether it starts with a given suffix" do
23
+ "authenticate".starts_with?("auth").should be_true
24
+ "authenticate".starts_with?("cate").should be_false
25
+ end
26
+ end
27
+
28
+ describe "strip_namespace" do
29
+ it "strips the namespace from a namespaced String" do
30
+ "ns:customer".strip_namespace.should == "customer"
31
+ end
32
+
33
+ it "returns the original String for a String without namespace" do
34
+ "customer".strip_namespace.should == "customer"
35
+ end
36
+ end
37
+
38
+ describe "map_soap_response" do
39
+ it "returns a DateTime Object for Strings matching the xs:dateTime format" do
40
+ "2012-03-22T16:22:33".map_soap_response.should ==
41
+ DateTime.new(2012, 03, 22, 16, 22, 33)
42
+ end
43
+
44
+ it "returns true for Strings matching 'true'" do
45
+ "true".map_soap_response.should be_true
46
+ end
47
+
48
+ it "returns false for Strings matching 'false'" do
49
+ "false".map_soap_response.should be_false
50
+ end
51
+
52
+ it "defaults to return the original value" do
53
+ "whatever".map_soap_response.should == "whatever"
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ describe Time do
4
+
5
+ describe "#xs_datetime" do
6
+ let(:time) { Time.utc(2011, 01, 04, 13, 45, 55) }
7
+
8
+ it "should return an xs:dateTime formatted String" do
9
+ time.xs_datetime.should == "2011-01-04T13:45:55UTC"
10
+ end
11
+ end
12
+
13
+ end
@@ -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 => Fixture.response(: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,85 @@
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
+ Savon.log = false # disable logging
11
+ end
12
+
13
+ describe "log" do
14
+ it "should default to true" do
15
+ Savon.log?.should be_true
16
+ end
17
+
18
+ it "should set whether to log HTTP requests" do
19
+ Savon.configure { |config| config.log = false }
20
+ Savon.log?.should be_false
21
+ end
22
+ end
23
+
24
+ describe "logger" do
25
+ it "should set the logger to use" do
26
+ MyLogger = Class.new
27
+ Savon.configure { |config| config.logger = MyLogger }
28
+ Savon.logger.should == MyLogger
29
+ end
30
+
31
+ it "should default to Logger writing to STDOUT" do
32
+ Savon.logger.should be_a(Logger)
33
+ end
34
+ end
35
+
36
+ describe "log_level" do
37
+ it "should default to :debug" do
38
+ Savon.log_level.should == :debug
39
+ end
40
+
41
+ it "should set the log level to use" do
42
+ Savon.configure { |config| config.log_level = :info }
43
+ Savon.log_level.should == :info
44
+ end
45
+ end
46
+
47
+ describe "raise_errors" do
48
+ it "should default to true" do
49
+ Savon.raise_errors?.should be_true
50
+ end
51
+
52
+ it "should not raise errors when disabled" do
53
+ Savon.raise_errors = false
54
+ Savon.raise_errors?.should be_false
55
+ end
56
+ end
57
+
58
+ describe "soap_version" do
59
+ it "should default to SOAP 1.1" do
60
+ Savon.soap_version.should == 1
61
+ end
62
+
63
+ it "should return 2 if set to SOAP 1.2" do
64
+ Savon.soap_version = 2
65
+ Savon.soap_version.should == 2
66
+ end
67
+
68
+ it "should raise an ArgumentError in case of an invalid version" do
69
+ lambda { Savon.soap_version = 3 }.should raise_error(ArgumentError)
70
+ end
71
+ end
72
+
73
+ describe "strip_namespaces" do
74
+ it "should default to true" do
75
+ Savon.strip_namespaces?.should == true
76
+ end
77
+
78
+ it "should not strip namespaces when set to false" do
79
+ Savon.strip_namespaces = false
80
+ Savon.strip_namespaces?.should == false
81
+ end
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,89 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::SOAP::Fault do
4
+ let(:soap_fault) { Savon::SOAP::Fault.new new_response(:body => Fixture.response(:soap_fault)) }
5
+ let(:soap_fault2) { Savon::SOAP::Fault.new new_response(:body => Fixture.response(:soap_fault12)) }
6
+ let(:another_soap_fault) { Savon::SOAP::Fault.new new_response(:body => Fixture.response(:another_soap_fault)) }
7
+ let(:no_fault) { Savon::SOAP::Fault.new new_response }
8
+
9
+ it "should be a Savon::Error" do
10
+ Savon::SOAP::Fault.should < Savon::Error
11
+ end
12
+
13
+ describe "#http" do
14
+ it "should return the HTTPI::Response" do
15
+ soap_fault.http.should be_an(HTTPI::Response)
16
+ end
17
+ end
18
+
19
+ describe "#present?" do
20
+ it "should return true if the HTTP response contains a SOAP 1.1 fault" do
21
+ soap_fault.should be_present
22
+ end
23
+
24
+ it "should return true if the HTTP response contains a SOAP 1.2 fault" do
25
+ soap_fault2.should be_present
26
+ end
27
+
28
+ it "should return true if the HTTP response contains a SOAP fault with different namespaces" do
29
+ another_soap_fault.should be_present
30
+ end
31
+
32
+ it "should return false unless the HTTP response contains a SOAP fault" do
33
+ no_fault.should_not be_present
34
+ end
35
+ end
36
+
37
+ [:message, :to_s].each do |method|
38
+ describe "##{method}" do
39
+ it "should return an empty String unless a SOAP fault is present" do
40
+ no_fault.send(method).should == ""
41
+ end
42
+
43
+ it "should return a SOAP 1.1 fault message" do
44
+ soap_fault.send(method).should == "(soap:Server) Fault occurred while processing."
45
+ end
46
+
47
+ it "should return a SOAP 1.2 fault message" do
48
+ soap_fault2.send(method).should == "(soap:Sender) Sender Timeout"
49
+ end
50
+
51
+ it "should return a SOAP fault message (with different namespaces)" do
52
+ another_soap_fault.send(method).should == "(ERR_NO_SESSION) Wrong session message"
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "#to_hash" do
58
+ it "should return the SOAP response as a Hash unless a SOAP fault is present" do
59
+ no_fault.to_hash[:authenticate_response][:return][:success].should be_true
60
+ end
61
+
62
+ it "should return a SOAP 1.1 fault as a Hash" do
63
+ soap_fault.to_hash.should == {
64
+ :fault => {
65
+ :faultstring => "Fault occurred while processing.",
66
+ :faultcode => "soap:Server"
67
+ }
68
+ }
69
+ end
70
+
71
+ it "should return a SOAP 1.2 fault as a Hash" do
72
+ soap_fault2.to_hash.should == {
73
+ :fault => {
74
+ :detail => { :max_time => "P5M" },
75
+ :reason => { :text => "Sender Timeout" },
76
+ :code => { :value => "soap:Sender", :subcode => { :value => "m:MessageTimeout" } }
77
+ }
78
+ }
79
+ end
80
+ end
81
+
82
+ def new_response(options = {})
83
+ defaults = { :code => 500, :headers => {}, :body => Fixture.response(:authentication) }
84
+ response = defaults.merge options
85
+
86
+ HTTPI::Response.new response[:code], response[:headers], response[:body]
87
+ end
88
+
89
+ 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, {}, Fixture.response(:authentication))
41
+ request.response.should be_a(Savon::SOAP::Response)
42
+ end
43
+ end
44
+
45
+ end