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,157 @@
1
+ require "spec_helper"
2
+ require "savon/mock/spec_helper"
3
+
4
+ describe "Savon's mock interface" do
5
+ include Savon::SpecHelper
6
+
7
+ before :all do
8
+ savon.mock!
9
+ end
10
+
11
+ after :all do
12
+ savon.unmock!
13
+ end
14
+
15
+ it "can verify a request and return a fixture response" do
16
+ message = { :username => "luke", :password => "secret" }
17
+ savon.expects(:authenticate).with(:message => message).returns("<fixture/>")
18
+
19
+ response = new_client.call(:authenticate) do
20
+ message(:username => "luke", :password => "secret")
21
+ end
22
+
23
+ expect(response.http.body).to eq("<fixture/>")
24
+ end
25
+
26
+ it "accepts a Hash to specify the response code, headers and body" do
27
+ soap_fault = Fixture.response(:soap_fault)
28
+ response = { :code => 500, :headers => { "X-Result" => "invalid" }, :body => soap_fault }
29
+
30
+ savon.expects(:authenticate).returns(response)
31
+ response = new_client(:raise_errors => false).call(:authenticate)
32
+
33
+ expect(response).to_not be_successful
34
+ expect(response).to be_a_soap_fault
35
+
36
+ expect(response.http.code).to eq(500)
37
+ expect(response.http.headers).to eq("X-Result" => "invalid")
38
+ expect(response.http.body).to eq(soap_fault)
39
+ end
40
+
41
+ it "works with multiple requests" do
42
+ authentication_message = { :username => "luke", :password => "secret" }
43
+ savon.expects(:authenticate).with(:message => authentication_message).returns("")
44
+
45
+ find_user_message = { :by_username => "lea" }
46
+ savon.expects(:find_user).with(:message => find_user_message).returns("")
47
+
48
+ new_client.call(:authenticate, :message => authentication_message)
49
+ new_client.call(:find_user, :message => find_user_message)
50
+ end
51
+
52
+ it "fails when the expected operation was not called" do
53
+ # TODO: find out how to test this! [dh, 2012-12-17]
54
+ #savon.expects(:authenticate)
55
+ end
56
+
57
+ it "fails when the return value for an expectation was not specified" do
58
+ savon.expects(:authenticate)
59
+
60
+ expect { new_client.call(:authenticate) }.
61
+ to raise_error(Savon::ExpectationError, "This expectation was not set up with a response.")
62
+ end
63
+
64
+ it "fails with an unexpected request" do
65
+ expect { new_client.call(:authenticate) }.
66
+ to raise_error(Savon::ExpectationError, "Unexpected request to the :authenticate operation.")
67
+ end
68
+
69
+ it "fails with multiple requests" do
70
+ authentication_message = { :username => "luke", :password => "secret" }
71
+ savon.expects(:authenticate).with(:message => authentication_message).returns("")
72
+
73
+ create_user_message = { :username => "lea" }
74
+ savon.expects(:create_user).with(:message => create_user_message).returns("")
75
+
76
+ find_user_message = { :by_username => "lea" }
77
+ savon.expects(:find_user).with(:message => find_user_message).returns("")
78
+
79
+ # reversed order from previous spec
80
+ new_client.call(:authenticate, :message => authentication_message)
81
+
82
+ expect { new_client.call(:find_user, :message => find_user_message) }.
83
+ to raise_error(Savon::ExpectationError, "Expected a request to the :create_user operation.\n" \
84
+ "Received a request to the :find_user operation instead.")
85
+ end
86
+
87
+ it "fails when the expected SOAP operation does not match the actual one" do
88
+ savon.expects(:logout).returns("<fixture/>")
89
+
90
+ expect { new_client.call(:authenticate) }.
91
+ to raise_error(Savon::ExpectationError, "Expected a request to the :logout operation.\n" \
92
+ "Received a request to the :authenticate operation instead.")
93
+ end
94
+
95
+ it "fails when there is no actual message to match" do
96
+ message = { :username => "luke" }
97
+ savon.expects(:find_user).with(:message => message).returns("<fixture/>")
98
+
99
+ expect { new_client.call(:find_user) }.
100
+ to raise_error(Savon::ExpectationError, "Expected a request to the :find_user operation\n" \
101
+ " with this message: #{message.inspect}\n" \
102
+ "Received a request to the :find_user operation\n" \
103
+ " with no message.")
104
+ end
105
+
106
+ it "fails when there is no expect but an actual message" do
107
+ savon.expects(:find_user).returns("<fixture/>")
108
+ message = { :username => "luke" }
109
+
110
+ expect { new_client.call(:find_user, :message => message) }.
111
+ to raise_error(Savon::ExpectationError, "Expected a request to the :find_user operation\n" \
112
+ " with no message.\n" \
113
+ "Received a request to the :find_user operation\n" \
114
+ " with this message: #{message.inspect}")
115
+ end
116
+
117
+ it "does not fail when any message is expected and an actual message" do
118
+ savon.expects(:find_user).with(:message => :any).returns("<fixture/>")
119
+ message = { :username => "luke" }
120
+
121
+ expect { new_client.call(:find_user, :message => message) }.to_not raise_error
122
+ end
123
+
124
+ it "does not fail when any message is expected and no actual message" do
125
+ savon.expects(:find_user).with(:message => :any).returns("<fixture/>")
126
+
127
+ expect { new_client.call(:find_user) }.to_not raise_error
128
+ end
129
+
130
+
131
+ it "allows code to rescue Savon::Error and still report test failures" do
132
+ message = { :username => "luke" }
133
+ savon.expects(:find_user).with(:message => message).returns("<fixture/>")
134
+
135
+ expect {
136
+ begin
137
+ new_client.call(:find_user)
138
+ rescue Savon::Error => e
139
+ puts "any real error (e.g. SOAP fault or HTTP error) is OK in the big picture, move on"
140
+ end
141
+ }.to raise_error(Savon::ExpectationError, "Expected a request to the :find_user operation\n" \
142
+ " with this message: #{message.inspect}\n" \
143
+ "Received a request to the :find_user operation\n" \
144
+ " with no message.")
145
+ end
146
+
147
+ def new_client(globals = {})
148
+ defaults = {
149
+ :endpoint => "http://example.com",
150
+ :namespace => "http://v1.example.com",
151
+ :log => false
152
+ }
153
+
154
+ Savon.client defaults.merge(globals)
155
+ end
156
+
157
+ end
@@ -0,0 +1,154 @@
1
+ require "spec_helper"
2
+ require "integration/support/server"
3
+
4
+ describe Savon::Model 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 ".client" do
15
+ it "returns the memoized client" do
16
+ model = Class.new {
17
+ extend Savon::Model
18
+ client :wsdl => Fixture.wsdl(:authentication)
19
+ }
20
+
21
+ expect(model.client).to be_a(Savon::Client)
22
+ expect(model.client).to equal(model.client)
23
+ end
24
+
25
+ it "raises if the client was not initialized properly" do
26
+ model = Class.new { extend Savon::Model }
27
+
28
+ expect { model.client }.
29
+ to raise_error(Savon::InitializationError, /^Expected the model to be initialized/)
30
+ end
31
+ end
32
+
33
+ describe ".global" do
34
+ it "sets global options" do
35
+ model = Class.new {
36
+ extend Savon::Model
37
+
38
+ client :wsdl => Fixture.wsdl(:authentication)
39
+
40
+ global :soap_version, 2
41
+ global :open_timeout, 71
42
+ global :wsse_auth, "luke", "secret", :digest
43
+ }
44
+
45
+ expect(model.client.globals[:soap_version]).to eq(2)
46
+ expect(model.client.globals[:open_timeout]).to eq(71)
47
+ expect(model.client.globals[:wsse_auth]).to eq(["luke", "secret", :digest])
48
+ end
49
+ end
50
+
51
+ describe ".operations" do
52
+ it "defines class methods for each operation" do
53
+ model = Class.new {
54
+ extend Savon::Model
55
+
56
+ client :wsdl => Fixture.wsdl(:authentication)
57
+ operations :authenticate
58
+ }
59
+
60
+ expect(model).to respond_to(:authenticate)
61
+ end
62
+
63
+ it "executes class-level SOAP operations" do
64
+ repeat_url = @server.url(:repeat)
65
+
66
+ model = Class.new {
67
+ extend Savon::Model
68
+
69
+ client :endpoint => repeat_url, :namespace => "http://v1.example.com"
70
+ global :log, false
71
+
72
+ operations :authenticate
73
+ }
74
+
75
+ response = model.authenticate(:xml => Fixture.response(:authentication))
76
+ expect(response.body[:authenticate_response][:return]).to include(:authentication_value)
77
+ end
78
+
79
+ it "defines instance methods for each operation" do
80
+ model = Class.new {
81
+ extend Savon::Model
82
+
83
+ client :wsdl => Fixture.wsdl(:authentication)
84
+ operations :authenticate
85
+ }
86
+
87
+ model_instance = model.new
88
+ expect(model_instance).to respond_to(:authenticate)
89
+ end
90
+
91
+ it "executes instance-level SOAP operations" do
92
+ repeat_url = @server.url(:repeat)
93
+
94
+ model = Class.new {
95
+ extend Savon::Model
96
+
97
+ client :endpoint => repeat_url, :namespace => "http://v1.example.com"
98
+ global :log, false
99
+
100
+ operations :authenticate
101
+ }
102
+
103
+ model_instance = model.new
104
+ response = model_instance.authenticate(:xml => Fixture.response(:authentication))
105
+ expect(response.body[:authenticate_response][:return]).to include(:authentication_value)
106
+ end
107
+ end
108
+
109
+ it "allows to overwrite class operations" do
110
+ repeat_url = @server.url(:repeat)
111
+
112
+ model = Class.new {
113
+ extend Savon::Model
114
+ client :endpoint => repeat_url, :namespace => "http://v1.example.com"
115
+ }
116
+
117
+ supermodel = model.dup
118
+ supermodel.operations :authenticate
119
+
120
+ def supermodel.authenticate(locals = {})
121
+ p "super"
122
+ super
123
+ end
124
+
125
+ supermodel.client.expects(:call).with(:authenticate, :message => { :username => "luke", :password => "secret" })
126
+ supermodel.expects(:p).with("super") # stupid, but works
127
+
128
+ supermodel.authenticate(:message => { :username => "luke", :password => "secret" })
129
+ end
130
+
131
+ it "allows to overwrite instance operations" do
132
+ repeat_url = @server.url(:repeat)
133
+
134
+ model = Class.new {
135
+ extend Savon::Model
136
+ client :endpoint => repeat_url, :namespace => "http://v1.example.com"
137
+ }
138
+
139
+ supermodel = model.dup
140
+ supermodel.operations :authenticate
141
+ supermodel = supermodel.new
142
+
143
+ def supermodel.authenticate(lcoals = {})
144
+ p "super"
145
+ super
146
+ end
147
+
148
+ supermodel.client.expects(:call).with(:authenticate, :message => { :username => "luke", :password => "secret" })
149
+ supermodel.expects(:p).with("super") # stupid, but works
150
+
151
+ supermodel.authenticate(:message => { :username => "luke", :password => "secret" })
152
+ end
153
+
154
+ end
@@ -0,0 +1,92 @@
1
+ require "spec_helper"
2
+ require "integration/support/server"
3
+
4
+ describe Savon 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 ".observers" do
15
+ after :each do
16
+ Savon.observers.clear
17
+ end
18
+
19
+ it "allows to register an observer for every request" do
20
+ observer = Class.new {
21
+
22
+ def notify(operation_name, builder, globals, locals)
23
+ @operation_name = operation_name
24
+
25
+ @builder = builder
26
+ @globals = globals
27
+ @locals = locals
28
+
29
+ # return nil to execute the request
30
+ nil
31
+ end
32
+
33
+ attr_reader :operation_name, :builder, :globals, :locals
34
+
35
+ }.new
36
+
37
+ Savon.observers << observer
38
+
39
+ new_client.call(:authenticate)
40
+
41
+ expect(observer.operation_name).to eq(:authenticate)
42
+
43
+ expect(observer.builder).to be_a(Savon::Builder)
44
+ expect(observer.globals).to be_a(Savon::GlobalOptions)
45
+ expect(observer.locals).to be_a(Savon::LocalOptions)
46
+ end
47
+
48
+ it "allows to register an observer which mocks requests" do
49
+ observer = Class.new {
50
+
51
+ def notify(*)
52
+ # return a response to mock the request
53
+ HTTPI::Response.new(201, { "X-Result" => "valid" }, "valid!")
54
+ end
55
+
56
+ }.new
57
+
58
+ Savon.observers << observer
59
+
60
+ response = new_client.call(:authenticate)
61
+
62
+ expect(response.http.code).to eq(201)
63
+ expect(response.http.headers).to eq("X-Result" => "valid")
64
+ expect(response.http.body).to eq("valid!")
65
+ end
66
+
67
+ it "raises if an observer returns something other than nil or an HTTPI::Response" do
68
+ observer = Class.new {
69
+
70
+ def notify(*)
71
+ []
72
+ end
73
+
74
+ }.new
75
+
76
+ Savon.observers << observer
77
+
78
+ expect { new_client.call(:authenticate) }.
79
+ to raise_error(Savon::Error, "Observers need to return an HTTPI::Response " \
80
+ "to mock the request or nil to execute the request.")
81
+ end
82
+ end
83
+
84
+ def new_client
85
+ Savon.client(
86
+ :endpoint => @server.url(:repeat),
87
+ :namespace => "http://v1.example.com",
88
+ :log => false
89
+ )
90
+ end
91
+
92
+ end
@@ -0,0 +1,211 @@
1
+ require "spec_helper"
2
+ require "integration/support/server"
3
+ require "json"
4
+ require "ostruct"
5
+
6
+ describe Savon::Operation do
7
+
8
+ let(:globals) { Savon::GlobalOptions.new(:endpoint => @server.url(:repeat), :log => false) }
9
+ let(:wsdl) { Wasabi::Document.new Fixture.wsdl(:taxcloud) }
10
+
11
+ let(:no_wsdl) {
12
+ wsdl = Wasabi::Document.new
13
+
14
+ wsdl.endpoint = "http://example.com"
15
+ wsdl.namespace = "http://v1.example.com"
16
+
17
+ wsdl
18
+ }
19
+
20
+ def new_operation(operation_name, wsdl, globals)
21
+ Savon::Operation.create(operation_name, wsdl, globals)
22
+ end
23
+
24
+ before :all do
25
+ @server = IntegrationServer.run
26
+ end
27
+
28
+ after :all do
29
+ @server.stop
30
+ end
31
+
32
+ describe ".create with a WSDL" do
33
+ it "returns a new operation" do
34
+ operation = new_operation(:verify_address, wsdl, globals)
35
+ expect(operation).to be_a(Savon::Operation)
36
+ end
37
+
38
+ it "raises if the operation name is not a Symbol" do
39
+ expect { new_operation("not a symbol", wsdl, globals) }.
40
+ to raise_error(ArgumentError, /Expected the first parameter \(the name of the operation to call\) to be a symbol/)
41
+ end
42
+
43
+ it "raises if the operation is not available for the service" do
44
+ expect { new_operation(:no_such_operation, wsdl, globals) }.
45
+ to raise_error(Savon::UnknownOperationError, /Unable to find SOAP operation: :no_such_operation/)
46
+ end
47
+ end
48
+
49
+ describe ".create without a WSDL" do
50
+ it "returns a new operation" do
51
+ operation = new_operation(:verify_address, no_wsdl, globals)
52
+ expect(operation).to be_a(Savon::Operation)
53
+ end
54
+ end
55
+
56
+ describe "#build" do
57
+ it "returns the Builder" do
58
+ operation = new_operation(:verify_address, wsdl, globals)
59
+ builder = operation.build(:message => { :test => 'message' })
60
+
61
+ expect(builder).to be_a(Savon::Builder)
62
+ expect(builder.to_s).to include('<tns:VerifyAddress><tns:test>message</tns:test></tns:VerifyAddress>')
63
+ end
64
+ end
65
+
66
+ describe "#call" do
67
+ it "returns a response object" do
68
+ operation = new_operation(:verify_address, wsdl, globals)
69
+ expect(operation.call).to be_a(Savon::Response)
70
+ end
71
+
72
+ it "uses the global :endpoint option for the request" do
73
+ globals.endpoint("http://v1.example.com")
74
+ HTTPI::Request.any_instance.expects(:url=).with("http://v1.example.com")
75
+
76
+ operation = new_operation(:verify_address, wsdl, globals)
77
+
78
+ # stub the actual request
79
+ http_response = HTTPI::Response.new(200, {}, "")
80
+ operation.expects(:call_with_logging).returns(http_response)
81
+
82
+ operation.call
83
+ end
84
+
85
+ it "falls back to use the WSDL's endpoint if the :endpoint option was not set" do
86
+ globals_without_endpoint = Savon::GlobalOptions.new(:log => false)
87
+ HTTPI::Request.any_instance.expects(:url=).with(wsdl.endpoint)
88
+
89
+ operation = new_operation(:verify_address, wsdl, globals_without_endpoint)
90
+
91
+ # stub the actual request
92
+ http_response = HTTPI::Response.new(200, {}, "")
93
+ operation.expects(:call_with_logging).returns(http_response)
94
+
95
+ operation.call
96
+ end
97
+
98
+ it "sets the Content-Length header" do
99
+ # XXX: probably the worst spec ever written. refactor! [dh, 2013-01-05]
100
+ http_request = HTTPI::Request.new
101
+ http_request.headers.expects(:[]=).with("Content-Length", "312")
102
+ Savon::SOAPRequest.any_instance.expects(:build).returns(http_request)
103
+
104
+ new_operation(:verify_address, wsdl, globals).call
105
+ end
106
+
107
+ it "passes the local :soap_action option to the request builder" do
108
+ globals.endpoint @server.url(:inspect_request)
109
+ soap_action = "http://v1.example.com/VerifyAddress"
110
+
111
+ operation = new_operation(:verify_address, wsdl, globals)
112
+ response = operation.call(:soap_action => soap_action)
113
+
114
+ actual_soap_action = inspect_request(response).soap_action
115
+ expect(actual_soap_action).to eq(%("#{soap_action}"))
116
+ end
117
+
118
+ it "uses the local :cookies option" do
119
+ globals.endpoint @server.url(:inspect_request)
120
+ cookies = [HTTPI::Cookie.new("some-cookie=choc-chip")]
121
+
122
+ HTTPI::Request.any_instance.expects(:set_cookies).with(cookies)
123
+
124
+ operation = new_operation(:verify_address, wsdl, globals)
125
+ operation.call(:cookies => cookies)
126
+ end
127
+
128
+ it "passes nil to the request builder if the :soap_action was set to nil" do
129
+ globals.endpoint @server.url(:inspect_request)
130
+
131
+ operation = new_operation(:verify_address, wsdl, globals)
132
+ response = operation.call(:soap_action => nil)
133
+
134
+ actual_soap_action = inspect_request(response).soap_action
135
+ expect(actual_soap_action).to be_nil
136
+ end
137
+
138
+ it "gets the SOAP action from the WSDL if available" do
139
+ globals.endpoint @server.url(:inspect_request)
140
+
141
+ operation = new_operation(:verify_address, wsdl, globals)
142
+ response = operation.call
143
+
144
+ actual_soap_action = inspect_request(response).soap_action
145
+ expect(actual_soap_action).to eq('"http://taxcloud.net/VerifyAddress"')
146
+ end
147
+
148
+ it "falls back to Gyoku if both option and WSDL are not available" do
149
+ globals.endpoint @server.url(:inspect_request)
150
+
151
+ operation = new_operation(:authenticate, no_wsdl, globals)
152
+ response = operation.call
153
+
154
+ actual_soap_action = inspect_request(response).soap_action
155
+ expect(actual_soap_action).to eq(%("authenticate"))
156
+ end
157
+
158
+ it "returns a Savon::Multipart::Response if available and requested globally" do
159
+ globals.multipart true
160
+
161
+ with_multipart_mocked do
162
+ operation = new_operation(:authenticate, no_wsdl, globals)
163
+ response = operation.call
164
+
165
+ expect(response).to be_a(Savon::Multipart::Response)
166
+ end
167
+ end
168
+
169
+ it "returns a Savon::Multipart::Response if available and requested locally" do
170
+ with_multipart_mocked do
171
+ operation = new_operation(:authenticate, no_wsdl, globals)
172
+ response = operation.call(:multipart => true)
173
+
174
+ expect(response).to be_a(Savon::Multipart::Response)
175
+ end
176
+ end
177
+
178
+ it "raises if savon-multipart is not available and it was requested globally" do
179
+ globals.multipart true
180
+
181
+ operation = new_operation(:authenticate, no_wsdl, globals)
182
+
183
+ expect { operation.call }.
184
+ to raise_error RuntimeError, /Unable to find Savon::Multipart/
185
+ end
186
+
187
+ it "raises if savon-multipart is not available and it was requested locally" do
188
+ operation = new_operation(:authenticate, no_wsdl, globals)
189
+
190
+ expect { operation.call(:multipart => true) }.
191
+ to raise_error RuntimeError, /Unable to find Savon::Multipart/
192
+ end
193
+ end
194
+
195
+ def with_multipart_mocked
196
+ multipart_response = Class.new { def initialize(*args); end }
197
+ multipart_mock = Module.new
198
+ multipart_mock.const_set('Response', multipart_response)
199
+
200
+ Savon.const_set('Multipart', multipart_mock)
201
+
202
+ yield
203
+ ensure
204
+ Savon.send(:remove_const, :Multipart) if Savon.const_defined? :Multipart
205
+ end
206
+
207
+ def inspect_request(response)
208
+ hash = JSON.parse(response.http.body)
209
+ OpenStruct.new(hash)
210
+ end
211
+ end