pelle-actionwebservice 2.3.3

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 (79) hide show
  1. data/CHANGELOG +320 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +173 -0
  5. data/TODO +32 -0
  6. data/examples/googlesearch/README +143 -0
  7. data/examples/googlesearch/autoloading/google_search_api.rb +50 -0
  8. data/examples/googlesearch/autoloading/google_search_controller.rb +57 -0
  9. data/examples/googlesearch/delegated/google_search_service.rb +108 -0
  10. data/examples/googlesearch/delegated/search_controller.rb +7 -0
  11. data/examples/googlesearch/direct/google_search_api.rb +50 -0
  12. data/examples/googlesearch/direct/search_controller.rb +58 -0
  13. data/examples/metaWeblog/README +17 -0
  14. data/examples/metaWeblog/apis/blogger_api.rb +60 -0
  15. data/examples/metaWeblog/apis/blogger_service.rb +34 -0
  16. data/examples/metaWeblog/apis/meta_weblog_api.rb +67 -0
  17. data/examples/metaWeblog/apis/meta_weblog_service.rb +48 -0
  18. data/examples/metaWeblog/controllers/xmlrpc_controller.rb +16 -0
  19. data/generators/web_service/USAGE +28 -0
  20. data/generators/web_service/templates/api_definition.rb +5 -0
  21. data/generators/web_service/templates/controller.rb +8 -0
  22. data/generators/web_service/templates/functional_test.rb +19 -0
  23. data/generators/web_service/web_service_generator.rb +29 -0
  24. data/lib/action_web_service/api.rb +297 -0
  25. data/lib/action_web_service/base.rb +38 -0
  26. data/lib/action_web_service/casting.rb +149 -0
  27. data/lib/action_web_service/client/base.rb +28 -0
  28. data/lib/action_web_service/client/soap_client.rb +113 -0
  29. data/lib/action_web_service/client/xmlrpc_client.rb +58 -0
  30. data/lib/action_web_service/client.rb +3 -0
  31. data/lib/action_web_service/container/action_controller_container.rb +93 -0
  32. data/lib/action_web_service/container/delegated_container.rb +86 -0
  33. data/lib/action_web_service/container/direct_container.rb +69 -0
  34. data/lib/action_web_service/container.rb +3 -0
  35. data/lib/action_web_service/dispatcher/abstract.rb +207 -0
  36. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +379 -0
  37. data/lib/action_web_service/dispatcher.rb +2 -0
  38. data/lib/action_web_service/invocation.rb +202 -0
  39. data/lib/action_web_service/protocol/abstract.rb +112 -0
  40. data/lib/action_web_service/protocol/discovery.rb +37 -0
  41. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +242 -0
  42. data/lib/action_web_service/protocol/soap_protocol.rb +176 -0
  43. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +122 -0
  44. data/lib/action_web_service/protocol.rb +4 -0
  45. data/lib/action_web_service/scaffolding.rb +281 -0
  46. data/lib/action_web_service/struct.rb +64 -0
  47. data/lib/action_web_service/support/class_inheritable_options.rb +26 -0
  48. data/lib/action_web_service/support/signature_types.rb +226 -0
  49. data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
  50. data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
  51. data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
  52. data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
  53. data/lib/action_web_service/test_invoke.rb +110 -0
  54. data/lib/action_web_service/version.rb +9 -0
  55. data/lib/action_web_service.rb +66 -0
  56. data/lib/actionwebservice.rb +1 -0
  57. data/setup.rb +1379 -0
  58. data/test/abstract_client.rb +183 -0
  59. data/test/abstract_dispatcher.rb +548 -0
  60. data/test/abstract_unit.rb +39 -0
  61. data/test/api_test.rb +102 -0
  62. data/test/apis/auto_load_api.rb +3 -0
  63. data/test/apis/broken_auto_load_api.rb +2 -0
  64. data/test/base_test.rb +42 -0
  65. data/test/casting_test.rb +94 -0
  66. data/test/client_soap_test.rb +155 -0
  67. data/test/client_xmlrpc_test.rb +153 -0
  68. data/test/container_test.rb +73 -0
  69. data/test/dispatcher_action_controller_soap_test.rb +138 -0
  70. data/test/dispatcher_action_controller_xmlrpc_test.rb +59 -0
  71. data/test/fixtures/db_definitions/mysql.sql +8 -0
  72. data/test/fixtures/users.yml +12 -0
  73. data/test/gencov +3 -0
  74. data/test/invocation_test.rb +185 -0
  75. data/test/run +6 -0
  76. data/test/scaffolded_controller_test.rb +146 -0
  77. data/test/struct_test.rb +52 -0
  78. data/test/test_invoke_test.rb +112 -0
  79. metadata +171 -0
@@ -0,0 +1,548 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+ require 'stringio'
3
+
4
+ class ActionController::Base; def rescue_action(e) raise e end; end
5
+
6
+ module DispatcherTest
7
+ Utf8String = "One World Caf\303\251"
8
+ WsdlNamespace = 'http://rubyonrails.com/some/namespace'
9
+
10
+ class Node < ActiveRecord::Base
11
+ def initialize(*args)
12
+ super(*args)
13
+ @new_record = false
14
+ end
15
+
16
+ class << self
17
+ def name
18
+ "DispatcherTest::Node"
19
+ end
20
+
21
+ def columns(*args)
22
+ [
23
+ ActiveRecord::ConnectionAdapters::Column.new('id', 0, 'int'),
24
+ ActiveRecord::ConnectionAdapters::Column.new('name', nil, 'string'),
25
+ ActiveRecord::ConnectionAdapters::Column.new('description', nil, 'string'),
26
+ ]
27
+ end
28
+
29
+ def connection
30
+ self
31
+ end
32
+ end
33
+ end
34
+
35
+ class Person < ActionWebService::Struct
36
+ member :id, :int
37
+ member :name, :string
38
+
39
+ def ==(other)
40
+ self.id == other.id && self.name == other.name
41
+ end
42
+ end
43
+
44
+ class API < ActionWebService::API::Base
45
+ api_method :add, :expects => [:int, :int], :returns => [:int]
46
+ api_method :interceptee
47
+ api_method :struct_return, :returns => [[Node]]
48
+ api_method :void
49
+ end
50
+
51
+ class DirectAPI < ActionWebService::API::Base
52
+ api_method :add, :expects => [{:a=>:int}, {:b=>:int}], :returns => [:int]
53
+ api_method :add2, :expects => [{:a=>:int}, {:b=>:int}], :returns => [:int]
54
+ api_method :before_filtered
55
+ api_method :after_filtered, :returns => [[:int]]
56
+ api_method :struct_return, :returns => [[Node]]
57
+ api_method :struct_pass, :expects => [{:person => Person}]
58
+ api_method :base_struct_return, :returns => [[Person]]
59
+ api_method :hash_struct_return, :returns => [[Person]]
60
+ api_method :thrower
61
+ api_method :void
62
+ api_method :test_utf8, :returns => [:string]
63
+ api_method :hex, :expects => [:base64], :returns => [:string]
64
+ api_method :unhex, :expects => [:string], :returns => [:base64]
65
+ api_method :time, :expects => [:time], :returns => [:time]
66
+ end
67
+
68
+ class VirtualAPI < ActionWebService::API::Base
69
+ default_api_method :fallback
70
+ end
71
+
72
+ class Service < ActionWebService::Base
73
+ web_service_api API
74
+
75
+ before_invocation :do_intercept, :only => [:interceptee]
76
+
77
+ attr :added
78
+ attr :intercepted
79
+ attr :void_called
80
+
81
+ def initialize
82
+ @void_called = false
83
+ end
84
+
85
+ def add(a, b)
86
+ @added = a + b
87
+ end
88
+
89
+ def interceptee
90
+ @intercepted = false
91
+ end
92
+
93
+ def struct_return
94
+ n1 = Node.new('id' => 1, 'name' => 'node1', 'description' => 'Node 1')
95
+ n2 = Node.new('id' => 2, 'name' => 'node2', 'description' => 'Node 2')
96
+ [n1, n2]
97
+ end
98
+
99
+ def void(*args)
100
+ @void_called = args
101
+ end
102
+
103
+ def do_intercept(name, args)
104
+ [false, "permission denied"]
105
+ end
106
+ end
107
+
108
+ class MTAPI < ActionWebService::API::Base
109
+ inflect_names false
110
+ api_method :getCategories, :returns => [[:string]]
111
+ api_method :bool, :returns => [:bool]
112
+ api_method :alwaysFail
113
+ api_method :person, :returns => [Person]
114
+ end
115
+
116
+ class BloggerAPI < ActionWebService::API::Base
117
+ inflect_names false
118
+ api_method :getCategories, :returns => [[:string]]
119
+ api_method :str, :expects => [:int], :returns => [:string]
120
+ api_method :alwaysFail
121
+ end
122
+
123
+ class MTService < ActionWebService::Base
124
+ web_service_api MTAPI
125
+
126
+ def getCategories
127
+ ["mtCat1", "mtCat2"]
128
+ end
129
+
130
+ def bool
131
+ 'y'
132
+ end
133
+
134
+ def alwaysFail
135
+ raise "MT AlwaysFail"
136
+ end
137
+
138
+ def person
139
+ Person.new('id' => 1, 'name' => 'person1')
140
+ end
141
+ end
142
+
143
+ class BloggerService < ActionWebService::Base
144
+ web_service_api BloggerAPI
145
+
146
+ def getCategories
147
+ ["bloggerCat1", "bloggerCat2"]
148
+ end
149
+
150
+ def str(int)
151
+ unless int.is_a?(Integer)
152
+ raise "Not an integer!"
153
+ end
154
+ 500 + int
155
+ end
156
+
157
+ def alwaysFail
158
+ raise "Blogger AlwaysFail"
159
+ end
160
+ end
161
+
162
+ class AbstractController < ActionController::Base
163
+ def generate_wsdl
164
+ self.request ||= ::ActionController::TestRequest.new
165
+ to_wsdl
166
+ end
167
+ end
168
+
169
+ class DelegatedController < AbstractController
170
+ web_service_dispatching_mode :delegated
171
+ wsdl_namespace WsdlNamespace
172
+
173
+ web_service(:test_service) { @service ||= Service.new; @service }
174
+ end
175
+
176
+ class LayeredController < AbstractController
177
+ web_service_dispatching_mode :layered
178
+ wsdl_namespace WsdlNamespace
179
+
180
+ web_service(:mt) { @mt_service ||= MTService.new; @mt_service }
181
+ web_service(:blogger) { @blogger_service ||= BloggerService.new; @blogger_service }
182
+ end
183
+
184
+ class DirectController < AbstractController
185
+ web_service_api DirectAPI
186
+ web_service_dispatching_mode :direct
187
+ wsdl_namespace WsdlNamespace
188
+
189
+ before_invocation :alwaysfail, :only => [:before_filtered]
190
+ after_invocation :alwaysok, :only => [:after_filtered]
191
+
192
+ attr :added
193
+ attr :added2
194
+ attr :before_filter_called
195
+ attr :before_filter_target_called
196
+ attr :after_filter_called
197
+ attr :after_filter_target_called
198
+ attr :void_called
199
+ attr :struct_pass_value
200
+
201
+ def initialize
202
+ @before_filter_called = false
203
+ @before_filter_target_called = false
204
+ @after_filter_called = false
205
+ @after_filter_target_called = false
206
+ @void_called = false
207
+ @struct_pass_value = false
208
+ end
209
+
210
+ def add
211
+ @added = params['a'] + params['b']
212
+ end
213
+
214
+ def add2(a, b)
215
+ @added2 = a + b
216
+ end
217
+
218
+ def before_filtered
219
+ @before_filter_target_called = true
220
+ end
221
+
222
+ def after_filtered
223
+ @after_filter_target_called = true
224
+ [5, 6, 7]
225
+ end
226
+
227
+ def thrower
228
+ raise "Hi, I'm an exception"
229
+ end
230
+
231
+ def struct_return
232
+ n1 = Node.new('id' => 1, 'name' => 'node1', 'description' => 'Node 1')
233
+ n2 = Node.new('id' => 2, 'name' => 'node2', 'description' => 'Node 2')
234
+ [n1, n2]
235
+ end
236
+
237
+ def struct_pass(person)
238
+ @struct_pass_value = person
239
+ end
240
+
241
+ def base_struct_return
242
+ p1 = Person.new('id' => 1, 'name' => 'person1')
243
+ p2 = Person.new('id' => 2, 'name' => 'person2')
244
+ [p1, p2]
245
+ end
246
+
247
+ def hash_struct_return
248
+ p1 = { :id => '1', 'name' => 'test' }
249
+ p2 = { 'id' => '2', :name => 'person2' }
250
+ [p1, p2]
251
+ end
252
+
253
+ def void
254
+ @void_called = @method_params
255
+ end
256
+
257
+ def test_utf8
258
+ Utf8String
259
+ end
260
+
261
+ def hex(s)
262
+ return s.unpack("H*")[0]
263
+ end
264
+
265
+ def unhex(s)
266
+ return [s].pack("H*")
267
+ end
268
+
269
+ def time(t)
270
+ t
271
+ end
272
+
273
+ protected
274
+ def alwaysfail(method_name, params)
275
+ @before_filter_called = true
276
+ false
277
+ end
278
+
279
+ def alwaysok(method_name, params, return_value)
280
+ @after_filter_called = true
281
+ end
282
+ end
283
+
284
+ class VirtualController < AbstractController
285
+ web_service_api VirtualAPI
286
+ wsdl_namespace WsdlNamespace
287
+
288
+ def fallback
289
+ "fallback!"
290
+ end
291
+ end
292
+ end
293
+
294
+ module DispatcherCommonTests
295
+ def test_direct_dispatching
296
+ assert_equal(70, do_method_call(@direct_controller, 'Add', 20, 50))
297
+ assert_equal(70, @direct_controller.added)
298
+ assert_equal(50, do_method_call(@direct_controller, 'Add2', 25, 25))
299
+ assert_equal(50, @direct_controller.added2)
300
+ assert(@direct_controller.void_called == false)
301
+ assert(do_method_call(@direct_controller, 'Void', 3, 4, 5).nil?)
302
+ assert(@direct_controller.void_called == [])
303
+ result = do_method_call(@direct_controller, 'BaseStructReturn')
304
+ assert(result[0].is_a?(DispatcherTest::Person))
305
+ assert(result[1].is_a?(DispatcherTest::Person))
306
+ assert_equal("cafe", do_method_call(@direct_controller, 'Hex', "\xca\xfe"))
307
+ assert_equal("\xca\xfe", do_method_call(@direct_controller, 'Unhex', "cafe"))
308
+ time = Time.gm(1998, "Feb", 02, 15, 12, 01)
309
+ assert_equal(time, do_method_call(@direct_controller, 'Time', time))
310
+ end
311
+
312
+ def test_direct_entrypoint
313
+ assert(@direct_controller.respond_to?(:api))
314
+ end
315
+
316
+ def test_virtual_dispatching
317
+ assert_equal("fallback!", do_method_call(@virtual_controller, 'VirtualOne'))
318
+ assert_equal("fallback!", do_method_call(@virtual_controller, 'VirtualTwo'))
319
+ end
320
+
321
+ def test_direct_filtering
322
+ assert_equal(false, @direct_controller.before_filter_called)
323
+ assert_equal(false, @direct_controller.before_filter_target_called)
324
+ do_method_call(@direct_controller, 'BeforeFiltered')
325
+ assert_equal(true, @direct_controller.before_filter_called)
326
+ assert_equal(false, @direct_controller.before_filter_target_called)
327
+ assert_equal(false, @direct_controller.after_filter_called)
328
+ assert_equal(false, @direct_controller.after_filter_target_called)
329
+ assert_equal([5, 6, 7], do_method_call(@direct_controller, 'AfterFiltered'))
330
+ assert_equal(true, @direct_controller.after_filter_called)
331
+ assert_equal(true, @direct_controller.after_filter_target_called)
332
+ end
333
+
334
+ def test_delegated_dispatching
335
+ assert_equal(130, do_method_call(@delegated_controller, 'Add', 50, 80))
336
+ service = @delegated_controller.web_service_object(:test_service)
337
+ assert_equal(130, service.added)
338
+ @delegated_controller.web_service_exception_reporting = true
339
+ assert(service.intercepted.nil?)
340
+ result = do_method_call(@delegated_controller, 'Interceptee')
341
+ assert(service.intercepted.nil?)
342
+ assert(is_exception?(result))
343
+ assert_match(/permission denied/, exception_message(result))
344
+ result = do_method_call(@delegated_controller, 'NonExistentMethod')
345
+ assert(is_exception?(result))
346
+ assert_match(/NonExistentMethod/, exception_message(result))
347
+ assert(service.void_called == false)
348
+ assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5).nil?)
349
+ assert(service.void_called == [])
350
+ end
351
+
352
+ def test_garbage_request
353
+ [@direct_controller, @delegated_controller].each do |controller|
354
+ controller.class.web_service_exception_reporting = true
355
+ send_garbage_request = lambda do
356
+ service_name = service_name(controller)
357
+ request = protocol.encode_action_pack_request(service_name, 'broken, method, name!', 'broken request body', :request_class => ActionController::TestRequest)
358
+ response = ActionController::TestResponse.new
359
+ controller.process(request, response)
360
+ # puts response.body
361
+ assert(response.status =~ /^500/)
362
+ end
363
+ send_garbage_request.call
364
+ controller.class.web_service_exception_reporting = false
365
+ send_garbage_request.call
366
+ end
367
+ end
368
+
369
+ def test_exception_marshaling
370
+ @direct_controller.web_service_exception_reporting = true
371
+ result = do_method_call(@direct_controller, 'Thrower')
372
+ assert(is_exception?(result))
373
+ assert_equal("Hi, I'm an exception", exception_message(result))
374
+ @direct_controller.web_service_exception_reporting = false
375
+ result = do_method_call(@direct_controller, 'Thrower')
376
+ assert(exception_message(result) != "Hi, I'm an exception")
377
+ end
378
+
379
+ def test_ar_struct_return
380
+ [@direct_controller, @delegated_controller].each do |controller|
381
+ result = do_method_call(controller, 'StructReturn')
382
+ assert(result[0].is_a?(DispatcherTest::Node))
383
+ assert(result[1].is_a?(DispatcherTest::Node))
384
+ assert_equal('node1', result[0].name)
385
+ assert_equal('node2', result[1].name)
386
+ end
387
+ end
388
+
389
+ def test_casting
390
+ assert_equal 70, do_method_call(@direct_controller, 'Add', "50", "20")
391
+ assert_equal false, @direct_controller.struct_pass_value
392
+ person = DispatcherTest::Person.new(:id => 1, :name => 'test')
393
+ result = do_method_call(@direct_controller, 'StructPass', person)
394
+ assert(nil == result || true == result)
395
+ assert_equal person, @direct_controller.struct_pass_value
396
+ assert !person.equal?(@direct_controller.struct_pass_value)
397
+ result = do_method_call(@direct_controller, 'StructPass', {'id' => '1', 'name' => 'test'})
398
+ case
399
+ when soap?
400
+ assert_equal(person, @direct_controller.struct_pass_value)
401
+ assert !person.equal?(@direct_controller.struct_pass_value)
402
+ when xmlrpc?
403
+ assert_equal(person, @direct_controller.struct_pass_value)
404
+ assert !person.equal?(@direct_controller.struct_pass_value)
405
+ end
406
+ assert_equal person, do_method_call(@direct_controller, 'HashStructReturn')[0]
407
+ result = do_method_call(@direct_controller, 'StructPass', {'id' => '1', 'name' => 'test', 'nonexistent_attribute' => 'value'})
408
+ case
409
+ when soap?
410
+ assert_equal(person, @direct_controller.struct_pass_value)
411
+ assert !person.equal?(@direct_controller.struct_pass_value)
412
+ when xmlrpc?
413
+ assert_equal(person, @direct_controller.struct_pass_value)
414
+ assert !person.equal?(@direct_controller.struct_pass_value)
415
+ end
416
+ end
417
+
418
+ def test_logging
419
+ buf = ""
420
+ ActionController::Base.logger = Logger.new(StringIO.new(buf))
421
+ test_casting
422
+ test_garbage_request
423
+ test_exception_marshaling
424
+ ActionController::Base.logger = nil
425
+ assert_match /Web Service Response/, buf
426
+ assert_match /Web Service Request/, buf
427
+ end
428
+
429
+ def test_allowed_http_methods
430
+ webservice_api = @direct_controller.class.web_service_api
431
+ original_allowed_http_methods = webservice_api.allowed_http_methods
432
+
433
+ # check defaults
434
+ assert_equal false, http_method_allowed?(:get)
435
+ assert_equal false, http_method_allowed?(:head)
436
+ assert_equal false, http_method_allowed?(:put)
437
+ assert_equal false, http_method_allowed?(:delete)
438
+ assert_equal true, http_method_allowed?(:post)
439
+
440
+ # allow get and post
441
+ webservice_api.allowed_http_methods = [ :get, :post ]
442
+ assert_equal true, http_method_allowed?(:get)
443
+ assert_equal true, http_method_allowed?(:post)
444
+
445
+ # allow get only
446
+ webservice_api.allowed_http_methods = [ :get ]
447
+ assert_equal true, http_method_allowed?(:get)
448
+ assert_equal false, http_method_allowed?(:post)
449
+
450
+ # allow delete only
451
+ webservice_api.allowed_http_methods = [ 'DELETE' ]
452
+ assert_equal false, http_method_allowed?(:get)
453
+ assert_equal false, http_method_allowed?(:head)
454
+ assert_equal false, http_method_allowed?(:post)
455
+ assert_equal false, http_method_allowed?(:put)
456
+ assert_equal true, http_method_allowed?(:delete)
457
+
458
+ ensure
459
+ webservice_api.allowed_http_methods = original_allowed_http_methods
460
+ end
461
+
462
+ protected
463
+ def service_name(container)
464
+ raise NotImplementedError
465
+ end
466
+
467
+ def exception_message(obj)
468
+ raise NotImplementedError
469
+ end
470
+
471
+ def is_exception?(obj)
472
+ raise NotImplementedError
473
+ end
474
+
475
+ def protocol
476
+ @protocol
477
+ end
478
+
479
+ def soap?
480
+ protocol.is_a? ActionWebService::Protocol::Soap::SoapProtocol
481
+ end
482
+
483
+ def xmlrpc?
484
+ protocol.is_a? ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
485
+ end
486
+
487
+ def do_method_call(container, public_method_name, *params)
488
+ request_env = {}
489
+ mode = container.web_service_dispatching_mode
490
+ case mode
491
+ when :direct
492
+ service_name = service_name(container)
493
+ api = container.class.web_service_api
494
+ method = api.public_api_method_instance(public_method_name)
495
+ when :delegated
496
+ service_name = service_name(container)
497
+ api = container.web_service_object(service_name).class.web_service_api
498
+ method = api.public_api_method_instance(public_method_name)
499
+ when :layered
500
+ service_name = nil
501
+ real_method_name = nil
502
+ if public_method_name =~ /^([^\.]+)\.(.*)$/
503
+ service_name = $1
504
+ real_method_name = $2
505
+ end
506
+ if soap?
507
+ public_method_name = real_method_name
508
+ request_env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{real_method_name}"
509
+ end
510
+ api = container.web_service_object(service_name.to_sym).class.web_service_api rescue nil
511
+ method = api.public_api_method_instance(real_method_name) rescue nil
512
+ service_name = self.service_name(container)
513
+ end
514
+ protocol.register_api(api)
515
+ virtual = false
516
+ unless method
517
+ virtual = true
518
+ method ||= ActionWebService::API::Method.new(public_method_name.underscore.to_sym, public_method_name, nil, nil)
519
+ end
520
+ body = protocol.encode_request(public_method_name, params.dup, method.expects)
521
+ # puts body
522
+ ap_request = protocol.encode_action_pack_request(service_name, public_method_name, body, :request_class => ActionController::TestRequest)
523
+ ap_request.env.update(request_env)
524
+ ap_response = ActionController::TestResponse.new
525
+ container.process(ap_request, ap_response)
526
+ # puts ap_response.body
527
+ @response_body = ap_response.body
528
+ public_method_name, return_value = protocol.decode_response(ap_response.body)
529
+ unless is_exception?(return_value) || virtual
530
+ return_value = method.cast_returns(return_value)
531
+ end
532
+ if soap?
533
+ # http://dev.rubyonrails.com/changeset/920
534
+ assert_match(/Response$/, public_method_name) unless public_method_name == "fault"
535
+ end
536
+ return_value
537
+ end
538
+
539
+ def http_method_allowed?(method)
540
+ method = method.to_s.upcase
541
+ test_request = ActionController::TestRequest.new
542
+ test_request.action = 'api'
543
+ test_response = ActionController::TestResponse.new
544
+ test_request.env['REQUEST_METHOD'] = method
545
+ result = @direct_controller.process(test_request, test_response)
546
+ result.body =~ /(GET|POST|PUT|DELETE|TRACE|CONNECT) not supported/ ? false : true
547
+ end
548
+ end
@@ -0,0 +1,39 @@
1
+ $: << "#{File.dirname(__FILE__)}/../lib"
2
+ ENV["RAILS_ENV"] = "test"
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'action_web_service'
6
+ require 'action_controller'
7
+ require 'action_controller/test_case'
8
+ require 'action_view'
9
+ require 'action_view/test_case'
10
+
11
+ # Show backtraces for deprecated behavior for quicker cleanup.
12
+ ActiveSupport::Deprecation.debug = true
13
+
14
+
15
+ ActiveRecord::Base.logger = ActionController::Base.logger = Logger.new("debug.log")
16
+
17
+ begin
18
+ require 'activerecord'
19
+ require "active_record/test_case"
20
+ require "active_record/fixtures" unless Object.const_defined?(:Fixtures)
21
+ rescue LoadError => e
22
+ fail "\nFailed to load activerecord: #{e}"
23
+ end
24
+
25
+ ActiveRecord::Base.configurations = {
26
+ 'mysql' => {
27
+ :adapter => "mysql",
28
+ :username => "root",
29
+ :encoding => "utf8",
30
+ :database => "actionwebservice_unittest"
31
+ }
32
+ }
33
+
34
+ ActiveRecord::Base.establish_connection 'mysql'
35
+
36
+ class ActiveSupport::TestCase
37
+ include ActiveRecord::TestFixtures
38
+ self.fixture_path = "#{File.dirname(__FILE__)}/fixtures/"
39
+ end
data/test/api_test.rb ADDED
@@ -0,0 +1,102 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+
3
+ module APITest
4
+ class API < ActionWebService::API::Base
5
+ api_method :void
6
+ api_method :expects_and_returns, :expects_and_returns => [:string]
7
+ api_method :expects, :expects => [:int, :bool]
8
+ api_method :returns, :returns => [:int, [:string]]
9
+ api_method :named_signature, :expects => [{:appkey=>:int}, {:publish=>:bool}]
10
+ api_method :string_types, :expects => ['int', 'string', 'bool', 'base64']
11
+ api_method :class_types, :expects => [TrueClass, Bignum, String]
12
+ end
13
+ end
14
+
15
+ class TC_API < ActiveSupport::TestCase
16
+ API = APITest::API
17
+
18
+ def test_api_method_declaration
19
+ %w(
20
+ void
21
+ expects_and_returns
22
+ expects
23
+ returns
24
+ named_signature
25
+ string_types
26
+ class_types
27
+ ).each do |name|
28
+ name = name.to_sym
29
+ public_name = API.public_api_method_name(name)
30
+ assert(API.has_api_method?(name))
31
+ assert(API.has_public_api_method?(public_name))
32
+ assert(API.api_method_name(public_name) == name)
33
+ assert(API.api_methods.has_key?(name))
34
+ end
35
+ end
36
+
37
+ def test_signature_canonicalization
38
+ assert_equal(nil, API.api_methods[:void].expects)
39
+ assert_equal(nil, API.api_methods[:void].returns)
40
+ assert_equal([String], API.api_methods[:expects_and_returns].expects.map{|x| x.type_class})
41
+ assert_equal([String], API.api_methods[:expects_and_returns].returns.map{|x| x.type_class})
42
+ assert_equal([Integer, TrueClass], API.api_methods[:expects].expects.map{|x| x.type_class})
43
+ assert_equal(nil, API.api_methods[:expects].returns)
44
+ assert_equal(nil, API.api_methods[:returns].expects)
45
+ assert_equal([Integer, [String]], API.api_methods[:returns].returns.map{|x| x.array?? [x.element_type.type_class] : x.type_class})
46
+ assert_equal([[:appkey, Integer], [:publish, TrueClass]], API.api_methods[:named_signature].expects.map{|x| [x.name, x.type_class]})
47
+ assert_equal(nil, API.api_methods[:named_signature].returns)
48
+ assert_equal([Integer, String, TrueClass, ActionWebService::Base64], API.api_methods[:string_types].expects.map{|x| x.type_class})
49
+ assert_equal(nil, API.api_methods[:string_types].returns)
50
+ assert_equal([TrueClass, Integer, String], API.api_methods[:class_types].expects.map{|x| x.type_class})
51
+ assert_equal(nil, API.api_methods[:class_types].returns)
52
+ end
53
+
54
+ def test_not_instantiable
55
+ assert_raises(NoMethodError) do
56
+ API.new
57
+ end
58
+ end
59
+
60
+ def test_api_errors
61
+ assert_raises(ActionWebService::ActionWebServiceError) do
62
+ klass = Class.new(ActionWebService::API::Base) do
63
+ api_method :test, :expects => [ActiveRecord::Base]
64
+ end
65
+ end
66
+ klass = Class.new(ActionWebService::API::Base) do
67
+ allow_active_record_expects true
68
+ api_method :test2, :expects => [ActiveRecord::Base]
69
+ end
70
+ assert_raises(ActionWebService::ActionWebServiceError) do
71
+ klass = Class.new(ActionWebService::API::Base) do
72
+ api_method :test, :invalid => [:int]
73
+ end
74
+ end
75
+ end
76
+
77
+ def test_parameter_names
78
+ method = API.api_methods[:named_signature]
79
+ assert_equal 0, method.expects_index_of(:appkey)
80
+ assert_equal 1, method.expects_index_of(:publish)
81
+ assert_equal 1, method.expects_index_of('publish')
82
+ assert_equal 0, method.expects_index_of('appkey')
83
+ assert_equal -1, method.expects_index_of('blah')
84
+ assert_equal -1, method.expects_index_of(:missing)
85
+ assert_equal -1, API.api_methods[:void].expects_index_of('test')
86
+ end
87
+
88
+ def test_parameter_hash
89
+ method = API.api_methods[:named_signature]
90
+ hash = method.expects_to_hash([5, false])
91
+ assert_equal({:appkey => 5, :publish => false}, hash)
92
+ end
93
+
94
+ def test_api_methods_compat
95
+ sig = API.api_methods[:named_signature][:expects]
96
+ assert_equal [{:appkey=>Integer}, {:publish=>TrueClass}], sig
97
+ end
98
+
99
+ def test_to_s
100
+ assert_equal 'void Expects(int param0, bool param1)', APITest::API.api_methods[:expects].to_s
101
+ end
102
+ end
@@ -0,0 +1,3 @@
1
+ class AutoLoadAPI < ActionWebService::API::Base
2
+ api_method :void
3
+ end
@@ -0,0 +1,2 @@
1
+
2
+