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