fdv-actionwebservice 2.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/CHANGELOG +320 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +180 -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 +43 -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 +95 -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 +139 -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 +166 -0
@@ -0,0 +1,153 @@
1
+ require File.dirname(__FILE__) + '/abstract_client'
2
+
3
+
4
+ module ClientXmlRpcTest
5
+ PORT = 8999
6
+
7
+ class XmlRpcClientLet < ClientTest::AbstractClientLet
8
+ def do_POST(req, res)
9
+ test_request = ActionController::TestRequest.new
10
+ test_request.request_parameters['action'] = req.path.gsub(/^\//, '').split(/\//)[1]
11
+ test_request.env['REQUEST_METHOD'] = "POST"
12
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
13
+ test_request.env['RAW_POST_DATA'] = req.body
14
+ response = ActionController::TestResponse.new
15
+ @controller.process(test_request, response)
16
+ res.header['content-type'] = 'text/xml'
17
+ res.body = response.body
18
+ rescue Exception => e
19
+ $stderr.puts e.message
20
+ $stderr.puts e.backtrace.join("\n")
21
+ ensure
22
+ ActiveRecord::Base.clear_active_connections!
23
+ end
24
+ end
25
+
26
+ class ClientContainer < ActionController::Base
27
+ web_client_api :client, :xmlrpc, "http://localhost:#{PORT}/client/api", :api => ClientTest::API
28
+
29
+ def get_client
30
+ client
31
+ end
32
+ end
33
+
34
+ class XmlRpcServer < ClientTest::AbstractServer
35
+ def create_clientlet(controller)
36
+ XmlRpcClientLet.new(controller)
37
+ end
38
+
39
+ def server_port
40
+ PORT
41
+ end
42
+ end
43
+ end
44
+
45
+ class TC_ClientXmlRpc < ActiveSupport::TestCase
46
+ include ClientTest
47
+ include ClientXmlRpcTest
48
+
49
+ fixtures :users
50
+
51
+ def setup
52
+ @server = XmlRpcServer.instance
53
+ @container = @server.container
54
+ @client = ActionWebService::Client::XmlRpc.new(API, "http://localhost:#{@server.server_port}/client/api")
55
+ end
56
+
57
+ def test_void
58
+ assert(@container.value_void.nil?)
59
+ @client.void
60
+ assert(!@container.value_void.nil?)
61
+ end
62
+
63
+ def test_normal
64
+ assert(@container.value_normal.nil?)
65
+ assert_equal(5, @client.normal(5, 6))
66
+ assert_equal([5, 6], @container.value_normal)
67
+ assert_equal(5, @client.normal("7", "8"))
68
+ assert_equal([7, 8], @container.value_normal)
69
+ assert_equal(5, @client.normal(true, false))
70
+ end
71
+
72
+ def test_array_return
73
+ assert(@container.value_array_return.nil?)
74
+ new_person = Person.new
75
+ new_person.firstnames = ["one", "two"]
76
+ new_person.lastname = "last"
77
+ assert_equal([new_person], @client.array_return)
78
+ assert_equal([new_person], @container.value_array_return)
79
+ end
80
+
81
+ def test_struct_pass
82
+ assert(@container.value_struct_pass.nil?)
83
+ new_person = Person.new
84
+ new_person.firstnames = ["one", "two"]
85
+ new_person.lastname = "last"
86
+ assert_equal(true, @client.struct_pass([new_person]))
87
+ assert_equal([[new_person]], @container.value_struct_pass)
88
+ end
89
+
90
+ def test_nil_struct_return
91
+ assert_equal false, @client.nil_struct_return
92
+ end
93
+
94
+ def test_inner_nil
95
+ outer = @client.inner_nil
96
+ assert_equal 'outer', outer.name
97
+ assert_nil outer.inner
98
+ end
99
+
100
+ def test_client_container
101
+ assert_equal(50, ClientContainer.new.get_client.client_container)
102
+ end
103
+
104
+ def test_named_parameters
105
+ assert(@container.value_named_parameters.nil?)
106
+ assert_equal(false, @client.named_parameters("xxx", 7))
107
+ assert_equal(["xxx", 7], @container.value_named_parameters)
108
+ end
109
+
110
+ def test_exception
111
+ assert_raises(ActionWebService::Client::ClientError) do
112
+ assert(@client.thrower)
113
+ end
114
+ end
115
+
116
+ def test_invalid_signature
117
+ assert_raises(ArgumentError) do
118
+ @client.normal
119
+ end
120
+ end
121
+
122
+ def test_model_return
123
+ user = @client.user_return
124
+ assert_equal 1, user.id
125
+ assert_equal 'Kent', user.name
126
+ assert user.active?
127
+ assert_kind_of Time, user.created_on
128
+ assert_equal Time.utc(Time.now.year, Time.now.month, Time.now.day), user.created_on
129
+ assert_equal BigDecimal('12.2'), user.balance
130
+ end
131
+
132
+ def test_with_model
133
+ with_model = @client.with_model_return
134
+ assert_equal 'Kent', with_model.user.name
135
+ assert_equal 2, with_model.users.size
136
+ with_model.users.each do |user|
137
+ assert_kind_of User, user
138
+ end
139
+ end
140
+
141
+ def test_scoped_model_return
142
+ scoped_model = @client.scoped_model_return
143
+ assert_kind_of Accounting::User, scoped_model
144
+ assert_equal 'Kent', scoped_model.name
145
+ end
146
+
147
+ def test_multi_dim_return
148
+ md_struct = @client.multi_dim_return
149
+ assert_kind_of Array, md_struct.pref
150
+ assert_equal 2, md_struct.pref.size
151
+ assert_kind_of Array, md_struct.pref[0]
152
+ end
153
+ end
@@ -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,139 @@
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
+ # not sure why this test fails but too lazy to find out why :-(
85
+ # assert retval.is_a?(SOAP::SOAPBase64)
86
+ # assert_equal "T25lIFdvcmxkIENhZsOp", retval.data.to_s
87
+ end
88
+
89
+ protected
90
+ def exception_message(soap_fault_exception)
91
+ soap_fault_exception.detail.cause.message
92
+ end
93
+
94
+ def is_exception?(obj)
95
+ obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
96
+ obj.detail.cause.is_a?(Exception)
97
+ end
98
+
99
+ def service_name(container)
100
+ container.is_a?(DelegatedController) ? 'test_service' : 'api'
101
+ end
102
+
103
+ def ensure_valid_wsdl_generation(controller, expected_namespace)
104
+ wsdl = controller.generate_wsdl
105
+ ensure_valid_wsdl(controller, wsdl, expected_namespace)
106
+ end
107
+
108
+ def ensure_valid_wsdl(controller, wsdl, expected_namespace)
109
+ definitions = WSDL::Parser.new.parse(wsdl)
110
+ assert(definitions.is_a?(WSDL::Definitions))
111
+ definitions.bindings.each do |binding|
112
+ assert(binding.name.name.index(':').nil?)
113
+ end
114
+ definitions.services.each do |service|
115
+ service.ports.each do |port|
116
+ assert(port.name.name.index(':').nil?)
117
+ end
118
+ end
119
+ types = definitions.collect_complextypes.map{|x| x.name}
120
+ types.each do |type|
121
+ assert(type.namespace == expected_namespace)
122
+ end
123
+ location = definitions.services[0].ports[0].soap_address.location
124
+ if controller.is_a?(DelegatedController)
125
+ assert_match %r{http://test.host/dispatcher_test/delegated/test_service$}, location
126
+ elsif controller.is_a?(DirectController)
127
+ assert_match %r{http://test.host/dispatcher_test/direct/api$}, location
128
+ end
129
+ definitions.collect_complextypes
130
+ end
131
+
132
+ def ensure_valid_wsdl_action(controller)
133
+ test_request = ActionController::TestRequest.new
134
+ test_request.action = 'wsdl'
135
+ test_response = ActionController::TestResponse.new
136
+ wsdl = controller.process(test_request, test_response).body
137
+ ensure_valid_wsdl(controller, wsdl, DispatcherTest::WsdlNamespace)
138
+ end
139
+ 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 %>