wash_out 0.10.0 → 0.11.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a23248a1bd38c14fe7eae75c2589b4eb945687f6
4
- data.tar.gz: 5f806cadfebf37d0b46ee2d7f69d00266f0bae53
3
+ metadata.gz: 9d49adf22c0c16c3f0e8e3e2dcf694b7d6851920
4
+ data.tar.gz: c42b0da56ed90cd44e4d014aff450f3bef83325f
5
5
  SHA512:
6
- metadata.gz: 5879036aca9ca31804573e45c5cc3aa4f7ffdb5303c27ea195c322c9246afd1ecde6d518783cd6e13dcd49ccb7a29c99f7017bc28a8feb43fbb45afeb2988063
7
- data.tar.gz: d791bece6a7eb059ff83dbac5bce07ccd6e7dfc95c761579ff53ff97776dae4c7a5156b76997131f8de931b5263ba846545ec5018daa75eeb66faf985bbb2a6e
6
+ metadata.gz: 9f2dd4239ee3fa9e449bd0903c977b5f2457382ee363cb3d1404d102f5fd0b531fe8f0e32dcee5cc6a5ff14996d60b37bb565ad702b913ac2ed344fbde90ea83
7
+ data.tar.gz: c9045dd957a04e6751b9ed5ffc2a28fdc6c1d4a1c4eff7a57d8564699423a442a4975fe8c6c4cac7a451a19cd3eeda112ba8357cd0e19228d838e4d8ffcabdb4
data/.travis.yml CHANGED
@@ -1,10 +1,10 @@
1
1
  script: bundle exec rspec
2
2
  gemfile:
3
- - gemfiles/rails_3.1.3.gemfile
4
- - gemfiles/rails_3.2.12.gemfile
3
+ - gemfiles/rails_3.2.13.gemfile
5
4
  - gemfiles/rails_4.0.0.gemfile
6
5
  - gemfiles/rails_4.1.0.gemfile
7
6
  - gemfiles/rails_4.2.0.gemfile
7
+ - gemfiles/rails_5.0.0.beta2.gemfile
8
8
  rvm:
9
9
  - 1.9.3
10
10
  - 2.0.0
@@ -15,12 +15,20 @@ rvm:
15
15
  matrix:
16
16
  exclude:
17
17
  - rvm: 2.2.4
18
- gemfile: gemfiles/rails_3.1.3.gemfile
19
- - rvm: 2.2.4
20
- gemfile: gemfiles/rails_3.2.12.gemfile
21
- - rvm: 2.3.0
22
- gemfile: gemfiles/rails_3.1.3.gemfile
18
+ gemfile: gemfiles/rails_3.2.13.gemfile
23
19
  - rvm: 2.3.0
24
- gemfile: gemfiles/rails_3.2.12.gemfile
20
+ gemfile: gemfiles/rails_3.2.13.gemfile
21
+ - rvm: 1.9.3
22
+ gemfile: gemfiles/rails_4.2.0.gemfile
23
+ - rvm: jruby
24
+ gemfile: gemfiles/rails_4.2.0.gemfile
25
+ - rvm: 1.9.3
26
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
27
+ - rvm: 2.0.0
28
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
29
+ - rvm: 2.1.8
30
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
31
+ - rvm: jruby
32
+ gemfile: gemfiles/rails_5.0.0.beta2.gemfile
25
33
  before_install:
26
34
  - gem update bundler
data/Appraisals CHANGED
@@ -1,21 +1,24 @@
1
- appraise "rails-3.1.3" do
2
- gem "rails", "3.1.3"
3
- gem "test-unit"
4
- end
5
-
6
- appraise "rails-3.2.12" do
7
- gem "rails", "3.2.12"
1
+ appraise "rails-3.2.13" do
2
+ gem "rails", "3.2.13"
8
3
  gem "test-unit"
4
+ gem "listen", "< 3.1.0"
9
5
  end
10
6
 
11
7
  appraise "rails-4.0.0" do
12
8
  gem "rails", "4.0.0"
9
+ gem "listen", "< 3.1.0"
13
10
  end
14
11
 
15
12
  appraise "rails-4.1.0" do
16
13
  gem "rails", "4.1.0"
14
+ gem "listen", "< 3.1.0"
17
15
  end
18
16
 
19
17
  appraise "rails-4.2.0" do
20
18
  gem "rails", "4.2.0"
19
+ gem "listen", "< 3.1.0"
21
20
  end
21
+
22
+ appraise "rails-5.0.0.beta2" do
23
+ gem "rails", "5.0.0.beta2"
24
+ end
data/README.md CHANGED
@@ -10,11 +10,7 @@ But if you have a chance, please [http://stopsoap.com/](http://stopsoap.com/).
10
10
 
11
11
  ## Compatibility
12
12
 
13
- Rails >3.0 only. MRI 1.9, 2.0, JRuby (--1.9).
14
-
15
- Ruby 1.8 is not officially supported since 0.5.3. We will accept further compatibilty pull-requests but no upcoming versions will be tested against it.
16
-
17
- Rubinius support temporarily dropped since 0.6.2 due to Rails 4 incompatibility.
13
+ Rails 3.2.13 and higher (if you are using SOAP and still on Ruby 1.9 - that's just too much evil, sorry)
18
14
 
19
15
  ## Installation
20
16
 
@@ -75,7 +71,7 @@ class RumbasController < ApplicationController
75
71
  :args => { :data => [:integer] },
76
72
  :return => [:boolean]
77
73
  def integers_to_boolean
78
- render :soap => params[:data].map{|x| x ? 1 : 0}
74
+ render :soap => params[:data].map{|i| i > 0}
79
75
  end
80
76
 
81
77
  # Params from XML attributes;
@@ -160,7 +156,7 @@ inside separate classes for the complex ones. Here's the way to do that:
160
156
  class Fluffy < WashOut::Type
161
157
  map :universe => {
162
158
  :name => :string,
163
- :age => :int
159
+ :age => :integer
164
160
  }
165
161
  end
166
162
 
@@ -3,7 +3,11 @@ module WashOutHelper
3
3
  def wsdl_data_options(param)
4
4
  case controller.soap_config.wsdl_style
5
5
  when 'rpc'
6
- { :"xsi:type" => param.namespaced_type }
6
+ if param.map.present? || param.value
7
+ { :"xsi:type" => param.namespaced_type }
8
+ else
9
+ { :"xsi:nil" => true }
10
+ end
7
11
  when 'document'
8
12
  { }
9
13
  end
@@ -96,11 +100,11 @@ module WashOutHelper
96
100
  end
97
101
 
98
102
  def wsdl_occurence(param, inject, extend_with = {})
99
- data = !param.multiplied ? {} : {
100
- "#{'xsi:' if inject}minOccurs" => 0,
101
- "#{'xsi:' if inject}maxOccurs" => 'unbounded'
102
- }
103
-
103
+ data = {"#{'xsi:' if inject}nillable" => 'true'}
104
+ if param.multiplied
105
+ data["#{'xsi:' if inject}minOccurs"] = 0
106
+ data["#{'xsi:' if inject}maxOccurs"] = 'unbounded'
107
+ end
104
108
  extend_with.merge(data)
105
109
  end
106
110
  end
@@ -62,7 +62,7 @@ xml.definitions 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
62
62
 
63
63
  xml.service :name => "service" do
64
64
  xml.port :name => "#{@name}_port", :binding => "tns:#{@name}_binding" do
65
- xml.tag! "soap:address", :location => send("#{@name}_action_url")
65
+ xml.tag! "soap:address", :location => WashOut::Router.url(request, @name)
66
66
  end
67
67
  end
68
68
  end
@@ -62,7 +62,7 @@ xml.definitions 'xmlns' => 'http://schemas.xmlsoap.org/wsdl/',
62
62
 
63
63
  xml.service :name => "service" do
64
64
  xml.port :name => "#{@name}_port", :binding => "tns:#{@name}_binding" do
65
- xml.tag! "soap:address", :location => send("#{@name}_action_url")
65
+ xml.tag! "soap:address", :location => WashOut::Router.url(request, @name)
66
66
  end
67
67
  end
68
68
  end
@@ -14,7 +14,8 @@ gem "tzinfo"
14
14
  gem "pry"
15
15
  gem "simplecov"
16
16
  gem "simplecov-summary"
17
- gem "rails", "3.2.12"
17
+ gem "rails", "3.2.13"
18
18
  gem "test-unit"
19
+ gem "listen", "< 3.1.0"
19
20
 
20
21
  gemspec :path => "../"
@@ -15,5 +15,6 @@ gem "pry"
15
15
  gem "simplecov"
16
16
  gem "simplecov-summary"
17
17
  gem "rails", "4.0.0"
18
+ gem "listen", "< 3.1.0"
18
19
 
19
20
  gemspec :path => "../"
@@ -15,5 +15,6 @@ gem "pry"
15
15
  gem "simplecov"
16
16
  gem "simplecov-summary"
17
17
  gem "rails", "4.1.0"
18
+ gem "listen", "< 3.1.0"
18
19
 
19
20
  gemspec :path => "../"
@@ -15,5 +15,6 @@ gem "pry"
15
15
  gem "simplecov"
16
16
  gem "simplecov-summary"
17
17
  gem "rails", "4.2.0"
18
+ gem "listen", "< 3.1.0"
18
19
 
19
20
  gemspec :path => "../"
@@ -14,7 +14,6 @@ gem "tzinfo"
14
14
  gem "pry"
15
15
  gem "simplecov"
16
16
  gem "simplecov-summary"
17
- gem "rails", "3.1.3"
18
- gem "test-unit"
17
+ gem "rails", "5.0.0.beta2"
19
18
 
20
19
  gemspec :path => "../"
@@ -16,9 +16,8 @@ module WashOut
16
16
  class ProgrammerError < Exception; end
17
17
 
18
18
  def _authenticate_wsse
19
-
20
19
  begin
21
- xml_security = env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
20
+ xml_security = request.env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
22
21
  xml_security = xml_security.values_at(:header, :Header).compact.first
23
22
  xml_security = xml_security.values_at(:security, :Security).compact.first
24
23
  username_token = xml_security.values_at(:username_token, :UsernameToken).compact.first
@@ -69,10 +68,9 @@ module WashOut
69
68
 
70
69
  # This action generates the WSDL for defined SOAP methods.
71
70
  def _generate_wsdl
72
-
73
71
  @map = self.class.soap_actions
74
72
  @namespace = soap_config.namespace
75
- @name = controller_path.gsub('/', '_')
73
+ @name = controller_path
76
74
 
77
75
  render :template => "wash_out/#{soap_config.wsdl_style}/wsdl", :layout => false,
78
76
  :content_type => 'text/xml'
@@ -140,6 +138,10 @@ module WashOut
140
138
  render_soap_error("Cannot find SOAP action mapping for #{request.env['wash_out.soap_action']}")
141
139
  end
142
140
 
141
+ def _invalid_request
142
+ render_soap_error("Invalid SOAP request")
143
+ end
144
+
143
145
  def _catch_soap_errors
144
146
  yield
145
147
  rescue SOAPError => error
@@ -158,36 +160,54 @@ module WashOut
158
160
  end
159
161
 
160
162
  def self.included(controller)
161
- controller.send :around_filter, :_catch_soap_errors
163
+ entity = if defined?(Rails::VERSION::MAJOR) && (Rails::VERSION::MAJOR >= 4)
164
+ 'action'
165
+ else
166
+ 'filter'
167
+ end
168
+
169
+ controller.send :"around_#{entity}", :_catch_soap_errors
162
170
  controller.send :helper, :wash_out
163
- controller.send :before_filter, :_authenticate_wsse, :except => [
164
- :_generate_wsdl, :_invalid_action ]
165
- controller.send :before_filter, :_map_soap_parameters, :except => [
166
- :_generate_wsdl, :_invalid_action ]
167
- controller.send :skip_before_filter, :verify_authenticity_token
171
+ controller.send :"before_#{entity}", :_authenticate_wsse, :if => :soap_action?
172
+ controller.send :"before_#{entity}", :_map_soap_parameters, :if => :soap_action?
173
+ controller.send :"skip_before_#{entity}", :verify_authenticity_token
168
174
  end
169
175
 
170
- def self.deep_select(hash, result=[], &blk)
171
- result += Hash[hash.select(&blk)].values
176
+ def self.deep_select(collection, result=[], &blk)
177
+ values = collection.respond_to?(:values) ? collection.values : collection
178
+ result += values.select(&blk)
172
179
 
173
- hash.each do |key, value|
174
- result = deep_select(value, result, &blk) if value.is_a? Hash
180
+ values.each do |value|
181
+ if value.is_a?(Hash) || value.is_a?(Array)
182
+ result = deep_select(value, result, &blk)
183
+ end
175
184
  end
176
185
 
177
186
  result
178
187
  end
179
188
 
180
- def self.deep_replace_href(hash, replace)
181
- return replace[hash[:@href]] if hash.has_key?(:@href)
189
+ def self.deep_replace_href(element, replace)
190
+ return element unless element.is_a?(Array) || element.is_a?(Hash)
182
191
 
183
- hash.keys.each do |key, value|
184
- hash[key] = deep_replace_href(hash[key], replace) if hash[key].is_a?(Hash)
192
+ if element.is_a?(Array) # Traverse arrays
193
+ return element.map{|x| deep_replace_href(x, replace)}
185
194
  end
186
195
 
187
- hash
196
+ if element.has_key?(:@href) # Replace needle and traverse replacement
197
+ return deep_replace_href(replace[element[:@href]], replace)
198
+ end
199
+
200
+ element.each do |key, value| # Traverse hashes
201
+ element[key] = deep_replace_href(value, replace)
202
+ end
203
+
204
+ element
188
205
  end
189
206
 
190
207
  private
208
+ def soap_action?
209
+ soap_action.present?
210
+ end
191
211
 
192
212
  def action_spec
193
213
  self.class.soap_actions[soap_action]
@@ -202,7 +222,7 @@ module WashOut
202
222
  end
203
223
 
204
224
  def xml_data
205
- xml_data = env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
225
+ xml_data = request.env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
206
226
  xml_data = xml_data.values_at(:body, :Body).compact.first || {}
207
227
  return xml_data if soap_config.wsdl_style == "document"
208
228
  xml_data = xml_data.values_at(soap_action.underscore.to_sym, soap_action.to_sym, request_input_tag.to_sym).compact.first || {}
@@ -4,6 +4,26 @@ module WashOut
4
4
  # This class is a Rack middleware used to route SOAP requests to a proper
5
5
  # action of a given SOAP controller.
6
6
  class Router
7
+ def self.url(request, controller_name)
8
+ route = Rails.application.routes.routes.select do |x|
9
+ defaults = x.defaults
10
+ defaults = defaults[:defaults] if defaults.include?(:defaults) # Rails 5
11
+ defaults[:controller] == controller_name && defaults[:action] == 'soap'
12
+ end.first
13
+
14
+ path = if route.respond_to?(:optimized_path) # Rails 4
15
+ route.optimized_path
16
+ elsif route.path.respond_to?(:build_formatter) # Rails 5
17
+ route.path.build_formatter.evaluate(nil)
18
+ else
19
+ route.format({}) # Rails 3.2
20
+ end
21
+
22
+ path = path.join('') if path.is_a?(Array)
23
+
24
+ request.protocol + request.host_with_port + path
25
+ end
26
+
7
27
  def initialize(controller_name)
8
28
  @controller_name = "#{controller_name.to_s}_controller".camelize
9
29
  end
@@ -17,15 +37,13 @@ module WashOut
17
37
 
18
38
  soap_action = controller.soap_config.soap_action_routing ? env['HTTP_SOAPACTION'].to_s.gsub(/^"(.*)"$/, '\1')
19
39
  : ''
20
-
21
40
  if soap_action.blank?
22
41
  parsed_soap_body = nori(controller.soap_config.snakecase_input).parse(soap_body env)
23
42
  return nil if parsed_soap_body.blank?
24
43
 
25
- soap_action = parsed_soap_body
26
- .values_at(:envelope, :Envelope).compact.first
27
- .values_at(:body, :Body).compact.first
28
- .keys.first.to_s
44
+ soap_action = parsed_soap_body.values_at(:envelope, :Envelope).try(:compact).try(:first)
45
+ soap_action = soap_action.values_at(:body, :Body).try(:compact).try(:first) if soap_action
46
+ soap_action = soap_action.keys.first.to_s if soap_action
29
47
  end
30
48
 
31
49
  # RUBY18 1.8 does not have force_encoding.
@@ -61,9 +79,8 @@ module WashOut
61
79
 
62
80
  def parse_soap_parameters(env)
63
81
  return env['wash_out.soap_data'] if env['wash_out.soap_data']
64
-
65
82
  env['wash_out.soap_data'] = nori(controller.soap_config.snakecase_input).parse(soap_body env)
66
- references = WashOut::Dispatcher.deep_select(env['wash_out.soap_data']){|k,v| v.is_a?(Hash) && v.has_key?(:@id)}
83
+ references = WashOut::Dispatcher.deep_select(env['wash_out.soap_data']){|v| v.is_a?(Hash) && v.has_key?(:@id)}
67
84
 
68
85
  unless references.blank?
69
86
  replaces = {}; references.each{|r| replaces['#'+r[:@id]] = r}
@@ -76,17 +93,19 @@ module WashOut
76
93
  def call(env)
77
94
  @controller = @controller_name.constantize
78
95
 
79
- soap_action = parse_soap_action(env)
80
- return [200, {}, ['OK']] if soap_action.blank?
81
-
82
- soap_parameters = parse_soap_parameters(env)
83
-
84
- action_spec = controller.soap_actions[soap_action]
96
+ soap_action = parse_soap_action(env)
85
97
 
86
- if action_spec
87
- action = action_spec[:to]
98
+ action = if soap_action.blank?
99
+ '_invalid_request'
88
100
  else
89
- action = '_invalid_action'
101
+ soap_parameters = parse_soap_parameters(env)
102
+ action_spec = controller.soap_actions[soap_action]
103
+
104
+ if action_spec
105
+ action_spec[:to]
106
+ else
107
+ '_invalid_action'
108
+ end
90
109
  end
91
110
 
92
111
  controller.action(action).call(env)
@@ -1,3 +1,3 @@
1
1
  module WashOut
2
- VERSION = "0.10.0"
2
+ VERSION = "0.11.0.beta.1"
3
3
  end
data/lib/wash_out.rb CHANGED
@@ -21,11 +21,18 @@ module ActionDispatch::Routing
21
21
  class Mapper
22
22
  # Adds the routes for a SOAP endpoint at +controller+.
23
23
  def wash_out(controller_name, options={})
24
- options.each_with_index { |key, value| @scope[key] = value } if @scope
25
- controller_class_name = [options[:module], controller_name].compact.join("/")
24
+ if @scope
25
+ scope_frame = @scope.respond_to?(:frame) ? @scope.frame : @scope
26
+ options.each{ |key, value| scope_frame[key] = value }
27
+ end
26
28
 
27
- match "#{controller_name}/wsdl" => "#{controller_name}#_generate_wsdl", :via => :get, :format => false
28
- match "#{controller_name}/action" => WashOut::Router.new(controller_class_name), :via => [:get, :post], :defaults => { :controller => controller_class_name, :action => '_action' }, :format => false
29
+ controller_class_name = [scope_frame[:module], controller_name].compact.join("/").underscore
30
+
31
+ match "#{controller_name}/wsdl" => "#{controller_name}#_generate_wsdl", :via => :get, :format => false,
32
+ :as => "#{controller_class_name}_wsdl"
33
+ match "#{controller_name}/action" => WashOut::Router.new(controller_class_name), :via => [:get, :post],
34
+ :defaults => { :controller => controller_class_name, :action => 'soap' }, :format => false,
35
+ :as => "#{controller_class_name}_soap"
29
36
  end
30
37
  end
31
38
  end
@@ -0,0 +1,19 @@
1
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <s:Body s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
5
+ <parent href="#id1" />
6
+ <q2:child id="id1" xsi:type="q2:child" xmlns:q2="urn:FakeService">
7
+ <first_list href="#id2" />
8
+ <second_list href="#id3" />
9
+ </q2:child>
10
+ <q3:Array id="id2" q3:arrayType="xsd:int[1]" xmlns:q3="http://schemas.xmlsoap.org/soap/encoding/">
11
+ <Item>1</Item>
12
+ <Item>2</Item>
13
+ </q3:Array>
14
+ <q4:Array id="id3" q4:arrayType="xsd:int[1]" xmlns:q4="http://schemas.xmlsoap.org/soap/encoding/">
15
+ <Item>11</Item>
16
+ <Item>22</Item>
17
+ </q4:Array>
18
+ </s:Body>
19
+ </s:Envelope>
@@ -0,0 +1,11 @@
1
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <s:Body s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
5
+ <list href="#id1" />
6
+ <q1:Array id="id1" q1:arrayType="xsd:int[1]" xmlns:q1="http://schemas.xmlsoap.org/soap/encoding/">
7
+ <Item>1</Item>
8
+ <Item>2</Item>
9
+ </q1:Array>
10
+ </s:Body>
11
+ </s:Envelope>
@@ -0,0 +1,16 @@
1
+ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <s:Body s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
5
+ <first_list href="#id1" />
6
+ <second_list href="#id2" />
7
+ <q1:Array id="id1" q1:arrayType="xsd:int[1]" xmlns:q1="http://schemas.xmlsoap.org/soap/encoding/">
8
+ <Item>1</Item>
9
+ <Item>2</Item>
10
+ </q1:Array>
11
+ <q2:Array id="id2" q2:arrayType="xsd:int[1]" xmlns:q2="http://schemas.xmlsoap.org/soap/encoding/">
12
+ <Item>11</Item>
13
+ <Item>22</Item>
14
+ </q2:Array>
15
+ </s:Body>
16
+ </s:Envelope>
@@ -12,14 +12,121 @@ describe WashOut::Dispatcher do
12
12
  end
13
13
  end
14
14
 
15
- it "finds nested hashes" do
16
- expect(WashOut::Dispatcher.deep_select(:foo => 1){|k,v| k == :foo}).to eq [1]
17
- expect(WashOut::Dispatcher.deep_select({:foo => {:foo => 1}}){|k,v| k == :foo}).to eq([{:foo => 1}, 1])
15
+ describe ".deep_select" do
16
+ blk = lambda{|v| v.is_a?(Hash) && v.has_key?(:@id)}
17
+
18
+ it "find no elements if there aren't any ids" do
19
+ expect(WashOut::Dispatcher.deep_select({k: {v: :v2}}, &blk)).to eq []
20
+ end
21
+
22
+ it "finds elements with ids in a hash" do
23
+ expect(WashOut::Dispatcher.deep_select({k: {:@id => 5, x: :y}}, &blk)).to eq [{:@id => 5, x: :y}]
24
+ end
25
+
26
+ it "finds elements with ids in a array" do
27
+ expect(WashOut::Dispatcher.deep_select({k: [{:@id => 5, x: :y}]}, &blk)).to eq [{:@id => 5, x: :y}]
28
+ end
29
+
30
+ it "finds elements with ids in hashes" do
31
+ expect(WashOut::Dispatcher.deep_select(
32
+ {
33
+ k: {:@id => 5, x: :y},
34
+ k2: {:@id => 6, n: :m}
35
+ }, &blk)).to eq [{:@id => 5, x: :y}, {:@id => 6, n: :m}]
36
+ end
37
+
38
+ it "finds elements in a hash and in a array" do
39
+ expect(WashOut::Dispatcher.deep_select(
40
+ {
41
+ k: [{:@id => 5, x: :y}],
42
+ k2: {:@id => 6, n: :m}
43
+ }, &blk)).to contain_exactly({:@id => 5, x: :y}, {:@id => 6, n: :m})
44
+ end
45
+
46
+ it "finds elements with ids in multiple arrays" do
47
+ expect(WashOut::Dispatcher.deep_select(
48
+ {
49
+ k: [{:@id => 5, x: :y}],
50
+ k2: [{:@id => 6, n: :m}]
51
+ }, &blk)).to eq [{:@id => 5, x: :y}, {:@id => 6, n: :m}]
52
+ end
18
53
  end
19
54
 
20
- it "replaces nested hashed" do
21
- expect(WashOut::Dispatcher.deep_replace_href({:foo => {:@href => 1}}, {1 => 2})).to eq({:foo => 2})
22
- expect(WashOut::Dispatcher.deep_replace_href({:bar => {:foo => {:@href => 1}}}, {1 => 2})).to eq({:bar => {:foo => 2}})
55
+ describe ".deep_replace_href" do
56
+ it "replaces nested hashed" do
57
+ expect(WashOut::Dispatcher.deep_replace_href(
58
+ {:foo => {:@href => 1}},
59
+ {1 => 2})).to eq(
60
+ {:foo => 2}
61
+ )
62
+ end
63
+
64
+ it "replaces deeper nested hashes" do
65
+ expect(WashOut::Dispatcher.deep_replace_href(
66
+ {:bar => {:foo => {:@href => 1}}},
67
+ {1 => 2}
68
+ )).to eq(
69
+ {:bar => {:foo => 2}}
70
+ )
71
+ end
72
+
73
+ it "replace nested refs" do
74
+ hash = {fizz: {:@href => "#id4"}}
75
+ replaces = {
76
+ "#id4" => {:@href => "#id6"},
77
+ "#id6" => {foo: :bar}
78
+ }
79
+ expect(WashOut::Dispatcher.deep_replace_href(hash, replaces)).to eq({
80
+ fizz: {foo: :bar}})
81
+ end
82
+
83
+ it "replace really nested refs" do
84
+ hash = {fizz: {:@href => "#id4"}}
85
+ replaces = {
86
+ "#id4" => {:@href => "#id6"},
87
+ "#id6" => {:@href => "#id7"},
88
+ "#id7" => {foo: :bar}
89
+ }
90
+ expect(WashOut::Dispatcher.deep_replace_href(hash, replaces)).to eq({
91
+ fizz: {foo: :bar}})
92
+ end
93
+
94
+ it "replaces arrays in nested hashes" do
95
+ hash = {
96
+ fizz: {:@href => "#id4"},
97
+ Array: [
98
+ {Item: [{:@href => "#id6"}, {:@href => "#id7"}]},
99
+ {Item: {loo: :iioo}}
100
+ ]
101
+ }
102
+ replaces = {
103
+ "#id4" => {Item: [{:@href => "#id6"}, {:@href => "#id7"}]},
104
+ "#id6" => {foo: :bar},
105
+ "#id7" => {baz: :bats}
106
+ }
107
+ expect(WashOut::Dispatcher.deep_replace_href(hash, replaces)).to eq({
108
+ fizz: {Item: [
109
+ {foo: :bar},
110
+ {baz: :bats}
111
+ ]},
112
+ Array: [
113
+ {Item: [{foo: :bar}, {baz: :bats}]},
114
+ {Item: {loo: :iioo}}
115
+ ]
116
+ })
117
+ end
118
+
119
+ it "can traverse arrays that do not contain hashes" do
120
+ hash = {
121
+ fizz: {:@href => "#id1"},
122
+ }
123
+ replaces = {
124
+ "#id1" => {Item: ["1", "2"]},
125
+ }
126
+ expect(WashOut::Dispatcher.deep_replace_href(hash, replaces)).to eq({
127
+ fizz: {Item: ["1", "2"]},
128
+ })
129
+ end
23
130
  end
24
131
 
25
132
  xit "parses typical request" do
@@ -11,12 +11,40 @@ describe WashOut::Router do
11
11
  env = {}
12
12
  env['REQUEST_METHOD'] = 'GET'
13
13
  env['rack.input'] = double 'basic-rack-input', {:string => ''}
14
- result = WashOut::Router.new('Api').call env
14
+ result = WashOut::Router.new('Route::Space::Api').call env
15
15
 
16
- expect(result[0]).to eq(200)
17
- #expect(result[1]['Content-Type']).to eq('text/xml')
16
+ expect(result[0]).to eq(500)
17
+ expect(result[1]['Content-Type']).to eq('text/xml; charset=utf-8')
18
+ end
19
+
20
+ def parse_soap_params_from_xml(filename)
21
+ xml = File.read(File.expand_path("../../../fixtures/#{filename}", __FILE__))
22
+ env = {'rack.input' => StringIO.new(xml)}
23
+
24
+ router = WashOut::Router.new('')
25
+ controller = double("controller", soap_config: WashOut::SoapConfig.new)
26
+ allow(router).to receive(:controller).and_return(controller)
27
+
28
+ router.parse_soap_parameters(env)[:Envelope][:Body]
29
+ end
30
+
31
+ it "returns refs to arrays correctly" do
32
+ body = parse_soap_params_from_xml('ref_to_one_array.xml')
33
+
34
+ expect(body[:list][:Item]).to eq(["1", "2"])
35
+ end
36
+
37
+ it "returns refs to multiple arrays correctly" do
38
+ body = parse_soap_params_from_xml('refs_to_arrays.xml')
39
+
40
+ expect(body[:first_list][:Item]).to eq(["1", "2"])
41
+ expect(body[:second_list][:Item]).to eq(["11", "22"])
42
+ end
43
+
44
+ it "returns nested refs to multiple arrays correctly" do
45
+ body = parse_soap_params_from_xml('nested_refs_to_arrays.xml')
18
46
 
19
- msg = result[2][0]
20
- expect(msg).to eq('OK')
47
+ expect(body[:parent][:first_list][:Item]).to eq(["1", "2"])
48
+ expect(body[:parent][:second_list][:Item]).to eq(["11", "22"])
21
49
  end
22
50
  end
@@ -12,17 +12,19 @@ describe WashOut do
12
12
  )
13
13
  end
14
14
 
15
- def savon(method, message={}, &block)
15
+ def savon(method, message={}, hashify=true, &block)
16
16
  message = {:value => message} unless message.is_a?(Hash)
17
17
 
18
- savon = Savon::Client.new(:log => false, :wsdl => 'http://app/api/wsdl', &block)
19
- savon.call(method, :message => message).to_hash
18
+ savon = Savon::Client.new(:log => false, :wsdl => 'http://app/route/api/wsdl', &block)
19
+ result = savon.call(method, :message => message)
20
+ result = result.to_hash if hashify
21
+ result
20
22
  end
21
23
 
22
24
  def savon!(method, message={}, &block)
23
25
  message = {:value => message} unless message.is_a?(Hash)
24
26
 
25
- savon = Savon::Client.new(:log => true, :wsdl => 'http://app/api/wsdl', &block)
27
+ savon = Savon::Client.new(:log => true, :wsdl => 'http://app/route/api/wsdl', &block)
26
28
  savon.call(method, :message => message).to_hash
27
29
  end
28
30
 
@@ -59,7 +61,7 @@ describe WashOut do
59
61
  :return => { :circle2 => { :y => :integer } }
60
62
  end
61
63
 
62
- HTTPI.get("http://app/api/wsdl").body
64
+ HTTPI.get("http://app/route/api/wsdl").body
63
65
  end
64
66
 
65
67
  let :xml do
@@ -84,6 +86,13 @@ describe WashOut do
84
86
 
85
87
  expect(x[:'@min_occurs']).to eq "0"
86
88
  expect(x[:'@max_occurs']).to eq "unbounded"
89
+ expect(x[:'@nillable']).to eq "true"
90
+ end
91
+
92
+ it "adds nillable to all type definitions" do
93
+ types = xml[:definitions][:message].map { |d| d[:part] }.compact
94
+ nillable = types.map { |t| t[:"@xsi:nillable"] }
95
+ expect(nillable.all? { |v| v == "true" }).to be true
87
96
  end
88
97
  end
89
98
 
@@ -109,7 +118,7 @@ describe WashOut do
109
118
  </env:Envelope>
110
119
  XML
111
120
 
112
- expect(HTTPI.post("http://app/api/action", request).body).to eq <<-XML
121
+ expect(HTTPI.post("http://app/route/api/action", request).body).to eq <<-XML
113
122
  <?xml version="1.0" encoding="UTF-8"?>
114
123
  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="false">
115
124
  <soap:Body>
@@ -145,6 +154,17 @@ describe WashOut do
145
154
  to eq "42"
146
155
  end
147
156
 
157
+ it "shows date in correct format" do
158
+ mock_controller do
159
+ soap_action "answer", :args => {}, :return => {:a => :date}
160
+ def answer
161
+ render :soap => {:a => DateTime.new(2000, 1, 1)}
162
+ end
163
+ end
164
+ result = Hash.from_xml savon(:answer, {}, false).http.body
165
+ expect(result['Envelope']['Body']['answerResponse']['A']).to eq '2000-01-01T00:00:00+00:00'
166
+ end
167
+
148
168
  it "accept empty parameter" do
149
169
  mock_controller do
150
170
  soap_action "answer", :args => {:a => :string}, :return => {:a => :string}
@@ -152,8 +172,7 @@ describe WashOut do
152
172
  render :soap => {:a => params[:a]}
153
173
  end
154
174
  end
155
- expect(savon(:answer, :a => '')[:answer_response][:a]).
156
- to eq({:"@xsi:type"=>"xsd:string"})
175
+ expect(savon(:answer, :a => '')[:answer_response][:a]).to be_nil
157
176
  end
158
177
 
159
178
  it "accept one parameter" do
@@ -410,10 +429,20 @@ describe WashOut do
410
429
  end
411
430
  end
412
431
 
413
- expect(savon(:rocknroll)[:rocknroll_response][:my_value]).
414
- to eq({
415
- :"@xsi:type" => "tns:MyValue"
416
- })
432
+ expect(savon(:rocknroll)[:rocknroll_response][:my_value]).to be_nil
433
+ end
434
+
435
+ it "responds with missing parameters" do
436
+ mock_controller do
437
+ soap_action "rocknroll",
438
+ args: nil,
439
+ return: {my_value: :integer}
440
+ def rocknroll
441
+ render soap: {my_value: nil}
442
+ end
443
+ end
444
+
445
+ expect(savon(:rocknroll)[:rocknroll_response][:my_value]).to be_nil
417
446
  end
418
447
 
419
448
  it "handles incomplete array response" do
@@ -642,11 +671,25 @@ describe WashOut do
642
671
 
643
672
  savon(:rocknroll, "ZOMG" => 'yam!')
644
673
  end
674
+ end
645
675
 
676
+ describe "Router" do
677
+ it "raises when SOAP message without SOAP Envelope arrives" do
678
+ mock_controller do; end
679
+ invalid_request = '<a></a>'
680
+ response_hash = Nori.new.parse(HTTPI.post("http://app/route/api/action", invalid_request).body)
681
+ expect(response_hash["soap:Envelope"]["soap:Body"]["soap:Fault"]['faultstring']).to eq "Invalid SOAP request"
682
+ end
683
+
684
+ it "raises when SOAP message without SOAP Body arrives" do
685
+ mock_controller do; end
686
+ invalid_request = '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"></s:Envelope>'
687
+ response_hash = Nori.new.parse(HTTPI.post("http://app/route/api/action", invalid_request).body)
688
+ expect(response_hash["soap:Envelope"]["soap:Body"]["soap:Fault"]['faultstring']).to eq "Invalid SOAP request"
689
+ end
646
690
  end
647
691
 
648
692
  describe "WS Security" do
649
-
650
693
  it "appends username_token to params" do
651
694
  mock_controller(wsse_username: "gorilla", wsse_password: "secret") do
652
695
  soap_action "checkToken", :args => :integer, :return => nil, :to => 'check_token'
data/spec/spec_helper.rb CHANGED
@@ -50,12 +50,18 @@ HTTPI.adapter = :rack
50
50
 
51
51
  HTTPI::Adapter::Rack.mount 'app', Dummy::Application
52
52
  Dummy::Application.routes.draw do
53
- wash_out :api
53
+ namespace :route do
54
+ scope module: 'space' do
55
+ wash_out :api
56
+ end
57
+ end
54
58
  end
55
59
 
56
60
  def mock_controller(options = {}, &block)
57
- Object.send :remove_const, :ApiController if defined?(ApiController)
58
- Object.send :const_set, :ApiController, Class.new(ApplicationController) {
61
+ Object.send :const_set, :Route, Module.new unless defined?(Route)
62
+ Route.send :const_set, :Space, Module.new unless defined?(Route::Space)
63
+ Route::Space.send :remove_const, :ApiController if defined?(Route::Space::ApiController)
64
+ Route::Space.send :const_set, :ApiController, Class.new(ApplicationController) {
59
65
  include RSpec::Matchers
60
66
 
61
67
  soap_service options.reverse_merge({
@@ -66,5 +72,17 @@ def mock_controller(options = {}, &block)
66
72
  class_exec &block if block
67
73
  }
68
74
 
69
- ActiveSupport::Dependencies::Reference.instance_variable_get(:'@store').delete('ApiController')
75
+ ActiveSupport::Dependencies::Reference.instance_variable_get(:'@store').delete('Route::Space::ApiController')
76
+ end
77
+
78
+ unless defined?(silence_stream) # Rails 5
79
+ def silence_stream(stream)
80
+ old_stream = stream.dup
81
+ stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
82
+ stream.sync = true
83
+ yield
84
+ ensure
85
+ stream.reopen(old_stream)
86
+ old_stream.close
87
+ end
70
88
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wash_out
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boris Staal
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-02-04 00:00:00.000000000 Z
12
+ date: 2016-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nori
@@ -48,11 +48,11 @@ files:
48
48
  - app/views/wash_out/rpc/error.builder
49
49
  - app/views/wash_out/rpc/response.builder
50
50
  - app/views/wash_out/rpc/wsdl.builder
51
- - gemfiles/rails_3.1.3.gemfile
52
- - gemfiles/rails_3.2.12.gemfile
51
+ - gemfiles/rails_3.2.13.gemfile
53
52
  - gemfiles/rails_4.0.0.gemfile
54
53
  - gemfiles/rails_4.1.0.gemfile
55
54
  - gemfiles/rails_4.2.0.gemfile
55
+ - gemfiles/rails_5.0.0.beta2.gemfile
56
56
  - init.rb
57
57
  - lib/wash_out.rb
58
58
  - lib/wash_out/configurable.rb
@@ -90,6 +90,9 @@ files:
90
90
  - spec/dummy/public/favicon.ico
91
91
  - spec/dummy/public/stylesheets/.gitkeep
92
92
  - spec/dummy/script/rails
93
+ - spec/fixtures/nested_refs_to_arrays.xml
94
+ - spec/fixtures/ref_to_one_array.xml
95
+ - spec/fixtures/refs_to_arrays.xml
93
96
  - spec/lib/wash_out/dispatcher_spec.rb
94
97
  - spec/lib/wash_out/middleware_spec.rb
95
98
  - spec/lib/wash_out/param_spec.rb
@@ -114,12 +117,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
117
  version: '0'
115
118
  required_rubygems_version: !ruby/object:Gem::Requirement
116
119
  requirements:
117
- - - ">="
120
+ - - ">"
118
121
  - !ruby/object:Gem::Version
119
- version: '0'
122
+ version: 1.3.1
120
123
  requirements: []
121
124
  rubyforge_project:
122
- rubygems_version: 2.2.5
125
+ rubygems_version: 2.5.1
123
126
  signing_key:
124
127
  specification_version: 4
125
128
  summary: Dead simple Rails 3 SOAP server library