jmeeks-actionwebservice 2.3.2

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.rb +66 -0
  25. data/lib/action_web_service/api.rb +297 -0
  26. data/lib/action_web_service/base.rb +38 -0
  27. data/lib/action_web_service/casting.rb +149 -0
  28. data/lib/action_web_service/client.rb +3 -0
  29. data/lib/action_web_service/client/base.rb +28 -0
  30. data/lib/action_web_service/client/soap_client.rb +113 -0
  31. data/lib/action_web_service/client/xmlrpc_client.rb +58 -0
  32. data/lib/action_web_service/container.rb +3 -0
  33. data/lib/action_web_service/container/action_controller_container.rb +93 -0
  34. data/lib/action_web_service/container/delegated_container.rb +86 -0
  35. data/lib/action_web_service/container/direct_container.rb +69 -0
  36. data/lib/action_web_service/dispatcher.rb +2 -0
  37. data/lib/action_web_service/dispatcher/abstract.rb +207 -0
  38. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +379 -0
  39. data/lib/action_web_service/invocation.rb +202 -0
  40. data/lib/action_web_service/protocol.rb +4 -0
  41. data/lib/action_web_service/protocol/abstract.rb +112 -0
  42. data/lib/action_web_service/protocol/discovery.rb +37 -0
  43. data/lib/action_web_service/protocol/soap_protocol.rb +176 -0
  44. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +242 -0
  45. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +122 -0
  46. data/lib/action_web_service/scaffolding.rb +281 -0
  47. data/lib/action_web_service/struct.rb +64 -0
  48. data/lib/action_web_service/support/class_inheritable_options.rb +26 -0
  49. data/lib/action_web_service/support/signature_types.rb +226 -0
  50. data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
  51. data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
  52. data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
  53. data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
  54. data/lib/action_web_service/test_invoke.rb +110 -0
  55. data/lib/action_web_service/version.rb +9 -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 +175 -0
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+
3
+ module ContainerTest
4
+ $immediate_service = Object.new
5
+ $deferred_service = Object.new
6
+
7
+ class DelegateContainer < ActionController::Base
8
+ web_service_dispatching_mode :delegated
9
+
10
+ attr :flag
11
+ attr :previous_flag
12
+
13
+ def initialize
14
+ @previous_flag = nil
15
+ @flag = true
16
+ end
17
+
18
+ web_service :immediate_service, $immediate_service
19
+ web_service(:deferred_service) { @previous_flag = @flag; @flag = false; $deferred_service }
20
+ end
21
+
22
+ class DirectContainer < ActionController::Base
23
+ web_service_dispatching_mode :direct
24
+ end
25
+
26
+ class InvalidContainer
27
+ include ActionWebService::Container::Direct
28
+ end
29
+ end
30
+
31
+ class TC_Container < Test::Unit::TestCase
32
+ include ContainerTest
33
+
34
+ def setup
35
+ @delegate_container = DelegateContainer.new
36
+ @direct_container = DirectContainer.new
37
+ end
38
+
39
+ def test_registration
40
+ assert(DelegateContainer.has_web_service?(:immediate_service))
41
+ assert(DelegateContainer.has_web_service?(:deferred_service))
42
+ assert(!DelegateContainer.has_web_service?(:fake_service))
43
+ assert_raises(ActionWebService::Container::Delegated::ContainerError) do
44
+ DelegateContainer.web_service('invalid')
45
+ end
46
+ end
47
+
48
+ def test_service_object
49
+ assert_raises(ActionWebService::Container::Delegated::ContainerError) do
50
+ @delegate_container.web_service_object(:nonexistent)
51
+ end
52
+ assert(@delegate_container.flag == true)
53
+ assert(@delegate_container.web_service_object(:immediate_service) == $immediate_service)
54
+ assert(@delegate_container.previous_flag.nil?)
55
+ assert(@delegate_container.flag == true)
56
+ assert(@delegate_container.web_service_object(:deferred_service) == $deferred_service)
57
+ assert(@delegate_container.previous_flag == true)
58
+ assert(@delegate_container.flag == false)
59
+ end
60
+
61
+ def test_direct_container
62
+ assert(DirectContainer.web_service_dispatching_mode == :direct)
63
+ end
64
+
65
+ def test_validity
66
+ assert_raises(ActionWebService::Container::Direct::ContainerError) do
67
+ InvalidContainer.web_service_api :test
68
+ end
69
+ assert_raises(ActionWebService::Container::Direct::ContainerError) do
70
+ InvalidContainer.web_service_api 50.0
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,138 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/apis')
2
+ require File.dirname(__FILE__) + '/abstract_dispatcher'
3
+ require 'wsdl/parser'
4
+
5
+ class ActionController::Base
6
+ class << self
7
+ alias :inherited_without_name_error :inherited
8
+ def inherited(child)
9
+ begin
10
+ inherited_without_name_error(child)
11
+ rescue NameError => e
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ class AutoLoadController < ActionController::Base; end
18
+ class FailingAutoLoadController < ActionController::Base; end
19
+ class BrokenAutoLoadController < ActionController::Base; end
20
+
21
+ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase
22
+ include DispatcherTest
23
+ include DispatcherCommonTests
24
+
25
+ def setup
26
+ @direct_controller = DirectController.new
27
+ @delegated_controller = DelegatedController.new
28
+ @virtual_controller = VirtualController.new
29
+ @layered_controller = LayeredController.new
30
+ @protocol = ActionWebService::Protocol::Soap::SoapProtocol.create(@direct_controller)
31
+ end
32
+
33
+ def test_wsdl_generation
34
+ ensure_valid_wsdl_generation DelegatedController.new, DispatcherTest::WsdlNamespace
35
+ ensure_valid_wsdl_generation DirectController.new, DispatcherTest::WsdlNamespace
36
+ end
37
+
38
+ def test_wsdl_action
39
+ delegated_types = ensure_valid_wsdl_action DelegatedController.new
40
+ delegated_names = delegated_types.map{|x| x.name.name}
41
+ assert(delegated_names.include?('DispatcherTest..NodeArray'))
42
+ assert(delegated_names.include?('DispatcherTest..Node'))
43
+ direct_types = ensure_valid_wsdl_action DirectController.new
44
+ direct_names = direct_types.map{|x| x.name.name}
45
+ assert(direct_names.include?('DispatcherTest..NodeArray'))
46
+ assert(direct_names.include?('DispatcherTest..Node'))
47
+ assert(direct_names.include?('IntegerArray'))
48
+ end
49
+
50
+ def test_autoloading
51
+ assert(!AutoLoadController.web_service_api.nil?)
52
+ assert(AutoLoadController.web_service_api.has_public_api_method?('Void'))
53
+ assert(FailingAutoLoadController.web_service_api.nil?)
54
+ assert_raises(MissingSourceFile) do
55
+ FailingAutoLoadController.require_web_service_api :blah
56
+ end
57
+ assert_raises(ArgumentError) do
58
+ FailingAutoLoadController.require_web_service_api 50.0
59
+ end
60
+ assert(BrokenAutoLoadController.web_service_api.nil?)
61
+ end
62
+
63
+ def test_layered_dispatching
64
+ mt_cats = do_method_call(@layered_controller, 'mt.getCategories')
65
+ assert_equal(["mtCat1", "mtCat2"], mt_cats)
66
+ blogger_cats = do_method_call(@layered_controller, 'blogger.getCategories')
67
+ assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats)
68
+ end
69
+
70
+ def test_utf8
71
+ @direct_controller.web_service_exception_reporting = true
72
+ $KCODE = 'u'
73
+ assert_equal(Utf8String, do_method_call(@direct_controller, 'TestUtf8'))
74
+ retval = SOAP::Processor.unmarshal(@response_body).body.response
75
+ assert retval.is_a?(SOAP::SOAPString)
76
+
77
+ # If $KCODE is not set to UTF-8, any strings with non-ASCII UTF-8 data
78
+ # will be sent back as base64 by SOAP4R. By the time we get it here though,
79
+ # it will be decoded back into a string. So lets read the base64 value
80
+ # from the message body directly.
81
+ $KCODE = 'NONE'
82
+ do_method_call(@direct_controller, 'TestUtf8')
83
+ retval = SOAP::Processor.unmarshal(@response_body).body.response
84
+ assert retval.is_a?(SOAP::SOAPBase64)
85
+ assert_equal "T25lIFdvcmxkIENhZsOp", retval.data.to_s
86
+ end
87
+
88
+ protected
89
+ def exception_message(soap_fault_exception)
90
+ soap_fault_exception.detail.cause.message
91
+ end
92
+
93
+ def is_exception?(obj)
94
+ obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
95
+ obj.detail.cause.is_a?(Exception)
96
+ end
97
+
98
+ def service_name(container)
99
+ container.is_a?(DelegatedController) ? 'test_service' : 'api'
100
+ end
101
+
102
+ def ensure_valid_wsdl_generation(controller, expected_namespace)
103
+ wsdl = controller.generate_wsdl
104
+ ensure_valid_wsdl(controller, wsdl, expected_namespace)
105
+ end
106
+
107
+ def ensure_valid_wsdl(controller, wsdl, expected_namespace)
108
+ definitions = WSDL::Parser.new.parse(wsdl)
109
+ assert(definitions.is_a?(WSDL::Definitions))
110
+ definitions.bindings.each do |binding|
111
+ assert(binding.name.name.index(':').nil?)
112
+ end
113
+ definitions.services.each do |service|
114
+ service.ports.each do |port|
115
+ assert(port.name.name.index(':').nil?)
116
+ end
117
+ end
118
+ types = definitions.collect_complextypes.map{|x| x.name}
119
+ types.each do |type|
120
+ assert(type.namespace == expected_namespace)
121
+ end
122
+ location = definitions.services[0].ports[0].soap_address.location
123
+ if controller.is_a?(DelegatedController)
124
+ assert_match %r{http://test.host/dispatcher_test/delegated/test_service$}, location
125
+ elsif controller.is_a?(DirectController)
126
+ assert_match %r{http://test.host/dispatcher_test/direct/api$}, location
127
+ end
128
+ definitions.collect_complextypes
129
+ end
130
+
131
+ def ensure_valid_wsdl_action(controller)
132
+ test_request = ActionController::TestRequest.new
133
+ test_request.action = 'wsdl'
134
+ test_response = ActionController::TestResponse.new
135
+ wsdl = controller.process(test_request, test_response).body
136
+ ensure_valid_wsdl(controller, wsdl, DispatcherTest::WsdlNamespace)
137
+ end
138
+ end
@@ -0,0 +1,59 @@
1
+ require File.dirname(__FILE__) + '/abstract_dispatcher'
2
+
3
+ class TC_DispatcherActionControllerXmlRpc < Test::Unit::TestCase
4
+ include DispatcherTest
5
+ include DispatcherCommonTests
6
+
7
+ def setup
8
+ @direct_controller = DirectController.new
9
+ @delegated_controller = DelegatedController.new
10
+ @layered_controller = LayeredController.new
11
+ @virtual_controller = VirtualController.new
12
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.create(@direct_controller)
13
+ end
14
+
15
+ def test_layered_dispatching
16
+ mt_cats = do_method_call(@layered_controller, 'mt.getCategories')
17
+ assert_equal(["mtCat1", "mtCat2"], mt_cats)
18
+ blogger_cats = do_method_call(@layered_controller, 'blogger.getCategories')
19
+ assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats)
20
+ end
21
+
22
+ def test_multicall
23
+ response = do_method_call(@layered_controller, 'system.multicall', [
24
+ {'methodName' => 'mt.getCategories'},
25
+ {'methodName' => 'blogger.getCategories'},
26
+ {'methodName' => 'mt.bool'},
27
+ {'methodName' => 'blogger.str', 'params' => ['2000']},
28
+ {'methodName' => 'mt.alwaysFail'},
29
+ {'methodName' => 'blogger.alwaysFail'},
30
+ {'methodName' => 'mt.blah'},
31
+ {'methodName' => 'blah.blah'},
32
+ {'methodName' => 'mt.person'}
33
+ ])
34
+ assert_equal [
35
+ [["mtCat1", "mtCat2"]],
36
+ [["bloggerCat1", "bloggerCat2"]],
37
+ [true],
38
+ ["2500"],
39
+ {"faultCode" => 3, "faultString" => "MT AlwaysFail"},
40
+ {"faultCode" => 3, "faultString" => "Blogger AlwaysFail"},
41
+ {"faultCode" => 4, "faultMessage" => "no such method 'blah' on API DispatcherTest::MTAPI"},
42
+ {"faultCode" => 4, "faultMessage" => "no such web service 'blah'"},
43
+ [{"name"=>"person1", "id"=>1}]
44
+ ], response
45
+ end
46
+
47
+ protected
48
+ def exception_message(xmlrpc_fault_exception)
49
+ xmlrpc_fault_exception.faultString
50
+ end
51
+
52
+ def is_exception?(obj)
53
+ obj.is_a?(XMLRPC::FaultException)
54
+ end
55
+
56
+ def service_name(container)
57
+ container.is_a?(DelegatedController) ? 'test_service' : 'api'
58
+ end
59
+ end
@@ -0,0 +1,8 @@
1
+ CREATE TABLE `users` (
2
+ `id` int(11) NOT NULL auto_increment,
3
+ `name` varchar(30) default NULL,
4
+ `active` tinyint(4) default NULL,
5
+ `balance` decimal(5, 2) default NULL,
6
+ `created_on` date default NULL,
7
+ PRIMARY KEY (`id`)
8
+ ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
@@ -0,0 +1,12 @@
1
+ user1:
2
+ id: 1
3
+ name: Kent
4
+ active: 1
5
+ balance: 12.2
6
+ created_on: <%= Date.today %>
7
+ user2:
8
+ id: 2
9
+ name: David
10
+ active: 1
11
+ balance: 16.4
12
+ created_on: <%= Date.today %>
data/test/gencov ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ rcov -x '.*_test\.rb,rubygems,abstract_,/run,/apis' ./run
@@ -0,0 +1,185 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+
3
+ module InvocationTest
4
+ class API < ActionWebService::API::Base
5
+ api_method :add, :expects => [:int, :int], :returns => [:int]
6
+ api_method :transmogrify, :expects_and_returns => [:string]
7
+ api_method :fail_with_reason
8
+ api_method :fail_generic
9
+ api_method :no_before
10
+ api_method :no_after
11
+ api_method :only_one
12
+ api_method :only_two
13
+ end
14
+
15
+ class Interceptor
16
+ attr :args
17
+
18
+ def initialize
19
+ @args = nil
20
+ end
21
+
22
+ def intercept(*args)
23
+ @args = args
24
+ end
25
+ end
26
+
27
+ InterceptorClass = Interceptor.new
28
+
29
+ class Service < ActionController::Base
30
+ web_service_api API
31
+
32
+ before_invocation :intercept_before, :except => [:no_before]
33
+ after_invocation :intercept_after, :except => [:no_after]
34
+ prepend_after_invocation :intercept_after_first, :except => [:no_after]
35
+ prepend_before_invocation :intercept_only, :only => [:only_one, :only_two]
36
+ after_invocation(:only => [:only_one]) do |*args|
37
+ args[0].instance_variable_set('@block_invoked', args[1])
38
+ end
39
+ after_invocation InterceptorClass, :only => [:only_one]
40
+
41
+ attr_accessor :before_invoked
42
+ attr_accessor :after_invoked
43
+ attr_accessor :after_first_invoked
44
+ attr_accessor :only_invoked
45
+ attr_accessor :block_invoked
46
+ attr_accessor :invocation_result
47
+
48
+ def initialize
49
+ @before_invoked = nil
50
+ @after_invoked = nil
51
+ @after_first_invoked = nil
52
+ @only_invoked = nil
53
+ @invocation_result = nil
54
+ @block_invoked = nil
55
+ end
56
+
57
+ def add(a, b)
58
+ a + b
59
+ end
60
+
61
+ def transmogrify(str)
62
+ str.upcase
63
+ end
64
+
65
+ def fail_with_reason
66
+ end
67
+
68
+ def fail_generic
69
+ end
70
+
71
+ def no_before
72
+ 5
73
+ end
74
+
75
+ def no_after
76
+ end
77
+
78
+ def only_one
79
+ end
80
+
81
+ def only_two
82
+ end
83
+
84
+ protected
85
+ def intercept_before(name, args)
86
+ @before_invoked = name
87
+ return [false, "permission denied"] if name == :fail_with_reason
88
+ return false if name == :fail_generic
89
+ end
90
+
91
+ def intercept_after(name, args, result)
92
+ @after_invoked = name
93
+ @invocation_result = result
94
+ end
95
+
96
+ def intercept_after_first(name, args, result)
97
+ @after_first_invoked = name
98
+ end
99
+
100
+ def intercept_only(name, args)
101
+ raise "Interception error" unless name == :only_one || name == :only_two
102
+ @only_invoked = name
103
+ end
104
+ end
105
+ end
106
+
107
+ class TC_Invocation < Test::Unit::TestCase
108
+ include ActionWebService::Invocation
109
+
110
+ def setup
111
+ @service = InvocationTest::Service.new
112
+ end
113
+
114
+ def test_invocation
115
+ assert(perform_invocation(:add, 5, 10) == 15)
116
+ assert(perform_invocation(:transmogrify, "hello") == "HELLO")
117
+ assert_raises(NoMethodError) do
118
+ perform_invocation(:nonexistent_method_xyzzy)
119
+ end
120
+ end
121
+
122
+ def test_interceptor_registration
123
+ assert(InvocationTest::Service.before_invocation_interceptors.length == 2)
124
+ assert(InvocationTest::Service.after_invocation_interceptors.length == 4)
125
+ assert_equal(:intercept_only, InvocationTest::Service.before_invocation_interceptors[0])
126
+ assert_equal(:intercept_after_first, InvocationTest::Service.after_invocation_interceptors[0])
127
+ end
128
+
129
+ def test_interception
130
+ assert(@service.before_invoked.nil?)
131
+ assert(@service.after_invoked.nil?)
132
+ assert(@service.only_invoked.nil?)
133
+ assert(@service.block_invoked.nil?)
134
+ assert(@service.invocation_result.nil?)
135
+ perform_invocation(:add, 20, 50)
136
+ assert(@service.before_invoked == :add)
137
+ assert(@service.after_invoked == :add)
138
+ assert(@service.invocation_result == 70)
139
+ end
140
+
141
+ def test_interception_canceling
142
+ reason = nil
143
+ perform_invocation(:fail_with_reason){|r| reason = r}
144
+ assert(@service.before_invoked == :fail_with_reason)
145
+ assert(@service.after_invoked.nil?)
146
+ assert(@service.invocation_result.nil?)
147
+ assert(reason == "permission denied")
148
+ reason = true
149
+ @service.before_invoked = @service.after_invoked = @service.invocation_result = nil
150
+ perform_invocation(:fail_generic){|r| reason = r}
151
+ assert(@service.before_invoked == :fail_generic)
152
+ assert(@service.after_invoked.nil?)
153
+ assert(@service.invocation_result.nil?)
154
+ assert(reason == true)
155
+ end
156
+
157
+ def test_interception_except_conditions
158
+ perform_invocation(:no_before)
159
+ assert(@service.before_invoked.nil?)
160
+ assert(@service.after_first_invoked == :no_before)
161
+ assert(@service.after_invoked == :no_before)
162
+ assert(@service.invocation_result == 5)
163
+ @service.before_invoked = @service.after_invoked = @service.invocation_result = nil
164
+ perform_invocation(:no_after)
165
+ assert(@service.before_invoked == :no_after)
166
+ assert(@service.after_invoked.nil?)
167
+ assert(@service.invocation_result.nil?)
168
+ end
169
+
170
+ def test_interception_only_conditions
171
+ assert(@service.only_invoked.nil?)
172
+ perform_invocation(:only_one)
173
+ assert(@service.only_invoked == :only_one)
174
+ assert(@service.block_invoked == :only_one)
175
+ assert(InvocationTest::InterceptorClass.args[1] == :only_one)
176
+ @service.only_invoked = nil
177
+ perform_invocation(:only_two)
178
+ assert(@service.only_invoked == :only_two)
179
+ end
180
+
181
+ private
182
+ def perform_invocation(method_name, *args, &block)
183
+ @service.perform_invocation(method_name, args, &block)
184
+ end
185
+ end