washout_builder 0.9.12 → 0.10.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 +8 -8
- data/.travis.yml +6 -0
- data/Gemfile +11 -0
- data/README.rdoc +2 -1
- data/Rakefile +3 -1
- data/app/helpers/washout_builder_helper.rb +7 -169
- data/app/views/wash_with_html/doc.builder +11 -11
- data/lib/washout_builder.rb +24 -5
- data/lib/washout_builder/dispatcher.rb +6 -7
- data/lib/washout_builder/document/complex_type.rb +102 -0
- data/lib/washout_builder/document/generator.rb +114 -0
- data/lib/washout_builder/document/virtus_model.rb +45 -0
- data/lib/washout_builder/type.rb +2 -1
- data/lib/washout_builder/version.rb +1 -1
- data/spec/app/controllers/washout_builder_controller_spec.rb +8 -0
- data/spec/app/helpers/washout_builder_helper_spec.rb +8 -0
- data/spec/app/integration/washout_builder_all_services_spec.rb +7 -0
- data/spec/app/integration/washout_builder_service_spec.rb +7 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +51 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +23 -0
- data/spec/dummy/config/environments/test.rb +29 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +8 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/stylesheets/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/lib/washout_builder/dispatcher_spec.rb +51 -0
- data/spec/lib/washout_builder/document/complex_type_spec.rb +0 -0
- data/spec/lib/washout_builder/document/generator_spec.rb +0 -0
- data/spec/lib/washout_builder/document/virtus_model_spec.rb +0 -0
- data/spec/lib/washout_builder/engine_spec.rb +6 -0
- data/spec/lib/washout_builder/soap_spec.rb +15 -0
- data/spec/lib/washout_builder/type_spec.rb +21 -0
- data/spec/lib/washout_builder_spec.rb +697 -0
- data/spec/spec_helper.rb +2 -0
- metadata +74 -1
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/404.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
23
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/422.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The change you wanted was rejected.</h1>
|
23
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
23
|
+
<p>We've been notified about this issue and we'll take a look at it shortly.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
File without changes
|
File without changes
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe WashoutBuilder::Dispatcher do
|
6
|
+
|
7
|
+
class Dispatcher < ApplicationController
|
8
|
+
soap_service
|
9
|
+
|
10
|
+
def params
|
11
|
+
@_params
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
describe "#_load_params" do
|
19
|
+
let(:dispatcher) { Dispatcher.new }
|
20
|
+
let(:soap_config) {
|
21
|
+
OpenStruct.new(
|
22
|
+
WashOut::Rails::Engine.config.wash_out.merge( { camelize_wsdl: false })
|
23
|
+
)
|
24
|
+
}
|
25
|
+
it "should load params for an array" do
|
26
|
+
spec = WashOut::Param.parse_def(soap_config, {:my_array => [:integer] } )
|
27
|
+
xml_data = {:my_array => [1, 2, 3]}
|
28
|
+
dispatcher._load_params(spec, xml_data).should == {"my_array" => [1, 2, 3]}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should load params for an empty array" do
|
32
|
+
spec = WashOut::Param.parse_def(soap_config, {:my_array => [:integer] } )
|
33
|
+
xml_data = {}
|
34
|
+
dispatcher._load_params(spec, xml_data).should == {}
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should load params for a nested array" do
|
38
|
+
spec = WashOut::Param.parse_def(soap_config, {:nested => {:my_array => [:integer]}} )
|
39
|
+
xml_data = {:nested => {:my_array => [1, 2, 3]}}
|
40
|
+
dispatcher._load_params(spec, xml_data).should == {"nested" => {"my_array" => [1, 2, 3]}}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should load params for an empty nested array" do
|
44
|
+
spec = WashOut::Param.parse_def(soap_config, {:nested => {:empty => [:integer] }} )
|
45
|
+
xml_data = {:nested => nil}
|
46
|
+
dispatcher._load_params(spec, xml_data).should == {"nested" => {}}
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe WashoutBuilder::SOAP do
|
6
|
+
|
7
|
+
# [
|
8
|
+
# WashoutBuilder::Dispatcher,
|
9
|
+
# WashOut::Rails::Controller
|
10
|
+
# ].each do |extension|
|
11
|
+
# specify { WashoutBuilder::SOAP.included_modules.should include(extension) }
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe WashoutBuilder::Type do
|
6
|
+
|
7
|
+
[ "string",
|
8
|
+
"integer",
|
9
|
+
"double",
|
10
|
+
"boolean",
|
11
|
+
"date",
|
12
|
+
"datetime",
|
13
|
+
"float",
|
14
|
+
"time",
|
15
|
+
"int"].each do |type|
|
16
|
+
it "defines a list of types" do
|
17
|
+
WashoutBuilder::Type::BASIC_TYPES.should include(type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,697 @@
|
|
1
|
+
#encoding:utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe WashoutBuilder do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
WashOut::Rails::Engine.config.wash_out[:wsdl_style] = 'rpc'
|
9
|
+
WashOut::Rails::Engine.config.wash_out[:parser] = :nokogiri
|
10
|
+
WashOut::Rails::Engine.config.wash_out[:catch_xml_errors] = true
|
11
|
+
end
|
12
|
+
|
13
|
+
let :nori do
|
14
|
+
Nori.new(
|
15
|
+
:strip_namespaces => true,
|
16
|
+
:advanced_typecasting => true,
|
17
|
+
:convert_tags_to => lambda {|x| x.snakecase.to_sym}
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def savon(method, message={}, &block)
|
22
|
+
message = {:value => message} unless message.is_a?(Hash)
|
23
|
+
|
24
|
+
savon_client = Savon::Client.new(:log => false, :wsdl => 'http://app/api/wsdl', &block)
|
25
|
+
result = savon_client.call(method, :message => message)
|
26
|
+
result.respond_to?(:to_hash) ? result.to_hash : result
|
27
|
+
end
|
28
|
+
|
29
|
+
def savon!(method, message={}, &block)
|
30
|
+
message = {:value => message} unless message.is_a?(Hash)
|
31
|
+
|
32
|
+
savon_client = Savon::Client.new(:log => true, :wsdl => 'http://app/api/wsdl', &block)
|
33
|
+
result = savon_client.call(method, :message => message)
|
34
|
+
result.respond_to?(:to_hash) ? result.to_hash : result
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "Module" do
|
38
|
+
it "includes" do
|
39
|
+
lambda {
|
40
|
+
mock_controller do
|
41
|
+
# nothing
|
42
|
+
end
|
43
|
+
}.should_not raise_exception
|
44
|
+
end
|
45
|
+
|
46
|
+
it "allows definition of a simple action" do
|
47
|
+
lambda {
|
48
|
+
mock_controller do
|
49
|
+
soap_action "answer", :args => nil, :return => :integer
|
50
|
+
end
|
51
|
+
}.should_not raise_exception
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "WSDL" do
|
56
|
+
let :wsdl do
|
57
|
+
mock_controller do
|
58
|
+
soap_action :result, :args => nil, :return => :int
|
59
|
+
|
60
|
+
soap_action "getArea", :args => {
|
61
|
+
:circle => [{
|
62
|
+
:center => { :x => [:integer], :y => :integer },
|
63
|
+
:radius => :double
|
64
|
+
}]},
|
65
|
+
:return => { :area => :double }
|
66
|
+
soap_action "rocky", :args => { :circle1 => { :x => :integer } },
|
67
|
+
:return => { :circle2 => { :y => :integer } }
|
68
|
+
end
|
69
|
+
|
70
|
+
HTTPI.get("http://app/api/wsdl").body
|
71
|
+
end
|
72
|
+
|
73
|
+
let :xml do
|
74
|
+
nori.parse wsdl
|
75
|
+
end
|
76
|
+
|
77
|
+
it "lists operations" do
|
78
|
+
operations = xml[:definitions][:binding][:operation]
|
79
|
+
operations.should be_a_kind_of(Array)
|
80
|
+
|
81
|
+
operations.map{|e| e[:'@name']}.sort.should == ['Result', 'getArea', 'rocky'].sort
|
82
|
+
end
|
83
|
+
|
84
|
+
it "defines complex types" do
|
85
|
+
wsdl.include?('<xsd:complexType name="Circle1">').should == true
|
86
|
+
end
|
87
|
+
|
88
|
+
it "defines arrays" do
|
89
|
+
x = xml[:definitions][:types][:schema][:complex_type].
|
90
|
+
find{|x| x[:'@name'] == 'Center'}[:sequence][:element].
|
91
|
+
find{|x| x[:'@name'] == 'X'}
|
92
|
+
|
93
|
+
x[:'@min_occurs'].should == "0"
|
94
|
+
x[:'@max_occurs'].should == "unbounded"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "Dispatcher" do
|
99
|
+
|
100
|
+
context "simple actions" do
|
101
|
+
it "accepts requests with no HTTP header" do
|
102
|
+
mock_controller do
|
103
|
+
soap_action "answer", :args => nil, :return => :int
|
104
|
+
def answer
|
105
|
+
render :soap => "42"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
request = <<-XML
|
110
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
111
|
+
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="false" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
112
|
+
<env:Body>
|
113
|
+
<tns:answer>
|
114
|
+
<value>42</value>
|
115
|
+
</tns:answer>
|
116
|
+
</env:Body>
|
117
|
+
</env:Envelope>
|
118
|
+
XML
|
119
|
+
|
120
|
+
HTTPI.post("http://app/api/action", request).body.should == <<-XML
|
121
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
122
|
+
<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">
|
123
|
+
<soap:Body>
|
124
|
+
<tns:answerResponse>
|
125
|
+
<Value xsi:type="xsd:int">42</Value>
|
126
|
+
</tns:answerResponse>
|
127
|
+
</soap:Body>
|
128
|
+
</soap:Envelope>
|
129
|
+
XML
|
130
|
+
end
|
131
|
+
|
132
|
+
it "accept no parameters" do
|
133
|
+
mock_controller do
|
134
|
+
soap_action "answer", :args => nil, :return => :int
|
135
|
+
def answer
|
136
|
+
render :soap => "42"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
savon(:answer)[:answer_response][:value].
|
141
|
+
should == "42"
|
142
|
+
end
|
143
|
+
|
144
|
+
it "accept insufficient parameters" do
|
145
|
+
mock_controller do
|
146
|
+
soap_action "answer", :args => {:a => :integer}, :return => :integer
|
147
|
+
def answer
|
148
|
+
render :soap => "42"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
savon(:answer)[:answer_response][:value].
|
153
|
+
should == "42"
|
154
|
+
end
|
155
|
+
|
156
|
+
it "accept empty parameter" do
|
157
|
+
mock_controller do
|
158
|
+
soap_action "answer", :args => {:a => :string}, :return => {:a => :string}
|
159
|
+
def answer
|
160
|
+
render :soap => {:a => params[:a]}
|
161
|
+
end
|
162
|
+
end
|
163
|
+
savon(:answer, :a => '')[:answer_response][:a].
|
164
|
+
should == {:"@xsi:type"=>"xsd:string"}
|
165
|
+
end
|
166
|
+
|
167
|
+
it "accept one parameter" do
|
168
|
+
mock_controller do
|
169
|
+
soap_action "checkAnswer", :args => :integer, :return => :boolean, :to => 'check_answer'
|
170
|
+
def check_answer
|
171
|
+
render :soap => (params[:value] == 42)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
savon(:check_answer, 42)[:check_answer_response][:value].should == true
|
176
|
+
savon(:check_answer, 13)[:check_answer_response][:value].should == false
|
177
|
+
end
|
178
|
+
|
179
|
+
it "accept two parameters" do
|
180
|
+
mock_controller do
|
181
|
+
soap_action "funky", :args => { :a => :integer, :b => :string }, :return => :string
|
182
|
+
def funky
|
183
|
+
render :soap => ((params[:a] * 10).to_s + params[:b])
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
savon(:funky, :a => 42, :b => 'k')[:funky_response][:value].should == '420k'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context "complex actions" do
|
192
|
+
it "accept nested structures" do
|
193
|
+
mock_controller do
|
194
|
+
soap_action "getArea", :args => { :circle => { :center => { :x => :integer,
|
195
|
+
:y => :integer },
|
196
|
+
:radius => :double } },
|
197
|
+
:return => { :area => :double,
|
198
|
+
:distance_from_o => :double },
|
199
|
+
:to => :get_area
|
200
|
+
def get_area
|
201
|
+
circle = params[:circle]
|
202
|
+
render :soap => { :area => Math::PI * circle[:radius] ** 2,
|
203
|
+
:distance_from_o => Math.sqrt(circle[:center][:x] ** 2 + circle[:center][:y] ** 2) }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
message = { :circle => { :center => { :x => 3, :y => 4 },
|
208
|
+
:radius => 5 } }
|
209
|
+
|
210
|
+
savon(:get_area, message)[:get_area_response].
|
211
|
+
should == ({ :area => (Math::PI * 25).to_s, :distance_from_o => (5.0).to_s })
|
212
|
+
end
|
213
|
+
|
214
|
+
it "accept arrays" do
|
215
|
+
mock_controller do
|
216
|
+
soap_action "rumba",
|
217
|
+
:args => {
|
218
|
+
:rumbas => [:integer]
|
219
|
+
},
|
220
|
+
:return => nil
|
221
|
+
def rumba
|
222
|
+
params.should == {"rumbas" => [1, 2, 3]}
|
223
|
+
render :soap => nil
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
savon(:rumba, :rumbas => [1, 2, 3])
|
228
|
+
end
|
229
|
+
|
230
|
+
it "accept empty arrays" do
|
231
|
+
mock_controller do
|
232
|
+
soap_action "rumba",
|
233
|
+
:args => {
|
234
|
+
:my_array => [:integer]
|
235
|
+
},
|
236
|
+
:return => nil
|
237
|
+
def rumba
|
238
|
+
params.should == {}
|
239
|
+
render :soap => nil
|
240
|
+
end
|
241
|
+
end
|
242
|
+
savon(:rumba, :empty => [])
|
243
|
+
end
|
244
|
+
|
245
|
+
it "accept nested empty arrays" do
|
246
|
+
mock_controller do
|
247
|
+
soap_action "rumba",
|
248
|
+
:args => {
|
249
|
+
:nested => {:my_array => [:integer] }
|
250
|
+
},
|
251
|
+
:return => nil
|
252
|
+
def rumba
|
253
|
+
params.should == {"nested" => {}}
|
254
|
+
render :soap => nil
|
255
|
+
end
|
256
|
+
end
|
257
|
+
savon(:rumba, :nested => {:my_array => []})
|
258
|
+
end
|
259
|
+
|
260
|
+
it "accept nested structures inside arrays" do
|
261
|
+
mock_controller do
|
262
|
+
soap_action "rumba",
|
263
|
+
:args => {
|
264
|
+
:rumbas => [ {
|
265
|
+
:zombies => :string,
|
266
|
+
:puppies => :string
|
267
|
+
} ]
|
268
|
+
},
|
269
|
+
:return => nil
|
270
|
+
def rumba
|
271
|
+
params.should == {
|
272
|
+
"rumbas" => [
|
273
|
+
{"zombies" => 'suck', "puppies" => 'rock'},
|
274
|
+
{"zombies" => 'slow', "puppies" => 'fast'}
|
275
|
+
]
|
276
|
+
}
|
277
|
+
render :soap => nil
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
savon :rumba, :rumbas => [
|
282
|
+
{:zombies => 'suck', :puppies => 'rock'},
|
283
|
+
{:zombies => 'slow', :puppies => 'fast'}
|
284
|
+
]
|
285
|
+
end
|
286
|
+
|
287
|
+
it "respond with nested structures" do
|
288
|
+
mock_controller do
|
289
|
+
soap_action "gogogo",
|
290
|
+
:args => nil,
|
291
|
+
:return => {
|
292
|
+
:zoo => :string,
|
293
|
+
:boo => { :moo => :string, :doo => :string }
|
294
|
+
}
|
295
|
+
def gogogo
|
296
|
+
render :soap => {
|
297
|
+
:zoo => 'zoo',
|
298
|
+
:boo => { :moo => 'moo', :doo => 'doo' }
|
299
|
+
}
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
savon(:gogogo)[:gogogo_response].
|
304
|
+
should == {:zoo=>"zoo", :boo=>{:moo=>"moo", :doo=>"doo", :"@xsi:type"=>"tns:Boo"}}
|
305
|
+
end
|
306
|
+
|
307
|
+
it "respond with arrays" do
|
308
|
+
mock_controller do
|
309
|
+
soap_action "rumba",
|
310
|
+
:args => nil,
|
311
|
+
:return => [:integer]
|
312
|
+
def rumba
|
313
|
+
render :soap => [1, 2, 3]
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
savon(:rumba)[:rumba_response].should == {:value => ["1", "2", "3"]}
|
318
|
+
end
|
319
|
+
|
320
|
+
it "respond with complex structures inside arrays" do
|
321
|
+
mock_controller do
|
322
|
+
soap_action "rumba",
|
323
|
+
:args => nil,
|
324
|
+
:return => {
|
325
|
+
:rumbas => [{:zombies => :string, :puppies => :string}]
|
326
|
+
}
|
327
|
+
def rumba
|
328
|
+
render :soap =>
|
329
|
+
{:rumbas => [
|
330
|
+
{:zombies => "suck1", :puppies => "rock1" },
|
331
|
+
{:zombies => "suck2", :puppies => "rock2" }
|
332
|
+
]
|
333
|
+
}
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
savon(:rumba)[:rumba_response].should == {
|
338
|
+
:rumbas => [
|
339
|
+
{:zombies => "suck1",:puppies => "rock1", :"@xsi:type"=>"tns:Rumbas"},
|
340
|
+
{:zombies => "suck2", :puppies => "rock2", :"@xsi:type"=>"tns:Rumbas" }
|
341
|
+
]
|
342
|
+
}
|
343
|
+
end
|
344
|
+
|
345
|
+
it "respond with structs in structs in arrays" do
|
346
|
+
mock_controller do
|
347
|
+
soap_action "rumba",
|
348
|
+
:args => nil,
|
349
|
+
:return => [{:rumbas => {:zombies => :integer}}]
|
350
|
+
|
351
|
+
def rumba
|
352
|
+
render :soap => [{:rumbas => {:zombies => 100000}}, {:rumbas => {:zombies => 2}}]
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
savon(:rumba)[:rumba_response].should == {
|
357
|
+
:value => [
|
358
|
+
{
|
359
|
+
:rumbas => {
|
360
|
+
:zombies => "100000",
|
361
|
+
:"@xsi:type" => "tns:Rumbas"
|
362
|
+
},
|
363
|
+
:"@xsi:type" => "tns:Value"
|
364
|
+
},
|
365
|
+
{
|
366
|
+
:rumbas => {
|
367
|
+
:zombies => "2",
|
368
|
+
:"@xsi:type" => "tns:Rumbas"
|
369
|
+
},
|
370
|
+
:"@xsi:type"=>"tns:Value"
|
371
|
+
}
|
372
|
+
]
|
373
|
+
}
|
374
|
+
end
|
375
|
+
|
376
|
+
context "with arrays missing" do
|
377
|
+
it "respond with simple definition" do
|
378
|
+
mock_controller do
|
379
|
+
soap_action "rocknroll",
|
380
|
+
:args => nil, :return => { :my_value => [:integer] }
|
381
|
+
def rocknroll
|
382
|
+
render :soap => {}
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
savon(:rocknroll)[:rocknroll_response].should be_nil
|
387
|
+
end
|
388
|
+
|
389
|
+
it "respond with complext definition" do
|
390
|
+
mock_controller do
|
391
|
+
soap_action "rocknroll",
|
392
|
+
:args => nil, :return => { :my_value => [{ :value => :integer }] }
|
393
|
+
def rocknroll
|
394
|
+
render :soap => {}
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
savon(:rocknroll)[:rocknroll_response].should be_nil
|
399
|
+
end
|
400
|
+
|
401
|
+
it "respond with nested simple definition" do
|
402
|
+
mock_controller do
|
403
|
+
soap_action "rocknroll",
|
404
|
+
:args => nil, :return => { :my_value => { :my_array => [{ :value => :integer }] } }
|
405
|
+
def rocknroll
|
406
|
+
render :soap => {}
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
savon(:rocknroll)[:rocknroll_response][:my_value].
|
411
|
+
should == { :"@xsi:type" => "tns:MyValue" }
|
412
|
+
end
|
413
|
+
|
414
|
+
it "handles incomplete array response" do
|
415
|
+
mock_controller do
|
416
|
+
soap_action "rocknroll",
|
417
|
+
:args => nil, :return => { :my_value => [{ :value => :string }] }
|
418
|
+
def rocknroll
|
419
|
+
render :soap => { :my_value => [nil] }
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
expect{savon(:rocknroll)}.not_to raise_error
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
context "types" do
|
429
|
+
it "recognize boolean" do
|
430
|
+
mock_controller do
|
431
|
+
soap_action "true", :args => :boolean, :return => :nil
|
432
|
+
def true
|
433
|
+
params[:value].should == true
|
434
|
+
render :soap => nil
|
435
|
+
end
|
436
|
+
|
437
|
+
soap_action "false", :args => :boolean, :return => :nil
|
438
|
+
def false
|
439
|
+
params[:value].should == false
|
440
|
+
render :soap => nil
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
savon(:true, :value => "true")
|
445
|
+
savon(:true, :value => "1")
|
446
|
+
savon(:false, :value => "false")
|
447
|
+
savon(:false, :value => "0")
|
448
|
+
end
|
449
|
+
|
450
|
+
it "recognize dates" do
|
451
|
+
mock_controller do
|
452
|
+
soap_action "date", :args => :date, :return => :nil
|
453
|
+
def date
|
454
|
+
params[:value].should == Date.parse('2000-12-30') unless params[:value].blank?
|
455
|
+
render :soap => nil
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
savon(:date, :value => '2000-12-30')
|
460
|
+
lambda { savon(:date) }.should_not raise_exception
|
461
|
+
end
|
462
|
+
|
463
|
+
it "recognize base64Binary" do
|
464
|
+
mock_controller do
|
465
|
+
soap_action "base64", :args => :base64Binary, :return => :nil
|
466
|
+
def base64
|
467
|
+
params[:value].should == 'test' unless params[:value].blank?
|
468
|
+
render :soap => nil
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
savon(:base64, :value => Base64.encode64('test'))
|
473
|
+
lambda { savon(:base64) }.should_not raise_exception
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
context "errors" do
|
478
|
+
it "raise for incorrect requests" do
|
479
|
+
mock_controller do
|
480
|
+
soap_action "duty",
|
481
|
+
:args => {:bad => {:a => :string, :b => :string}, :good => {:a => :string, :b => :string}},
|
482
|
+
:return => nil
|
483
|
+
def duty
|
484
|
+
render :soap => nil
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
lambda {
|
489
|
+
savon(:duty, :bad => 42, :good => nil)
|
490
|
+
}.should raise_exception(Savon::SOAPFault)
|
491
|
+
end
|
492
|
+
|
493
|
+
it "raise for date in incorrect format" do
|
494
|
+
mock_controller do
|
495
|
+
soap_action "date", :args => :date, :return => :nil
|
496
|
+
def date
|
497
|
+
render :soap => nil
|
498
|
+
end
|
499
|
+
end
|
500
|
+
lambda {
|
501
|
+
savon(:date, :value => 'incorrect format')
|
502
|
+
}.should raise_exception(Savon::SOAPFault)
|
503
|
+
end
|
504
|
+
|
505
|
+
it "raise to report SOAP errors", :fails =>true do
|
506
|
+
mock_controller do
|
507
|
+
soap_action "error", :args => { :need_error => :boolean }, :return => nil
|
508
|
+
def error
|
509
|
+
raise self.class.const_get(:SOAPError), "you wanted one" if params[:need_error]
|
510
|
+
render :soap => nil
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
lambda { savon(:error, :need_error => false) }.should_not raise_exception
|
515
|
+
lambda { savon(:error, :need_error => true) }.should raise_exception(Savon::SOAPFault)
|
516
|
+
end
|
517
|
+
|
518
|
+
it "raise for manual throws" do
|
519
|
+
mock_controller do
|
520
|
+
soap_action "error", :args => nil, :return => nil
|
521
|
+
def error
|
522
|
+
render_soap_error "a message"
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
lambda { savon(:error) }.should raise_exception(Savon::SOAPFault)
|
527
|
+
end
|
528
|
+
|
529
|
+
it "raise when response structure mismatches" do
|
530
|
+
mock_controller do
|
531
|
+
soap_action 'bad', :args => :integer, :return => {
|
532
|
+
:basic => :string,
|
533
|
+
:stallions => {
|
534
|
+
:stallion => [
|
535
|
+
:name => :string,
|
536
|
+
:wyldness => :integer,
|
537
|
+
]
|
538
|
+
},
|
539
|
+
}
|
540
|
+
def bad
|
541
|
+
render :soap => {
|
542
|
+
:basic => 'hi',
|
543
|
+
:stallions => [{:name => 'ted', :wyldness => 11}]
|
544
|
+
}
|
545
|
+
end
|
546
|
+
|
547
|
+
soap_action 'bad2', :args => :integer, :return => {
|
548
|
+
:basic => :string,
|
549
|
+
:telephone_booths => [:string]
|
550
|
+
}
|
551
|
+
def bad2
|
552
|
+
render :soap => {
|
553
|
+
:basic => 'hihi',
|
554
|
+
:telephone_booths => 'oops'
|
555
|
+
}
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
lambda { savon(:bad) }.should raise_exception(
|
560
|
+
WashOut::ProgrammerError,
|
561
|
+
/SOAP response .*wyldness.*Array.*Hash.*stallion/
|
562
|
+
)
|
563
|
+
|
564
|
+
lambda { savon(:bad2) }.should raise_exception(
|
565
|
+
WashOut::ProgrammerError,
|
566
|
+
/SOAP response .*oops.*String.*telephone_booths.*Array/
|
567
|
+
)
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
context "deprecates" do
|
572
|
+
it "old syntax" do
|
573
|
+
# save rspec context check
|
574
|
+
raise_runtime_exception = raise_exception(RuntimeError)
|
575
|
+
|
576
|
+
mock_controller do
|
577
|
+
lambda {
|
578
|
+
soap_action "rumba",
|
579
|
+
:args => :integer,
|
580
|
+
:return => []
|
581
|
+
}.should raise_runtime_exception
|
582
|
+
def rumba
|
583
|
+
render :soap => nil
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
it "allows arbitrary action names" do
|
590
|
+
name = 'AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything'
|
591
|
+
|
592
|
+
mock_controller do
|
593
|
+
soap_action name, :args => nil, :return => :integer, :to => :answer
|
594
|
+
def answer
|
595
|
+
render :soap => "forty two"
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
savon(name.underscore.to_sym)["#{name.underscore}_response".to_sym][:value].
|
600
|
+
should == "forty two"
|
601
|
+
end
|
602
|
+
|
603
|
+
it "respects :response_tag option" do
|
604
|
+
mock_controller do
|
605
|
+
soap_action "specific", :response_tag => "test", :return => :string
|
606
|
+
def specific
|
607
|
+
render :soap => "test"
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
savon(:specific).should == {:test => {:value=>"test"}}
|
612
|
+
end
|
613
|
+
|
614
|
+
it "handles snakecase option properly" do
|
615
|
+
mock_controller(snakecase_input: false, camelize_wsdl: false) do
|
616
|
+
soap_action "rocknroll", :args => {:ZOMG => :string}, :return => nil
|
617
|
+
def rocknroll
|
618
|
+
params["ZOMG"].should == "yam!"
|
619
|
+
render :soap => nil
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
savon(:rocknroll, "ZOMG" => 'yam!')
|
624
|
+
end
|
625
|
+
|
626
|
+
end
|
627
|
+
|
628
|
+
describe "WS Security" do
|
629
|
+
|
630
|
+
it "appends username_token to params" do
|
631
|
+
mock_controller(wsse_username: "gorilla", wsse_password: "secret") do
|
632
|
+
soap_action "checkToken", :args => :integer, :return => nil, :to => 'check_token'
|
633
|
+
def check_token
|
634
|
+
request.env['WSSE_TOKEN']['username'].should == "gorilla"
|
635
|
+
request.env['WSSE_TOKEN']['password'].should == "secret"
|
636
|
+
render :soap => nil
|
637
|
+
end
|
638
|
+
end
|
639
|
+
|
640
|
+
savon(:check_token, 42) do
|
641
|
+
wsse_auth "gorilla", "secret"
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
it "handles PasswordText auth" do
|
646
|
+
mock_controller(wsse_username: "gorilla", wsse_password: "secret") do
|
647
|
+
soap_action "checkAuth", :args => :integer, :return => :boolean, :to => 'check_auth'
|
648
|
+
def check_auth
|
649
|
+
render :soap => (params[:value] == 42)
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
# correct auth
|
654
|
+
lambda { savon(:check_auth, 42){ wsse_auth "gorilla", "secret" } }.
|
655
|
+
should_not raise_exception
|
656
|
+
|
657
|
+
# wrong user
|
658
|
+
lambda { savon(:check_auth, 42){ wsse_auth "chimpanzee", "secret" } }.
|
659
|
+
should raise_exception(Savon::SOAPFault)
|
660
|
+
|
661
|
+
# wrong pass
|
662
|
+
lambda { savon(:check_auth, 42){ wsse_auth "gorilla", "nicetry" } }.
|
663
|
+
should raise_exception(Savon::SOAPFault)
|
664
|
+
|
665
|
+
# no auth
|
666
|
+
lambda { savon(:check_auth, 42) }.
|
667
|
+
should raise_exception(Savon::SOAPFault)
|
668
|
+
end
|
669
|
+
|
670
|
+
it "handles PasswordDigest auth" do
|
671
|
+
mock_controller(wsse_username: "gorilla", wsse_password: "secret") do
|
672
|
+
soap_action "checkAuth", :args => :integer, :return => :boolean, :to => 'check_auth'
|
673
|
+
def check_auth
|
674
|
+
render :soap => (params[:value] == 42)
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
# correct auth
|
679
|
+
lambda { savon(:check_auth, 42){ wsse_auth "gorilla", "secret", :digest } }.
|
680
|
+
should_not raise_exception
|
681
|
+
|
682
|
+
# wrong user
|
683
|
+
lambda { savon(:check_auth, 42){ wsse_auth "chimpanzee", "secret", :digest } }.
|
684
|
+
should raise_exception(Savon::SOAPFault)
|
685
|
+
|
686
|
+
# wrong pass
|
687
|
+
lambda { savon(:check_auth, 42){ wsse_auth "gorilla", "nicetry", :digest } }.
|
688
|
+
should raise_exception(Savon::SOAPFault)
|
689
|
+
|
690
|
+
# no auth
|
691
|
+
lambda { savon(:check_auth, 42) }.
|
692
|
+
should raise_exception(Savon::SOAPFault)
|
693
|
+
end
|
694
|
+
|
695
|
+
end
|
696
|
+
|
697
|
+
end
|