wash_out 0.10.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.
- checksums.yaml +4 -4
- data/.travis.yml +16 -8
- data/Appraisals +10 -7
- data/README.md +3 -7
- data/app/helpers/wash_out_helper.rb +10 -6
- data/app/views/wash_out/document/wsdl.builder +1 -1
- data/app/views/wash_out/rpc/wsdl.builder +1 -1
- data/gemfiles/{rails_3.2.12.gemfile → rails_3.2.13.gemfile} +2 -1
- data/gemfiles/rails_4.0.0.gemfile +1 -0
- data/gemfiles/rails_4.1.0.gemfile +1 -0
- data/gemfiles/rails_4.2.0.gemfile +1 -0
- data/gemfiles/{rails_3.1.3.gemfile → rails_5.0.0.beta2.gemfile} +1 -2
- data/lib/wash_out/dispatcher.rb +40 -20
- data/lib/wash_out/router.rb +35 -16
- data/lib/wash_out/version.rb +1 -1
- data/lib/wash_out.rb +11 -4
- data/spec/fixtures/nested_refs_to_arrays.xml +19 -0
- data/spec/fixtures/ref_to_one_array.xml +11 -0
- data/spec/fixtures/refs_to_arrays.xml +16 -0
- data/spec/lib/wash_out/dispatcher_spec.rb +113 -6
- data/spec/lib/wash_out/router_spec.rb +33 -5
- data/spec/lib/wash_out_spec.rb +56 -13
- data/spec/spec_helper.rb +22 -4
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d49adf22c0c16c3f0e8e3e2dcf694b7d6851920
|
4
|
+
data.tar.gz: c42b0da56ed90cd44e4d014aff450f3bef83325f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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.
|
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.
|
2
|
-
gem "rails", "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
|
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{|
|
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 => :
|
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
|
-
|
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 =
|
100
|
-
|
101
|
-
"#{'xsi:' if inject}
|
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 =>
|
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 =>
|
65
|
+
xml.tag! "soap:address", :location => WashOut::Router.url(request, @name)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
data/lib/wash_out/dispatcher.rb
CHANGED
@@ -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
|
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
|
-
|
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 :
|
164
|
-
|
165
|
-
controller.send :
|
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(
|
171
|
-
|
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
|
-
|
174
|
-
|
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(
|
181
|
-
return
|
189
|
+
def self.deep_replace_href(element, replace)
|
190
|
+
return element unless element.is_a?(Array) || element.is_a?(Hash)
|
182
191
|
|
183
|
-
|
184
|
-
|
192
|
+
if element.is_a?(Array) # Traverse arrays
|
193
|
+
return element.map{|x| deep_replace_href(x, replace)}
|
185
194
|
end
|
186
195
|
|
187
|
-
|
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 || {}
|
data/lib/wash_out/router.rb
CHANGED
@@ -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
|
-
|
27
|
-
|
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']){|
|
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
|
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
|
87
|
-
|
98
|
+
action = if soap_action.blank?
|
99
|
+
'_invalid_request'
|
88
100
|
else
|
89
|
-
|
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)
|
data/lib/wash_out/version.rb
CHANGED
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
|
-
|
25
|
-
|
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
|
-
|
28
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
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(
|
17
|
-
|
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
|
-
|
20
|
-
expect(
|
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
|
data/spec/lib/wash_out_spec.rb
CHANGED
@@ -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
|
19
|
-
savon.call(method, :message => message)
|
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
|
-
|
415
|
-
|
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
|
-
|
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 :
|
58
|
-
|
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.
|
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-
|
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.
|
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:
|
122
|
+
version: 1.3.1
|
120
123
|
requirements: []
|
121
124
|
rubyforge_project:
|
122
|
-
rubygems_version: 2.
|
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
|