savon 2.11.2 → 2.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/CHANGELOG.md +103 -73
- data/CONTRIBUTING.md +15 -19
- data/Gemfile +2 -7
- data/README.md +26 -15
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_both.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc.png +0 -0
- data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
- data/coverage/assets/0.12.3/application.css +1 -0
- data/coverage/assets/0.12.3/application.js +7 -0
- data/coverage/assets/0.12.3/colorbox/border.png +0 -0
- data/coverage/assets/0.12.3/colorbox/controls.png +0 -0
- data/coverage/assets/0.12.3/colorbox/loading.gif +0 -0
- data/coverage/assets/0.12.3/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.12.3/favicon_green.png +0 -0
- data/coverage/assets/0.12.3/favicon_red.png +0 -0
- data/coverage/assets/0.12.3/favicon_yellow.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.12.3/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.12.3/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/assets/0.12.3/loading.gif +0 -0
- data/coverage/assets/0.12.3/magnify.png +0 -0
- data/coverage/index.html +21518 -0
- data/lib/savon/block_interface.rb +1 -0
- data/lib/savon/builder.rb +95 -29
- data/lib/savon/client.rb +1 -0
- data/lib/savon/core_ext/string.rb +1 -0
- data/lib/savon/header.rb +2 -6
- data/lib/savon/http_error.rb +4 -4
- data/lib/savon/log_message.rb +1 -0
- data/lib/savon/message.rb +1 -0
- data/lib/savon/mock/expectation.rb +1 -0
- data/lib/savon/mock/spec_helper.rb +1 -0
- data/lib/savon/mock.rb +1 -0
- data/lib/savon/model.rb +1 -0
- data/lib/savon/operation.rb +20 -18
- data/lib/savon/options.rb +70 -1
- data/lib/savon/qualified_message.rb +5 -4
- data/lib/savon/request.rb +18 -3
- data/lib/savon/request_logger.rb +8 -2
- data/lib/savon/response.rb +49 -2
- data/lib/savon/soap_fault.rb +2 -3
- data/lib/savon/version.rb +2 -1
- data/lib/savon.rb +1 -0
- data/savon.gemspec +10 -9
- data/spec/fixtures/response/empty_soap_fault.xml +13 -0
- data/spec/fixtures/response/no_body.xml +1 -0
- data/spec/fixtures/wsdl/elements_in_types.xml +43 -0
- data/spec/integration/support/application.rb +34 -2
- data/spec/integration/support/server.rb +1 -0
- data/spec/integration/zipcode_example_spec.rb +5 -8
- data/spec/savon/builder_spec.rb +2 -1
- data/spec/savon/client_spec.rb +5 -4
- data/spec/savon/core_ext/string_spec.rb +2 -1
- data/spec/savon/features/message_tag_spec.rb +2 -1
- data/spec/savon/http_error_spec.rb +9 -1
- data/spec/savon/log_message_spec.rb +2 -1
- data/spec/savon/message_spec.rb +2 -11
- data/spec/savon/mock_spec.rb +2 -1
- data/spec/savon/model_spec.rb +2 -1
- data/spec/savon/multipart_request_spec.rb +46 -0
- data/spec/savon/observers_spec.rb +2 -1
- data/spec/savon/operation_spec.rb +20 -43
- data/spec/savon/options_spec.rb +84 -5
- data/spec/savon/qualified_message_spec.rb +35 -1
- data/spec/savon/request_logger_spec.rb +2 -1
- data/spec/savon/request_spec.rb +99 -14
- data/spec/savon/response_spec.rb +7 -1
- data/spec/savon/soap_fault_spec.rb +12 -1
- data/spec/savon/softlayer_spec.rb +3 -2
- data/spec/spec_helper.rb +5 -4
- data/spec/support/adapters.rb +1 -0
- data/spec/support/endpoint.rb +1 -0
- data/spec/support/fixture.rb +1 -0
- data/spec/support/integration.rb +2 -1
- data/spec/support/stdout.rb +1 -0
- metadata +86 -33
- data/.travis.yml +0 -19
- data/donate.png +0 -0
- data/spec/integration/centra_spec.rb +0 -66
- data/spec/integration/email_example_spec.rb +0 -32
- data/spec/integration/random_quote_spec.rb +0 -23
- data/spec/integration/ratp_example_spec.rb +0 -28
- data/spec/integration/stockquote_example_spec.rb +0 -34
- data/spec/integration/temperature_example_spec.rb +0 -46
data/lib/savon/soap_fault.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
3
2
|
module Savon
|
4
3
|
class SOAPFault < Error
|
5
4
|
|
6
5
|
def self.present?(http, xml = nil)
|
7
6
|
xml ||= http.body
|
8
7
|
fault_node = xml.include?("Fault>")
|
9
|
-
soap1_fault = xml.
|
8
|
+
soap1_fault = xml.match(/faultcode\/?\>/) && xml.match(/faultstring\/?\>/)
|
10
9
|
soap2_fault = xml.include?("Code>") && xml.include?("Reason>")
|
11
10
|
|
12
11
|
fault_node && (soap1_fault || soap2_fault)
|
data/lib/savon/version.rb
CHANGED
data/lib/savon.rb
CHANGED
data/savon.gemspec
CHANGED
@@ -12,29 +12,30 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.homepage = "http://savonrb.com"
|
13
13
|
s.summary = "Heavy metal SOAP client"
|
14
14
|
s.description = s.summary
|
15
|
-
s.required_ruby_version = '>=
|
15
|
+
s.required_ruby_version = '>= 2.5.0'
|
16
16
|
|
17
|
-
s.rubyforge_project = s.name
|
18
17
|
s.license = 'MIT'
|
19
18
|
|
20
19
|
s.add_dependency "nori", "~> 2.4"
|
21
|
-
s.add_dependency "httpi", "
|
20
|
+
s.add_dependency "httpi", ">= 2.4.5"
|
22
21
|
s.add_dependency "wasabi", "~> 3.4"
|
23
22
|
s.add_dependency "akami", "~> 1.2"
|
24
23
|
s.add_dependency "gyoku", "~> 1.2"
|
25
24
|
s.add_dependency "builder", ">= 2.1.2"
|
26
|
-
s.add_dependency "nokogiri", ">= 1.
|
25
|
+
s.add_dependency "nokogiri", ">= 1.8.1"
|
26
|
+
s.add_dependency "mail", "~> 2.5"
|
27
27
|
|
28
28
|
s.add_development_dependency "rack"
|
29
|
-
s.add_development_dependency "puma", "
|
29
|
+
s.add_development_dependency "puma", ">= 4.3.8"
|
30
30
|
|
31
|
-
s.add_development_dependency "
|
32
|
-
s.add_development_dependency "
|
31
|
+
s.add_development_dependency "byebug"
|
32
|
+
s.add_development_dependency "rake", ">= 12.3.3"
|
33
|
+
s.add_development_dependency "rspec", "~> 3.9"
|
33
34
|
s.add_development_dependency "mocha", "~> 0.14"
|
34
|
-
s.add_development_dependency "json", "
|
35
|
+
s.add_development_dependency "json", ">= 2.3.0"
|
35
36
|
|
36
37
|
ignores = File.readlines(".gitignore").grep(/\S+/).map(&:chomp)
|
37
|
-
dotfiles = %w[.gitignore .
|
38
|
+
dotfiles = %w[.gitignore .yardopts]
|
38
39
|
|
39
40
|
all_files_without_ignores = Dir["**/*"].reject { |f|
|
40
41
|
File.directory?(f) || ignores.any? { |i| File.fnmatch(i, f) }
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
|
2
|
+
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
|
3
|
+
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
|
4
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
5
|
+
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
6
|
+
<SOAP-ENV:Body>
|
7
|
+
<SOAP-ENV:Fault>
|
8
|
+
<faultcode/>
|
9
|
+
<faultstring/>
|
10
|
+
<detail><soapVal><ERRNO xsi:type="xsd:string">80:1289245853:55</ERRNO></soapVal></detail>
|
11
|
+
</SOAP-ENV:Fault>
|
12
|
+
</SOAP-ENV:Body>
|
13
|
+
</SOAP-ENV:Envelope>
|
@@ -0,0 +1 @@
|
|
1
|
+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">Text</soap:Envelope>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<wsdl:definitions xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="www.example.com/XML" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s1="http://microsoft.com/wsdl/types/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="www.example.com/XML" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
|
3
|
+
<wsdl:types>
|
4
|
+
<s:schema elementFormDefault="qualified" targetNamespace="www.example.com/XML">
|
5
|
+
<s:complexType name="Transaction" abstract="true">
|
6
|
+
<s:sequence>
|
7
|
+
<s:element minOccurs="0" maxOccurs="1" name="Qualified" type="s:string" />
|
8
|
+
</s:sequence>
|
9
|
+
</s:complexType>
|
10
|
+
<s:complexType name="TopLevelTransaction">
|
11
|
+
<s:complexContent mixed="false">
|
12
|
+
<s:extension base="tns:Transaction">
|
13
|
+
</s:extension>
|
14
|
+
</s:complexContent>
|
15
|
+
</s:complexType>
|
16
|
+
<s:element name="TopLevelTransaction">
|
17
|
+
<s:complexType>
|
18
|
+
<s:sequence>
|
19
|
+
<s:element minOccurs="0" maxOccurs="1" name="TopLevelTransaction" type="tns:TopLevelTransaction" />
|
20
|
+
</s:sequence>
|
21
|
+
</s:complexType>
|
22
|
+
</s:element>
|
23
|
+
</s:schema>
|
24
|
+
</wsdl:types>
|
25
|
+
<wsdl:message name="TopLevelTransactionSoapIn">
|
26
|
+
<wsdl:part name="parameters" element="tns:TopLevelTransaction" />
|
27
|
+
</wsdl:message>
|
28
|
+
<wsdl:portType name="XMLTESoap">
|
29
|
+
<wsdl:operation name="TopLevelTransaction">
|
30
|
+
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">TopLevelTransaction.</wsdl:documentation>
|
31
|
+
<wsdl:input message="tns:TopLevelTransactionSoapIn" />
|
32
|
+
</wsdl:operation>
|
33
|
+
</wsdl:portType>
|
34
|
+
<wsdl:binding name="XMLTESoap12" type="tns:XMLTESoap">
|
35
|
+
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
|
36
|
+
<wsdl:operation name="TopLevelTransaction">
|
37
|
+
<soap12:operation soapAction="www.example.com/XML/TopLevelTransaction" style="document" />
|
38
|
+
<wsdl:input>
|
39
|
+
<soap12:body use="literal" />
|
40
|
+
</wsdl:input>
|
41
|
+
</wsdl:operation>
|
42
|
+
</wsdl:binding>
|
43
|
+
</wsdl:definitions>
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "rack"
|
2
3
|
require "json"
|
3
4
|
|
4
5
|
class IntegrationServer
|
@@ -6,7 +7,7 @@ class IntegrationServer
|
|
6
7
|
def self.respond_with(options = {})
|
7
8
|
code = options.fetch(:code, 200)
|
8
9
|
body = options.fetch(:body, "")
|
9
|
-
headers = { "Content-Type" => "text/plain", "Content-Length" => body.size.to_s }
|
10
|
+
headers = { "Content-Type" => "text/plain", "Content-Length" => body.size.to_s }.merge options.fetch(:headers, {})
|
10
11
|
|
11
12
|
[code, headers, [body]]
|
12
13
|
end
|
@@ -78,5 +79,36 @@ class IntegrationServer
|
|
78
79
|
run app
|
79
80
|
end
|
80
81
|
|
82
|
+
map "/multipart" do
|
83
|
+
run lambda { |env|
|
84
|
+
boundary = 'mimepart_boundary'
|
85
|
+
message = Mail.new
|
86
|
+
xml_part = Mail::Part.new do
|
87
|
+
content_type 'text/xml'
|
88
|
+
body %{<?xml version='1.0' encoding='UTF-8'?>
|
89
|
+
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
|
90
|
+
<soapenv:Header>response header</soapenv:Header>
|
91
|
+
<soapenv:Body>response body</soapenv:Body>
|
92
|
+
</soapenv:Envelope>}
|
93
|
+
# in Content-Type the start parameter is recommended (RFC 2387)
|
94
|
+
content_id '<soap-request-body@soap>'
|
95
|
+
end
|
96
|
+
message.add_part xml_part
|
97
|
+
|
98
|
+
message.add_file File.expand_path("../../../fixtures/gzip/message.gz", __FILE__)
|
99
|
+
message.parts.last.content_location = 'message.gz'
|
100
|
+
message.parts.last.content_id = 'attachment1'
|
101
|
+
|
102
|
+
message.ready_to_send!
|
103
|
+
message.body.set_sort_order [ "text/xml" ]
|
104
|
+
message.body.encoded(message.content_transfer_encoding)
|
105
|
+
|
106
|
+
IntegrationServer.respond_with({
|
107
|
+
headers: { "Content-Type" => "multipart/related; boundary=\"#{message.body.boundary}\"; type=\"text/xml\"; start=\"#{xml_part.content_id}\"" },
|
108
|
+
body: message.body.encoded(message.content_transfer_encoding)
|
109
|
+
})
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
81
113
|
end
|
82
114
|
end
|
@@ -1,18 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe "ZIP code example" do
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
4
3
|
|
4
|
+
RSpec.describe "ZIP code example" do
|
5
5
|
it "supports threads making requests simultaneously" do
|
6
6
|
client = Savon.client(
|
7
|
-
# The WSDL document provided by the service.
|
8
7
|
:wsdl => "http://www.thomas-bayer.com/axis2/services/BLZService?wsdl",
|
9
8
|
|
10
9
|
# Lower timeouts so these specs don't take forever when the service is not available.
|
11
10
|
:open_timeout => 10,
|
12
11
|
:read_timeout => 10,
|
13
12
|
|
14
|
-
# Disable logging for cleaner spec output.
|
15
|
-
:log => false
|
13
|
+
:log => false # Disable logging for cleaner spec output.
|
16
14
|
)
|
17
15
|
|
18
16
|
mutex = Mutex.new
|
@@ -22,7 +20,7 @@ describe "ZIP code example" do
|
|
22
20
|
|
23
21
|
threads = request_data.map do |blz|
|
24
22
|
thread = Thread.new do
|
25
|
-
response = call_and_fail_gracefully
|
23
|
+
response = call_and_fail_gracefully(client, :get_bank, :message => { :blz => blz })
|
26
24
|
Thread.current[:value] = response.body[:get_bank_response][:details]
|
27
25
|
mutex.synchronize { threads_waiting -= 1 }
|
28
26
|
end
|
@@ -38,5 +36,4 @@ describe "ZIP code example" do
|
|
38
36
|
|
39
37
|
expect(values.uniq.size).to eq(values.size)
|
40
38
|
end
|
41
|
-
|
42
39
|
end
|
data/spec/savon/builder_spec.rb
CHANGED
data/spec/savon/client_spec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "spec_helper"
|
2
3
|
require "integration/support/server"
|
3
4
|
|
4
|
-
describe Savon::Client do
|
5
|
+
RSpec.describe Savon::Client do
|
5
6
|
|
6
7
|
before :all do
|
7
8
|
@server = IntegrationServer.run
|
@@ -231,15 +232,15 @@ describe Savon::Client do
|
|
231
232
|
end
|
232
233
|
|
233
234
|
it "raises when the operation name is not a symbol" do
|
234
|
-
expect { new_client.build_request("not a symbol") }.to raise_error
|
235
|
+
expect { new_client.build_request("not a symbol") }.to raise_error ArgumentError
|
235
236
|
end
|
236
237
|
|
237
238
|
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
|
+
expect { new_client.build_request(:authenticate, :invalid_local_option => true) }.to raise_error Savon::UnknownOptionError
|
239
240
|
end
|
240
241
|
|
241
242
|
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
|
+
expect { new_client.build_request(:authenticate) { another_invalid_local_option true } }.to raise_error Savon::UnknownOptionError
|
243
244
|
end
|
244
245
|
end
|
245
246
|
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "spec_helper"
|
2
3
|
|
3
|
-
describe Savon::HTTPError do
|
4
|
+
RSpec.describe Savon::HTTPError do
|
4
5
|
let(:http_error) { Savon::HTTPError.new new_response(:code => 404, :body => "Not Found") }
|
6
|
+
let(:http_error_with_empty_body) { Savon::HTTPError.new new_response(:code => 404, :body => "") }
|
5
7
|
let(:no_error) { Savon::HTTPError.new new_response }
|
6
8
|
|
7
9
|
it "inherits from Savon::Error" do
|
@@ -30,6 +32,12 @@ describe Savon::HTTPError do
|
|
30
32
|
it "returns the HTTP error message" do
|
31
33
|
expect(http_error.send method).to eq("HTTP error (404): Not Found")
|
32
34
|
end
|
35
|
+
|
36
|
+
context "when the body is empty" do
|
37
|
+
it "returns the HTTP error without the body message" do
|
38
|
+
expect(http_error_with_empty_body.send method).to eq("HTTP error (404)")
|
39
|
+
end
|
40
|
+
end
|
33
41
|
end
|
34
42
|
end
|
35
43
|
|
data/spec/savon/message_spec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "spec_helper"
|
2
3
|
require "integration/support/server"
|
3
4
|
|
4
|
-
describe Savon::Message do
|
5
|
+
RSpec.describe Savon::Message do
|
5
6
|
|
6
7
|
before do
|
7
8
|
@server = IntegrationServer.run
|
@@ -55,16 +56,6 @@ describe Savon::Message do
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
end
|
58
|
-
|
59
|
-
context 'wsa:MessageID' do
|
60
|
-
let(:message_id_tag) {
|
61
|
-
'<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">'
|
62
|
-
}
|
63
|
-
it 'should include xmlns:wsa attribute' do
|
64
|
-
response = client.call(:something, message: {})
|
65
|
-
expect(response.xml).to include(message_id_tag)
|
66
|
-
end
|
67
|
-
end
|
68
59
|
end
|
69
60
|
|
70
61
|
end
|
data/spec/savon/mock_spec.rb
CHANGED
data/spec/savon/model_spec.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe Savon::Builder do
|
4
|
+
|
5
|
+
let(:globals) { Savon::GlobalOptions.new({ :endpoint => "http://example.co", :namespace => "http://v1.example.com" }) }
|
6
|
+
let(:no_wsdl) { Wasabi::Document.new }
|
7
|
+
|
8
|
+
it "building multipart request from inline content" do
|
9
|
+
locals = {
|
10
|
+
attachments: [
|
11
|
+
{ filename: 'x1.xml', content: '<xml>abc1</xml>'},
|
12
|
+
{ filename: 'x2.xml', content: '<xml>abc2</xml>'},
|
13
|
+
]
|
14
|
+
}
|
15
|
+
builder = Savon::Builder.new(:operation1, no_wsdl, globals, Savon::LocalOptions.new(locals))
|
16
|
+
request_body = builder.to_s
|
17
|
+
|
18
|
+
expect(request_body).to include('Content-Type')
|
19
|
+
expect(request_body).to match(/<[a-z]+:operation1>/)
|
20
|
+
|
21
|
+
locals[:attachments].each do |attachment|
|
22
|
+
expect(request_body).to match(/^Content-Location: #{attachment[:filename]}\s$/)
|
23
|
+
expect(request_body).to include(Base64.encode64(attachment[:content]).strip)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
it "building multipart request from file" do
|
29
|
+
locals = {
|
30
|
+
attachments: {
|
31
|
+
'file.gz' => File.expand_path("../../fixtures/gzip/message.gz", __FILE__)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
builder = Savon::Builder.new(:operation1, no_wsdl, globals, Savon::LocalOptions.new(locals))
|
35
|
+
request_body = builder.to_s
|
36
|
+
|
37
|
+
expect(request_body).to include('Content-Type')
|
38
|
+
expect(request_body).to match(/<[a-z]+:operation1>/)
|
39
|
+
|
40
|
+
locals[:attachments].each do |id, file|
|
41
|
+
expect(request_body).to match(/^Content-Location: #{id}\s$/)
|
42
|
+
expect(request_body.gsub("\r", "")).to include(Base64.encode64(File.read(file)).strip)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "spec_helper"
|
2
3
|
require "integration/support/server"
|
3
4
|
require "json"
|
4
5
|
require "ostruct"
|
5
6
|
|
6
|
-
describe Savon::Operation do
|
7
|
+
RSpec.describe Savon::Operation do
|
7
8
|
|
8
9
|
let(:globals) { Savon::GlobalOptions.new(:endpoint => @server.url(:repeat), :log => false) }
|
9
10
|
let(:wsdl) { Wasabi::Document.new Fixture.wsdl(:taxcloud) }
|
@@ -108,7 +109,7 @@ describe Savon::Operation do
|
|
108
109
|
it "sets the Content-Length header" do
|
109
110
|
# XXX: probably the worst spec ever written. refactor! [dh, 2013-01-05]
|
110
111
|
http_request = HTTPI::Request.new
|
111
|
-
http_request.headers.expects(:[]=).with("Content-Length", "
|
112
|
+
http_request.headers.expects(:[]=).with("Content-Length", "723")
|
112
113
|
Savon::SOAPRequest.any_instance.expects(:build).returns(http_request)
|
113
114
|
|
114
115
|
new_operation(:verify_address, wsdl, globals).call
|
@@ -165,40 +166,28 @@ describe Savon::Operation do
|
|
165
166
|
expect(actual_soap_action).to eq(%("authenticate"))
|
166
167
|
end
|
167
168
|
|
168
|
-
it "
|
169
|
-
globals.multipart
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
169
|
+
it "handle multipart response" do
|
170
|
+
globals.endpoint @server.url(:multipart)
|
171
|
+
operation = new_operation(:example, no_wsdl, globals)
|
172
|
+
response = operation.call do
|
173
|
+
attachments [
|
174
|
+
{ filename: 'x1.xml', content: '<xml>abc</xml>'},
|
175
|
+
{ filename: 'x2.xml', content: '<xml>cde</xml>'},
|
176
|
+
]
|
176
177
|
end
|
177
|
-
end
|
178
|
-
|
179
|
-
it "returns a Savon::Multipart::Response if available and requested locally" do
|
180
|
-
with_multipart_mocked do
|
181
|
-
operation = new_operation(:authenticate, no_wsdl, globals)
|
182
|
-
response = operation.call(:multipart => true)
|
183
178
|
|
184
|
-
|
185
|
-
|
179
|
+
expect(response.multipart?).to be true
|
180
|
+
expect(response.header).to eq 'response header'
|
181
|
+
expect(response.body).to eq 'response body'
|
182
|
+
expect(response.attachments.first.content_id).to eq 'attachment1'
|
186
183
|
end
|
187
184
|
|
188
|
-
it "
|
189
|
-
globals
|
190
|
-
|
191
|
-
operation = new_operation(:authenticate, no_wsdl, globals)
|
185
|
+
it "simple request is not multipart" do
|
186
|
+
operation = new_operation(:example, no_wsdl, globals)
|
187
|
+
response = operation.call
|
192
188
|
|
193
|
-
expect
|
194
|
-
|
195
|
-
end
|
196
|
-
|
197
|
-
it "raises if savon-multipart is not available and it was requested locally" do
|
198
|
-
operation = new_operation(:authenticate, no_wsdl, globals)
|
199
|
-
|
200
|
-
expect { operation.call(:multipart => true) }.
|
201
|
-
to raise_error RuntimeError, /Unable to find Savon::Multipart/
|
189
|
+
expect(response.multipart?).to be false
|
190
|
+
expect(response.attachments).to be_empty
|
202
191
|
end
|
203
192
|
end
|
204
193
|
|
@@ -211,18 +200,6 @@ describe Savon::Operation do
|
|
211
200
|
end
|
212
201
|
end
|
213
202
|
|
214
|
-
def with_multipart_mocked
|
215
|
-
multipart_response = Class.new { def initialize(*args); end }
|
216
|
-
multipart_mock = Module.new
|
217
|
-
multipart_mock.const_set('Response', multipart_response)
|
218
|
-
|
219
|
-
Savon.const_set('Multipart', multipart_mock)
|
220
|
-
|
221
|
-
yield
|
222
|
-
ensure
|
223
|
-
Savon.send(:remove_const, :Multipart) if Savon.const_defined? :Multipart
|
224
|
-
end
|
225
|
-
|
226
203
|
def inspect_request(response)
|
227
204
|
hash = JSON.parse(response.http.body)
|
228
205
|
OpenStruct.new(hash)
|
data/spec/savon/options_spec.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "spec_helper"
|
2
3
|
require "integration/support/server"
|
3
4
|
require "json"
|
4
5
|
require "ostruct"
|
5
6
|
require "logger"
|
6
7
|
|
7
|
-
describe "Options" do
|
8
|
+
RSpec.describe "Options" do
|
8
9
|
|
9
10
|
before :all do
|
10
11
|
@server = IntegrationServer.run
|
@@ -219,6 +220,17 @@ describe "Options" do
|
|
219
220
|
expect(response.http.body).to include("<user>lea</user>")
|
220
221
|
expect(response.http.body).to include("<password>top-secret</password>")
|
221
222
|
end
|
223
|
+
|
224
|
+
it "qualifies elements embedded in complex types" do
|
225
|
+
client = new_client(:endpoint => @server.url(:repeat),
|
226
|
+
:wsdl => Fixture.wsdl(:elements_in_types))
|
227
|
+
msg = {":TopLevelTransaction"=>{":Qualified"=>"A Value"}}
|
228
|
+
|
229
|
+
response = client.call(:top_level_transaction, :message => msg)
|
230
|
+
|
231
|
+
expect(response.http.body.scan(/<tns:Qualified>/).count).to eq(1)
|
232
|
+
end
|
233
|
+
|
222
234
|
end
|
223
235
|
|
224
236
|
context "global :env_namespace" do
|
@@ -387,20 +399,67 @@ describe "Options" do
|
|
387
399
|
end
|
388
400
|
end
|
389
401
|
|
402
|
+
context "global :log_headers" do
|
403
|
+
it "instructs Savon to log SOAP requests and responses headers" do
|
404
|
+
stdout = mock_stdout {
|
405
|
+
client = new_client(:endpoint => @server.url, :log => true)
|
406
|
+
client.call(:authenticate)
|
407
|
+
}
|
408
|
+
soap_header = stdout.string.include? "Content-Type"
|
409
|
+
expect(soap_header).to be true
|
410
|
+
end
|
411
|
+
|
412
|
+
it "stops Savon from logging SOAP requests and responses headers" do
|
413
|
+
stdout = mock_stdout {
|
414
|
+
client = new_client(:endpoint => @server.url, :log => true, :log_headers => false)
|
415
|
+
client.call(:authenticate)
|
416
|
+
}
|
417
|
+
soap_header = stdout.string.include? "Content-Type"
|
418
|
+
expect(soap_header).to be false
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
390
422
|
context "global :ssl_version" do
|
391
423
|
it "sets the SSL version to use" do
|
392
|
-
HTTPI::Auth::SSL.any_instance.expects(:ssl_version=).with(:
|
424
|
+
HTTPI::Auth::SSL.any_instance.expects(:ssl_version=).with(:TLSv1).twice
|
425
|
+
|
426
|
+
client = new_client(:endpoint => @server.url, :ssl_version => :TLSv1)
|
427
|
+
client.call(:authenticate)
|
428
|
+
end
|
429
|
+
end
|
393
430
|
|
394
|
-
|
431
|
+
context "global :ssl_min_version" do
|
432
|
+
it "sets the SSL min_version to use" do
|
433
|
+
HTTPI::Auth::SSL.any_instance.expects(:min_version=).with(:TLS1_2).twice
|
434
|
+
|
435
|
+
client = new_client(:endpoint => @server.url, :ssl_min_version => :TLS1_2)
|
436
|
+
client.call(:authenticate)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
context "global :ssl_max_version" do
|
441
|
+
it "sets the SSL max_version to use" do
|
442
|
+
HTTPI::Auth::SSL.any_instance.expects(:max_version=).with(:TLS1_2).twice
|
443
|
+
|
444
|
+
client = new_client(:endpoint => @server.url, :ssl_max_version => :TLS1_2)
|
395
445
|
client.call(:authenticate)
|
396
446
|
end
|
397
447
|
end
|
398
448
|
|
399
449
|
context "global :ssl_verify_mode" do
|
400
450
|
it "sets the verify mode to use" do
|
401
|
-
HTTPI::Auth::SSL.any_instance.expects(:verify_mode=).with(:
|
451
|
+
HTTPI::Auth::SSL.any_instance.expects(:verify_mode=).with(:peer).twice
|
452
|
+
|
453
|
+
client = new_client(:endpoint => @server.url, :ssl_verify_mode => :peer)
|
454
|
+
client.call(:authenticate)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
context "global :ssl_ciphers" do
|
459
|
+
it "sets the ciphers to use" do
|
460
|
+
HTTPI::Auth::SSL.any_instance.expects(:ciphers=).with(:none).twice
|
402
461
|
|
403
|
-
client = new_client(:endpoint => @server.url, :
|
462
|
+
client = new_client(:endpoint => @server.url, :ssl_ciphers => :none)
|
404
463
|
client.call(:authenticate)
|
405
464
|
end
|
406
465
|
end
|
@@ -469,6 +528,26 @@ describe "Options" do
|
|
469
528
|
end
|
470
529
|
end
|
471
530
|
|
531
|
+
context "global :ssl_ca_cert_path" do
|
532
|
+
it "sets the ca cert path to use" do
|
533
|
+
ca_cert_path = "../../fixtures/ssl"
|
534
|
+
HTTPI::Auth::SSL.any_instance.expects(:ca_cert_path=).with(ca_cert_path).twice
|
535
|
+
|
536
|
+
client = new_client(:endpoint => @server.url, :ssl_ca_cert_path => ca_cert_path)
|
537
|
+
client.call(:authenticate)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
context "global :ssl_ca_cert_store" do
|
542
|
+
it "sets the cert store to use" do
|
543
|
+
cert_store = OpenSSL::X509::Store.new
|
544
|
+
HTTPI::Auth::SSL.any_instance.expects(:cert_store=).with(cert_store).twice
|
545
|
+
|
546
|
+
client = new_client(:endpoint => @server.url, :ssl_cert_store => cert_store)
|
547
|
+
client.call(:authenticate)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
472
551
|
context "global :ssl_ca_cert" do
|
473
552
|
it "sets the ca cert file to use" do
|
474
553
|
ca_cert = File.open(File.expand_path("../../fixtures/ssl/client_cert.pem", __FILE__)).read
|