actionwebservice 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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