wash-out 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
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