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 +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
|