savon 2.11.0 → 2.12.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.
@@ -2,14 +2,16 @@ require 'spec_helper'
2
2
 
3
3
  module LogInterceptor
4
4
  @@intercepted_request = ""
5
- def self.debug(message)
5
+ def self.debug(message = nil)
6
+ message ||= yield if block_given?
7
+
6
8
  # save only the first XMLly message
7
9
  if message.include? "xml version"
8
10
  @@intercepted_request = message if @@intercepted_request == ""
9
11
  end
10
12
  end
11
13
 
12
- def self.info(message)
14
+ def self.info(message = nil)
13
15
  end
14
16
 
15
17
  def self.get_intercepted_request
@@ -27,6 +29,7 @@ describe 'Correct translation of attributes to XML' do
27
29
 
28
30
  client = Savon.client(
29
31
  :wsdl => "http://mt205.sabameeting.com/CWS/CWS.asmx?WSDL",
32
+ :log => true,
30
33
  :logger => LogInterceptor
31
34
  )
32
35
 
@@ -48,14 +51,12 @@ describe 'Correct translation of attributes to XML' do
48
51
 
49
52
  client = Savon.client(
50
53
  :wsdl => "http://mt205.sabameeting.com/CWS/CWS.asmx?WSDL",
54
+ :log => true,
51
55
  :logger => LogInterceptor
52
56
  )
53
57
 
54
58
  response = nil
55
- begin
56
- response = call_and_fail_gracefully(client, :add_new_user, :message => { :user => {}, :attributes! => { :user => { :userID => "test" } } })
57
- rescue
58
- end
59
+ response = call_and_fail_gracefully(client, :add_new_user, :message => { :user => {}, :attributes! => { :user => { :userID => "test" } } })
59
60
 
60
61
  xml_doc = Nokogiri::XML(LogInterceptor.get_intercepted_request)
61
62
  xml_doc.remove_namespaces!
@@ -16,7 +16,7 @@ describe 'rpc/encoded binding test' do
16
16
  $stderr.puts e.to_hash.inspect
17
17
  f_c = e.to_hash[:fault][:faultstring]
18
18
  expect(f_c).not_to eq('No such operation \'getQuoteRequest\'')
19
- expect(f_c).to eq('soapenv:Server.userException')
19
+ expect(f_c).to eq('lucee.runtime.exp.DatabaseException: ')
20
20
  pending e
21
21
  end
22
22
  end
@@ -19,6 +19,12 @@ describe "Stockquote example" do
19
19
 
20
20
  cdata = response.body[:get_quote_response][:get_quote_result]
21
21
 
22
+ if cdata == "exception"
23
+ # Fallback to not fail the specs when the service's API limit is reached,
24
+ # but to mark the spec as pending instead.
25
+ pending "Exception on API"
26
+ end
27
+
22
28
  nori_options = { :convert_tags_to => lambda { |tag| tag.snakecase.to_sym } }
23
29
  result = Nori.new(nori_options).parse(cdata)
24
30
 
@@ -1,4 +1,4 @@
1
- require "rack/builder"
1
+ require "rack"
2
2
  require "json"
3
3
 
4
4
  class IntegrationServer
@@ -83,10 +83,19 @@ describe Savon::Builder do
83
83
  end
84
84
 
85
85
  describe "#wsse_signature" do
86
- let(:private_key) { "spec/fixtures/ssl/client_key.pem" }
87
- let(:cert) { "spec/fixtures/ssl/client_cert.pem" }
88
- let(:signature) { Akami::WSSE::Signature.new(Akami::WSSE::Certs.new(:cert_file => cert, :private_key_file => private_key))}
89
- let(:globals) { Savon::GlobalOptions.new(wsse_signature: signature) }
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) }
90
99
 
91
100
  subject(:signed_message_nn) {Nokogiri::XML(builder.to_s).remove_namespaces!}
92
101
  subject(:signed_message) {Nokogiri::XML(builder.to_s)}
@@ -21,9 +21,15 @@ describe Savon::LogMessage do
21
21
  expect(message).to include("\n <body>")
22
22
  end
23
23
 
24
- it "filters tags in a given message" do
24
+ it "filters tags in a given message without pretty printing" do
25
25
  message = log_message("<root><password>secret</password></root>", [:password], false).to_s
26
26
  expect(message).to include("<password>***FILTERED***</password>")
27
+ expect(message).to_not include("\n <password>***FILTERED***</password>") # no pretty printing
28
+ end
29
+
30
+ it "filters tags in a given message with pretty printing" do
31
+ message = log_message("<root><password>secret</password></root>", [:password], true).to_s
32
+ expect(message).to include("\n <password>***FILTERED***</password>")
27
33
  end
28
34
 
29
35
  it "properly applies Proc filter" do
@@ -23,6 +23,17 @@ describe "Savon's mock interface" do
23
23
  expect(response.http.body).to eq("<fixture/>")
24
24
  end
25
25
 
26
+ it "can verify a request with any parameters and return a fixture response" do
27
+ message = { :username => "luke", :password => :any }
28
+ savon.expects(:authenticate).with(:message => message).returns("<fixture/>")
29
+
30
+ response = new_client.call(:authenticate) do
31
+ message(:username => "luke", :password => "secret")
32
+ end
33
+
34
+ expect(response.http.body).to eq("<fixture/>")
35
+ end
36
+
26
37
  it "accepts a Hash to specify the response code, headers and body" do
27
38
  soap_fault = Fixture.response(:soap_fault)
28
39
  response = { :code => 500, :headers => { "X-Result" => "invalid" }, :body => soap_fault }
@@ -114,6 +114,15 @@ describe "Options" do
114
114
  end
115
115
  end
116
116
 
117
+ context "global :host" do
118
+ it "overrides the WSDL endpoint host" do
119
+ client = new_client(:wsdl => Fixture.wsdl(:no_message_tag), host: "https://example.com:8080")
120
+
121
+ request = client.build_request(:update_orders)
122
+ expect(request.url.to_s).to eq "https://example.com:8080/webserviceexternal/contracts.asmx"
123
+ end
124
+ end
125
+
117
126
  context "global :headers" do
118
127
  it "sets the HTTP headers for the next request" do
119
128
  client = new_client(:endpoint => @server.url(:inspect_request), :headers => { "X-Token" => "secret" })
@@ -380,18 +389,27 @@ describe "Options" do
380
389
 
381
390
  context "global :ssl_version" do
382
391
  it "sets the SSL version to use" do
383
- HTTPI::Auth::SSL.any_instance.expects(:ssl_version=).with(:SSLv3).twice
392
+ HTTPI::Auth::SSL.any_instance.expects(:ssl_version=).with(:TLSv1).twice
384
393
 
385
- client = new_client(:endpoint => @server.url, :ssl_version => :SSLv3)
394
+ client = new_client(:endpoint => @server.url, :ssl_version => :TLSv1)
386
395
  client.call(:authenticate)
387
396
  end
388
397
  end
389
398
 
390
399
  context "global :ssl_verify_mode" do
391
400
  it "sets the verify mode to use" do
392
- HTTPI::Auth::SSL.any_instance.expects(:verify_mode=).with(:none).twice
401
+ HTTPI::Auth::SSL.any_instance.expects(:verify_mode=).with(:peer).twice
402
+
403
+ client = new_client(:endpoint => @server.url, :ssl_verify_mode => :peer)
404
+ client.call(:authenticate)
405
+ end
406
+ end
407
+
408
+ context "global :ssl_ciphers" do
409
+ it "sets the ciphers to use" do
410
+ HTTPI::Auth::SSL.any_instance.expects(:ciphers=).with(:none).twice
393
411
 
394
- client = new_client(:endpoint => @server.url, :ssl_verify_mode => :none)
412
+ client = new_client(:endpoint => @server.url, :ssl_ciphers => :none)
395
413
  client.call(:authenticate)
396
414
  end
397
415
  end
@@ -460,6 +478,26 @@ describe "Options" do
460
478
  end
461
479
  end
462
480
 
481
+ context "global :ssl_ca_cert_path" do
482
+ it "sets the ca cert path to use" do
483
+ ca_cert_path = "../../fixtures/ssl"
484
+ HTTPI::Auth::SSL.any_instance.expects(:ca_cert_path=).with(ca_cert_path).twice
485
+
486
+ client = new_client(:endpoint => @server.url, :ssl_ca_cert_path => ca_cert_path)
487
+ client.call(:authenticate)
488
+ end
489
+ end
490
+
491
+ context "global :ssl_ca_cert_store" do
492
+ it "sets the cert store to use" do
493
+ cert_store = OpenSSL::X509::Store.new
494
+ HTTPI::Auth::SSL.any_instance.expects(:cert_store=).with(cert_store).twice
495
+
496
+ client = new_client(:endpoint => @server.url, :ssl_cert_store => cert_store)
497
+ client.call(:authenticate)
498
+ end
499
+ end
500
+
463
501
  context "global :ssl_ca_cert" do
464
502
  it "sets the ca cert file to use" do
465
503
  ca_cert = File.open(File.expand_path("../../fixtures/ssl/client_cert.pem", __FILE__)).read
@@ -578,7 +616,7 @@ describe "Options" do
578
616
  expect(request).to include("<wsse:Username>#{username}</wsse:Username>")
579
617
 
580
618
  # the nonce node
581
- expect(request).to match(/<wsse:Nonce.*>.+\n<\/wsse:Nonce>/)
619
+ expect(request).to match(/<wsse:Nonce.*>.+\n?<\/wsse:Nonce>/)
582
620
 
583
621
  # the created node with a timestamp
584
622
  expect(request).to match(/<wsu:Created>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*<\/wsu:Created>/)
@@ -1037,6 +1075,17 @@ describe "Options" do
1037
1075
  end
1038
1076
  end
1039
1077
 
1078
+ context "request :headers" do
1079
+ it "sets headers" do
1080
+ client = new_client(:endpoint => @server.url(:inspect_request))
1081
+
1082
+ response = client.call(:authenticate, :headers => { "X-Token" => "secret" })
1083
+ x_token = inspect_request(response).x_token
1084
+
1085
+ expect(x_token).to eq("secret")
1086
+ end
1087
+ end
1088
+
1040
1089
  def new_client(globals = {}, &block)
1041
1090
  globals = { :wsdl => Fixture.wsdl(:authentication), :log => false }.merge(globals)
1042
1091
  Savon.client(globals, &block)
@@ -4,15 +4,96 @@ module Savon
4
4
  describe QualifiedMessage, "#to_hash" do
5
5
 
6
6
  context "if a key ends with !" do
7
- it "restores the ! in a key" do
8
- used_namespaces = {}
9
- key_converter = :camelcase
10
- types = {}
7
+ let(:used_namespaces) { {} }
8
+ let(:key_converter) { :camelcase }
9
+ let(:types) { {} }
11
10
 
11
+ it "restores the ! in a key" do
12
12
  message = described_class.new(types, used_namespaces, key_converter)
13
13
  resulting_hash = message.to_hash({:Metal! => "<Nice/>"}, ["Rock"])
14
14
 
15
- expect(resulting_hash).to eq({"Metal!" => "<Nice/>"})
15
+ expect(resulting_hash).to eq({ :Metal! => "<Nice/>" })
16
+ end
17
+
18
+ it "properly handles special keys when namespaces are present" do
19
+ used_namespaces = {
20
+ %w(tns Foo) => 'ns',
21
+ %w(tns Foo Bar) => 'ns'
22
+ }
23
+
24
+ hash = {
25
+ :foo => {
26
+ :bar => {
27
+ :zing => 'pow'
28
+ },
29
+ :cash => {
30
+ :@attr1 => 'val1',
31
+ :content! => 'Chunky Bacon'
32
+ },
33
+ :attributes! => {
34
+ :bar => { :attr2 => 'val2' },
35
+ },
36
+ :"self_closing/" => '',
37
+ :order! => [:cash, :bar, :"self_closing/"]
38
+ }
39
+ }
40
+
41
+ good_result = {
42
+ "ns:Foo" => {
43
+ 'ns:Bar' => { :zing => "pow" },
44
+ :cash => {
45
+ :@attr1 => "val1",
46
+ :content! => "Chunky Bacon"
47
+ },
48
+ :attributes! => {
49
+ 'ns:Bar' => { :attr2 => 'val2' }
50
+ },
51
+ :"self_closing/" => '',
52
+ :order! => [:cash, 'ns:Bar', :"self_closing/"]
53
+ }
54
+ }
55
+
56
+ good_xml = %(<ns:Foo><Cash attr1="val1">Chunky Bacon</Cash><ns:Bar attr2="val2"><Zing>pow</Zing></ns:Bar><SelfClosing/></ns:Foo>)
57
+
58
+ message = described_class.new(types, used_namespaces, key_converter)
59
+ resulting_hash = message.to_hash(hash, ['tns'])
60
+ xml = Gyoku.xml(resulting_hash, key_converter: key_converter)
61
+
62
+ expect(resulting_hash).to eq good_result
63
+ expect(xml).to eq good_xml
64
+ end
65
+
66
+ it "properly handles boolean false" do
67
+ used_namespaces = {
68
+ %w(tns Foo) => 'ns'
69
+ }
70
+
71
+ hash = {
72
+ :foo => {
73
+ :falsey => {
74
+ :@attr1 => false,
75
+ :content! => false
76
+ }
77
+ }
78
+ }
79
+
80
+ good_result = {
81
+ "ns:Foo" => {
82
+ :falsey => {
83
+ :@attr1 => false,
84
+ :content! => false
85
+ }
86
+ }
87
+ }
88
+
89
+ good_xml = %(<ns:Foo><Falsey attr1="false">false</Falsey></ns:Foo>)
90
+
91
+ message = described_class.new(types, used_namespaces, key_converter)
92
+ resulting_hash = message.to_hash(hash, ['tns'])
93
+ xml = Gyoku.xml(resulting_hash, key_converter: key_converter)
94
+
95
+ expect(resulting_hash).to eq good_result
96
+ expect(xml).to eq good_xml
16
97
  end
17
98
  end
18
99
 
@@ -5,6 +5,7 @@ describe Savon::WSDLRequest do
5
5
 
6
6
  let(:globals) { Savon::GlobalOptions.new }
7
7
  let(:http_request) { HTTPI::Request.new }
8
+ let(:ciphers) { OpenSSL::Cipher.ciphers }
8
9
 
9
10
  def new_wsdl_request
10
11
  Savon::WSDLRequest.new(globals, http_request)
@@ -16,6 +17,20 @@ describe Savon::WSDLRequest do
16
17
  expect(wsdl_request.build).to be_an(HTTPI::Request)
17
18
  end
18
19
 
20
+ describe "headers" do
21
+ it "are set when specified" do
22
+ globals.headers("Proxy-Authorization" => "Basic auth")
23
+ configured_http_request = new_wsdl_request.build
24
+
25
+ expect(configured_http_request.headers["Proxy-Authorization"]).to eq("Basic auth")
26
+ end
27
+
28
+ it "are not set otherwise" do
29
+ configured_http_request = new_wsdl_request.build
30
+ expect(configured_http_request.headers).to_not include("Proxy-Authorization")
31
+ end
32
+ end
33
+
19
34
  describe "proxy" do
20
35
  it "is set when specified" do
21
36
  globals.proxy("http://proxy.example.com")
@@ -60,8 +75,8 @@ describe Savon::WSDLRequest do
60
75
 
61
76
  describe "ssl version" do
62
77
  it "is set when specified" do
63
- globals.ssl_version(:SSLv3)
64
- http_request.auth.ssl.expects(:ssl_version=).with(:SSLv3)
78
+ globals.ssl_version(:TLSv1)
79
+ http_request.auth.ssl.expects(:ssl_version=).with(:TLSv1)
65
80
 
66
81
  new_wsdl_request.build
67
82
  end
@@ -74,8 +89,8 @@ describe Savon::WSDLRequest do
74
89
 
75
90
  describe "ssl verify mode" do
76
91
  it "is set when specified" do
77
- globals.ssl_verify_mode(:none)
78
- http_request.auth.ssl.expects(:verify_mode=).with(:none)
92
+ globals.ssl_verify_mode(:peer)
93
+ http_request.auth.ssl.expects(:verify_mode=).with(:peer)
79
94
 
80
95
  new_wsdl_request.build
81
96
  end
@@ -86,6 +101,20 @@ describe Savon::WSDLRequest do
86
101
  end
87
102
  end
88
103
 
104
+ describe "ssl ciphers" do
105
+ it "is set when specified" do
106
+ globals.ssl_ciphers(ciphers)
107
+ http_request.auth.ssl.expects(:ciphers=).with(ciphers)
108
+
109
+ new_wsdl_request.build
110
+ end
111
+
112
+ it "is not set otherwise" do
113
+ http_request.auth.ssl.expects(:ciphers=).never
114
+ new_wsdl_request.build
115
+ end
116
+ end
117
+
89
118
  describe "ssl cert key file" do
90
119
  it "is set when specified" do
91
120
  cert_key = File.expand_path("../../fixtures/ssl/client_key.pem", __FILE__)
@@ -232,6 +261,7 @@ describe Savon::SOAPRequest do
232
261
 
233
262
  let(:globals) { Savon::GlobalOptions.new }
234
263
  let(:http_request) { HTTPI::Request.new }
264
+ let(:ciphers) { OpenSSL::Cipher.ciphers }
235
265
 
236
266
  def new_soap_request
237
267
  Savon::SOAPRequest.new(globals, http_request)
@@ -364,8 +394,8 @@ describe Savon::SOAPRequest do
364
394
 
365
395
  describe "ssl version" do
366
396
  it "is set when specified" do
367
- globals.ssl_version(:SSLv3)
368
- http_request.auth.ssl.expects(:ssl_version=).with(:SSLv3)
397
+ globals.ssl_version(:TLSv1)
398
+ http_request.auth.ssl.expects(:ssl_version=).with(:TLSv1)
369
399
 
370
400
  new_soap_request.build
371
401
  end
@@ -378,8 +408,8 @@ describe Savon::SOAPRequest do
378
408
 
379
409
  describe "ssl verify mode" do
380
410
  it "is set when specified" do
381
- globals.ssl_verify_mode(:none)
382
- http_request.auth.ssl.expects(:verify_mode=).with(:none)
411
+ globals.ssl_verify_mode(:peer)
412
+ http_request.auth.ssl.expects(:verify_mode=).with(:peer)
383
413
 
384
414
  new_soap_request.build
385
415
  end
@@ -390,6 +420,20 @@ describe Savon::SOAPRequest do
390
420
  end
391
421
  end
392
422
 
423
+ describe "ssl ciphers" do
424
+ it "is set when specified" do
425
+ globals.ssl_ciphers(ciphers)
426
+ http_request.auth.ssl.expects(:ciphers=).with(ciphers)
427
+
428
+ new_soap_request.build
429
+ end
430
+
431
+ it "is not set otherwise" do
432
+ http_request.auth.ssl.expects(:ciphers=).never
433
+ new_soap_request.build
434
+ end
435
+ end
436
+
393
437
  describe "ssl cert key file" do
394
438
  it "is set when specified" do
395
439
  cert_key = File.expand_path("../../fixtures/ssl/client_key.pem", __FILE__)