s-savon 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
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