savon 0.6.8 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -76,6 +76,11 @@ module Savon
76
76
  @namespaces ||= { "xmlns:env" => SOAPNamespace[version] }
77
77
  end
78
78
 
79
+ # Convenience method for setting the "xmlns:wsdl" namespace.
80
+ def namespace=(namespace)
81
+ namespaces["xmlns:wsdl"] = namespace
82
+ end
83
+
79
84
  # Sets the SOAP version.
80
85
  def version=(version)
81
86
  @version = version if Savon::SOAPVersions.include? version
@@ -10,6 +10,14 @@ module Savon
10
10
  @request = request
11
11
  end
12
12
 
13
+ # Sets whether to use the WSDL.
14
+ attr_writer :enabled
15
+
16
+ # Returns whether to use the WSDL. Defaults to +true+.
17
+ def enabled?
18
+ @enabled.nil? ? true : @enabled
19
+ end
20
+
13
21
  # Returns the namespace URI of the WSDL.
14
22
  def namespace_uri
15
23
  @namespace_uri ||= stream.namespace_uri
@@ -0,0 +1,12 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "spec"
4
+ require "mocha"
5
+ require "fakeweb"
6
+
7
+ Spec::Runner.configure do |config|
8
+ config.mock_with :mocha
9
+ end
10
+
11
+ require "savon"
12
+ Savon::Request.log = false
@@ -23,10 +23,14 @@ class ResponseFixture
23
23
  @@soap_fault12 ||= load_fixture :soap_fault12
24
24
  end
25
25
 
26
+ def self.multi_ref
27
+ @@multi_ref ||= load_fixture :multi_ref
28
+ end
29
+
26
30
  private
27
31
 
28
32
  def self.load_fixture(fixture)
29
- File.read(File.dirname(__FILE__) + "/xml/#{fixture}.xml")
33
+ File.read File.dirname(__FILE__) + "/xml/#{fixture}.xml"
30
34
  end
31
35
 
32
36
  end
@@ -0,0 +1,39 @@
1
+ <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
2
+ <soapenv:Body>
3
+ <ns1:listResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://ws.example.com">
4
+ <listReturn soapenc:arrayType="ns2:HistoryEntry[3]" xsi:type="soapenc:Array" xmlns:ns2="http://ws.example.com/ws/history" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
5
+ <listReturn href="#id0"/>
6
+ <listReturn href="#id1"/>
7
+ <listReturn href="#id2"/>
8
+ </listReturn>
9
+ </ns1:listResponse>
10
+ <multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns5:HistoryEntry" xmlns:ns5="http://ws.example.com/ws/history" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
11
+ <date xsi:type="xsd:dateTime">2009-09-22T13:47:23.000Z</date>
12
+ <location xsi:type="soapenc:string">Archive</location>
13
+ <mailId href="#id9"/>
14
+ <referenceId href="#id8"/>
15
+ <state xsi:type="soapenc:string">Original</state>
16
+ <subject xsi:type="soapenc:string">Mail from 09-22-2009: Misc</subject>
17
+ </multiRef>
18
+ <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns6:HistoryEntry" xmlns:ns6="http://ws.example.com/ws/history" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
19
+ <date xsi:type="xsd:dateTime">2009-04-30T06:38:34.000Z</date>
20
+ <location xsi:type="soapenc:string">Archive</location>
21
+ <mailId href="#id10"/>
22
+ <referenceId href="#id8"/>
23
+ <state xsi:type="soapenc:string">Original</state>
24
+ <subject xsi:type="soapenc:string">Mail from 04-29-2009: Technical support</subject>
25
+ </multiRef>
26
+ <multiRef id="id2" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns7:HistoryEntry" xmlns:ns7="http://ws.example.com/ws/history" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
27
+ <date xsi:type="xsd:dateTime">2009-12-18T15:43:21.000Z</date>
28
+ <location xsi:type="soapenc:string">Archive</location>
29
+ <mailId href="#id11"/>
30
+ <referenceId href="#id8"/>
31
+ <state xsi:type="soapenc:string">Original</state>
32
+ <subject xsi:type="soapenc:string">Mail from 12-17-2009: Misc</subject>
33
+ </multiRef>
34
+ <multiRef id="id11" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">972219</multiRef>
35
+ <multiRef id="id10" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">708021</multiRef>
36
+ <multiRef id="id8" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">0</multiRef>
37
+ <multiRef id="id9" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">855763</multiRef>
38
+ </soapenv:Body>
39
+ </soapenv:Envelope>
@@ -1,18 +1,18 @@
1
1
  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:m="http://www.example.org/timeouts">
2
- <soap:Body>
3
- <soap:Fault>
4
- <Code>
5
- <Value>soap:Sender</Value>
6
- <Subcode>
7
- <Value>m:MessageTimeout</Value>
8
- </Subcode>
9
- </Code>
10
- <Reason>
11
- <Text xml:lang="en">Sender Timeout</Text>
12
- </Reason>
13
- <Detail>
14
- <m:MaxTime>P5M</m:MaxTime>
15
- </Detail>
16
- </soap:Fault>
17
- </soap:Body>
18
- </soap:Envelope>
2
+ <soap:Body>
3
+ <soap:Fault>
4
+ <Code>
5
+ <Value>soap:Sender</Value>
6
+ <Subcode>
7
+ <Value>m:MessageTimeout</Value>
8
+ </Subcode>
9
+ </Code>
10
+ <Reason>
11
+ <Text xml:lang="en">Sender Timeout</Text>
12
+ </Reason>
13
+ <Detail>
14
+ <m:MaxTime>P5M</m:MaxTime>
15
+ </Detail>
16
+ </soap:Fault>
17
+ </soap:Body>
18
+ </soap:Envelope>
@@ -20,7 +20,7 @@ private
20
20
  def self.expectations
21
21
  return @@expectations if @@expectations
22
22
 
23
- file = File.read(File.dirname(__FILE__) + "/wsdl_fixture.yml")
23
+ file = File.read File.dirname(__FILE__) + "/wsdl_fixture.yml"
24
24
  @@expectations = YAML.load ERB.new(file).result
25
25
  end
26
26
 
@@ -30,7 +30,7 @@ private
30
30
  def self.wsdl(wsdl)
31
31
  return @@wsdl[wsdl] if @@wsdl[wsdl]
32
32
 
33
- file = File.read(File.dirname(__FILE__) + "/xml/#{wsdl}.xml")
33
+ file = File.read File.dirname(__FILE__) + "/xml/#{wsdl}.xml"
34
34
  @@wsdl[wsdl] = file
35
35
  end
36
36
 
@@ -0,0 +1,12 @@
1
+ require "basic_spec_helper"
2
+
3
+ describe Savon do
4
+ before { @endpoint = "http://localhost:8080/http-basic-auth" }
5
+
6
+ it "should be able to handle HTTP basic authentication" do
7
+ client = Savon::Client.new @endpoint
8
+ client.request.basic_auth "user", "password"
9
+ response = client.do_something!
10
+ response.to_hash[:authenticate_response][:return][:success].should == true
11
+ end
12
+ end
@@ -0,0 +1,51 @@
1
+ require "webrick"
2
+
3
+ include WEBrick
4
+
5
+ # Run WEBrick. Yields the server to a given block.
6
+ def run_webrick(config = {})
7
+ config.update :Port => 8080
8
+ server = HTTPServer.new config
9
+ yield server if block_given?
10
+ ["INT", "TERM"].each { |signal| trap(signal) { server.shutdown } }
11
+ server.start
12
+ end
13
+
14
+ # Returns the SOAP response fixture for a given +file+.
15
+ def respond_with(file)
16
+ response_path = File.dirname(__FILE__) + "/../fixtures/response/xml"
17
+ File.read "#{response_path}/#{file}.xml"
18
+ end
19
+
20
+ # Returns HTML links for a given Hash of link URI's and names.
21
+ def link_to(links)
22
+ links.map { |link| "<a href='#{link[:uri]}'>#{link[:name]}</a>" }.join("<br>")
23
+ end
24
+
25
+ run_webrick do |server|
26
+ user, password, realm = "user", "password", "realm"
27
+
28
+ htdigest = HTTPAuth::Htdigest.new "/tmp/webrick-htdigest"
29
+ htdigest.set_passwd realm, user, password
30
+ authenticator = HTTPAuth::DigestAuth.new :UserDB => htdigest, :Realm => realm
31
+
32
+ # Homepage including links to subpages.
33
+ server.mount_proc("/") do |request, response|
34
+ response.body = link_to [
35
+ { :uri => "http-basic-auth", :name => "HTTP basic auth" },
36
+ { :uri => "http-digest-auth", :name => "HTTP digest auth" }
37
+ ]
38
+ end
39
+
40
+ # HTTP basic authentication.
41
+ server.mount_proc("/http-basic-auth") do |request, response|
42
+ HTTPAuth.basic_auth(request, response, realm) { |u, p| u == user && p == password }
43
+ response.body = respond_with :authentication
44
+ end
45
+
46
+ # HTTP digest authentication.
47
+ server.mount_proc("/http-digest-auth") do |request, response|
48
+ authenticator.authenticate request, response
49
+ response.body = "HTTP digest authentication successfull"
50
+ end
51
+ end
@@ -3,32 +3,26 @@ require "spec_helper"
3
3
  describe Savon::Client do
4
4
  before { @client = Savon::Client.new EndpointHelper.wsdl_endpoint }
5
5
 
6
- it "is initialized with a SOAP endpoint String" do
7
- Savon::Client.new EndpointHelper.wsdl_endpoint
6
+ it "should be initialized with an endpoint String" do
7
+ client = Savon::Client.new EndpointHelper.wsdl_endpoint
8
+ client.request.http.proxy?.should be_false
8
9
  end
9
10
 
10
- it "accepts a proxy URI passed in via options" do
11
- Savon::Client.new EndpointHelper.wsdl_endpoint, :proxy => 'http://proxy'
11
+ it "should accept a proxy URI via an optional Hash of options" do
12
+ client = Savon::Client.new EndpointHelper.wsdl_endpoint, :proxy => "http://proxy"
13
+ client.request.http.proxy?.should be_true
14
+ client.request.http.proxy_address == "http://proxy"
12
15
  end
13
16
 
14
- it "accepts settings for SSL client authentication via options" do
15
- Savon::Client.new EndpointHelper.wsdl_endpoint, :ssl => {
16
- :client_cert => "client cert",
17
- :client_key => "client key",
18
- :ca_file => "ca file",
19
- :verify => OpenSSL::SSL::VERIFY_PEER
20
- }
17
+ it "should have a method that returns the Savon::WSDL" do
18
+ @client.wsdl.should be_a(Savon::WSDL)
21
19
  end
22
20
 
23
- it "has a getter for accessing the Savon::WSDL" do
24
- @client.wsdl.should be_a Savon::WSDL
21
+ it "should have a method that returns the Savon::Request" do
22
+ @client.request.should be_a(Savon::Request)
25
23
  end
26
24
 
27
- it "has a getter for accessing the Savon::Request" do
28
- @client.request.should be_a Savon::Request
29
- end
30
-
31
- it "responds to SOAP actions while still behaving as usual otherwise" do
25
+ it "should respond to available SOAP actions while behaving as expected otherwise" do
32
26
  WSDLFixture.authentication(:operations).keys.each do |soap_action|
33
27
  @client.respond_to?(soap_action).should be_true
34
28
  end
@@ -37,61 +31,47 @@ describe Savon::Client do
37
31
  @client.respond_to?(:some_undefined_method).should be_false
38
32
  end
39
33
 
40
- it "dispatches SOAP calls via method_missing and returns the Savon::Response" do
41
- @client.authenticate.should be_a Savon::Response
34
+ it "should dispatch available SOAP calls via method_missing and return the Savon::Response" do
35
+ @client.authenticate.should be_a(Savon::Response)
42
36
  end
43
37
 
44
- describe "disabling retrieving and parsing the WSDL document" do
45
- it "can be done globally for every instance of Savon::Client" do
46
- @client.wsdl?.should be_true
47
- Savon::Client.wsdl = false
48
-
49
- expect_the_wsdl_to_be_disabled
50
- @client.authenticate.should be_a Savon::Response
51
-
52
- Savon::Client.wsdl = true
53
- end
54
-
55
- it "can be done per request" do
56
- @client.wsdl = false
57
-
58
- expect_the_wsdl_to_be_disabled
59
- @client.authenticate.should be_a Savon::Response
38
+ it "should disable the Savon::WSDL when passed a method with an exclamation mark" do
39
+ @client.wsdl.enabled?.should be_true
40
+ [:respond_to?, :operations, :namespace_uri, :soap_endpoint].each do |method|
41
+ Savon::WSDL.any_instance.expects(method).never
60
42
  end
61
43
 
62
- def expect_the_wsdl_to_be_disabled
63
- @client.wsdl?.should be_false
64
- [:respond_to?, :operations, :namespace_uri, :soap_endpoint].each do |method|
65
- Savon::WSDL.any_instance.expects(method).never
66
- end
44
+ response = @client.authenticate! do |soap|
45
+ soap.input.should == "authenticate"
46
+ soap.input.should == "authenticate"
67
47
  end
48
+ response.should be_a(Savon::Response)
49
+ @client.wsdl.enabled?.should be_false
68
50
  end
69
51
 
70
- it "raises a Savon::SOAPFault in case of a SOAP fault" do
52
+ it "should raise a Savon::SOAPFault in case of a SOAP fault" do
71
53
  client = Savon::Client.new EndpointHelper.wsdl_endpoint(:soap_fault)
72
- client.wsdl = false
73
- lambda { client.authenticate }.should raise_error Savon::SOAPFault
54
+ lambda { client.authenticate! }.should raise_error(Savon::SOAPFault)
74
55
  end
75
56
 
76
- it "raises a Savon::HTTPError in case of an HTTP error" do
57
+ it "should raise a Savon::HTTPError in case of an HTTP error" do
77
58
  client = Savon::Client.new EndpointHelper.wsdl_endpoint(:http_error)
78
- client.wsdl = false
79
- lambda { client.authenticate }.should raise_error Savon::HTTPError
59
+ lambda { client.authenticate! }.should raise_error(Savon::HTTPError)
80
60
  end
81
61
 
82
- it "yields the SOAP object to a block when it expects one argument" do
83
- @client.authenticate { |soap| soap.should be_a Savon::SOAP }
62
+ it "should yield an instance of Savon::SOAP to a given block expecting one argument" do
63
+ @client.authenticate { |soap| soap.should be_a(Savon::SOAP) }
84
64
  end
85
65
 
86
- it "yields the SOAP and WSSE object to a block when it expects two argument" do
66
+ it "should yield an instance of Savon::SOAP and Savon::WSSE to a gven block expecting two arguments" do
87
67
  @client.authenticate do |soap, wsse|
88
- soap.should be_a Savon::SOAP
89
- wsse.should be_a Savon::WSSE
68
+ soap.should be_a(Savon::SOAP)
69
+ wsse.should be_a(Savon::WSSE)
90
70
  end
91
71
  end
92
72
 
93
- it "still raises a NoMethodError for undefined methods" do
94
- lambda { @client.some_undefined_method }.should raise_error NoMethodError
73
+ it "should raise a NoMethodError when the method does not match an available SOAP action or method" do
74
+ lambda { @client.some_undefined_method }.should raise_error(NoMethodError)
95
75
  end
96
76
 
97
77
  end
@@ -2,26 +2,13 @@ require "spec_helper"
2
2
 
3
3
  describe Hash do
4
4
 
5
- describe "find_regexp" do
6
- before do
7
- @soap_fault_hash = { "soap:Envelope" => { "soap:Body" => { "soap:Fault" => {
8
- "faultcode" => "soap:Server", "faultstring" => "Fault occurred while processing."
9
- } } } }
5
+ describe "find_soap_body" do
6
+ it "returns the content from the 'soap:Body' element" do
7
+ { "soap:Envelope" => { "soap:Body" => "content" } }.find_soap_body.should == "content"
10
8
  end
11
9
 
12
- it "returns an empty Hash in case it did not find the specified value" do
13
- result = @soap_fault_hash.find_regexp "soap:Fault"
14
-
15
- result.should be_a Hash
16
- result.should be_empty
17
- end
18
-
19
- it "returns the value of the last Regexp filter found in the Hash" do
20
- @soap_fault_hash.find_regexp([".+:Envelope", ".+:Body"]).
21
- should == @soap_fault_hash["soap:Envelope"]["soap:Body"]
22
-
23
- @soap_fault_hash.find_regexp([/.+:Envelope/, /.+:Body/, /.+Fault/]).
24
- should == @soap_fault_hash["soap:Envelope"]["soap:Body"]["soap:Fault"]
10
+ it "returns an empty Hash in case the 'soap:Body' element could not be found" do
11
+ { "some_hash" => "content" }.find_soap_body.should == {}
25
12
  end
26
13
  end
27
14
 
@@ -39,8 +26,8 @@ describe Hash do
39
26
  it "for a Hash with multiple keys" do
40
27
  soap_xml = { :all => "users", :before => "whatever" }.to_soap_xml
41
28
 
42
- soap_xml.should include "<all>users</all>"
43
- soap_xml.should include "<before>whatever</before>"
29
+ soap_xml.should include("<all>users</all>")
30
+ soap_xml.should include("<before>whatever</before>")
44
31
  end
45
32
 
46
33
  it "for a Hash containing an Array" do
@@ -92,6 +79,23 @@ describe Hash do
92
79
  { :some => object }.to_soap_xml.should == "<some>#{object}</some>"
93
80
  end
94
81
  end
82
+
83
+ it "preserves the order of Hash keys and values specified through :@inorder" do
84
+ { :find_user => { :name => "Lucy", :id => 666, :@inorder => [:id, :name] } }.to_soap_xml.
85
+ should == "<findUser><id>666</id><name>Lucy</name></findUser>"
86
+
87
+ { :find_user => { :by_name => { :mname => "in the", :lname => "Sky", :fname => "Lucy",
88
+ :@inorder => [:fname, :mname, :lname] } } }.to_soap_xml. should ==
89
+ "<findUser><byName><fname>Lucy</fname><mname>in the</mname><lname>Sky</lname></byName></findUser>"
90
+ end
91
+
92
+ it "raises an error if the :@inorder Array does not match the Hash keys" do
93
+ lambda { { :name => "Lucy", :id => 666, :@inorder => [:name] }.to_soap_xml }.
94
+ should raise_error(RuntimeError)
95
+
96
+ lambda { { :by_name => { :name => "Lucy", :lname => "Sky", :@inorder => [:mname, :name] } }.to_soap_xml }.
97
+ should raise_error(RuntimeError)
98
+ end
95
99
  end
96
100
 
97
101
  describe "map_soap_response" do
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+
3
+ describe Net::HTTP do
4
+ before do
5
+ @some_uri = URI "http://example.com"
6
+ @another_uri = URI "http://example.org"
7
+ @http = Net::HTTP.new @some_uri.host, @some_uri.port
8
+ end
9
+
10
+ describe "endpoint" do
11
+ it "changes the address and port of a Net::HTTP object" do
12
+ @http.address.should == @some_uri.host
13
+ @http.port.should == @some_uri.port
14
+
15
+ @http.endpoint @another_uri.host, @another_uri.port
16
+ @http.address.should == @another_uri.host
17
+ @http.port.should == @another_uri.port
18
+ end
19
+ end
20
+
21
+ describe "ssl_client_auth" do
22
+ it "accepts a Hash of options for SSL client authentication" do
23
+ @http.cert.should be_nil
24
+ @http.key.should be_nil
25
+ @http.ca_file.should be_nil
26
+ @http.verify_mode.should be_nil
27
+
28
+ @http.ssl_client_auth :cert => "cert", :key => "key",
29
+ :ca_file => "ca_file", :verify_mode => OpenSSL::SSL::VERIFY_PEER
30
+
31
+ @http.cert.should == "cert"
32
+ @http.key.should == "key"
33
+ @http.ca_file.should == "ca_file"
34
+ @http.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
35
+ end
36
+ end
37
+
38
+ end