savon 2.11.1 → 2.15.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 (92) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +132 -73
  3. data/README.md +35 -20
  4. data/lib/savon/block_interface.rb +1 -0
  5. data/lib/savon/builder.rb +126 -30
  6. data/lib/savon/client.rb +2 -2
  7. data/lib/savon/header.rb +2 -6
  8. data/lib/savon/http_error.rb +4 -4
  9. data/lib/savon/log_message.rb +2 -1
  10. data/lib/savon/message.rb +1 -0
  11. data/lib/savon/mock/expectation.rb +1 -0
  12. data/lib/savon/mock/spec_helper.rb +1 -0
  13. data/lib/savon/mock.rb +1 -0
  14. data/lib/savon/model.rb +4 -3
  15. data/lib/savon/operation.rb +22 -19
  16. data/lib/savon/options.rb +98 -19
  17. data/lib/savon/qualified_message.rb +29 -27
  18. data/lib/savon/request.rb +22 -6
  19. data/lib/savon/request_logger.rb +8 -2
  20. data/lib/savon/response.rb +58 -10
  21. data/lib/savon/soap_fault.rb +3 -4
  22. data/lib/savon/string_utils.rb +17 -0
  23. data/lib/savon/version.rb +2 -1
  24. data/lib/savon.rb +2 -0
  25. metadata +80 -100
  26. data/.gitignore +0 -14
  27. data/.travis.yml +0 -15
  28. data/.yardopts +0 -6
  29. data/CONTRIBUTING.md +0 -46
  30. data/Gemfile +0 -18
  31. data/donate.png +0 -0
  32. data/lib/savon/core_ext/string.rb +0 -29
  33. data/savon.gemspec +0 -46
  34. data/spec/fixtures/gzip/message.gz +0 -0
  35. data/spec/fixtures/response/another_soap_fault.xml +0 -14
  36. data/spec/fixtures/response/authentication.xml +0 -14
  37. data/spec/fixtures/response/f5.xml +0 -39
  38. data/spec/fixtures/response/header.xml +0 -13
  39. data/spec/fixtures/response/list.xml +0 -18
  40. data/spec/fixtures/response/multi_ref.xml +0 -39
  41. data/spec/fixtures/response/soap_fault.xml +0 -8
  42. data/spec/fixtures/response/soap_fault12.xml +0 -18
  43. data/spec/fixtures/response/soap_fault_funky.xml +0 -8
  44. data/spec/fixtures/response/taxcloud.xml +0 -1
  45. data/spec/fixtures/ssl/client_cert.pem +0 -16
  46. data/spec/fixtures/ssl/client_encrypted_key.pem +0 -30
  47. data/spec/fixtures/ssl/client_encrypted_key_cert.pem +0 -24
  48. data/spec/fixtures/ssl/client_key.pem +0 -15
  49. data/spec/fixtures/wsdl/authentication.xml +0 -63
  50. data/spec/fixtures/wsdl/betfair.xml +0 -2981
  51. data/spec/fixtures/wsdl/edialog.xml +0 -15416
  52. data/spec/fixtures/wsdl/interhome.xml +0 -2137
  53. data/spec/fixtures/wsdl/lower_camel.xml +0 -52
  54. data/spec/fixtures/wsdl/multiple_namespaces.xml +0 -92
  55. data/spec/fixtures/wsdl/multiple_types.xml +0 -60
  56. data/spec/fixtures/wsdl/no_message_tag.xml +0 -1267
  57. data/spec/fixtures/wsdl/taxcloud.xml +0 -934
  58. data/spec/fixtures/wsdl/team_software.xml +0 -1
  59. data/spec/fixtures/wsdl/vies.xml +0 -176
  60. data/spec/fixtures/wsdl/wasmuth.xml +0 -153
  61. data/spec/integration/centra_spec.rb +0 -66
  62. data/spec/integration/email_example_spec.rb +0 -32
  63. data/spec/integration/random_quote_spec.rb +0 -23
  64. data/spec/integration/ratp_example_spec.rb +0 -28
  65. data/spec/integration/stockquote_example_spec.rb +0 -28
  66. data/spec/integration/support/application.rb +0 -82
  67. data/spec/integration/support/server.rb +0 -84
  68. data/spec/integration/temperature_example_spec.rb +0 -46
  69. data/spec/integration/zipcode_example_spec.rb +0 -42
  70. data/spec/savon/builder_spec.rb +0 -137
  71. data/spec/savon/client_spec.rb +0 -271
  72. data/spec/savon/core_ext/string_spec.rb +0 -37
  73. data/spec/savon/features/message_tag_spec.rb +0 -61
  74. data/spec/savon/http_error_spec.rb +0 -49
  75. data/spec/savon/log_message_spec.rb +0 -44
  76. data/spec/savon/message_spec.rb +0 -70
  77. data/spec/savon/mock_spec.rb +0 -174
  78. data/spec/savon/model_spec.rb +0 -182
  79. data/spec/savon/observers_spec.rb +0 -92
  80. data/spec/savon/operation_spec.rb +0 -230
  81. data/spec/savon/options_spec.rb +0 -1064
  82. data/spec/savon/qualified_message_spec.rb +0 -20
  83. data/spec/savon/request_logger_spec.rb +0 -37
  84. data/spec/savon/request_spec.rb +0 -496
  85. data/spec/savon/response_spec.rb +0 -270
  86. data/spec/savon/soap_fault_spec.rb +0 -131
  87. data/spec/spec_helper.rb +0 -30
  88. data/spec/support/adapters.rb +0 -48
  89. data/spec/support/endpoint.rb +0 -25
  90. data/spec/support/fixture.rb +0 -39
  91. data/spec/support/integration.rb +0 -9
  92. data/spec/support/stdout.rb +0 -25
@@ -1,82 +0,0 @@
1
- require "rack/builder"
2
- require "json"
3
-
4
- class IntegrationServer
5
-
6
- def self.respond_with(options = {})
7
- code = options.fetch(:code, 200)
8
- body = options.fetch(:body, "")
9
- headers = { "Content-Type" => "text/plain", "Content-Length" => body.size.to_s }
10
-
11
- [code, headers, [body]]
12
- end
13
-
14
- Application = Rack::Builder.new do
15
-
16
- map "/" do
17
- run lambda { |env|
18
- IntegrationServer.respond_with :body => env["REQUEST_METHOD"].downcase
19
- }
20
- end
21
-
22
- map "/repeat" do
23
- run lambda { |env|
24
- # stupid way of extracting the value from a query string (e.g. "code=500") [dh, 2012-12-08]
25
- IntegrationServer.respond_with :body => env["rack.input"].read
26
- }
27
- end
28
-
29
- map "/404" do
30
- run lambda { |env|
31
- IntegrationServer.respond_with :code => 404, :body => env["rack.input"].read
32
- }
33
- end
34
-
35
- map "/timeout" do
36
- run lambda { |env|
37
- sleep 2
38
- IntegrationServer.respond_with :body => "timeout"
39
- }
40
- end
41
-
42
- map "/inspect_request" do
43
- run lambda { |env|
44
- body = {
45
- :soap_action => env["HTTP_SOAPACTION"],
46
- :cookie => env["HTTP_COOKIE"],
47
- :x_token => env["HTTP_X_TOKEN"],
48
- :content_type => env["CONTENT_TYPE"]
49
- }
50
-
51
- IntegrationServer.respond_with :body => JSON.dump(body)
52
- }
53
- end
54
-
55
- map "/basic_auth" do
56
- use Rack::Auth::Basic, "basic-realm" do |username, password|
57
- username == "admin" && password == "secret"
58
- end
59
-
60
- run lambda { |env|
61
- IntegrationServer.respond_with :body => "basic-auth"
62
- }
63
- end
64
-
65
- map "/digest_auth" do
66
- unprotected_app = lambda { |env|
67
- IntegrationServer.respond_with :body => "digest-auth"
68
- }
69
-
70
- realm = 'digest-realm'
71
- app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
72
- username == 'admin' ? Digest::MD5.hexdigest("admin:#{realm}:secret") : nil
73
- end
74
- app.realm = realm
75
- app.opaque = 'this-should-be-secret'
76
- app.passwords_hashed = true
77
-
78
- run app
79
- end
80
-
81
- end
82
- end
@@ -1,84 +0,0 @@
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
@@ -1,46 +0,0 @@
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
@@ -1,42 +0,0 @@
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
- expect(values.uniq.size).to eq(values.size)
40
- end
41
-
42
- end
@@ -1,137 +0,0 @@
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
-
85
- describe "#wsse_signature" do
86
- fixture_dir = File.join(File.dirname(__FILE__), '..', 'fixtures', 'ssl')
87
-
88
- let(:cert) { File.join(fixture_dir, 'client_cert.pem') }
89
- let(:private_key) { File.join(fixture_dir, 'client_key.pem') }
90
- let(:signature) do
91
- Akami::WSSE::Signature.new(
92
- Akami::WSSE::Certs.new(
93
- :cert_file => cert,
94
- :private_key_file => private_key
95
- )
96
- )
97
- end
98
- let(:globals) { Savon::GlobalOptions.new(wsse_signature: signature) }
99
-
100
- subject(:signed_message_nn) {Nokogiri::XML(builder.to_s).remove_namespaces!}
101
- subject(:signed_message) {Nokogiri::XML(builder.to_s)}
102
-
103
- it "should contain a header" do
104
- expect(signed_message_nn.xpath('/Envelope/Header').size).to eq(1)
105
- end
106
-
107
- it "should contain a wsse:Security" do
108
- expect(signed_message_nn.xpath('/Envelope/Header/Security').size).to eq(1)
109
- end
110
-
111
- it "should have a Body[@wsu:Id]" do
112
- #must investigate: acts funny in mri ruby
113
- #expect(signed_message.xpath('//soapenv:Body', soapenv: "http://schemas.xmlsoap.org/soap/envelope/").attribute('ws:Id').value).to include('Body-')
114
- expect(signed_message_nn.xpath('//Body').attr('Id').value).to include('Body-')
115
- end
116
-
117
- it "signature should be valid" do
118
- certs = Akami::WSSE::Certs.new(:cert_file => cert, :private_key_file => private_key)
119
- signature_value = signed_message_nn.xpath('//SignatureValue').text
120
- signed_info_fragment = signed_message.xpath('//default:SignedInfo', default: "http://www.w3.org/2000/09/xmldsig#").to_xml
121
- data = Nokogiri::XML(signed_info_fragment){|config| config.options = Nokogiri::XML::ParseOptions::NOBLANKS}
122
- data.root.default_namespace='http://www.w3.org/2000/09/xmldsig#'
123
-
124
- signed_info = data.canonicalize Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
125
-
126
- signature = certs.private_key.sign(OpenSSL::Digest::SHA1.new, signed_info)
127
- expect(Base64.encode64(signature).gsub("\n", '')).to eq(signature_value)
128
- end
129
- end
130
- end
131
-
132
- describe '#body_attributes' do
133
- it 'should not be nil' do
134
- expect(builder.body_attributes).to eq({})
135
- end
136
- end
137
- end
@@ -1,271 +0,0 @@
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
-
66
- fit "defaults :log to false" do
67
- client = Savon.client(:wsdl => Fixture.wsdl(:authentication))
68
- expect(client.globals[:log]).to be_falsey
69
- end
70
- end
71
-
72
- describe "#service_name" do
73
- it "returns the name of the service" do
74
- expect(new_client.service_name).to eq('AuthenticationWebServiceImplService')
75
- end
76
- end
77
-
78
- describe "#operations" do
79
- it "returns all operation names" do
80
- operations = new_client.operations
81
- expect(operations).to eq([:authenticate])
82
- end
83
-
84
- it "raises when there is no WSDL document" do
85
- expect { new_client_without_wsdl.operations }.to raise_error("Unable to inspect the service without a WSDL document.")
86
- end
87
- end
88
-
89
- describe "#operation" do
90
- it "returns a new SOAP operation" do
91
- operation = new_client.operation(:authenticate)
92
- expect(operation).to be_a(Savon::Operation)
93
- end
94
-
95
- it "raises if there's no such SOAP operation" do
96
- expect { new_client.operation(:does_not_exist) }.
97
- to raise_error(Savon::UnknownOperationError)
98
- end
99
-
100
- it "does not raise when there is no WSDL document" do
101
- new_client_without_wsdl.operation(:does_not_exist)
102
- end
103
- end
104
-
105
- describe "#call" do
106
- it "calls a new SOAP operation" do
107
- locals = { :message => { :symbol => "AAPL" } }
108
- soap_response = new_soap_response
109
-
110
- wsdl = Wasabi::Document.new('http://example.com')
111
- operation = Savon::Operation.new(:authenticate, wsdl, Savon::GlobalOptions.new)
112
- operation.expects(:call).with(locals).returns(soap_response)
113
-
114
- Savon::Operation.expects(:create).with(
115
- :authenticate,
116
- instance_of(Wasabi::Document),
117
- instance_of(Savon::GlobalOptions)
118
- ).returns(operation)
119
-
120
- response = new_client.call(:authenticate, locals)
121
- expect(response).to eq(soap_response)
122
- end
123
-
124
- it "supports a block without arguments to call an operation with local options" do
125
- client = new_client(:endpoint => @server.url(:repeat))
126
-
127
- response = client.call(:authenticate) do
128
- message(:symbol => "AAPL" )
129
- end
130
-
131
- expect(response.http.body).to include("<symbol>AAPL</symbol>")
132
- end
133
-
134
- it "supports a block with one argument to call an operation with local options" do
135
- client = new_client(:endpoint => @server.url(:repeat))
136
-
137
- # supports instance variables!
138
- @instance_variable = { :symbol => "AAPL" }
139
-
140
- response = client.call(:authenticate) do |locals|
141
- locals.message(@instance_variable)
142
- end
143
-
144
- expect(response.http.body).to include("<symbol>AAPL</symbol>")
145
- end
146
-
147
- it "accepts arguments for the message tag" do
148
- client = new_client(:endpoint => @server.url(:repeat))
149
- response = client.call(:authenticate, :attributes => { "ID" => "ABC321"})
150
-
151
- expect(response.http.body).to include('<tns:authenticate ID="ABC321">')
152
- end
153
-
154
- it "raises when the operation name is not a symbol" do
155
- expect { new_client.call("not a symbol") }.to raise_error(
156
- ArgumentError,
157
- "Expected the first parameter (the name of the operation to call) to be a symbol\n" \
158
- "Actual: \"not a symbol\" (String)"
159
- )
160
- end
161
-
162
- it "raises a when given an unknown option via the Hash syntax" do
163
- expect { new_client.call(:authenticate, :invalid_local_option => true) }.
164
- to raise_error(Savon::UnknownOptionError, "Unknown local option: :invalid_local_option")
165
- end
166
-
167
- it "raises a when given an unknown option via the block syntax" do
168
- expect { new_client.call(:authenticate) { another_invalid_local_option true } }.
169
- to raise_error(Savon::UnknownOptionError, "Unknown local option: :another_invalid_local_option")
170
- end
171
- end
172
-
173
- describe "#build_request" do
174
- it "returns the request without making an actual call" do
175
- expected_request = mock('request')
176
- wsdl = Wasabi::Document.new('http://example.com')
177
-
178
- operation = Savon::Operation.new(
179
- :authenticate,
180
- wsdl,
181
- Savon::GlobalOptions.new
182
- )
183
- operation.expects(:request).returns(expected_request)
184
-
185
- Savon::Operation.expects(:create).with(
186
- :authenticate,
187
- instance_of(Wasabi::Document),
188
- instance_of(Savon::GlobalOptions)
189
- ).returns(operation)
190
-
191
- operation.expects(:call).never
192
-
193
- client = new_client(:endpoint => @server.url(:repeat))
194
- request = client.build_request(:authenticate) do
195
- message(:symbol => "AAPL" )
196
- end
197
-
198
- expect(request).to eq expected_request
199
- end
200
-
201
- it "accepts a block without arguments" do
202
- client = new_client(:endpoint => @server.url(:repeat))
203
- request = client.build_request(:authenticate) do
204
- message(:symbol => "AAPL" )
205
- end
206
-
207
- expect(request.body).
208
- to include('<tns:authenticate><symbol>AAPL</symbol></tns:authenticate>')
209
- end
210
-
211
- it "accepts a block with one argument" do
212
- client = new_client(:endpoint => @server.url(:repeat))
213
-
214
- # supports instance variables!
215
- @instance_variable = { :symbol => "AAPL" }
216
-
217
- request = client.build_request(:authenticate) do |locals|
218
- locals.message(@instance_variable)
219
- end
220
-
221
- expect(request.body).
222
- to include("<tns:authenticate><symbol>AAPL</symbol></tns:authenticate>")
223
- end
224
-
225
- it "accepts argument for the message tag" do
226
- client = new_client(:endpoint => @server.url(:repeat))
227
- request = client.build_request(:authenticate, :attributes => { "ID" => "ABC321" })
228
-
229
- expect(request.body).
230
- to include("<tns:authenticate ID=\"ABC321\"></tns:authenticate>")
231
- end
232
-
233
- it "raises when the operation name is not a symbol" do
234
- expect { new_client.build_request("not a symbol") }.to raise_error
235
- end
236
-
237
- it "raises when given an unknown option via the Hash syntax" do
238
- expect { new_client.build_request(:authenticate, :invalid_local_option => true) }.to raise_error
239
- end
240
-
241
- it "raises when given an unknown option via the block syntax" do
242
- expect { new_client.build_request(:authenticate) { another_invalid_local_option true } }.to raise_error
243
- end
244
- end
245
-
246
- def new_http_response(options = {})
247
- defaults = { :code => 200, :headers => {}, :body => Fixture.response(:authentication) }
248
- response = defaults.merge options
249
-
250
- HTTPI::Response.new response[:code], response[:headers], response[:body]
251
- end
252
-
253
- def new_soap_response(options = {})
254
- http = new_http_response(options)
255
- globals = Savon::GlobalOptions.new
256
- locals = Savon::LocalOptions.new
257
-
258
- Savon::Response.new(http, globals, locals)
259
- end
260
-
261
- def new_client(globals = {})
262
- globals = { :wsdl => Fixture.wsdl(:authentication), :log => false }.merge(globals)
263
- Savon.client(globals)
264
- end
265
-
266
- def new_client_without_wsdl(globals = {})
267
- globals = { :endpoint => "http://example.co", :namespace => "http://v1.example.com", :log => false }.merge(globals)
268
- Savon.client(globals)
269
- end
270
-
271
- end