wash_out 0.9.0 → 0.11.0.beta.1

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.travis.yml +31 -3
  4. data/Appraisals +17 -8
  5. data/Gemfile +2 -2
  6. data/README.md +68 -8
  7. data/Rakefile +6 -7
  8. data/app/helpers/wash_out_helper.rb +59 -24
  9. data/app/views/{wash_with_soap → wash_out}/document/error.builder +1 -1
  10. data/app/views/{wash_with_soap → wash_out}/document/response.builder +1 -3
  11. data/app/views/{wash_with_soap → wash_out}/document/wsdl.builder +16 -16
  12. data/app/views/{wash_with_soap → wash_out}/rpc/error.builder +1 -1
  13. data/app/views/{wash_with_soap → wash_out}/rpc/response.builder +1 -3
  14. data/app/views/{wash_with_soap → wash_out}/rpc/wsdl.builder +17 -17
  15. data/gemfiles/rails_3.2.13.gemfile +21 -0
  16. data/gemfiles/rails_4.0.0.gemfile +20 -0
  17. data/gemfiles/rails_4.1.0.gemfile +20 -0
  18. data/gemfiles/rails_4.2.0.gemfile +20 -0
  19. data/gemfiles/rails_5.0.0.beta2.gemfile +19 -0
  20. data/lib/wash_out/dispatcher.rb +94 -48
  21. data/lib/wash_out/model.rb +1 -1
  22. data/lib/wash_out/param.rb +14 -1
  23. data/lib/wash_out/router.rb +46 -18
  24. data/lib/wash_out/soap.rb +5 -3
  25. data/lib/wash_out/soap_config.rb +2 -0
  26. data/lib/wash_out/version.rb +1 -1
  27. data/lib/wash_out/wsse.rb +27 -6
  28. data/lib/wash_out.rb +18 -5
  29. data/spec/dummy/config/environments/test.rb +1 -0
  30. data/spec/fixtures/nested_refs_to_arrays.xml +19 -0
  31. data/spec/fixtures/ref_to_one_array.xml +11 -0
  32. data/spec/fixtures/refs_to_arrays.xml +16 -0
  33. data/spec/lib/wash_out/dispatcher_spec.rb +135 -13
  34. data/spec/lib/wash_out/middleware_spec.rb +8 -8
  35. data/spec/lib/wash_out/param_spec.rb +43 -11
  36. data/spec/lib/wash_out/router_spec.rb +50 -0
  37. data/spec/lib/wash_out/type_spec.rb +9 -9
  38. data/spec/lib/wash_out_spec.rb +196 -88
  39. data/spec/spec_helper.rb +24 -4
  40. metadata +26 -17
@@ -5,13 +5,19 @@ module WashOut
5
5
  module Dispatcher
6
6
  # A SOAPError exception can be raised to return a correct SOAP error
7
7
  # response.
8
- class SOAPError < Exception; end
8
+ class SOAPError < Exception
9
+ attr_accessor :code
10
+ def initialize(message, code=nil)
11
+ super(message)
12
+ @code = code
13
+ end
14
+ end
15
+
9
16
  class ProgrammerError < Exception; end
10
17
 
11
18
  def _authenticate_wsse
12
-
13
19
  begin
14
- 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
15
21
  xml_security = xml_security.values_at(:header, :Header).compact.first
16
22
  xml_security = xml_security.values_at(:security, :Security).compact.first
17
23
  username_token = xml_security.values_at(:username_token, :UsernameToken).compact.first
@@ -25,32 +31,27 @@ module WashOut
25
31
  end
26
32
 
27
33
  def _map_soap_parameters
34
+ @_params = _load_params action_spec[:in],
35
+ _strip_empty_nodes(action_spec[:in], xml_data)
36
+ end
28
37
 
29
- soap_action = request.env['wash_out.soap_action']
30
- action_spec = self.class.soap_actions[soap_action]
31
-
32
- xml_data = env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
33
- xml_data = xml_data.values_at(:body, :Body).compact.first
34
- xml_data = xml_data.values_at(soap_action.underscore.to_sym,
35
- soap_action.to_sym).compact.first || {}
38
+ def _strip_empty_nodes(params, hash)
39
+ hash.keys.each do |key|
40
+ param = params.detect { |a| a.raw_name.to_s == key.to_s }
41
+ next if !(param && hash[key].is_a?(Hash))
36
42
 
37
- strip_empty_nodes = lambda{|hash|
38
- hash.keys.each do |key|
39
- if hash[key].is_a? Hash
40
- value = hash[key].delete_if{|k, v| key.to_s[0] == '@'}
43
+ value = hash[key].delete_if do |k, _|
44
+ k.to_s[0] == '@' && !param.map.detect { |a| a.raw_name.to_s == k.to_s }
45
+ end
41
46
 
42
- if value.length > 0
43
- hash[key] = strip_empty_nodes.call(value)
44
- else
45
- hash[key] = nil
46
- end
47
- end
47
+ if value.length > 0
48
+ hash[key] = _strip_empty_nodes param.map, value
49
+ else
50
+ hash[key] = nil
48
51
  end
52
+ end
49
53
 
50
- hash
51
- }
52
- xml_data = strip_empty_nodes.call(xml_data)
53
- @_params = _load_params(action_spec[:in], xml_data)
54
+ hash
54
55
  end
55
56
 
56
57
  # Creates the final parameter hash based on the request spec and xml_data from the request
@@ -67,12 +68,11 @@ module WashOut
67
68
 
68
69
  # This action generates the WSDL for defined SOAP methods.
69
70
  def _generate_wsdl
70
-
71
71
  @map = self.class.soap_actions
72
72
  @namespace = soap_config.namespace
73
- @name = controller_path.gsub('/', '_')
73
+ @name = controller_path
74
74
 
75
- render :template => "wash_with_soap/#{soap_config.wsdl_style}/wsdl", :layout => false,
75
+ render :template => "wash_out/#{soap_config.wsdl_style}/wsdl", :layout => false,
76
76
  :content_type => 'text/xml'
77
77
  end
78
78
 
@@ -127,7 +127,7 @@ module WashOut
127
127
  return result_spec
128
128
  }
129
129
 
130
- render :template => "wash_with_soap/#{soap_config.wsdl_style}/response",
130
+ render :template => "wash_out/#{soap_config.wsdl_style}/response",
131
131
  :layout => false,
132
132
  :locals => { :result => inject.call(result, @action_spec[:out]) },
133
133
  :content_type => 'text/xml'
@@ -138,49 +138,95 @@ module WashOut
138
138
  render_soap_error("Cannot find SOAP action mapping for #{request.env['wash_out.soap_action']}")
139
139
  end
140
140
 
141
- def _render_soap_exception(error)
142
- render_soap_error(error.message)
141
+ def _invalid_request
142
+ render_soap_error("Invalid SOAP request")
143
+ end
144
+
145
+ def _catch_soap_errors
146
+ yield
147
+ rescue SOAPError => error
148
+ render_soap_error(error.message, error.code)
143
149
  end
144
150
 
145
151
  # Render a SOAP error response.
146
152
  #
147
153
  # Rails do not support sequental rescue_from handling, that is, rescuing an
148
154
  # exception from a rescue_from handler. Hence this function is a public API.
149
- def render_soap_error(message)
150
- render :template => "wash_with_soap/#{soap_config.wsdl_style}/error", :status => 500,
155
+ def render_soap_error(message, code=nil)
156
+ render :template => "wash_out/#{soap_config.wsdl_style}/error", :status => 500,
151
157
  :layout => false,
152
- :locals => { :error_message => message },
158
+ :locals => { :error_message => message, :error_code => (code || 'Server') },
153
159
  :content_type => 'text/xml'
154
160
  end
155
161
 
156
162
  def self.included(controller)
157
- controller.send :rescue_from, SOAPError, :with => :_render_soap_exception
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
158
170
  controller.send :helper, :wash_out
159
- controller.send :before_filter, :_authenticate_wsse, :except => [
160
- :_generate_wsdl, :_invalid_action ]
161
- controller.send :before_filter, :_map_soap_parameters, :except => [
162
- :_generate_wsdl, :_invalid_action ]
163
- 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
164
174
  end
165
175
 
166
- def self.deep_select(hash, result=[], &blk)
167
- 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)
168
179
 
169
- hash.each do |key, value|
170
- 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
171
184
  end
172
185
 
173
186
  result
174
187
  end
175
188
 
176
- def self.deep_replace_href(hash, replace)
177
- 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)
178
191
 
179
- hash.keys.each do |key, value|
180
- 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)}
181
194
  end
182
195
 
183
- 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
205
+ end
206
+
207
+ private
208
+ def soap_action?
209
+ soap_action.present?
184
210
  end
211
+
212
+ def action_spec
213
+ self.class.soap_actions[soap_action]
214
+ end
215
+
216
+ def request_input_tag
217
+ action_spec[:request_tag]
218
+ end
219
+
220
+ def soap_action
221
+ request.env['wash_out.soap_action']
222
+ end
223
+
224
+ def xml_data
225
+ xml_data = request.env['wash_out.soap_data'].values_at(:envelope, :Envelope).compact.first
226
+ xml_data = xml_data.values_at(:body, :Body).compact.first || {}
227
+ return xml_data if soap_config.wsdl_style == "document"
228
+ xml_data = xml_data.values_at(soap_action.underscore.to_sym, soap_action.to_sym, request_input_tag.to_sym).compact.first || {}
229
+ end
230
+
185
231
  end
186
232
  end
@@ -22,7 +22,7 @@ module WashOut
22
22
  map
23
23
  end
24
24
 
25
- def wash_out_param_name
25
+ def wash_out_param_name(*args)
26
26
  return name.underscore
27
27
  end
28
28
  end
@@ -7,6 +7,7 @@ module WashOut
7
7
  attr_accessor :multiplied
8
8
  attr_accessor :value
9
9
  attr_accessor :source_class
10
+ attr_accessor :soap_config
10
11
 
11
12
  # Defines a WSDL parameter with name +name+ and type specifier +type+.
12
13
  # The type specifier format is described in #parse_def.
@@ -63,6 +64,7 @@ module WashOut
63
64
  operation = case type
64
65
  when 'string'; :to_s
65
66
  when 'integer'; :to_i
67
+ when 'long'; :to_i
66
68
  when 'double'; :to_f
67
69
  when 'boolean'; lambda{|dat| dat === "0" ? false : !!dat}
68
70
  when 'date'; :to_date
@@ -160,9 +162,19 @@ module WashOut
160
162
  def flat_copy
161
163
  copy = self.class.new(@soap_config, @name, @type.to_sym, @multiplied)
162
164
  copy.raw_name = raw_name
165
+ copy.source_class = source_class
163
166
  copy
164
167
  end
165
168
 
169
+ def attribute?
170
+ name[0] == "@"
171
+ end
172
+
173
+ def attr_name
174
+ raise 'Not attribute' unless attribute?
175
+ name[1..-1]
176
+ end
177
+
166
178
  private
167
179
 
168
180
  # Used to load an entire structure.
@@ -177,7 +189,8 @@ module WashOut
177
189
  # RUBY18 Enumerable#each_with_object is better, but 1.9 only.
178
190
  @map.map do |param|
179
191
  if data.has_key? param.raw_name
180
- struct[param.raw_name] = yield param, data, param.raw_name
192
+ param_name = param.attribute? ? param.attr_name : param.raw_name
193
+ struct[param_name] = yield param, data, param.raw_name
181
194
  end
182
195
  end
183
196
 
@@ -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
@@ -15,13 +35,15 @@ module WashOut
15
35
  def parse_soap_action(env)
16
36
  return env['wash_out.soap_action'] if env['wash_out.soap_action']
17
37
 
18
- soap_action = env['HTTP_SOAPACTION'].to_s.gsub(/^"(.*)"$/, '\1')
19
-
38
+ soap_action = controller.soap_config.soap_action_routing ? env['HTTP_SOAPACTION'].to_s.gsub(/^"(.*)"$/, '\1')
39
+ : ''
20
40
  if soap_action.blank?
21
- soap_action = nori.parse(soap_body env)
22
- .values_at(:envelope, :Envelope).compact.first
23
- .values_at(:body, :Body).compact.first
24
- .keys.first.to_s
41
+ parsed_soap_body = nori(controller.soap_config.snakecase_input).parse(soap_body env)
42
+ return nil if parsed_soap_body.blank?
43
+
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
25
47
  end
26
48
 
27
49
  # RUBY18 1.8 does not have force_encoding.
@@ -41,22 +63,24 @@ module WashOut
41
63
  :strip_namespaces => true,
42
64
  :advanced_typecasting => true,
43
65
  :convert_tags_to => (
44
- snakecase ? lambda { |tag| tag.snakecase.to_sym }
66
+ snakecase ? lambda { |tag| tag.snakecase.to_sym }
45
67
  : lambda { |tag| tag.to_sym }
46
68
  )
47
69
  )
48
70
  end
49
71
 
50
72
  def soap_body(env)
51
- env['rack.input'].respond_to?(:string) ? env['rack.input'].string
52
- : env['rack.input'].read
73
+ body = env['rack.input']
74
+ body.rewind if body.respond_to? :rewind
75
+ body.respond_to?(:string) ? body.string : body.read
76
+ ensure
77
+ body.rewind if body.respond_to? :rewind
53
78
  end
54
79
 
55
80
  def parse_soap_parameters(env)
56
81
  return env['wash_out.soap_data'] if env['wash_out.soap_data']
57
-
58
82
  env['wash_out.soap_data'] = nori(controller.soap_config.snakecase_input).parse(soap_body env)
59
- 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)}
60
84
 
61
85
  unless references.blank?
62
86
  replaces = {}; references.each{|r| replaces['#'+r[:@id]] = r}
@@ -69,15 +93,19 @@ module WashOut
69
93
  def call(env)
70
94
  @controller = @controller_name.constantize
71
95
 
72
- soap_action = parse_soap_action(env)
73
- soap_parameters = parse_soap_parameters(env)
74
-
75
- action_spec = controller.soap_actions[soap_action]
96
+ soap_action = parse_soap_action(env)
76
97
 
77
- if action_spec
78
- action = action_spec[:to]
98
+ action = if soap_action.blank?
99
+ '_invalid_request'
79
100
  else
80
- 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
81
109
  end
82
110
 
83
111
  controller.action(action).call(env)
data/lib/wash_out/soap.rb CHANGED
@@ -26,20 +26,22 @@ module WashOut
26
26
  end
27
27
 
28
28
  default_response_tag = soap_config.camelize_wsdl ? 'Response' : '_response'
29
- default_response_tag = "tns:#{action}#{default_response_tag}"
29
+ default_response_tag = action+default_response_tag
30
30
 
31
- self.soap_actions[action] = {
31
+ self.soap_actions[action] = options.merge(
32
32
  :in => WashOut::Param.parse_def(soap_config, options[:args]),
33
+ :request_tag => options[:as] || action,
33
34
  :out => WashOut::Param.parse_def(soap_config, options[:return]),
34
35
  :to => options[:to] || action,
35
36
  :response_tag => options[:response_tag] || default_response_tag
36
- }
37
+ )
37
38
  end
38
39
  end
39
40
 
40
41
  included do
41
42
  include WashOut::Configurable
42
43
  include WashOut::Dispatcher
44
+ include WashOut::WsseParams
43
45
  self.soap_actions = {}
44
46
  end
45
47
  end
@@ -13,6 +13,8 @@ module WashOut
13
13
  catch_xml_errors: false,
14
14
  wsse_username: nil,
15
15
  wsse_password: nil,
16
+ wsse_auth_callback: nil,
17
+ soap_action_routing: true,
16
18
  }
17
19
 
18
20
  attr_reader :config
@@ -1,3 +1,3 @@
1
1
  module WashOut
2
- VERSION = "0.9.0"
2
+ VERSION = "0.11.0.beta.1"
3
3
  end
data/lib/wash_out/wsse.rb CHANGED
@@ -1,4 +1,13 @@
1
1
  module WashOut
2
+
3
+ module WsseParams
4
+ def wsse_username
5
+ if request.env['WSSE_TOKEN']
6
+ request.env['WSSE_TOKEN'].values_at(:username, :Username).compact.first
7
+ end
8
+ end
9
+ end
10
+
2
11
  class Wsse
3
12
  attr_reader :soap_config
4
13
  def self.authenticate(soap_config, token)
@@ -18,7 +27,15 @@ module WashOut
18
27
  end
19
28
 
20
29
  def required?
21
- !soap_config.wsse_username.blank?
30
+ !soap_config.wsse_username.blank? || auth_callback?
31
+ end
32
+
33
+ def auth_callback?
34
+ return !!soap_config.wsse_auth_callback && soap_config.wsse_auth_callback.respond_to?(:call) && soap_config.wsse_auth_callback.arity == 2
35
+ end
36
+
37
+ def perform_auth_callback(user, password)
38
+ soap_config.wsse_auth_callback.call(user, password)
22
39
  end
23
40
 
24
41
  def expected_user
@@ -32,8 +49,8 @@ module WashOut
32
49
  def matches_expected_digest?(password)
33
50
  nonce = @username_token.values_at(:nonce, :Nonce).compact.first
34
51
  timestamp = @username_token.values_at(:created, :Created).compact.first
35
-
36
52
  return false if nonce.nil? || timestamp.nil?
53
+ timestamp = timestamp.to_datetime
37
54
 
38
55
  # Token should not be accepted if timestamp is older than 5 minutes ago
39
56
  # http://www.oasis-open.org/committees/download.php/16782/wss-v1.1-spec-os-UsernameTokenProfile.pdf
@@ -45,11 +62,11 @@ module WashOut
45
62
  flavors = Array.new
46
63
 
47
64
  # Ruby / Savon
48
- token = nonce + timestamp.to_s + expected_password
65
+ token = nonce + timestamp.strftime("%Y-%m-%dT%H:%M:%SZ") + expected_password
49
66
  flavors << Base64.encode64(Digest::SHA1.hexdigest(token)).chomp!
50
67
 
51
68
  # Java
52
- token = Base64.decode64(nonce) + timestamp.to_s + expected_password
69
+ token = Base64.decode64(nonce) + timestamp.strftime("%Y-%m-%dT%H:%M:%SZ") + expected_password
53
70
  flavors << Base64.encode64(Digest::SHA1.digest(token)).chomp!
54
71
 
55
72
  flavors.each do |f|
@@ -65,11 +82,15 @@ module WashOut
65
82
  user = @username_token.values_at(:username, :Username).compact.first
66
83
  password = @username_token.values_at(:password, :Password).compact.first
67
84
 
68
- if (expected_user == user && expected_password == password)
85
+ if (expected_user == user && matches_expected_digest?(password))
69
86
  return true
70
87
  end
71
88
 
72
- if (expected_user == user && matches_expected_digest?(password))
89
+ if auth_callback?
90
+ return perform_auth_callback(user, password)
91
+ end
92
+
93
+ if (expected_user == user && expected_password == password)
73
94
  return true
74
95
  end
75
96
 
data/lib/wash_out.rb CHANGED
@@ -11,15 +11,28 @@ require 'wash_out/model'
11
11
  require 'wash_out/wsse'
12
12
  require 'wash_out/middleware'
13
13
 
14
+ module WashOut
15
+ def self.root
16
+ File.expand_path '../..', __FILE__
17
+ end
18
+ end
19
+
14
20
  module ActionDispatch::Routing
15
21
  class Mapper
16
22
  # Adds the routes for a SOAP endpoint at +controller+.
17
23
  def wash_out(controller_name, options={})
18
- options.reverse_merge!(@scope) if @scope
19
- 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
20
28
 
21
- match "#{controller_name}/wsdl" => "#{controller_name}#_generate_wsdl", :via => :get, :format => false
22
- 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"
23
36
  end
24
37
  end
25
38
  end
@@ -44,4 +57,4 @@ ActionController::Base.class_eval do
44
57
  include WashOut::SOAP
45
58
  self.soap_config = options
46
59
  end
47
- end
60
+ end
@@ -26,4 +26,5 @@ Dummy::Application.configure do
26
26
 
27
27
  # Print deprecation notices to the stderr
28
28
  config.active_support.deprecation = :stderr
29
+ config.active_support.test_order = :random
29
30
  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>