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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +15 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +1024 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +8 -0
- data/LICENSE +20 -0
- data/README.md +81 -0
- data/Rakefile +14 -0
- data/donate.png +0 -0
- data/lib/savon/block_interface.rb +26 -0
- data/lib/savon/builder.rb +166 -0
- data/lib/savon/client.rb +88 -0
- data/lib/savon/core_ext/string.rb +29 -0
- data/lib/savon/header.rb +70 -0
- data/lib/savon/http_error.rb +27 -0
- data/lib/savon/log_message.rb +48 -0
- data/lib/savon/message.rb +36 -0
- data/lib/savon/mock/expectation.rb +71 -0
- data/lib/savon/mock/spec_helper.rb +62 -0
- data/lib/savon/mock.rb +5 -0
- data/lib/savon/model.rb +80 -0
- data/lib/savon/operation.rb +127 -0
- data/lib/savon/options.rb +330 -0
- data/lib/savon/qualified_message.rb +49 -0
- data/lib/savon/request.rb +89 -0
- data/lib/savon/request_logger.rb +48 -0
- data/lib/savon/response.rb +112 -0
- data/lib/savon/soap_fault.rb +48 -0
- data/lib/savon/version.rb +5 -0
- data/lib/savon.rb +27 -0
- data/savon.gemspec +47 -0
- data/spec/fixtures/gzip/message.gz +0 -0
- data/spec/fixtures/response/another_soap_fault.xml +14 -0
- data/spec/fixtures/response/authentication.xml +14 -0
- data/spec/fixtures/response/header.xml +13 -0
- data/spec/fixtures/response/list.xml +18 -0
- data/spec/fixtures/response/multi_ref.xml +39 -0
- data/spec/fixtures/response/soap_fault.xml +8 -0
- data/spec/fixtures/response/soap_fault12.xml +18 -0
- data/spec/fixtures/response/taxcloud.xml +1 -0
- data/spec/fixtures/ssl/client_cert.pem +16 -0
- data/spec/fixtures/ssl/client_encrypted_key.pem +30 -0
- data/spec/fixtures/ssl/client_encrypted_key_cert.pem +24 -0
- data/spec/fixtures/ssl/client_key.pem +15 -0
- data/spec/fixtures/wsdl/authentication.xml +63 -0
- data/spec/fixtures/wsdl/betfair.xml +2981 -0
- data/spec/fixtures/wsdl/edialog.xml +15416 -0
- data/spec/fixtures/wsdl/interhome.xml +2137 -0
- data/spec/fixtures/wsdl/lower_camel.xml +52 -0
- data/spec/fixtures/wsdl/multiple_namespaces.xml +92 -0
- data/spec/fixtures/wsdl/multiple_types.xml +60 -0
- data/spec/fixtures/wsdl/taxcloud.xml +934 -0
- data/spec/fixtures/wsdl/team_software.xml +1 -0
- data/spec/fixtures/wsdl/vies.xml +176 -0
- data/spec/fixtures/wsdl/wasmuth.xml +153 -0
- data/spec/integration/email_example_spec.rb +32 -0
- data/spec/integration/ratp_example_spec.rb +28 -0
- data/spec/integration/stockquote_example_spec.rb +28 -0
- data/spec/integration/support/application.rb +82 -0
- data/spec/integration/support/server.rb +84 -0
- data/spec/integration/temperature_example_spec.rb +46 -0
- data/spec/integration/zipcode_example_spec.rb +42 -0
- data/spec/savon/builder_spec.rb +86 -0
- data/spec/savon/client_spec.rb +193 -0
- data/spec/savon/core_ext/string_spec.rb +37 -0
- data/spec/savon/features/message_tag_spec.rb +61 -0
- data/spec/savon/http_error_spec.rb +49 -0
- data/spec/savon/log_message_spec.rb +33 -0
- data/spec/savon/message_spec.rb +40 -0
- data/spec/savon/mock_spec.rb +157 -0
- data/spec/savon/model_spec.rb +154 -0
- data/spec/savon/observers_spec.rb +92 -0
- data/spec/savon/operation_spec.rb +211 -0
- data/spec/savon/options_spec.rb +772 -0
- data/spec/savon/request_spec.rb +493 -0
- data/spec/savon/response_spec.rb +258 -0
- data/spec/savon/soap_fault_spec.rb +126 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/endpoint.rb +25 -0
- data/spec/support/fixture.rb +39 -0
- data/spec/support/integration.rb +9 -0
- data/spec/support/stdout.rb +25 -0
- 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
|