actionwebservice 0.5.0

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 (54) hide show
  1. data/ChangeLog +47 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +238 -0
  4. data/Rakefile +144 -0
  5. data/TODO +13 -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 +16 -0
  14. data/examples/metaWeblog/blog_controller.rb +127 -0
  15. data/lib/action_web_service.rb +60 -0
  16. data/lib/action_web_service/api.rb +2 -0
  17. data/lib/action_web_service/api/abstract.rb +192 -0
  18. data/lib/action_web_service/api/action_controller.rb +92 -0
  19. data/lib/action_web_service/base.rb +41 -0
  20. data/lib/action_web_service/client.rb +3 -0
  21. data/lib/action_web_service/client/base.rb +39 -0
  22. data/lib/action_web_service/client/soap_client.rb +88 -0
  23. data/lib/action_web_service/client/xmlrpc_client.rb +77 -0
  24. data/lib/action_web_service/container.rb +85 -0
  25. data/lib/action_web_service/dispatcher.rb +2 -0
  26. data/lib/action_web_service/dispatcher/abstract.rb +150 -0
  27. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +299 -0
  28. data/lib/action_web_service/invocation.rb +205 -0
  29. data/lib/action_web_service/protocol.rb +4 -0
  30. data/lib/action_web_service/protocol/abstract.rb +128 -0
  31. data/lib/action_web_service/protocol/registry.rb +55 -0
  32. data/lib/action_web_service/protocol/soap_protocol.rb +484 -0
  33. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +168 -0
  34. data/lib/action_web_service/struct.rb +55 -0
  35. data/lib/action_web_service/support/class_inheritable_options.rb +26 -0
  36. data/lib/action_web_service/support/signature.rb +100 -0
  37. data/setup.rb +1360 -0
  38. data/test/abstract_client.rb +131 -0
  39. data/test/abstract_soap.rb +58 -0
  40. data/test/abstract_unit.rb +9 -0
  41. data/test/api_test.rb +52 -0
  42. data/test/base_test.rb +42 -0
  43. data/test/client_soap_test.rb +93 -0
  44. data/test/client_xmlrpc_test.rb +92 -0
  45. data/test/container_test.rb +53 -0
  46. data/test/dispatcher_action_controller_test.rb +186 -0
  47. data/test/gencov +3 -0
  48. data/test/invocation_test.rb +149 -0
  49. data/test/protocol_registry_test.rb +53 -0
  50. data/test/protocol_soap_test.rb +252 -0
  51. data/test/protocol_xmlrpc_test.rb +147 -0
  52. data/test/run +5 -0
  53. data/test/struct_test.rb +40 -0
  54. metadata +131 -0
@@ -0,0 +1,131 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+ require 'webrick'
3
+ require 'webrick/log'
4
+ require 'singleton'
5
+
6
+ module ClientTest
7
+ class Person < ActionWebService::Struct
8
+ member :firstnames, [:string]
9
+ member :lastname, :string
10
+
11
+ def ==(other)
12
+ firstnames == other.firstnames && lastname == other.lastname
13
+ end
14
+ end
15
+
16
+ class API < ActionWebService::API::Base
17
+ api_method :void
18
+ api_method :normal, :expects => [:int, :int], :returns => [:int]
19
+ api_method :array_return, :returns => [[Person]]
20
+ api_method :struct_pass, :expects => [[Person]], :returns => [:bool]
21
+ api_method :client_container, :returns => [:int]
22
+ api_method :named_parameters, :expects => [{:key=>:string}, {:id=>:int}]
23
+ end
24
+
25
+ class NullLogOut
26
+ def <<(*args); end
27
+ end
28
+
29
+ class Container < ActionController::Base
30
+ web_service_api API
31
+
32
+ attr :value_void
33
+ attr :value_normal
34
+ attr :value_array_return
35
+ attr :value_struct_pass
36
+ attr :value_named_parameters
37
+
38
+ def initialize
39
+ @session = @assigns = {}
40
+ @value_void = nil
41
+ @value_normal = nil
42
+ @value_array_return = nil
43
+ @value_struct_pass = nil
44
+ @value_named_parameters = nil
45
+ end
46
+
47
+ def void
48
+ @value_void = @method_params
49
+ end
50
+
51
+ def normal
52
+ @value_normal = @method_params
53
+ 5
54
+ end
55
+
56
+ def array_return
57
+ person = Person.new
58
+ person.firstnames = ["one", "two"]
59
+ person.lastname = "last"
60
+ @value_array_return = [person]
61
+ end
62
+
63
+ def struct_pass
64
+ @value_struct_pass = @method_params
65
+ true
66
+ end
67
+
68
+ def client_container
69
+ 50
70
+ end
71
+
72
+ def named_parameters
73
+ @value_named_parameters = @method_params
74
+ end
75
+
76
+ def protocol_request(request)
77
+ probe_request_protocol(request)
78
+ end
79
+
80
+ def dispatch_request(protocol_request)
81
+ dispatch_protocol_request(protocol_request)
82
+ end
83
+ end
84
+
85
+ class AbstractClientLet < WEBrick::HTTPServlet::AbstractServlet
86
+ def initialize(controller)
87
+ @controller = controller
88
+ end
89
+
90
+ def get_instance(*args)
91
+ self
92
+ end
93
+
94
+ def require_path_info?
95
+ false
96
+ end
97
+
98
+ def do_GET(req, res)
99
+ raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed."
100
+ end
101
+
102
+ def do_POST(req, res)
103
+ raise NotImplementedError
104
+ end
105
+ end
106
+
107
+ class AbstractServer
108
+ include ClientTest
109
+ include Singleton
110
+ attr :container
111
+ def initialize
112
+ @container = Container.new
113
+ @clientlet = create_clientlet(@container)
114
+ log = WEBrick::BasicLog.new(NullLogOut.new)
115
+ @server = WEBrick::HTTPServer.new(:Port => server_port, :Logger => log, :AccessLog => log)
116
+ @server.mount('/', @clientlet)
117
+ @thr = Thread.new { @server.start }
118
+ until @server.status == :Running; end
119
+ at_exit { @server.stop; @thr.join }
120
+ end
121
+
122
+ protected
123
+ def create_clientlet
124
+ raise NotImplementedError
125
+ end
126
+
127
+ def server_port
128
+ raise NotImplementedError
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+ require 'soap/rpc/element'
3
+
4
+ class SoapTestError < StandardError
5
+ end
6
+
7
+ class AbstractSoapTest < Test::Unit::TestCase
8
+ def default_test
9
+ end
10
+
11
+ protected
12
+ def service_name
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def do_soap_call(public_method_name, *args)
17
+ mapper = @container.class.soap_mapper
18
+ param_def = []
19
+ i = 1
20
+ args.each do |arg|
21
+ mapping = mapper.lookup(arg.class)
22
+ param_def << ["in", "param#{i}", mapping.registry_mapping]
23
+ i += 1
24
+ end
25
+ qname = XSD::QName.new('urn:ActionWebService', public_method_name)
26
+ request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
27
+ soap_args = []
28
+ i = 1
29
+ args.each do |arg|
30
+ soap_args << ["param#{i}", SOAP::Mapping.obj2soap(arg)]
31
+ i += 1
32
+ end
33
+ request.set_param(soap_args)
34
+ header = SOAP::SOAPHeader.new
35
+ body = SOAP::SOAPBody.new(request)
36
+ envelope = SOAP::SOAPEnvelope.new(header, body)
37
+ raw_request = SOAP::Processor.marshal(envelope)
38
+ test_request = ActionController::TestRequest.new
39
+ test_request.request_parameters['action'] = service_name
40
+ test_request.env['REQUEST_METHOD'] = "POST"
41
+ test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
42
+ test_request.env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{public_method_name}"
43
+ test_request.env['RAW_POST_DATA'] = raw_request
44
+ test_response = ActionController::TestResponse.new
45
+ response = yield test_request, test_response
46
+ raw_body = response.respond_to?(:body) ? response.body : response.raw_body
47
+ envelope = SOAP::Processor.unmarshal(raw_body)
48
+ if envelope
49
+ if envelope.body.response
50
+ SOAP::Mapping.soap2obj(envelope.body.response)
51
+ else
52
+ nil
53
+ end
54
+ else
55
+ raise(SoapTestError, "empty/invalid body from server")
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'test/unit'
4
+ require 'action_web_service'
5
+ require 'action_controller'
6
+ require 'action_controller/test_process'
7
+
8
+ ActionController::Base.logger = nil
9
+ ActionController::Base.ignore_missing_templates = true
data/test/api_test.rb ADDED
@@ -0,0 +1,52 @@
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']
11
+ api_method :class_types, :expects => [TrueClass, Bignum, String]
12
+ end
13
+ end
14
+
15
+ class TC_API < Test::Unit::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({:expects=>nil, :returns=>nil}, API.api_methods[:void])
39
+ assert_equal({:expects=>[String], :returns=>[String]}, API.api_methods[:expects_and_returns])
40
+ assert_equal({:expects=>[Integer, TrueClass], :returns=>nil}, API.api_methods[:expects])
41
+ assert_equal({:expects=>nil, :returns=>[Integer, [String]]}, API.api_methods[:returns])
42
+ assert_equal({:expects=>[{:appkey=>Integer}, {:publish=>TrueClass}], :returns=>nil}, API.api_methods[:named_signature])
43
+ assert_equal({:expects=>[Integer, String, TrueClass], :returns=>nil}, API.api_methods[:string_types])
44
+ assert_equal({:expects=>[TrueClass, Bignum, String], :returns=>nil}, API.api_methods[:class_types])
45
+ end
46
+
47
+ def test_not_instantiable
48
+ assert_raises(NoMethodError) do
49
+ API.new
50
+ end
51
+ end
52
+ end
data/test/base_test.rb ADDED
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/abstract_unit'
2
+
3
+ module BaseTest
4
+ class API < ActionWebService::API::Base
5
+ api_method :add, :expects => [:int, :int], :returns => [:int]
6
+ api_method :void
7
+ end
8
+
9
+ class PristineAPI < ActionWebService::API::Base
10
+ inflect_names false
11
+
12
+ api_method :add
13
+ api_method :under_score
14
+ end
15
+
16
+ class Service < ActionWebService::Base
17
+ web_service_api API
18
+
19
+ def add(a, b)
20
+ end
21
+
22
+ def void
23
+ end
24
+ end
25
+
26
+ class PristineService < ActionWebService::Base
27
+ web_service_api PristineAPI
28
+
29
+ def add
30
+ end
31
+
32
+ def under_score
33
+ end
34
+ end
35
+ end
36
+
37
+ class TC_Base < Test::Unit::TestCase
38
+ def test_options
39
+ assert(BaseTest::PristineService.web_service_api.inflect_names == false)
40
+ assert(BaseTest::Service.web_service_api.inflect_names == true)
41
+ end
42
+ end
@@ -0,0 +1,93 @@
1
+ require File.dirname(__FILE__) + '/abstract_client'
2
+
3
+
4
+ module ClientSoapTest
5
+ PORT = 8998
6
+
7
+ class SoapClientLet < 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_CONTENTTYPE'] = 'text/xml'
13
+ test_request.env['HTTP_SOAPACTION'] = req.header['soapaction'][0]
14
+ test_request.env['RAW_POST_DATA'] = req.body
15
+ protocol_request = @controller.protocol_request(test_request)
16
+ response = @controller.dispatch_request(protocol_request)
17
+ res.header['content-type'] = 'text/xml'
18
+ res.body = response.raw_body
19
+ rescue Exception => e
20
+ $stderr.puts e.message
21
+ $stderr.puts e.backtrace.join("\n")
22
+ end
23
+ end
24
+
25
+ class ClientContainer < ActionController::Base
26
+ web_client_api :client, :soap, "http://localhost:#{PORT}/client/api", :api => ClientTest::API
27
+
28
+ def get_client
29
+ client
30
+ end
31
+ end
32
+
33
+ class SoapServer < ClientTest::AbstractServer
34
+ def create_clientlet(controller)
35
+ SoapClientLet.new(controller)
36
+ end
37
+
38
+ def server_port
39
+ PORT
40
+ end
41
+ end
42
+ end
43
+
44
+ class TC_ClientSoap < Test::Unit::TestCase
45
+ include ClientTest
46
+ include ClientSoapTest
47
+
48
+ def setup
49
+ @server = SoapServer.instance
50
+ @container = @server.container
51
+ @client = ActionWebService::Client::Soap.new(API, "http://localhost:#{@server.server_port}/client/api")
52
+ end
53
+
54
+ def test_void
55
+ assert(@container.value_void.nil?)
56
+ @client.void
57
+ assert(!@container.value_void.nil?)
58
+ end
59
+
60
+ def test_normal
61
+ assert(@container.value_normal.nil?)
62
+ assert_equal(5, @client.normal(5, 6))
63
+ assert_equal([5, 6], @container.value_normal)
64
+ end
65
+
66
+ def test_array_return
67
+ assert(@container.value_array_return.nil?)
68
+ new_person = Person.new
69
+ new_person.firstnames = ["one", "two"]
70
+ new_person.lastname = "last"
71
+ assert_equal([new_person], @client.array_return)
72
+ assert_equal([new_person], @container.value_array_return)
73
+ end
74
+
75
+ def test_struct_pass
76
+ assert(@container.value_struct_pass.nil?)
77
+ new_person = Person.new
78
+ new_person.firstnames = ["one", "two"]
79
+ new_person.lastname = "last"
80
+ assert_equal(true, @client.struct_pass([new_person]))
81
+ assert_equal([[new_person]], @container.value_struct_pass)
82
+ end
83
+
84
+ def test_client_container
85
+ assert_equal(50, ClientContainer.new.get_client.client_container)
86
+ end
87
+
88
+ def test_named_parameters
89
+ assert(@container.value_named_parameters.nil?)
90
+ assert(@client.named_parameters("key", 5).nil?)
91
+ assert_equal(["key", 5], @container.value_named_parameters)
92
+ end
93
+ end
@@ -0,0 +1,92 @@
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_CONTENTTYPE'] = 'text/xml'
13
+ test_request.env['RAW_POST_DATA'] = req.body
14
+ protocol_request = @controller.protocol_request(test_request)
15
+ response = @controller.dispatch_request(protocol_request)
16
+ res.header['content-type'] = 'text/xml'
17
+ res.body = response.raw_body
18
+ rescue Exception => e
19
+ $stderr.puts e.message
20
+ $stderr.puts e.backtrace.join("\n")
21
+ end
22
+ end
23
+
24
+ class ClientContainer < ActionController::Base
25
+ web_client_api :client, :xmlrpc, "http://localhost:#{PORT}/client/api", :api => ClientTest::API
26
+
27
+ def get_client
28
+ client
29
+ end
30
+ end
31
+
32
+ class XmlRpcServer < ClientTest::AbstractServer
33
+ def create_clientlet(controller)
34
+ XmlRpcClientLet.new(controller)
35
+ end
36
+
37
+ def server_port
38
+ PORT
39
+ end
40
+ end
41
+ end
42
+
43
+ class TC_ClientXmlRpc < Test::Unit::TestCase
44
+ include ClientTest
45
+ include ClientXmlRpcTest
46
+
47
+ def setup
48
+ @server = XmlRpcServer.instance
49
+ @container = @server.container
50
+ @client = ActionWebService::Client::XmlRpc.new(API, "http://localhost:#{@server.server_port}/client/api")
51
+ end
52
+
53
+ def test_void
54
+ assert(@container.value_void.nil?)
55
+ @client.void
56
+ assert(!@container.value_void.nil?)
57
+ end
58
+
59
+ def test_normal
60
+ assert(@container.value_normal.nil?)
61
+ assert_equal(5, @client.normal(5, 6))
62
+ assert_equal([5, 6], @container.value_normal)
63
+ end
64
+
65
+ def test_array_return
66
+ assert(@container.value_array_return.nil?)
67
+ new_person = Person.new
68
+ new_person.firstnames = ["one", "two"]
69
+ new_person.lastname = "last"
70
+ assert_equal([new_person], @client.array_return)
71
+ assert_equal([new_person], @container.value_array_return)
72
+ end
73
+
74
+ def test_struct_pass
75
+ assert(@container.value_struct_pass.nil?)
76
+ new_person = Person.new
77
+ new_person.firstnames = ["one", "two"]
78
+ new_person.lastname = "last"
79
+ assert_equal(true, @client.struct_pass([new_person]))
80
+ assert_equal([[new_person]], @container.value_struct_pass)
81
+ end
82
+
83
+ def test_client_container
84
+ assert_equal(50, ClientContainer.new.get_client.client_container)
85
+ end
86
+
87
+ def test_named_parameters
88
+ assert(@container.value_named_parameters.nil?)
89
+ assert_equal(true, @client.named_parameters("xxx", 7))
90
+ assert_equal(["xxx", 7], @container.value_named_parameters)
91
+ end
92
+ end