savon 2.5.1 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/lib/savon/builder.rb +6 -1
- data/lib/savon/header.rb +2 -2
- data/lib/savon/options.rb +37 -11
- data/lib/savon/request.rb +7 -2
- data/lib/savon/version.rb +1 -1
- data/savon.gemspec +1 -1
- data/spec/fixtures/wsdl/no_message_tag.xml +1267 -0
- data/spec/integration/email_example_spec.rb +1 -1
- data/spec/integration/random_quote_spec.rb +2 -2
- data/spec/integration/stockquote_example_spec.rb +1 -1
- data/spec/integration/zipcode_example_spec.rb +1 -1
- data/spec/savon/builder_spec.rb +5 -0
- data/spec/savon/client_spec.rb +1 -1
- data/spec/savon/core_ext/string_spec.rb +9 -9
- data/spec/savon/http_error_spec.rb +2 -2
- data/spec/savon/options_spec.rb +235 -53
- data/spec/savon/request_spec.rb +2 -2
- data/spec/savon/response_spec.rb +33 -31
- data/spec/savon/soap_fault_spec.rb +5 -5
- metadata +5 -4
@@ -25,7 +25,7 @@ describe "Email example" do
|
|
25
25
|
pending "API limit exceeded"
|
26
26
|
else
|
27
27
|
# The expected result. We unfortunately don't have a license key for this service.
|
28
|
-
response_text.
|
28
|
+
expect(response_text).to eq("Email Domain Not Found")
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -15,8 +15,8 @@ describe 'rpc/encoded binding test' do
|
|
15
15
|
rescue Savon::SOAPFault => e
|
16
16
|
$stderr.puts e.to_hash.inspect
|
17
17
|
f_c = e.to_hash[:fault][:faultstring]
|
18
|
-
f_c.
|
19
|
-
f_c.
|
18
|
+
expect(f_c).not_to eq('No such operation \'getQuoteRequest\'')
|
19
|
+
expect(f_c).to eq('soapenv:Server.userException')
|
20
20
|
pending e
|
21
21
|
end
|
22
22
|
end
|
@@ -22,7 +22,7 @@ describe "Stockquote example" do
|
|
22
22
|
nori_options = { :convert_tags_to => lambda { |tag| tag.snakecase.to_sym } }
|
23
23
|
result = Nori.new(nori_options).parse(cdata)
|
24
24
|
|
25
|
-
result[:stock_quotes][:stock][:symbol].
|
25
|
+
expect(result[:stock_quotes][:stock][:symbol]).to eq("AAPL")
|
26
26
|
end
|
27
27
|
|
28
28
|
end
|
data/spec/savon/builder_spec.rb
CHANGED
data/spec/savon/client_spec.rb
CHANGED
@@ -4,33 +4,33 @@ describe String do
|
|
4
4
|
|
5
5
|
describe "snakecase" do
|
6
6
|
it "lowercases one word CamelCase" do
|
7
|
-
"Merb".snakecase.
|
7
|
+
expect("Merb".snakecase).to eq("merb")
|
8
8
|
end
|
9
9
|
|
10
10
|
it "makes one underscore snakecase two word CamelCase" do
|
11
|
-
"MerbCore".snakecase.
|
11
|
+
expect("MerbCore".snakecase).to eq("merb_core")
|
12
12
|
end
|
13
13
|
|
14
14
|
it "handles CamelCase with more than 2 words" do
|
15
|
-
"SoYouWantContributeToMerbCore".snakecase.
|
15
|
+
expect("SoYouWantContributeToMerbCore".snakecase).to eq("so_you_want_contribute_to_merb_core")
|
16
16
|
end
|
17
17
|
|
18
18
|
it "handles CamelCase with more than 2 capital letter in a row" do
|
19
|
-
"CNN".snakecase.
|
20
|
-
"CNNNews".snakecase.
|
21
|
-
"HeadlineCNNNews".snakecase.
|
19
|
+
expect("CNN".snakecase).to eq("cnn")
|
20
|
+
expect("CNNNews".snakecase).to eq("cnn_news")
|
21
|
+
expect("HeadlineCNNNews".snakecase).to eq("headline_cnn_news")
|
22
22
|
end
|
23
23
|
|
24
24
|
it "does NOT change one word lowercase" do
|
25
|
-
"merb".snakecase.
|
25
|
+
expect("merb".snakecase).to eq("merb")
|
26
26
|
end
|
27
27
|
|
28
28
|
it "leaves snake_case as is" do
|
29
|
-
"merb_core".snakecase.
|
29
|
+
expect("merb_core".snakecase).to eq("merb_core")
|
30
30
|
end
|
31
31
|
|
32
32
|
it "converts period characters to underscores" do
|
33
|
-
"User.GetEmail".snakecase.
|
33
|
+
expect("User.GetEmail".snakecase).to eq("user_get_email")
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -11,11 +11,11 @@ describe Savon::HTTPError do
|
|
11
11
|
describe ".present?" do
|
12
12
|
it "returns true if there was an HTTP error" do
|
13
13
|
http = new_response(:code => 404, :body => "Not Found")
|
14
|
-
expect(Savon::HTTPError.present? http).to
|
14
|
+
expect(Savon::HTTPError.present? http).to be_truthy
|
15
15
|
end
|
16
16
|
|
17
17
|
it "returns false unless there was an HTTP error" do
|
18
|
-
expect(Savon::HTTPError.present? new_response).to
|
18
|
+
expect(Savon::HTTPError.present? new_response).to be_falsey
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
data/spec/savon/options_spec.rb
CHANGED
@@ -45,6 +45,35 @@ describe "Options" do
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
context "global: :no_message_tag" do
|
49
|
+
it "omits the 'message tag' encapsulation step" do
|
50
|
+
client = new_client(:endpoint => @server.url(:repeat), :no_message_tag => true,
|
51
|
+
:wsdl => Fixture.wsdl(:no_message_tag))
|
52
|
+
msg = {'extLoginData' => {'Login' => 'test.user', 'Password' => 'secret', 'FacilityID' => 1,
|
53
|
+
'ThreePLKey' => '{XXXX-XXXX-XXXX-XXXX}', 'ThreePLID' => 1},
|
54
|
+
'Items' => ['Item' => {'SKU' => '001002003A', 'CustomerID' => 1,
|
55
|
+
'InventoryMethod' => 'FIFO', 'UPC' => '001002003A'}]}
|
56
|
+
response = client.call(:create_items, :message => msg)
|
57
|
+
|
58
|
+
expect(response.http.body.scan(/<tns:extLoginData>/).count).to eq(1)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "includes the 'message tag' encapsulation step" do
|
62
|
+
# This test is probably just exposing a bug while the previous
|
63
|
+
# test is using a workaround fix.
|
64
|
+
# That is just a guess though. I don't really have to properly debug the WSDL parser.
|
65
|
+
client = new_client(:endpoint => @server.url(:repeat), :no_message_tag => false,
|
66
|
+
:wsdl => Fixture.wsdl(:no_message_tag))
|
67
|
+
msg = {'extLoginData' => {'Login' => 'test.user', 'Password' => 'secret', 'FacilityID' => 1,
|
68
|
+
'ThreePLKey' => '{XXXX-XXXX-XXXX-XXXX}', 'ThreePLID' => 1},
|
69
|
+
'Items' => ['Item' => {'SKU' => '001002003A', 'CustomerID' => 1,
|
70
|
+
'InventoryMethod' => 'FIFO', 'UPC' => '001002003A'}]}
|
71
|
+
response = client.call(:create_items, :message => msg)
|
72
|
+
|
73
|
+
expect(response.http.body.scan(/<tns:extLoginData>/).count).to eq(2)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
48
77
|
context "global :namespaces" do
|
49
78
|
it "adds additional namespaces to the SOAP envelope" do
|
50
79
|
namespaces = { "xmlns:whatever" => "http://whatever.example.com" }
|
@@ -55,6 +84,24 @@ describe "Options" do
|
|
55
84
|
end
|
56
85
|
end
|
57
86
|
|
87
|
+
context 'global :follow_redirects' do
|
88
|
+
it 'sets whether or not request should follow redirects' do
|
89
|
+
client = new_client(:endpoint => @server.url, :follow_redirects => true)
|
90
|
+
|
91
|
+
HTTPI::Request.any_instance.expects(:follow_redirect=).with(true)
|
92
|
+
|
93
|
+
response = client.call(:authenticate)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'defaults to false' do
|
97
|
+
client = new_client(:endpoint => @server.url)
|
98
|
+
|
99
|
+
HTTPI::Request.any_instance.expects(:follow_redirect=).with(false)
|
100
|
+
|
101
|
+
response = client.call(:authenticate)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
58
105
|
context "global :proxy" do
|
59
106
|
it "sets the proxy server to use" do
|
60
107
|
proxy_url = "http://example.com"
|
@@ -457,80 +504,215 @@ describe "Options" do
|
|
457
504
|
end
|
458
505
|
end
|
459
506
|
|
460
|
-
context "
|
461
|
-
|
462
|
-
|
463
|
-
|
507
|
+
context ":wsse_auth" do
|
508
|
+
let(:username) { "luke" }
|
509
|
+
let(:password) { "secret" }
|
510
|
+
let(:request) { response.http.body }
|
464
511
|
|
465
|
-
|
512
|
+
shared_examples "WSSE basic auth" do
|
513
|
+
it "adds WSSE basic auth information to the request" do
|
514
|
+
# the header and wsse security node
|
515
|
+
wsse_namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
516
|
+
expect(request).to include("<env:Header><wsse:Security xmlns:wsse=\"#{wsse_namespace}\">")
|
517
|
+
|
518
|
+
# split up to prevent problems with unordered Hash attributes in 1.8 [dh, 2012-12-13]
|
519
|
+
expect(request).to include("<wsse:UsernameToken")
|
520
|
+
expect(request).to include("wsu:Id=\"UsernameToken-1\"")
|
521
|
+
expect(request).to include("xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"")
|
522
|
+
|
523
|
+
# the username and password node with type attribute
|
524
|
+
expect(request).to include("<wsse:Username>#{username}</wsse:Username>")
|
525
|
+
password_text = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"
|
526
|
+
expect(request).to include("<wsse:Password Type=\"#{password_text}\">#{password}</wsse:Password>")
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
shared_examples "WSSE digest auth" do
|
531
|
+
it "adds WSSE digest auth information to the request" do
|
532
|
+
# the header and wsse security node
|
533
|
+
wsse_namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
534
|
+
expect(request).to include("<env:Header><wsse:Security xmlns:wsse=\"#{wsse_namespace}\">")
|
535
|
+
|
536
|
+
# split up to prevent problems with unordered Hash attributes in 1.8 [dh, 2012-12-13]
|
537
|
+
expect(request).to include("<wsse:UsernameToken")
|
538
|
+
expect(request).to include("wsu:Id=\"UsernameToken-1\"")
|
539
|
+
expect(request).to include("xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"")
|
540
|
+
|
541
|
+
# the username node
|
542
|
+
expect(request).to include("<wsse:Username>#{username}</wsse:Username>")
|
543
|
+
|
544
|
+
# the nonce node
|
545
|
+
expect(request).to match(/<wsse:Nonce.*>.+\n<\/wsse:Nonce>/)
|
466
546
|
|
467
|
-
|
468
|
-
|
469
|
-
expect(request).to include("<env:Header><wsse:Security xmlns:wsse=\"#{wsse_namespace}\">")
|
547
|
+
# the created node with a timestamp
|
548
|
+
expect(request).to match(/<wsu:Created>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*<\/wsu:Created>/)
|
470
549
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
550
|
+
# the password node contains the encrypted value
|
551
|
+
password_digest = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"
|
552
|
+
expect(request).to match(/<wsse:Password Type=\"#{password_digest}\">.+<\/wsse:Password>/)
|
553
|
+
expect(request).to_not include(password)
|
554
|
+
end
|
555
|
+
end
|
475
556
|
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
557
|
+
shared_examples "no WSSE auth" do
|
558
|
+
it "does not add WSSE auth to the request" do
|
559
|
+
expect(request).not_to include("<wsse:UsernameToken")
|
560
|
+
end
|
480
561
|
end
|
481
562
|
|
482
|
-
|
483
|
-
|
484
|
-
|
563
|
+
describe "global" do
|
564
|
+
context "enabled" do
|
565
|
+
context "without digest" do
|
566
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat), :wsse_auth => [username, password]) }
|
567
|
+
let(:response) { client.call(:authenticate) }
|
568
|
+
include_examples "WSSE basic auth"
|
569
|
+
end
|
485
570
|
|
486
|
-
|
571
|
+
context "with digest" do
|
572
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat), :wsse_auth => [username, password, :digest]) }
|
573
|
+
let(:response) { client.call(:authenticate) }
|
574
|
+
include_examples "WSSE digest auth"
|
575
|
+
end
|
487
576
|
|
488
|
-
|
489
|
-
|
490
|
-
|
577
|
+
context "local override" do
|
578
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat), :wsse_auth => ["luke", "secret"]) }
|
579
|
+
|
580
|
+
context "enabled" do
|
581
|
+
let(:username) { "lea" }
|
582
|
+
let(:password) { "top-secret" }
|
583
|
+
|
584
|
+
context "without digest" do
|
585
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_auth(username, password)} }
|
586
|
+
include_examples "WSSE basic auth"
|
587
|
+
end
|
588
|
+
|
589
|
+
context "with digest" do
|
590
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_auth(username, password, :digest)} }
|
591
|
+
include_examples "WSSE digest auth"
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
context "disabled" do
|
596
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_auth(false)} }
|
597
|
+
include_examples "no WSSE auth"
|
598
|
+
end
|
599
|
+
|
600
|
+
context "set to nil" do
|
601
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_auth(nil)} }
|
602
|
+
include_examples "WSSE basic auth"
|
603
|
+
end
|
604
|
+
end
|
491
605
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
606
|
+
context "global" do
|
607
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat), :wsse_auth => [username, password, :digest]) }
|
608
|
+
let(:response) { client.call(:authenticate) }
|
609
|
+
include_examples "WSSE digest auth"
|
610
|
+
end
|
611
|
+
end
|
496
612
|
|
497
|
-
|
498
|
-
|
613
|
+
context "not enabled" do
|
614
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat)) }
|
499
615
|
|
500
|
-
|
501
|
-
|
616
|
+
describe "local" do
|
617
|
+
context "enabled" do
|
618
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_auth(username, password, :digest)} }
|
619
|
+
include_examples "WSSE digest auth"
|
620
|
+
end
|
502
621
|
|
503
|
-
|
504
|
-
|
622
|
+
context "disabled" do
|
623
|
+
let(:response) { client.call(:authenticate) { |locals| locals.wsse_auth(false)} }
|
624
|
+
include_examples "no WSSE auth"
|
625
|
+
end
|
505
626
|
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
627
|
+
context "set to nil" do
|
628
|
+
let(:response) { client.call(:authenticate) { |locals| locals.wsse_auth(nil)} }
|
629
|
+
include_examples "no WSSE auth"
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
510
633
|
end
|
511
634
|
end
|
512
635
|
|
513
|
-
context "
|
514
|
-
|
515
|
-
client = new_client(:endpoint => @server.url(:repeat), :wsse_timestamp => true)
|
516
|
-
response = client.call(:authenticate)
|
636
|
+
context ":wsse_timestamp" do
|
637
|
+
let(:request) { response.http.body }
|
517
638
|
|
518
|
-
|
639
|
+
shared_examples "WSSE timestamp" do
|
640
|
+
it "adds WSSE timestamp auth information to the request" do
|
641
|
+
# the header and wsse security node
|
642
|
+
wsse_namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
643
|
+
expect(request).to include("<env:Header><wsse:Security xmlns:wsse=\"#{wsse_namespace}\">")
|
519
644
|
|
520
|
-
|
521
|
-
|
522
|
-
|
645
|
+
# split up to prevent problems with unordered Hash attributes in 1.8 [dh, 2012-12-13]
|
646
|
+
expect(request).to include("<wsu:Timestamp")
|
647
|
+
expect(request).to include("wsu:Id=\"Timestamp-1\"")
|
648
|
+
expect(request).to include("xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"")
|
523
649
|
|
524
|
-
|
525
|
-
|
526
|
-
expect(request).to include("wsu:Id=\"Timestamp-1\"")
|
527
|
-
expect(request).to include("xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"")
|
650
|
+
# the created node with a timestamp
|
651
|
+
expect(request).to match(/<wsu:Created>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*<\/wsu:Created>/)
|
528
652
|
|
529
|
-
|
530
|
-
|
653
|
+
# the expires node with a timestamp
|
654
|
+
expect(request).to match(/<wsu:Expires>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*<\/wsu:Expires>/)
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
shared_examples "no WSSE timestamp" do
|
659
|
+
it "does not add WSSE timestamp to the request" do
|
660
|
+
expect(request).not_to include("<wsu:Timestamp")
|
661
|
+
end
|
662
|
+
end
|
663
|
+
|
664
|
+
describe "global" do
|
665
|
+
context "enabled" do
|
666
|
+
context "through block without arguments" do
|
667
|
+
let(:client) do
|
668
|
+
new_client(:endpoint => @server.url(:repeat)) do |globals|
|
669
|
+
globals.wsse_timestamp
|
670
|
+
end
|
671
|
+
end
|
672
|
+
let(:response) { client.call(:authenticate) }
|
673
|
+
include_examples "WSSE timestamp"
|
674
|
+
end
|
531
675
|
|
532
|
-
|
533
|
-
|
676
|
+
context "through initializer options" do
|
677
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat), :wsse_timestamp => true) }
|
678
|
+
let(:response) { client.call(:authenticate) }
|
679
|
+
include_examples "WSSE timestamp"
|
680
|
+
end
|
681
|
+
|
682
|
+
context "with local override" do
|
683
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat), :wsse_timestamp => true) }
|
684
|
+
context "enabled" do
|
685
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_timestamp} }
|
686
|
+
include_examples "WSSE timestamp"
|
687
|
+
end
|
688
|
+
context "disabled" do
|
689
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_timestamp(false) } }
|
690
|
+
include_examples "no WSSE timestamp"
|
691
|
+
end
|
692
|
+
context "set to nil" do
|
693
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_timestamp(nil) } }
|
694
|
+
include_examples "WSSE timestamp"
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
context "not enabled" do
|
700
|
+
let(:client) { new_client(:endpoint => @server.url(:repeat)) }
|
701
|
+
describe "local" do
|
702
|
+
context "enabled" do
|
703
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_timestamp} }
|
704
|
+
include_examples "WSSE timestamp"
|
705
|
+
end
|
706
|
+
context "disabled" do
|
707
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_timestamp(false) } }
|
708
|
+
include_examples "no WSSE timestamp"
|
709
|
+
end
|
710
|
+
context "set to nil" do
|
711
|
+
let(:response) { client.call(:authenticate) {|locals| locals.wsse_timestamp(nil) } }
|
712
|
+
include_examples "no WSSE timestamp"
|
713
|
+
end
|
714
|
+
end
|
715
|
+
end
|
534
716
|
end
|
535
717
|
end
|
536
718
|
|
data/spec/savon/request_spec.rb
CHANGED
@@ -129,7 +129,7 @@ describe Savon::WSDLRequest do
|
|
129
129
|
|
130
130
|
new_wsdl_request.build
|
131
131
|
|
132
|
-
expect { http_request.auth.ssl.cert_key }.to raise_error
|
132
|
+
expect { http_request.auth.ssl.cert_key }.to raise_error
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
@@ -145,7 +145,7 @@ describe Savon::WSDLRequest do
|
|
145
145
|
|
146
146
|
new_wsdl_request.build
|
147
147
|
|
148
|
-
http_request.auth.ssl.cert_key.to_s.
|
148
|
+
expect(http_request.auth.ssl.cert_key.to_s).to match(/BEGIN RSA PRIVATE KEY/)
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|