wash-out 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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +35 -0
  5. data/Appraisals +25 -0
  6. data/CHANGELOG.md +102 -0
  7. data/Gemfile +16 -0
  8. data/Guardfile +12 -0
  9. data/LICENSE +22 -0
  10. data/README.md +246 -0
  11. data/Rakefile +13 -0
  12. data/app/helpers/wash_out_helper.rb +106 -0
  13. data/app/views/wash_out/document/error.builder +9 -0
  14. data/app/views/wash_out/document/response.builder +10 -0
  15. data/app/views/wash_out/document/wsdl.builder +68 -0
  16. data/app/views/wash_out/rpc/error.builder +10 -0
  17. data/app/views/wash_out/rpc/response.builder +11 -0
  18. data/app/views/wash_out/rpc/wsdl.builder +68 -0
  19. data/gemfiles/rails_3.1.3.gemfile +20 -0
  20. data/gemfiles/rails_3.2.12.gemfile +20 -0
  21. data/gemfiles/rails_4.0.0.gemfile +19 -0
  22. data/gemfiles/rails_4.1.0.gemfile +19 -0
  23. data/gemfiles/rails_4.2.0.gemfile +19 -0
  24. data/gemfiles/rails_5.0.0.beta2.gemfile +19 -0
  25. data/init.rb +1 -0
  26. data/lib/wash_out.rb +53 -0
  27. data/lib/wash_out/configurable.rb +41 -0
  28. data/lib/wash_out/dispatcher.rb +218 -0
  29. data/lib/wash_out/engine.rb +12 -0
  30. data/lib/wash_out/middleware.rb +41 -0
  31. data/lib/wash_out/model.rb +29 -0
  32. data/lib/wash_out/param.rb +200 -0
  33. data/lib/wash_out/router.rb +95 -0
  34. data/lib/wash_out/soap.rb +48 -0
  35. data/lib/wash_out/soap_config.rb +93 -0
  36. data/lib/wash_out/type.rb +29 -0
  37. data/lib/wash_out/version.rb +3 -0
  38. data/lib/wash_out/wsse.rb +101 -0
  39. data/spec/dummy/Rakefile +7 -0
  40. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  41. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  42. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  43. data/spec/dummy/config.ru +4 -0
  44. data/spec/dummy/config/application.rb +51 -0
  45. data/spec/dummy/config/boot.rb +10 -0
  46. data/spec/dummy/config/environment.rb +5 -0
  47. data/spec/dummy/config/environments/development.rb +23 -0
  48. data/spec/dummy/config/environments/test.rb +30 -0
  49. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/spec/dummy/config/initializers/inflections.rb +10 -0
  51. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  52. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  53. data/spec/dummy/config/initializers/session_store.rb +8 -0
  54. data/spec/dummy/config/locales/en.yml +5 -0
  55. data/spec/dummy/config/routes.rb +58 -0
  56. data/spec/dummy/public/404.html +26 -0
  57. data/spec/dummy/public/422.html +26 -0
  58. data/spec/dummy/public/500.html +26 -0
  59. data/spec/dummy/public/favicon.ico +0 -0
  60. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  61. data/spec/dummy/script/rails +6 -0
  62. data/spec/lib/wash_out/dispatcher_spec.rb +99 -0
  63. data/spec/lib/wash_out/middleware_spec.rb +33 -0
  64. data/spec/lib/wash_out/param_spec.rb +94 -0
  65. data/spec/lib/wash_out/router_spec.rb +22 -0
  66. data/spec/lib/wash_out/type_spec.rb +41 -0
  67. data/spec/lib/wash_out_spec.rb +754 -0
  68. data/spec/spec_helper.rb +82 -0
  69. data/wash_out.gemspec +21 -0
  70. metadata +128 -0
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'wash_out/router'
3
+
4
+ describe WashOut::Router do
5
+ it 'returns a 200 with empty soap action' do
6
+
7
+ mock_controller do
8
+ # nothing
9
+ end
10
+
11
+ env = {}
12
+ env['REQUEST_METHOD'] = 'GET'
13
+ env['rack.input'] = double 'basic-rack-input', {:string => ''}
14
+ result = WashOut::Router.new('Api').call env
15
+
16
+ expect(result[0]).to eq(200)
17
+ #expect(result[1]['Content-Type']).to eq('text/xml')
18
+
19
+ msg = result[2][0]
20
+ expect(msg).to eq('OK')
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ #encoding:utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe WashOut::Type do
6
+
7
+ it "defines custom type" do
8
+
9
+ class Abraka1 < WashOut::Type
10
+ map :test => :string
11
+ end
12
+
13
+ class Abraka2 < WashOut::Type
14
+ type_name 'test'
15
+ map :foo => Abraka1
16
+ end
17
+
18
+ expect(Abraka1.wash_out_param_name).to eq 'abraka1'
19
+ expect(Abraka1.wash_out_param_map).to eq({:test => :string})
20
+
21
+ expect(Abraka2.wash_out_param_name).to eq 'test'
22
+ expect(Abraka2.wash_out_param_map).to eq({:foo => Abraka1})
23
+ end
24
+
25
+ it "allows arrays inside custom types" do
26
+ class Abraka1 < WashOut::Type
27
+ map :test => :string
28
+ end
29
+ class Abraka2 < WashOut::Type
30
+ type_name 'test'
31
+ map :foo => [:bar => Abraka1]
32
+ end
33
+
34
+ expect(Abraka1.wash_out_param_name).to eq 'abraka1'
35
+ expect(Abraka1.wash_out_param_map).to eq({:test => :string})
36
+
37
+ expect(Abraka2.wash_out_param_name).to eq 'test'
38
+ expect(Abraka2.wash_out_param_map).to eq({:foo => [:bar => Abraka1]})
39
+ end
40
+
41
+ end
@@ -0,0 +1,754 @@
1
+ #encoding:utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe WashOut do
6
+
7
+ let :nori do
8
+ Nori.new(
9
+ :strip_namespaces => true,
10
+ :advanced_typecasting => true,
11
+ :convert_tags_to => lambda {|x| x.snakecase.to_sym}
12
+ )
13
+ end
14
+
15
+ def savon(method, message={}, &block)
16
+ message = {:value => message} unless message.is_a?(Hash)
17
+
18
+ savon = Savon::Client.new(:log => false, :wsdl => 'http://app/api/wsdl', &block)
19
+ savon.call(method, :message => message).to_hash
20
+ end
21
+
22
+ def savon!(method, message={}, &block)
23
+ message = {:value => message} unless message.is_a?(Hash)
24
+
25
+ savon = Savon::Client.new(:log => true, :wsdl => 'http://app/api/wsdl', &block)
26
+ savon.call(method, :message => message).to_hash
27
+ end
28
+
29
+ describe "Module" do
30
+ it "includes" do
31
+ expect {
32
+ mock_controller do
33
+ # nothing
34
+ end
35
+ }.not_to raise_exception
36
+ end
37
+
38
+ it "allows definition of a simple action" do
39
+ expect {
40
+ mock_controller do
41
+ soap_action "answer", :args => nil, :return => :integer
42
+ end
43
+ }.not_to raise_exception
44
+ end
45
+ end
46
+
47
+ describe "WSDL" do
48
+ let :wsdl do
49
+ mock_controller do
50
+ soap_action :result, :args => nil, :return => :int
51
+
52
+ soap_action "getArea", :args => {
53
+ :circle => [{
54
+ :center => { :x => [:integer], :y => :integer },
55
+ :radius => :double
56
+ }]},
57
+ :return => { :area => :double }
58
+ soap_action "rocky", :args => { :circle1 => { :x => :integer } },
59
+ :return => { :circle2 => { :y => :integer } }
60
+ end
61
+
62
+ HTTPI.get("http://app/api/wsdl").body
63
+ end
64
+
65
+ let :xml do
66
+ nori.parse wsdl
67
+ end
68
+
69
+ it "lists operations" do
70
+ operations = xml[:definitions][:binding][:operation]
71
+ expect(operations).to be_a_kind_of(Array)
72
+
73
+ expect(operations.map{|e| e[:'@name']}.sort).to eq ['Result', 'getArea', 'rocky'].sort
74
+ end
75
+
76
+ it "defines complex types" do
77
+ expect(wsdl.include?('<xsd:complexType name="Circle1">')).to be true
78
+ end
79
+
80
+ it "defines arrays" do
81
+ x = xml[:definitions][:types][:schema][:complex_type].
82
+ find{|x| x[:'@name'] == 'Center'}[:sequence][:element].
83
+ find{|x| x[:'@name'] == 'X'}
84
+
85
+ expect(x[:'@min_occurs']).to eq "0"
86
+ expect(x[:'@max_occurs']).to eq "unbounded"
87
+ end
88
+ end
89
+
90
+ describe "Dispatcher" do
91
+
92
+ context "simple actions" do
93
+ it "accepts requests with no HTTP header" do
94
+ mock_controller do
95
+ soap_action "answer", :args => nil, :return => :int
96
+ def answer
97
+ render :soap => "42"
98
+ end
99
+ end
100
+
101
+ request = <<-XML
102
+ <?xml version="1.0" encoding="UTF-8"?>
103
+ <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/">
104
+ <env:Body>
105
+ <tns:answer>
106
+ <value>42</value>
107
+ </tns:answer>
108
+ </env:Body>
109
+ </env:Envelope>
110
+ XML
111
+
112
+ expect(HTTPI.post("http://app/api/action", request).body).to eq <<-XML
113
+ <?xml version="1.0" encoding="UTF-8"?>
114
+ <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
+ <soap:Body>
116
+ <tns:answerResponse>
117
+ <Value xsi:type="xsd:int">42</Value>
118
+ </tns:answerResponse>
119
+ </soap:Body>
120
+ </soap:Envelope>
121
+ XML
122
+ end
123
+
124
+ it "accept no parameters" do
125
+ mock_controller do
126
+ soap_action "answer", :args => nil, :return => :int
127
+ def answer
128
+ render :soap => "42"
129
+ end
130
+ end
131
+
132
+ expect(savon(:answer)[:answer_response][:value]).
133
+ to eq "42"
134
+ end
135
+
136
+ it "accept insufficient parameters" do
137
+ mock_controller do
138
+ soap_action "answer", :args => {:a => :integer}, :return => :integer
139
+ def answer
140
+ render :soap => "42"
141
+ end
142
+ end
143
+
144
+ expect(savon(:answer)[:answer_response][:value]).
145
+ to eq "42"
146
+ end
147
+
148
+ it "accept empty parameter" do
149
+ mock_controller do
150
+ soap_action "answer", :args => {:a => :string}, :return => {:a => :string}
151
+ def answer
152
+ render :soap => {:a => params[:a]}
153
+ end
154
+ end
155
+ expect(savon(:answer, :a => '')[:answer_response][:a]).
156
+ to eq({:"@xsi:type"=>"xsd:string"})
157
+ end
158
+
159
+ it "accept one parameter" do
160
+ mock_controller do
161
+ soap_action "checkAnswer", :args => :integer, :return => :boolean, :to => 'check_answer'
162
+ def check_answer
163
+ render :soap => (params[:value] == 42)
164
+ end
165
+ end
166
+
167
+ expect(savon(:check_answer, 42)[:check_answer_response][:value]).to be true
168
+ expect(savon(:check_answer, 13)[:check_answer_response][:value]).to be false
169
+ end
170
+
171
+ it "accept two parameters" do
172
+ mock_controller do
173
+ soap_action "funky", :args => { :a => :integer, :b => :string }, :return => :string
174
+ def funky
175
+ render :soap => ((params[:a] * 10).to_s + params[:b])
176
+ end
177
+ end
178
+
179
+ expect(savon(:funky, :a => 42, :b => 'k')[:funky_response][:value]).to eq '420k'
180
+ end
181
+ end
182
+
183
+ context "complex actions" do
184
+ it "accept nested structures" do
185
+ mock_controller do
186
+ soap_action "getArea", :args => { :circle => { :center => { :x => :integer,
187
+ :y => :integer },
188
+ :radius => :double } },
189
+ :return => { :area => :double,
190
+ :distance_from_o => :double },
191
+ :to => :get_area
192
+ def get_area
193
+ circle = params[:circle]
194
+ render :soap => { :area => Math::PI * circle[:radius] ** 2,
195
+ :distance_from_o => Math.sqrt(circle[:center][:x] ** 2 + circle[:center][:y] ** 2) }
196
+ end
197
+ end
198
+
199
+ message = { :circle => { :center => { :x => 3, :y => 4 },
200
+ :radius => 5 } }
201
+
202
+ expect(savon(:get_area, message)[:get_area_response]).
203
+ to eq ({ :area => (Math::PI * 25).to_s, :distance_from_o => (5.0).to_s })
204
+ end
205
+
206
+ it "accept arrays" do
207
+ mock_controller do
208
+ soap_action "rumba",
209
+ :args => {
210
+ :rumbas => [:integer]
211
+ },
212
+ :return => nil
213
+ def rumba
214
+ expect(params).to eq({"rumbas" => [1, 2, 3]})
215
+ render :soap => nil
216
+ end
217
+ end
218
+
219
+ savon(:rumba, :rumbas => [1, 2, 3])
220
+ end
221
+
222
+ it "accept empty arrays" do
223
+ mock_controller do
224
+ soap_action "rumba",
225
+ :args => {
226
+ :my_array => [:integer]
227
+ },
228
+ :return => nil
229
+ def rumba
230
+ expect(params).to eq({})
231
+ render :soap => nil
232
+ end
233
+ end
234
+ savon(:rumba, :empty => [])
235
+ end
236
+
237
+ it "accept nested empty arrays" do
238
+ mock_controller do
239
+ soap_action "rumba",
240
+ :args => {
241
+ :nested => {:my_array => [:integer] }
242
+ },
243
+ :return => nil
244
+ def rumba
245
+ expect(params).to eq({"nested" => {}})
246
+ render :soap => nil
247
+ end
248
+ end
249
+ savon(:rumba, :nested => {:my_array => []})
250
+ end
251
+
252
+ it "accept nested structures inside arrays" do
253
+ mock_controller do
254
+ soap_action "rumba",
255
+ :args => {
256
+ :rumbas => [ {
257
+ :zombies => :string,
258
+ :puppies => :string
259
+ } ]
260
+ },
261
+ :return => nil
262
+ def rumba
263
+ expect(params).to eq({
264
+ "rumbas" => [
265
+ {"zombies" => 'suck', "puppies" => 'rock'},
266
+ {"zombies" => 'slow', "puppies" => 'fast'}
267
+ ]
268
+ })
269
+ render :soap => nil
270
+ end
271
+ end
272
+
273
+ savon :rumba, :rumbas => [
274
+ {:zombies => 'suck', :puppies => 'rock'},
275
+ {:zombies => 'slow', :puppies => 'fast'}
276
+ ]
277
+ end
278
+
279
+ it "respond with nested structures" do
280
+ mock_controller do
281
+ soap_action "gogogo",
282
+ :args => nil,
283
+ :return => {
284
+ :zoo => :string,
285
+ :boo => { :moo => :string, :doo => :string }
286
+ }
287
+ def gogogo
288
+ render :soap => {
289
+ :zoo => 'zoo',
290
+ :boo => { :moo => 'moo', :doo => 'doo' }
291
+ }
292
+ end
293
+ end
294
+
295
+ expect(savon(:gogogo)[:gogogo_response]).
296
+ to eq({
297
+ :zoo=>"zoo",
298
+ :boo=>{
299
+ :moo=>"moo",
300
+ :doo=>"doo",
301
+ :"@xsi:type"=>"tns:Boo"
302
+ }
303
+ })
304
+ end
305
+
306
+ it "respond with arrays" do
307
+ mock_controller do
308
+ soap_action "rumba",
309
+ :args => nil,
310
+ :return => [:integer]
311
+ def rumba
312
+ render :soap => [1, 2, 3]
313
+ end
314
+ end
315
+
316
+ expect(savon(:rumba)[:rumba_response]).to eq({
317
+ :value => ["1", "2", "3"]
318
+ })
319
+ end
320
+
321
+ it "respond with complex structures inside arrays" do
322
+ mock_controller do
323
+ soap_action "rumba",
324
+ :args => nil,
325
+ :return => {
326
+ :rumbas => [{:@level => :integer, :zombies => :string, :puppies => :string}]
327
+ }
328
+ def rumba
329
+ render :soap =>
330
+ {:rumbas => [
331
+ {:@level => 80, :zombies => "suck1", :puppies => "rock1" },
332
+ {:zombies => "suck2", :puppies => "rock2" }
333
+ ]
334
+ }
335
+ end
336
+ end
337
+
338
+ expect(savon(:rumba)[:rumba_response]).to eq({
339
+ :rumbas => [
340
+ {:zombies => "suck1",:puppies => "rock1", :"@xsi:type"=>"tns:Rumbas", :@level => "80"},
341
+ {:zombies => "suck2", :puppies => "rock2", :"@xsi:type"=>"tns:Rumbas" }
342
+ ]
343
+ })
344
+ end
345
+
346
+ it "respond with structs in structs in arrays" do
347
+ mock_controller do
348
+ soap_action "rumba",
349
+ :args => nil,
350
+ :return => [{:rumbas => {:@level => :integer, :zombies => :integer}}]
351
+
352
+ def rumba
353
+ render :soap => [{:rumbas => {:@level => 80, :zombies => 100000}}, {:rumbas => {:@level => 90, :zombies => 2}}]
354
+ end
355
+ end
356
+
357
+ expect(savon(:rumba)[:rumba_response]).to eq({
358
+ :value => [
359
+ {
360
+ :rumbas => {
361
+ :zombies => "100000",
362
+ :"@xsi:type" => "tns:Rumbas",
363
+ :"@level" => "80"
364
+ },
365
+ :"@xsi:type" => "tns:Value"
366
+ },
367
+ {
368
+ :rumbas => {
369
+ :zombies => "2",
370
+ :"@xsi:type" => "tns:Rumbas",
371
+ :@level => "90",
372
+ },
373
+ :"@xsi:type"=>"tns:Value"
374
+ }
375
+ ]
376
+ })
377
+ end
378
+
379
+ context "with arrays missing" do
380
+ it "respond with simple definition" do
381
+ mock_controller do
382
+ soap_action "rocknroll",
383
+ :args => nil, :return => { :my_value => [:integer] }
384
+ def rocknroll
385
+ render :soap => {}
386
+ end
387
+ end
388
+
389
+ expect(savon(:rocknroll)[:rocknroll_response]).to be nil
390
+ end
391
+
392
+ it "respond with complext definition" do
393
+ mock_controller do
394
+ soap_action "rocknroll",
395
+ :args => nil, :return => { :my_value => [{ :value => :integer }] }
396
+ def rocknroll
397
+ render :soap => {}
398
+ end
399
+ end
400
+
401
+ expect(savon(:rocknroll)[:rocknroll_response]).to be nil
402
+ end
403
+
404
+ it "respond with nested simple definition" do
405
+ mock_controller do
406
+ soap_action "rocknroll",
407
+ :args => nil, :return => { :my_value => { :my_array => [{ :value => :integer }] } }
408
+ def rocknroll
409
+ render :soap => {}
410
+ end
411
+ end
412
+
413
+ expect(savon(:rocknroll)[:rocknroll_response][:my_value]).
414
+ to eq({
415
+ :"@xsi:type" => "tns:MyValue"
416
+ })
417
+ end
418
+
419
+ it "handles incomplete array response" do
420
+ mock_controller do
421
+ soap_action "rocknroll",
422
+ :args => nil, :return => { :my_value => [{ :value => :string }] }
423
+ def rocknroll
424
+ render :soap => { :my_value => [nil] }
425
+ end
426
+ end
427
+
428
+ expect{savon(:rocknroll)}.not_to raise_error
429
+ end
430
+ end
431
+ end
432
+
433
+ context "types" do
434
+ it "recognize boolean" do
435
+ mock_controller do
436
+ soap_action "true", :args => :boolean, :return => :nil
437
+ def true
438
+ expect(params[:value]).to be true
439
+ render :soap => nil
440
+ end
441
+
442
+ soap_action "false", :args => :boolean, :return => :nil
443
+ def false
444
+ expect(params[:value]).to be false
445
+ render :soap => nil
446
+ end
447
+ end
448
+
449
+ savon(:true, :value => "true")
450
+ savon(:true, :value => "1")
451
+ savon(:false, :value => "false")
452
+ savon(:false, :value => "0")
453
+ end
454
+
455
+ it "recognize dates" do
456
+ mock_controller do
457
+ soap_action "date", :args => :date, :return => :nil
458
+ def date
459
+ expect(params[:value]).to eq Date.parse('2000-12-30') unless params[:value].blank?
460
+ render :soap => nil
461
+ end
462
+ end
463
+
464
+ savon(:date, :value => '2000-12-30')
465
+ expect { savon(:date) }.not_to raise_exception
466
+ end
467
+
468
+ it "recognize base64Binary" do
469
+ mock_controller do
470
+ soap_action "base64", :args => :base64Binary, :return => :nil
471
+ def base64
472
+ expect(params[:value]).to eq('test') unless params[:value].blank?
473
+ render :soap => nil
474
+ end
475
+ end
476
+
477
+ savon(:base64, :value => Base64.encode64('test'))
478
+ expect { savon(:base64) }.not_to raise_exception
479
+ end
480
+ end
481
+
482
+ context "errors" do
483
+ it "raise for incorrect requests" do
484
+ mock_controller do
485
+ soap_action "duty",
486
+ :args => {:bad => {:a => :string, :b => :string}, :good => {:a => :string, :b => :string}},
487
+ :return => nil
488
+ def duty
489
+ render :soap => nil
490
+ end
491
+ end
492
+
493
+ expect {
494
+ savon(:duty, :bad => 42, :good => nil)
495
+ }.to raise_exception(Savon::SOAPFault)
496
+ end
497
+
498
+ it "raise for date in incorrect format" do
499
+ mock_controller do
500
+ soap_action "date", :args => :date, :return => :nil
501
+ def date
502
+ render :soap => nil
503
+ end
504
+ end
505
+ expect {
506
+ savon(:date, :value => 'incorrect format')
507
+ }.to raise_exception(Savon::SOAPFault)
508
+ end
509
+
510
+ it "raise to report SOAP errors" do
511
+ mock_controller do
512
+ soap_action "error", :args => { :need_error => :boolean }, :return => nil
513
+ def error
514
+ raise self.class.const_get(:SOAPError), "you wanted one" if params[:need_error]
515
+ render :soap => nil
516
+ end
517
+ end
518
+
519
+ expect { savon(:error, :need_error => false) }.not_to raise_exception
520
+ expect { savon(:error, :need_error => true) }.to raise_exception(Savon::SOAPFault)
521
+ end
522
+
523
+ it "misses basic exceptions" do
524
+ mock_controller do
525
+ soap_action "error", :args => { :need_error => :boolean }, :return => nil
526
+ def error
527
+ raise self.class.const_get(:Exception), "you wanted one" if params[:need_error]
528
+ render :soap => nil
529
+ end
530
+ end
531
+
532
+ expect { savon(:error, :need_error => false) }.not_to raise_exception
533
+ expect { savon(:error, :need_error => true) }.to raise_exception(Exception)
534
+ end
535
+
536
+ it "raise for manual throws" do
537
+ mock_controller do
538
+ soap_action "error", :args => nil, :return => nil
539
+ def error
540
+ render_soap_error "a message"
541
+ end
542
+ end
543
+
544
+ expect { savon(:error) }.to raise_exception(Savon::SOAPFault)
545
+ end
546
+
547
+ it "raise when response structure mismatches" do
548
+ mock_controller do
549
+ soap_action 'bad', :args => :integer, :return => {
550
+ :basic => :string,
551
+ :stallions => {
552
+ :stallion => [
553
+ :name => :string,
554
+ :wyldness => :integer,
555
+ ]
556
+ },
557
+ }
558
+ def bad
559
+ render :soap => {
560
+ :basic => 'hi',
561
+ :stallions => [{:name => 'ted', :wyldness => 11}]
562
+ }
563
+ end
564
+
565
+ soap_action 'bad2', :args => :integer, :return => {
566
+ :basic => :string,
567
+ :telephone_booths => [:string]
568
+ }
569
+ def bad2
570
+ render :soap => {
571
+ :basic => 'hihi',
572
+ :telephone_booths => 'oops'
573
+ }
574
+ end
575
+ end
576
+
577
+ expect { savon(:bad) }.to raise_exception(
578
+ WashOut::Dispatcher::ProgrammerError,
579
+ /SOAP response .*wyldness.*Array.*Hash.*stallion/
580
+ )
581
+
582
+ expect { savon(:bad2) }.to raise_exception(
583
+ WashOut::Dispatcher::ProgrammerError,
584
+ /SOAP response .*oops.*String.*telephone_booths.*Array/
585
+ )
586
+ end
587
+ end
588
+
589
+ context "deprecates" do
590
+ # This test uses deprecated rspec expectations
591
+ # and it's not clear how to rewrite it.
592
+ xit "old syntax" do
593
+ # save rspec context check
594
+ raise_runtime_exception = raise_exception(RuntimeError)
595
+
596
+ mock_controller do
597
+
598
+ lambda {
599
+ soap_action "rumba",
600
+ :args => :integer,
601
+ :return => []
602
+ }.should raise_runtime_exception
603
+ def rumba
604
+ render :soap => nil
605
+ end
606
+ end
607
+ end
608
+ end
609
+
610
+ it "allows arbitrary action names" do
611
+ name = 'AnswerToTheUltimateQuestionOfLifeTheUniverseAndEverything'
612
+
613
+ mock_controller do
614
+ soap_action name, :args => nil, :return => :integer, :to => :answer
615
+ def answer
616
+ render :soap => "forty two"
617
+ end
618
+ end
619
+
620
+ expect(savon(name.underscore.to_sym)["#{name.underscore}_response".to_sym][:value]).to eq "forty two"
621
+ end
622
+
623
+ it "respects :response_tag option" do
624
+ mock_controller do
625
+ soap_action "specific", :response_tag => "test", :return => :string
626
+ def specific
627
+ render :soap => "test"
628
+ end
629
+ end
630
+
631
+ expect(savon(:specific)).to eq({:test => {:value=>"test"}})
632
+ end
633
+
634
+ it "handles snakecase option properly" do
635
+ mock_controller(snakecase_input: false, camelize_wsdl: false) do
636
+ soap_action "rocknroll", :args => {:ZOMG => :string}, :return => nil
637
+ def rocknroll
638
+ expect(params["ZOMG"]).to eq "yam!"
639
+ render :soap => nil
640
+ end
641
+ end
642
+
643
+ savon(:rocknroll, "ZOMG" => 'yam!')
644
+ end
645
+
646
+ end
647
+
648
+ describe "WS Security" do
649
+
650
+ it "appends username_token to params" do
651
+ mock_controller(wsse_username: "gorilla", wsse_password: "secret") do
652
+ soap_action "checkToken", :args => :integer, :return => nil, :to => 'check_token'
653
+ def check_token
654
+ expect(request.env['WSSE_TOKEN']['username']).to eq "gorilla"
655
+ expect(request.env['WSSE_TOKEN']['password']).to eq "secret"
656
+ render :soap => nil
657
+ end
658
+ end
659
+
660
+ savon(:check_token, 42) do
661
+ wsse_auth "gorilla", "secret"
662
+ end
663
+ end
664
+
665
+ it "handles PasswordText auth" do
666
+ mock_controller(wsse_username: "gorilla", wsse_password: "secret") do
667
+ soap_action "checkAuth", :args => :integer, :return => :boolean, :to => 'check_auth'
668
+ def check_auth
669
+ render :soap => (params[:value] == 42)
670
+ end
671
+ end
672
+
673
+ # correct auth
674
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "secret" } }.
675
+ not_to raise_exception
676
+
677
+ # wrong user
678
+ expect { savon(:check_auth, 42){ wsse_auth "chimpanzee", "secret" } }.
679
+ to raise_exception(Savon::SOAPFault)
680
+
681
+ # wrong pass
682
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "nicetry" } }.
683
+ to raise_exception(Savon::SOAPFault)
684
+
685
+ # no auth
686
+ expect { savon(:check_auth, 42) }.
687
+ to raise_exception(Savon::SOAPFault)
688
+ end
689
+
690
+ it "handles PasswordDigest auth" do
691
+ mock_controller(wsse_username: "gorilla", wsse_password: "secret") do
692
+ soap_action "checkAuth", :args => :integer, :return => :boolean, :to => 'check_auth'
693
+ def check_auth
694
+ render :soap => (params[:value] == 42)
695
+ end
696
+ end
697
+
698
+ # correct auth
699
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "secret" } }.
700
+ not_to raise_exception
701
+
702
+ # correct digest auth
703
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "secret", :digest } }.
704
+ not_to raise_exception
705
+
706
+ # wrong user
707
+ expect { savon(:check_auth, 42){ wsse_auth "chimpanzee", "secret", :digest } }.
708
+ to raise_exception(Savon::SOAPFault)
709
+
710
+ # wrong pass
711
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "nicetry", :digest } }.
712
+ to raise_exception(Savon::SOAPFault)
713
+
714
+ # no auth
715
+ expect { savon(:check_auth, 42) }.
716
+ to raise_exception(Savon::SOAPFault)
717
+ end
718
+
719
+ it "handles auth callback" do
720
+ mock_controller(
721
+ wsse_auth_callback: lambda {|user, password|
722
+ return user == "gorilla" && password == "secret"
723
+ }
724
+ ) do
725
+ soap_action "checkAuth", :args => :integer, :return => :boolean, :to => 'check_auth'
726
+ def check_auth
727
+ render :soap => (params[:value] == 42)
728
+ end
729
+ end
730
+
731
+ # correct auth
732
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "secret" } }.
733
+ not_to raise_exception
734
+
735
+ # correct digest auth
736
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "secret", :digest } }.
737
+ to raise_exception(Savon::SOAPFault)
738
+
739
+ # wrong user
740
+ expect { savon(:check_auth, 42){ wsse_auth "chimpanzee", "secret", :digest } }.
741
+ to raise_exception(Savon::SOAPFault)
742
+
743
+ # wrong pass
744
+ expect { savon(:check_auth, 42){ wsse_auth "gorilla", "nicetry", :digest } }.
745
+ to raise_exception(Savon::SOAPFault)
746
+
747
+ # no auth
748
+ expect { savon(:check_auth, 42) }.
749
+ to raise_exception(Savon::SOAPFault)
750
+ end
751
+
752
+ end
753
+
754
+ end