savon-ng-1.6 2.4.0

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.travis.yml +15 -0
  4. data/.yardopts +6 -0
  5. data/CHANGELOG.md +1024 -0
  6. data/CONTRIBUTING.md +46 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE +20 -0
  9. data/README.md +81 -0
  10. data/Rakefile +14 -0
  11. data/donate.png +0 -0
  12. data/lib/savon/block_interface.rb +26 -0
  13. data/lib/savon/builder.rb +166 -0
  14. data/lib/savon/client.rb +88 -0
  15. data/lib/savon/core_ext/string.rb +29 -0
  16. data/lib/savon/header.rb +70 -0
  17. data/lib/savon/http_error.rb +27 -0
  18. data/lib/savon/log_message.rb +48 -0
  19. data/lib/savon/message.rb +36 -0
  20. data/lib/savon/mock/expectation.rb +71 -0
  21. data/lib/savon/mock/spec_helper.rb +62 -0
  22. data/lib/savon/mock.rb +5 -0
  23. data/lib/savon/model.rb +80 -0
  24. data/lib/savon/operation.rb +127 -0
  25. data/lib/savon/options.rb +330 -0
  26. data/lib/savon/qualified_message.rb +49 -0
  27. data/lib/savon/request.rb +89 -0
  28. data/lib/savon/request_logger.rb +48 -0
  29. data/lib/savon/response.rb +112 -0
  30. data/lib/savon/soap_fault.rb +48 -0
  31. data/lib/savon/version.rb +5 -0
  32. data/lib/savon.rb +27 -0
  33. data/savon.gemspec +47 -0
  34. data/spec/fixtures/gzip/message.gz +0 -0
  35. data/spec/fixtures/response/another_soap_fault.xml +14 -0
  36. data/spec/fixtures/response/authentication.xml +14 -0
  37. data/spec/fixtures/response/header.xml +13 -0
  38. data/spec/fixtures/response/list.xml +18 -0
  39. data/spec/fixtures/response/multi_ref.xml +39 -0
  40. data/spec/fixtures/response/soap_fault.xml +8 -0
  41. data/spec/fixtures/response/soap_fault12.xml +18 -0
  42. data/spec/fixtures/response/taxcloud.xml +1 -0
  43. data/spec/fixtures/ssl/client_cert.pem +16 -0
  44. data/spec/fixtures/ssl/client_encrypted_key.pem +30 -0
  45. data/spec/fixtures/ssl/client_encrypted_key_cert.pem +24 -0
  46. data/spec/fixtures/ssl/client_key.pem +15 -0
  47. data/spec/fixtures/wsdl/authentication.xml +63 -0
  48. data/spec/fixtures/wsdl/betfair.xml +2981 -0
  49. data/spec/fixtures/wsdl/edialog.xml +15416 -0
  50. data/spec/fixtures/wsdl/interhome.xml +2137 -0
  51. data/spec/fixtures/wsdl/lower_camel.xml +52 -0
  52. data/spec/fixtures/wsdl/multiple_namespaces.xml +92 -0
  53. data/spec/fixtures/wsdl/multiple_types.xml +60 -0
  54. data/spec/fixtures/wsdl/taxcloud.xml +934 -0
  55. data/spec/fixtures/wsdl/team_software.xml +1 -0
  56. data/spec/fixtures/wsdl/vies.xml +176 -0
  57. data/spec/fixtures/wsdl/wasmuth.xml +153 -0
  58. data/spec/integration/email_example_spec.rb +32 -0
  59. data/spec/integration/ratp_example_spec.rb +28 -0
  60. data/spec/integration/stockquote_example_spec.rb +28 -0
  61. data/spec/integration/support/application.rb +82 -0
  62. data/spec/integration/support/server.rb +84 -0
  63. data/spec/integration/temperature_example_spec.rb +46 -0
  64. data/spec/integration/zipcode_example_spec.rb +42 -0
  65. data/spec/savon/builder_spec.rb +86 -0
  66. data/spec/savon/client_spec.rb +193 -0
  67. data/spec/savon/core_ext/string_spec.rb +37 -0
  68. data/spec/savon/features/message_tag_spec.rb +61 -0
  69. data/spec/savon/http_error_spec.rb +49 -0
  70. data/spec/savon/log_message_spec.rb +33 -0
  71. data/spec/savon/message_spec.rb +40 -0
  72. data/spec/savon/mock_spec.rb +157 -0
  73. data/spec/savon/model_spec.rb +154 -0
  74. data/spec/savon/observers_spec.rb +92 -0
  75. data/spec/savon/operation_spec.rb +211 -0
  76. data/spec/savon/options_spec.rb +772 -0
  77. data/spec/savon/request_spec.rb +493 -0
  78. data/spec/savon/response_spec.rb +258 -0
  79. data/spec/savon/soap_fault_spec.rb +126 -0
  80. data/spec/spec_helper.rb +30 -0
  81. data/spec/support/endpoint.rb +25 -0
  82. data/spec/support/fixture.rb +39 -0
  83. data/spec/support/integration.rb +9 -0
  84. data/spec/support/stdout.rb +25 -0
  85. metadata +308 -0
@@ -0,0 +1,84 @@
1
+ require "puma"
2
+ require "puma/minissl"
3
+
4
+ require "integration/support/application"
5
+
6
+ class IntegrationServer
7
+
8
+ def self.run(options = {})
9
+ server = new(options)
10
+ server.run
11
+ server
12
+ end
13
+
14
+ def self.ssl_ca_file; integration_fixture("ca_all.pem") end
15
+ def self.ssl_key_file; integration_fixture("server.key") end
16
+ def self.ssl_cert_file; integration_fixture("server.cert") end
17
+
18
+ def self.integration_fixture(file)
19
+ file = File.expand_path("../../fixtures/#{file}", __FILE__)
20
+ raise "No such file '#{file}'" unless File.exist? file
21
+ file
22
+ end
23
+
24
+ def initialize(options = {})
25
+ @app = Application
26
+ @host = options.fetch(:host, "localhost")
27
+ @port = options.fetch(:port, 17172)
28
+ @ssl = options.fetch(:ssl, false)
29
+
30
+ @server = Puma::Server.new(app, events)
31
+
32
+ if ssl?
33
+ add_ssl_listener
34
+ else
35
+ add_tcp_listener
36
+ end
37
+ end
38
+
39
+ attr_reader :app, :host, :port, :server
40
+
41
+ def url(path = "")
42
+ protocol = ssl? ? "https" : "http"
43
+ File.join "#{protocol}://#{host}:#{port}/", path.to_s
44
+ end
45
+
46
+ def ssl?
47
+ @ssl
48
+ end
49
+
50
+ def run
51
+ server.run
52
+ end
53
+
54
+ def stop
55
+ server.stop(true)
56
+ end
57
+
58
+ private
59
+
60
+ def events
61
+ Puma::Events.new($stdout, $stderr)
62
+ end
63
+
64
+ def add_tcp_listener
65
+ server.add_tcp_listener(host, port)
66
+ rescue Errno::EADDRINUSE
67
+ raise "Panther is already running at #{url}"
68
+ end
69
+
70
+ def add_ssl_listener
71
+ server.add_ssl_listener(host, port, ssl_context)
72
+ end
73
+
74
+ def ssl_context
75
+ context = Puma::MiniSSL::Context.new
76
+
77
+ context.key = IntegrationServer.ssl_key_file
78
+ context.cert = IntegrationServer.ssl_cert_file
79
+ context.verify_mode = Puma::MiniSSL::VERIFY_PEER
80
+
81
+ context
82
+ end
83
+
84
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ describe "Temperature example" do
4
+
5
+ it "converts 30 degrees celsius to 86 degrees fahrenheit" do
6
+ client = Savon.client do
7
+ # The WSDL document provided by the service.
8
+ wsdl "http://www.webservicex.net/ConvertTemperature.asmx?WSDL"
9
+
10
+ # Needed because (up until now), Savon doesn't match XS types to Hash keys,
11
+ # but defaults to convert Hash message Symbols (like :from_unit) to lowerCamelCase.
12
+ # The service expects these to be CamelCase instead. Look at Savon's log output
13
+ # and compare it with an example request generated by soapUI.
14
+ convert_request_keys_to :camelcase
15
+
16
+ # Lower timeouts so these specs don't take forever when the service is not available.
17
+ open_timeout 10
18
+ read_timeout 10
19
+
20
+ # Disable logging for cleaner spec output.
21
+ log false
22
+ end
23
+
24
+ response = call_and_fail_gracefully(client, :convert_temp) do
25
+ # For the corrent values to pass for :from_unit and :to_unit, I searched the WSDL for
26
+ # the "FromUnit" type which is a "TemperatureUnit" enumeration that looks like this:
27
+ #
28
+ # <s:simpleType name="TemperatureUnit">
29
+ # <s:restriction base="s:string">
30
+ # <s:enumeration value="degreeCelsius"/>
31
+ # <s:enumeration value="degreeFahrenheit"/>
32
+ # <s:enumeration value="degreeRankine"/>
33
+ # <s:enumeration value="degreeReaumur"/>
34
+ # <s:enumeration value="kelvin"/>
35
+ # </s:restriction>
36
+ # </s:simpleType>
37
+ #
38
+ # Support for XS schema types needs to be improved.
39
+ message(:temperature => 30, :from_unit => "degreeCelsius", :to_unit => "degreeFahrenheit")
40
+ end
41
+
42
+ fahrenheit = response.body[:convert_temp_response][:convert_temp_result]
43
+ expect(fahrenheit).to eq("86")
44
+ end
45
+
46
+ end
@@ -0,0 +1,42 @@
1
+ require "spec_helper"
2
+
3
+ describe "ZIP code example" do
4
+
5
+ it "supports threads making requests simultaneously" do
6
+ client = Savon.client(
7
+ # The WSDL document provided by the service.
8
+ :wsdl => "http://www.thomas-bayer.com/axis2/services/BLZService?wsdl",
9
+
10
+ # Lower timeouts so these specs don't take forever when the service is not available.
11
+ :open_timeout => 10,
12
+ :read_timeout => 10,
13
+
14
+ # Disable logging for cleaner spec output.
15
+ :log => false
16
+ )
17
+
18
+ mutex = Mutex.new
19
+
20
+ request_data = [70070010, 24050110, 20050550]
21
+ threads_waiting = request_data.size
22
+
23
+ threads = request_data.map do |blz|
24
+ thread = Thread.new do
25
+ response = call_and_fail_gracefully client, :get_bank, :message => { :blz => blz }
26
+ Thread.current[:value] = response.body[:get_bank_response][:details]
27
+ mutex.synchronize { threads_waiting -= 1 }
28
+ end
29
+
30
+ thread.abort_on_exception = true
31
+ thread
32
+ end
33
+
34
+ sleep(1) until threads_waiting == 0
35
+
36
+ threads.each(&:kill)
37
+ values = threads.map { |thr| thr[:value] }.compact
38
+
39
+ values.uniq.size.should == values.size
40
+ end
41
+
42
+ end
@@ -0,0 +1,86 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::Builder do
4
+
5
+ subject(:builder) { Savon::Builder.new(:authenticate, wsdl, globals, locals) }
6
+
7
+ let(:globals) { Savon::GlobalOptions.new }
8
+ let(:locals) { Savon::LocalOptions.new }
9
+ let(:wsdl) { Wasabi::Document.new Fixture.wsdl(:authentication) }
10
+ let(:no_wsdl) { Wasabi::Document.new }
11
+
12
+ describe "#pretty" do
13
+ it "returns the pretty printed request" do
14
+ expect(builder.pretty).to include("<env:Body>\n <tns:authenticate/>")
15
+ end
16
+ end
17
+
18
+ describe "#to_s" do
19
+ it "includes the global :env_namespace if it's available" do
20
+ globals[:env_namespace] = :soapenv
21
+ expect(builder.to_s).to include("<soapenv:Envelope")
22
+ end
23
+
24
+ it "defaults to include the default envelope namespace of :env" do
25
+ expect(builder.to_s).to include("<env:Envelope")
26
+ end
27
+
28
+ it "includes the target namespace from the WSDL" do
29
+ expect(builder.to_s).to include('xmlns:tns="http://v1_0.ws.auth.order.example.com/"')
30
+ end
31
+
32
+ it "includes the target namespace from the global :namespace if it's available" do
33
+ globals[:namespace] = "http://v1.example.com"
34
+ expect(builder.to_s).to include('xmlns:tns="http://v1.example.com"')
35
+ end
36
+
37
+ it "includes the local :message_tag if available" do
38
+ locals[:message_tag] = "doAuthenticate"
39
+ expect(builder.to_s).to include("<tns:doAuthenticate>")
40
+ end
41
+
42
+ it "includes the message tag from the WSDL if its available" do
43
+ expect(builder.to_s).to include("<tns:authenticate>")
44
+ end
45
+
46
+ it "includes a message tag created by Gyoku if both option and WSDL are missing" do
47
+ globals[:namespace] = "http://v1.example.com"
48
+
49
+ locals = Savon::LocalOptions.new
50
+ builder = Savon::Builder.new(:authenticate, no_wsdl, globals, locals)
51
+
52
+ expect(builder.to_s).to include("<wsdl:authenticate>")
53
+ end
54
+
55
+ it "uses the global :namespace_identifier option if it's available" do
56
+ globals[:namespace_identifier] = :v1
57
+ expect(builder.to_s).to include("<v1:authenticate>")
58
+ end
59
+
60
+ it "uses the WSDL's namespace_identifier if the global option was not specified" do
61
+ expect(builder.to_s).to include("<tns:authenticate>")
62
+ end
63
+
64
+ it "uses the default :wsdl identifier if both option and WSDL were not specified" do
65
+ globals[:namespace] = "http://v1.example.com"
66
+
67
+ builder = Savon::Builder.new(:authenticate, no_wsdl, globals, locals)
68
+ expect(builder.to_s).to include("<wsdl:authenticate>")
69
+ end
70
+
71
+ it "uses the global :element_form_default option if it's available " do
72
+ globals[:element_form_default] = :qualified
73
+ locals[:message] = { :username => "luke", :password => "secret" }
74
+
75
+ expect(builder.to_s).to include("<tns:username>luke</tns:username>")
76
+ end
77
+
78
+ it "uses the WSDL's element_form_default value if the global option was set specified" do
79
+ locals[:message] = { :username => "luke", :password => "secret" }
80
+ wsdl.element_form_default = :qualified
81
+
82
+ expect(builder.to_s).to include("<tns:username>luke</tns:username>")
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,193 @@
1
+ require "spec_helper"
2
+ require "integration/support/server"
3
+
4
+ describe Savon::Client do
5
+
6
+ before :all do
7
+ @server = IntegrationServer.run
8
+ end
9
+
10
+ after :all do
11
+ @server.stop
12
+ end
13
+
14
+ describe ".new" do
15
+ it "supports a block without arguments to create a client with global options" do
16
+ client = Savon.client do
17
+ wsdl Fixture.wsdl(:authentication)
18
+ end
19
+
20
+ expect(client.globals[:wsdl]).to eq(Fixture.wsdl(:authentication))
21
+ end
22
+
23
+ it "supports a block with one argument to create a client with global options" do
24
+ client = Savon.client do |globals|
25
+ globals.wsdl Fixture.wsdl(:authentication)
26
+ end
27
+
28
+ expect(client.globals[:wsdl]).to eq(Fixture.wsdl(:authentication))
29
+ end
30
+
31
+ it "builds an HTTPI request for Wasabi" do
32
+ http_request = mock
33
+ wsdl_request = mock(:build => http_request)
34
+ Savon::WSDLRequest.expects(:new).with(instance_of(Savon::GlobalOptions)).returns(wsdl_request)
35
+
36
+ Wasabi::Document.any_instance.expects(:request=).with(http_request)
37
+ Savon.client(:wsdl => "http://example.com")
38
+ end
39
+
40
+ it "raises if initialized with anything other than a Hash" do
41
+ expect { Savon.client("http://example.com") }.
42
+ to raise_error(Savon::InitializationError, /Some code tries to initialize Savon with the "http:\/\/example\.com" \(String\)/)
43
+ end
44
+
45
+ it "raises if not initialized with either a :wsdl or both :endpoint and :namespace options" do
46
+ expect { Savon.client(:endpoint => "http://example.com") }.
47
+ to raise_error(Savon::InitializationError, /Expected either a WSDL document or the SOAP endpoint and target namespace options/)
48
+ end
49
+
50
+ it "raises a when given an unknown option via the Hash syntax" do
51
+ expect { Savon.client(:invalid_global_option => true) }.
52
+ to raise_error(Savon::UnknownOptionError, "Unknown global option: :invalid_global_option")
53
+ end
54
+
55
+ it "raises a when given an unknown option via the block syntax" do
56
+ expect { Savon.client { another_invalid_global_option true } }.
57
+ to raise_error(Savon::UnknownOptionError, "Unknown global option: :another_invalid_global_option")
58
+ end
59
+ end
60
+
61
+ describe "#globals" do
62
+ it "returns the current set of global options" do
63
+ expect(new_client.globals).to be_an_instance_of(Savon::GlobalOptions)
64
+ end
65
+ end
66
+
67
+ describe "#service_name" do
68
+ it "returns the name of the service" do
69
+ expect(new_client.service_name).to eq('AuthenticationWebServiceImplService')
70
+ end
71
+ end
72
+
73
+ describe "#operations" do
74
+ it "returns all operation names" do
75
+ operations = new_client.operations
76
+ expect(operations).to eq([:authenticate])
77
+ end
78
+
79
+ it "raises when there is no WSDL document" do
80
+ expect { new_client_without_wsdl.operations }.to raise_error("Unable to inspect the service without a WSDL document.")
81
+ end
82
+ end
83
+
84
+ describe "#operation" do
85
+ it "returns a new SOAP operation" do
86
+ operation = new_client.operation(:authenticate)
87
+ expect(operation).to be_a(Savon::Operation)
88
+ end
89
+
90
+ it "raises if there's no such SOAP operation" do
91
+ expect { new_client.operation(:does_not_exist) }.
92
+ to raise_error(Savon::UnknownOperationError)
93
+ end
94
+
95
+ it "does not raise when there is no WSDL document" do
96
+ new_client_without_wsdl.operation(:does_not_exist)
97
+ end
98
+ end
99
+
100
+ describe "#call" do
101
+ it "calls a new SOAP operation" do
102
+ locals = { :message => { :symbol => "AAPL" } }
103
+ soap_response = new_soap_response
104
+
105
+ wsdl = Wasabi::Document.new('http://example.com')
106
+ operation = Savon::Operation.new(:authenticate, wsdl, Savon::GlobalOptions.new)
107
+ operation.expects(:call).with(locals).returns(soap_response)
108
+
109
+ Savon::Operation.expects(:create).with(
110
+ :authenticate,
111
+ instance_of(Wasabi::Document),
112
+ instance_of(Savon::GlobalOptions)
113
+ ).returns(operation)
114
+
115
+ response = new_client.call(:authenticate, locals)
116
+ expect(response).to eq(soap_response)
117
+ end
118
+
119
+ it "supports a block without arguments to call an operation with local options" do
120
+ client = new_client(:endpoint => @server.url(:repeat))
121
+
122
+ response = client.call(:authenticate) do
123
+ message(:symbol => "AAPL" )
124
+ end
125
+
126
+ expect(response.http.body).to include("<symbol>AAPL</symbol>")
127
+ end
128
+
129
+ it "supports a block with one argument to call an operation with local options" do
130
+ client = new_client(:endpoint => @server.url(:repeat))
131
+
132
+ # supports instance variables!
133
+ @instance_variable = { :symbol => "AAPL" }
134
+
135
+ response = client.call(:authenticate) do |locals|
136
+ locals.message(@instance_variable)
137
+ end
138
+
139
+ expect(response.http.body).to include("<symbol>AAPL</symbol>")
140
+ end
141
+
142
+ it "accepts arguments for the message tag" do
143
+ client = new_client(:endpoint => @server.url(:repeat))
144
+ response = client.call(:authenticate, :attributes => { "ID" => "ABC321"})
145
+
146
+ expect(response.http.body).to include('<tns:authenticate ID="ABC321">')
147
+ end
148
+
149
+ it "raises when the operation name is not a symbol" do
150
+ expect { new_client.call("not a symbol") }.to raise_error(
151
+ ArgumentError,
152
+ "Expected the first parameter (the name of the operation to call) to be a symbol\n" \
153
+ "Actual: \"not a symbol\" (String)"
154
+ )
155
+ end
156
+
157
+ it "raises a when given an unknown option via the Hash syntax" do
158
+ expect { new_client.call(:authenticate, :invalid_local_option => true) }.
159
+ to raise_error(Savon::UnknownOptionError, "Unknown local option: :invalid_local_option")
160
+ end
161
+
162
+ it "raises a when given an unknown option via the block syntax" do
163
+ expect { new_client.call(:authenticate) { another_invalid_local_option true } }.
164
+ to raise_error(Savon::UnknownOptionError, "Unknown local option: :another_invalid_local_option")
165
+ end
166
+ end
167
+
168
+ def new_http_response(options = {})
169
+ defaults = { :code => 200, :headers => {}, :body => Fixture.response(:authentication) }
170
+ response = defaults.merge options
171
+
172
+ HTTPI::Response.new response[:code], response[:headers], response[:body]
173
+ end
174
+
175
+ def new_soap_response(options = {})
176
+ http = new_http_response(options)
177
+ globals = Savon::GlobalOptions.new
178
+ locals = Savon::LocalOptions.new
179
+
180
+ Savon::Response.new(http, globals, locals)
181
+ end
182
+
183
+ def new_client(globals = {})
184
+ globals = { :wsdl => Fixture.wsdl(:authentication), :log => false }.merge(globals)
185
+ Savon.client(globals)
186
+ end
187
+
188
+ def new_client_without_wsdl(globals = {})
189
+ globals = { :endpoint => "http://example.co", :namespace => "http://v1.example.com", :log => false }.merge(globals)
190
+ Savon.client(globals)
191
+ end
192
+
193
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe String do
4
+
5
+ describe "snakecase" do
6
+ it "lowercases one word CamelCase" do
7
+ "Merb".snakecase.should == "merb"
8
+ end
9
+
10
+ it "makes one underscore snakecase two word CamelCase" do
11
+ "MerbCore".snakecase.should == "merb_core"
12
+ end
13
+
14
+ it "handles CamelCase with more than 2 words" do
15
+ "SoYouWantContributeToMerbCore".snakecase.should == "so_you_want_contribute_to_merb_core"
16
+ end
17
+
18
+ it "handles CamelCase with more than 2 capital letter in a row" do
19
+ "CNN".snakecase.should == "cnn"
20
+ "CNNNews".snakecase.should == "cnn_news"
21
+ "HeadlineCNNNews".snakecase.should == "headline_cnn_news"
22
+ end
23
+
24
+ it "does NOT change one word lowercase" do
25
+ "merb".snakecase.should == "merb"
26
+ end
27
+
28
+ it "leaves snake_case as is" do
29
+ "merb_core".snakecase.should == "merb_core"
30
+ end
31
+
32
+ it "converts period characters to underscores" do
33
+ "User.GetEmail".snakecase.should == "user_get_email"
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Savon do
4
+
5
+ it 'knows the message tag for :authentication' do
6
+ message_tag = message_tag_for(:authentication, :authenticate)
7
+ expect(message_tag).to eq(['http://v1_0.ws.auth.order.example.com/', 'authenticate'])
8
+ end
9
+
10
+ it 'knows the message tag for :taxcloud' do
11
+ message_tag = message_tag_for(:taxcloud, :verify_address)
12
+ expect(message_tag).to eq(['http://taxcloud.net', 'VerifyAddress'])
13
+ end
14
+
15
+ it 'knows the message tag for :team_software' do
16
+ message_tag = message_tag_for(:team_software, :login)
17
+ expect(message_tag).to eq(['http://tempuri.org/', 'Login'])
18
+ end
19
+
20
+ it 'knows the message tag for :interhome' do
21
+ message_tag = message_tag_for(:interhome, :price_list)
22
+ expect(message_tag).to eq(['http://www.interhome.com/webservice', 'PriceList'])
23
+ end
24
+
25
+ it 'knows the message tag for :betfair' do
26
+ message_tag = message_tag_for(:betfair, :get_bet)
27
+ expect(message_tag).to eq(['http://www.betfair.com/publicapi/v5/BFExchangeService/', 'getBet'])
28
+ end
29
+
30
+ it 'knows the message tag for :vies' do
31
+ message_tag = message_tag_for(:vies, :check_vat)
32
+ expect(message_tag).to eq(['urn:ec.europa.eu:taxud:vies:services:checkVat:types', 'checkVat'])
33
+ end
34
+
35
+ it 'knows the message tag for :wasmuth' do
36
+ message_tag = message_tag_for(:wasmuth, :get_st_tables)
37
+ expect(message_tag).to eq(['http://ws.online.msw/', 'getStTables'])
38
+ end
39
+
40
+ def message_tag_for(fixture, operation_name)
41
+ globals = Savon::GlobalOptions.new(:log => false)
42
+ wsdl = Wasabi::Document.new Fixture.wsdl(fixture)
43
+ operation = Savon::Operation.create(operation_name, wsdl, globals)
44
+ request_xml = operation.build.to_s
45
+
46
+ nsid, local = extract_message_tag_from_request(request_xml)
47
+ namespace = extract_namespace_from_request(nsid, request_xml)
48
+
49
+ [namespace, local]
50
+ end
51
+
52
+ def extract_message_tag_from_request(xml)
53
+ match = xml.match(/<\w+?:Body><(.+?):(.+?)>/)
54
+ [ match[1], match[2] ]
55
+ end
56
+
57
+ def extract_namespace_from_request(nsid, xml)
58
+ xml.match(/xmlns:#{nsid}="(.+?)"/)[1]
59
+ end
60
+
61
+ end
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::HTTPError do
4
+ let(:http_error) { Savon::HTTPError.new new_response(:code => 404, :body => "Not Found") }
5
+ let(:no_error) { Savon::HTTPError.new new_response }
6
+
7
+ it "inherits from Savon::Error" do
8
+ expect(Savon::HTTPError.ancestors).to include(Savon::Error)
9
+ end
10
+
11
+ describe ".present?" do
12
+ it "returns true if there was an HTTP error" do
13
+ http = new_response(:code => 404, :body => "Not Found")
14
+ expect(Savon::HTTPError.present? http).to be_true
15
+ end
16
+
17
+ it "returns false unless there was an HTTP error" do
18
+ expect(Savon::HTTPError.present? new_response).to be_false
19
+ end
20
+ end
21
+
22
+ describe "#http" do
23
+ it "returns the HTTPI::Response" do
24
+ expect(http_error.http).to be_a(HTTPI::Response)
25
+ end
26
+ end
27
+
28
+ [:message, :to_s].each do |method|
29
+ describe "##{method}" do
30
+ it "returns the HTTP error message" do
31
+ expect(http_error.send method).to eq("HTTP error (404): Not Found")
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#to_hash" do
37
+ it "returns the HTTP response details as a Hash" do
38
+ expect(http_error.to_hash).to eq(:code => 404, :headers => {}, :body => "Not Found")
39
+ end
40
+ end
41
+
42
+ def new_response(options = {})
43
+ defaults = { :code => 200, :headers => {}, :body => Fixture.response(:authentication) }
44
+ response = defaults.merge options
45
+
46
+ HTTPI::Response.new response[:code], response[:headers], response[:body]
47
+ end
48
+
49
+ end
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::LogMessage do
4
+
5
+ it "returns the message if it's not XML" do
6
+ message = log_message("hello", [:password], :pretty_print).to_s
7
+ expect(message).to eq("hello")
8
+ end
9
+
10
+ it "returns the message if it shouldn't be filtered or pretty printed" do
11
+ Nokogiri.expects(:XML).never
12
+
13
+ message = log_message("<hello/>", [], false).to_s
14
+ expect(message).to eq("<hello/>")
15
+ end
16
+
17
+ it "pretty prints a given message" do
18
+ message = log_message("<envelope><body>hello</body></envelope>", [], :pretty_print).to_s
19
+
20
+ expect(message).to include("\n<envelope>")
21
+ expect(message).to include("\n <body>")
22
+ end
23
+
24
+ it "filters tags in a given message" do
25
+ message = log_message("<root><password>secret</password></root>", [:password], false).to_s
26
+ expect(message).to include("<password>***FILTERED***</password>")
27
+ end
28
+
29
+ def log_message(*args)
30
+ Savon::LogMessage.new(*args)
31
+ end
32
+
33
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "integration/support/server"
3
+
4
+ describe Savon::Message do
5
+
6
+ before do
7
+ @server = IntegrationServer.run
8
+ end
9
+
10
+ after do
11
+ @server.stop
12
+ end
13
+
14
+ context "with a qualified message" do
15
+ it "converts request Hash keys for which there is not namespace" do
16
+ client = Savon.client(
17
+ :endpoint => @server.url(:repeat),
18
+ :namespace => 'http://example.com',
19
+ :log => false,
20
+
21
+ :element_form_default => :qualified,
22
+ :convert_request_keys_to => :camelcase,
23
+
24
+ :convert_response_tags_to => nil
25
+ )
26
+
27
+ message = {
28
+ :email_count => 3,
29
+ :user_name => 'josh',
30
+ :order! => [:user_name, :email_count]
31
+ }
32
+
33
+ response = client.call(:something, :message => message)
34
+ body = response.hash['Envelope']['Body']
35
+
36
+ expect(response.xml).to include('<wsdl:UserName>josh</wsdl:UserName><wsdl:EmailCount>3</wsdl:EmailCount>')
37
+ end
38
+ end
39
+
40
+ end