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.
Files changed (51) hide show
  1. checksums.yaml +8 -8
  2. data/.travis.yml +6 -0
  3. data/Gemfile +11 -0
  4. data/README.rdoc +2 -1
  5. data/Rakefile +3 -1
  6. data/app/helpers/washout_builder_helper.rb +7 -169
  7. data/app/views/wash_with_html/doc.builder +11 -11
  8. data/lib/washout_builder.rb +24 -5
  9. data/lib/washout_builder/dispatcher.rb +6 -7
  10. data/lib/washout_builder/document/complex_type.rb +102 -0
  11. data/lib/washout_builder/document/generator.rb +114 -0
  12. data/lib/washout_builder/document/virtus_model.rb +45 -0
  13. data/lib/washout_builder/type.rb +2 -1
  14. data/lib/washout_builder/version.rb +1 -1
  15. data/spec/app/controllers/washout_builder_controller_spec.rb +8 -0
  16. data/spec/app/helpers/washout_builder_helper_spec.rb +8 -0
  17. data/spec/app/integration/washout_builder_all_services_spec.rb +7 -0
  18. data/spec/app/integration/washout_builder_service_spec.rb +7 -0
  19. data/spec/dummy/Rakefile +7 -0
  20. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  21. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  22. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  23. data/spec/dummy/config.ru +4 -0
  24. data/spec/dummy/config/application.rb +51 -0
  25. data/spec/dummy/config/boot.rb +10 -0
  26. data/spec/dummy/config/environment.rb +5 -0
  27. data/spec/dummy/config/environments/development.rb +23 -0
  28. data/spec/dummy/config/environments/test.rb +29 -0
  29. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  30. data/spec/dummy/config/initializers/inflections.rb +10 -0
  31. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  32. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  33. data/spec/dummy/config/initializers/session_store.rb +8 -0
  34. data/spec/dummy/config/locales/en.yml +5 -0
  35. data/spec/dummy/config/routes.rb +58 -0
  36. data/spec/dummy/public/404.html +26 -0
  37. data/spec/dummy/public/422.html +26 -0
  38. data/spec/dummy/public/500.html +26 -0
  39. data/spec/dummy/public/favicon.ico +0 -0
  40. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  41. data/spec/dummy/script/rails +6 -0
  42. data/spec/lib/washout_builder/dispatcher_spec.rb +51 -0
  43. data/spec/lib/washout_builder/document/complex_type_spec.rb +0 -0
  44. data/spec/lib/washout_builder/document/generator_spec.rb +0 -0
  45. data/spec/lib/washout_builder/document/virtus_model_spec.rb +0 -0
  46. data/spec/lib/washout_builder/engine_spec.rb +6 -0
  47. data/spec/lib/washout_builder/soap_spec.rb +15 -0
  48. data/spec/lib/washout_builder/type_spec.rb +21 -0
  49. data/spec/lib/washout_builder_spec.rb +697 -0
  50. data/spec/spec_helper.rb +2 -0
  51. 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
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe WashoutBuilder::Engine do
5
+
6
+ end
@@ -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