actionservice 0.2.100 → 0.2.102
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.
- data/ChangeLog +3 -0
- data/README +39 -12
- data/Rakefile +7 -4
- data/TODO +12 -29
- data/examples/soap/app/controllers/search_controller.rb +1 -2
- data/examples/soap/lib/google_search_service.rb +5 -2
- data/lib/action_service/base.rb +2 -57
- data/lib/action_service/container.rb +88 -36
- data/lib/action_service/exporting.rb +140 -0
- data/lib/action_service/invocation.rb +46 -16
- data/lib/action_service/protocol/abstract.rb +80 -50
- data/lib/action_service/protocol/registry.rb +3 -5
- data/lib/action_service/protocol/soap.rb +156 -80
- data/lib/action_service/protocol/xmlrpc.rb +77 -47
- data/lib/action_service/router/action_controller.rb +41 -29
- data/lib/action_service/router/wsdl.rb +149 -132
- data/lib/action_service.rb +5 -0
- data/test/abstract_soap.rb +47 -0
- data/test/base_test.rb +31 -29
- data/test/container_test.rb +53 -32
- data/test/invocation_test.rb +97 -86
- data/test/protocol_registry_test.rb +9 -10
- data/test/protocol_soap_test.rb +125 -159
- data/test/protocol_xmlrpc_test.rb +61 -58
- data/test/router_action_controller_test.rb +52 -83
- data/test/router_wsdl_test.rb +31 -25
- data/test/struct_test.rb +11 -9
- metadata +15 -3
- data/CHANGELOG +0 -3
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
+
require 'soap/rpc/element'
|
3
|
+
|
4
|
+
class AbstractSoapTest < Test::Unit::TestCase
|
5
|
+
def default_test
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
def service_name
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
def do_soap_call(public_method_name, *args)
|
14
|
+
mapper = @container.class.soap_mapper
|
15
|
+
param_def = []
|
16
|
+
i = 1
|
17
|
+
args.each do |arg|
|
18
|
+
mapping = mapper.lookup(arg.class)
|
19
|
+
param_def << ["in", "param#{i}", mapping.registry_mapping]
|
20
|
+
i += 1
|
21
|
+
end
|
22
|
+
qname = XSD::QName.new('urn:ActionService', public_method_name)
|
23
|
+
request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
|
24
|
+
soap_args = []
|
25
|
+
i = 1
|
26
|
+
args.each do |arg|
|
27
|
+
soap_args << ["param#{i}", SOAP::Mapping.obj2soap(arg)]
|
28
|
+
i += 1
|
29
|
+
end
|
30
|
+
request.set_param(soap_args)
|
31
|
+
header = SOAP::SOAPHeader.new
|
32
|
+
body = SOAP::SOAPBody.new(request)
|
33
|
+
envelope = SOAP::SOAPEnvelope.new(header, body)
|
34
|
+
raw_request = SOAP::Processor.marshal(envelope)
|
35
|
+
test_request = ActionController::TestRequest.new
|
36
|
+
test_request.request_parameters['action'] = service_name
|
37
|
+
test_request.env['REQUEST_METHOD'] = "POST"
|
38
|
+
test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
|
39
|
+
test_request.env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{public_method_name}"
|
40
|
+
test_request.env['RAW_POST_DATA'] = raw_request
|
41
|
+
test_response = ActionController::TestResponse.new
|
42
|
+
response = yield test_request, test_response
|
43
|
+
raw_body = response.respond_to?(:body) ? response.body : response.raw_body
|
44
|
+
envelope = SOAP::Processor.unmarshal(raw_body)
|
45
|
+
SOAP::Mapping.soap2obj(envelope.body.response) if envelope.body.response
|
46
|
+
end
|
47
|
+
end
|
data/test/base_test.rb
CHANGED
@@ -1,51 +1,53 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/abstract_unit'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
module BaseTest
|
4
|
+
class Service < ActionService::Base
|
5
|
+
def add(a, b)
|
6
|
+
end
|
7
|
+
|
8
|
+
def void
|
9
|
+
end
|
10
|
+
|
11
|
+
export :add, :expects => [Integer, Integer], :returns => [Integer]
|
12
|
+
export :void
|
13
|
+
end
|
14
|
+
|
15
|
+
class BaseTest::UnmangledOrReportedService < ActionService::Base
|
16
|
+
export_name_mangling false
|
17
|
+
report_exceptions false
|
18
|
+
|
19
|
+
def custom_name_casing
|
20
|
+
end
|
21
|
+
|
22
|
+
export :custom_name_casing
|
5
23
|
end
|
6
|
-
|
7
|
-
def void
|
8
|
-
end
|
9
|
-
|
10
|
-
export :add, :expects => [Integer, Integer], :returns => [Integer]
|
11
|
-
export :void
|
12
|
-
end
|
13
|
-
|
14
|
-
class UnmangledOrReportedService < ActionService::Base
|
15
|
-
export_name_mangling false
|
16
|
-
report_exceptions false
|
17
|
-
|
18
|
-
def custom_name_casing
|
19
|
-
end
|
20
|
-
|
21
|
-
export :custom_name_casing
|
22
24
|
end
|
23
25
|
|
24
|
-
class
|
26
|
+
class TC_Base < Test::Unit::TestCase
|
25
27
|
def test_exports
|
26
|
-
assert(
|
27
|
-
assert(
|
28
|
+
assert(BaseTest::Service.has_export?(:add))
|
29
|
+
assert(BaseTest::Service.exports.keys.map{|x|x.to_s}.sort == ['add', 'void'])
|
28
30
|
end
|
29
31
|
|
30
32
|
def test_signatures
|
31
|
-
expects =
|
33
|
+
expects = BaseTest::Service.exports[:add][:expects]
|
32
34
|
assert(expects == [Integer, Integer])
|
33
|
-
returns =
|
35
|
+
returns = BaseTest::Service.exports[:add][:returns]
|
34
36
|
assert(returns == [Integer])
|
35
37
|
end
|
36
38
|
|
37
39
|
def test_options
|
38
|
-
assert(UnmangledOrReportedService.export_name_mangling == false)
|
39
|
-
assert(UnmangledOrReportedService.report_exceptions == false)
|
40
|
+
assert(BaseTest::UnmangledOrReportedService.export_name_mangling == false)
|
41
|
+
assert(BaseTest::UnmangledOrReportedService.report_exceptions == false)
|
40
42
|
end
|
41
43
|
|
42
44
|
def test_mangling
|
43
|
-
assert(
|
44
|
-
assert(
|
45
|
-
assert(UnmangledOrReportedService.public_export_name(:custom_name_casing) == 'custom_name_casing')
|
45
|
+
assert(BaseTest::Service.has_public_export?('Add'))
|
46
|
+
assert(BaseTest::Service.internal_export_name('Add') == :add)
|
47
|
+
assert(BaseTest::UnmangledOrReportedService.public_export_name(:custom_name_casing) == 'custom_name_casing')
|
46
48
|
end
|
47
49
|
|
48
50
|
def test_missing_method
|
49
|
-
assert(
|
51
|
+
assert(BaseTest::Service.has_public_export?('NoSuchMethod') == false)
|
50
52
|
end
|
51
53
|
end
|
data/test/container_test.rb
CHANGED
@@ -1,46 +1,67 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/abstract_unit'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
3
|
+
module ContainerTest
|
4
|
+
class AbstractContainer
|
5
|
+
end
|
6
|
+
|
7
|
+
AbstractContainer.class_eval do
|
8
|
+
include ActionService::Exporting
|
9
|
+
include ActionService::Container
|
10
|
+
end
|
11
|
+
|
12
|
+
$immediate_service = Object.new
|
13
|
+
$deferred_service = Object.new
|
14
|
+
|
15
|
+
class DelegateContainer < AbstractContainer
|
16
|
+
service_dispatching_mode :delegated
|
17
|
+
|
18
|
+
attr :flag
|
19
|
+
attr :previous_flag
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@previous_flag = nil
|
23
|
+
@flag = true
|
24
|
+
end
|
25
|
+
|
26
|
+
service :immediate_service, $immediate_service
|
27
|
+
service(:deferred_service) { @previous_flag = @flag; @flag = false; $deferred_service }
|
28
|
+
end
|
29
|
+
|
30
|
+
class DirectContainer < AbstractContainer
|
31
|
+
service_dispatching_mode :direct
|
32
|
+
export_name_mangling false
|
33
|
+
|
34
|
+
def findNodes
|
35
|
+
end
|
36
|
+
|
37
|
+
export :findNodes
|
20
38
|
end
|
21
|
-
|
22
|
-
service :immediate_service, $immediate_service
|
23
|
-
service(:deferred_service) { @previous_flag = @flag; @flag = false; $deferred_service }
|
24
39
|
end
|
25
40
|
|
26
|
-
class
|
41
|
+
class TC_Container < Test::Unit::TestCase
|
27
42
|
def setup
|
28
|
-
@
|
43
|
+
@delegate_container = ContainerTest::DelegateContainer.new
|
44
|
+
@direct_container = ContainerTest::DirectContainer.new
|
29
45
|
end
|
30
46
|
|
31
47
|
def test_registration
|
32
|
-
assert(
|
33
|
-
assert(
|
34
|
-
assert(!
|
48
|
+
assert(ContainerTest::DelegateContainer.has_service?(:immediate_service))
|
49
|
+
assert(ContainerTest::DelegateContainer.has_service?(:deferred_service))
|
50
|
+
assert(!ContainerTest::DelegateContainer.has_service?(:fake_service))
|
35
51
|
end
|
36
52
|
|
37
53
|
def test_service_object
|
38
|
-
assert(@
|
39
|
-
assert(@
|
40
|
-
assert(@
|
41
|
-
assert(@
|
42
|
-
assert(@
|
43
|
-
assert(@
|
44
|
-
assert(@
|
54
|
+
assert(@delegate_container.flag == true)
|
55
|
+
assert(@delegate_container.service_object(:immediate_service) == $immediate_service)
|
56
|
+
assert(@delegate_container.previous_flag.nil?)
|
57
|
+
assert(@delegate_container.flag == true)
|
58
|
+
assert(@delegate_container.service_object(:deferred_service) == $deferred_service)
|
59
|
+
assert(@delegate_container.previous_flag == true)
|
60
|
+
assert(@delegate_container.flag == false)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_direct_container
|
64
|
+
assert(ContainerTest::DirectContainer.has_export?(:findNodes))
|
65
|
+
assert(!ContainerTest::DirectContainer.has_export?(:fakeExport))
|
45
66
|
end
|
46
67
|
end
|
data/test/invocation_test.rb
CHANGED
@@ -1,105 +1,108 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/abstract_unit'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@before_invoked = nil
|
11
|
-
@after_invoked = nil
|
12
|
-
@only_invoked = nil
|
13
|
-
@invocation_result = nil
|
14
|
-
end
|
15
|
-
|
16
|
-
def add(a, b)
|
17
|
-
a + b
|
18
|
-
end
|
19
|
-
|
20
|
-
def transmogrify(str)
|
21
|
-
str.upcase
|
22
|
-
end
|
3
|
+
module InvocationTest
|
4
|
+
class Service < ActionService::Base
|
5
|
+
attr_accessor :before_invoked
|
6
|
+
attr_accessor :after_invoked
|
7
|
+
attr_accessor :only_invoked
|
8
|
+
attr_accessor :invocation_result
|
23
9
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def no_before
|
31
|
-
5
|
32
|
-
end
|
33
|
-
|
34
|
-
def no_after
|
35
|
-
end
|
36
|
-
|
37
|
-
def only_one
|
38
|
-
end
|
39
|
-
|
40
|
-
def only_two
|
41
|
-
end
|
42
|
-
|
43
|
-
def not_exported
|
44
|
-
end
|
45
|
-
|
46
|
-
export :add, :expects => [Integer, Integer], :returns => [Integer]
|
47
|
-
export :transmogrify, :expects_and_returns => [String]
|
48
|
-
export :fail_with_reason
|
49
|
-
export :fail_generic
|
50
|
-
export :no_before
|
51
|
-
export :no_after
|
52
|
-
export :only_one
|
53
|
-
export :only_two
|
54
|
-
|
55
|
-
before_invocation :intercept_before, :except => [:no_before]
|
56
|
-
after_invocation :intercept_after, :except => [:no_after]
|
57
|
-
|
58
|
-
before_invocation :intercept_only, :only => [:only_one, :only_two]
|
59
|
-
|
60
|
-
protected
|
61
|
-
def intercept_before(name, args)
|
62
|
-
@before_invoked = name
|
63
|
-
return [false, "permission denied"] if name == :fail_with_reason
|
64
|
-
return false if name == :fail_generic
|
10
|
+
def initialize
|
11
|
+
@before_invoked = nil
|
12
|
+
@after_invoked = nil
|
13
|
+
@only_invoked = nil
|
14
|
+
@invocation_result = nil
|
65
15
|
end
|
66
|
-
|
67
|
-
def
|
68
|
-
|
69
|
-
@invocation_result = result
|
16
|
+
|
17
|
+
def add(a, b)
|
18
|
+
a + b
|
70
19
|
end
|
71
|
-
|
72
|
-
def
|
73
|
-
|
74
|
-
|
20
|
+
|
21
|
+
def transmogrify(str)
|
22
|
+
str.upcase
|
23
|
+
end
|
24
|
+
|
25
|
+
def fail_with_reason
|
26
|
+
end
|
27
|
+
|
28
|
+
def fail_generic
|
29
|
+
end
|
30
|
+
|
31
|
+
def no_before
|
32
|
+
5
|
33
|
+
end
|
34
|
+
|
35
|
+
def no_after
|
36
|
+
end
|
37
|
+
|
38
|
+
def only_one
|
39
|
+
end
|
40
|
+
|
41
|
+
def only_two
|
42
|
+
end
|
43
|
+
|
44
|
+
def not_exported
|
75
45
|
end
|
46
|
+
|
47
|
+
export :add, :expects => [Integer, Integer], :returns => [Integer]
|
48
|
+
export :transmogrify, :expects_and_returns => [String]
|
49
|
+
export :fail_with_reason
|
50
|
+
export :fail_generic
|
51
|
+
export :no_before
|
52
|
+
export :no_after
|
53
|
+
export :only_one
|
54
|
+
export :only_two
|
55
|
+
|
56
|
+
before_invocation :intercept_before, :except => [:no_before]
|
57
|
+
after_invocation :intercept_after, :except => [:no_after]
|
58
|
+
|
59
|
+
before_invocation :intercept_only, :only => [:only_one, :only_two]
|
60
|
+
|
61
|
+
protected
|
62
|
+
def intercept_before(name, args)
|
63
|
+
@before_invoked = name
|
64
|
+
return [false, "permission denied"] if name == :fail_with_reason
|
65
|
+
return false if name == :fail_generic
|
66
|
+
end
|
67
|
+
|
68
|
+
def intercept_after(name, args, result)
|
69
|
+
@after_invoked = name
|
70
|
+
@invocation_result = result
|
71
|
+
end
|
72
|
+
|
73
|
+
def intercept_only(name, args)
|
74
|
+
raise "Interception error" unless name == :only_one || name == :only_two
|
75
|
+
@only_invoked = name
|
76
|
+
end
|
77
|
+
end
|
76
78
|
end
|
77
79
|
|
78
|
-
class
|
80
|
+
class TC_Invocation < Test::Unit::TestCase
|
81
|
+
include ActionService::Invocation
|
79
82
|
|
80
83
|
def setup
|
81
|
-
@service =
|
84
|
+
@service = InvocationTest::Service.new
|
82
85
|
end
|
83
86
|
|
84
87
|
def test_invocation
|
85
|
-
assert(
|
86
|
-
assert(
|
87
|
-
assert_raises(
|
88
|
-
|
88
|
+
assert(perform_invocation(:add, 5, 10) == 15)
|
89
|
+
assert(perform_invocation(:transmogrify, "hello") == "HELLO")
|
90
|
+
assert_raises(InvocationError) do
|
91
|
+
perform_invocation(:not_exported)
|
89
92
|
end
|
90
|
-
assert_raises(
|
91
|
-
|
93
|
+
assert_raises(InvocationError) do
|
94
|
+
perform_invocation(:nonexistent_method_xyzzy)
|
92
95
|
end
|
93
96
|
end
|
94
97
|
|
95
98
|
def test_interceptor_registration
|
96
|
-
assert(
|
97
|
-
assert(
|
99
|
+
assert(InvocationTest::Service.before_invocation_interceptors.length == 2)
|
100
|
+
assert(InvocationTest::Service.after_invocation_interceptors.length == 1)
|
98
101
|
end
|
99
102
|
|
100
103
|
def test_interception
|
101
104
|
assert(@service.before_invoked.nil? && @service.after_invoked.nil? && @service.only_invoked.nil? && @service.invocation_result.nil?)
|
102
|
-
|
105
|
+
perform_invocation(:add, 20, 50)
|
103
106
|
assert(@service.before_invoked == :add)
|
104
107
|
assert(@service.after_invoked == :add)
|
105
108
|
assert(@service.invocation_result == 70)
|
@@ -107,14 +110,14 @@ class InvocationTest < Test::Unit::TestCase
|
|
107
110
|
|
108
111
|
def test_interception_canceling
|
109
112
|
reason = nil
|
110
|
-
|
113
|
+
perform_invocation(:fail_with_reason){|r| reason = r}
|
111
114
|
assert(@service.before_invoked == :fail_with_reason)
|
112
115
|
assert(@service.after_invoked.nil?)
|
113
116
|
assert(@service.invocation_result.nil?)
|
114
117
|
assert(reason == "permission denied")
|
115
118
|
reason = true
|
116
119
|
@service.before_invoked = @service.after_invoked = @service.invocation_result = nil
|
117
|
-
|
120
|
+
perform_invocation(:fail_generic){|r| reason = r}
|
118
121
|
assert(@service.before_invoked == :fail_generic)
|
119
122
|
assert(@service.after_invoked.nil?)
|
120
123
|
assert(@service.invocation_result.nil?)
|
@@ -122,12 +125,12 @@ class InvocationTest < Test::Unit::TestCase
|
|
122
125
|
end
|
123
126
|
|
124
127
|
def test_interception_except_conditions
|
125
|
-
|
128
|
+
perform_invocation(:no_before)
|
126
129
|
assert(@service.before_invoked.nil?)
|
127
130
|
assert(@service.after_invoked == :no_before)
|
128
131
|
assert(@service.invocation_result == 5)
|
129
132
|
@service.before_invoked = @service.after_invoked = @service.invocation_result = nil
|
130
|
-
|
133
|
+
perform_invocation(:no_after)
|
131
134
|
assert(@service.before_invoked == :no_after)
|
132
135
|
assert(@service.after_invoked.nil?)
|
133
136
|
assert(@service.invocation_result.nil?)
|
@@ -135,10 +138,18 @@ class InvocationTest < Test::Unit::TestCase
|
|
135
138
|
|
136
139
|
def test_interception_only_conditions
|
137
140
|
assert(@service.only_invoked.nil?)
|
138
|
-
|
141
|
+
perform_invocation(:only_one)
|
139
142
|
assert(@service.only_invoked == :only_one)
|
140
143
|
@service.only_invoked = nil
|
141
|
-
|
144
|
+
perform_invocation(:only_two)
|
142
145
|
assert(@service.only_invoked == :only_two)
|
143
146
|
end
|
147
|
+
|
148
|
+
private
|
149
|
+
def perform_invocation(method_name, *args, &block)
|
150
|
+
public_method_name = @service.class.public_export_name(method_name)
|
151
|
+
args ||= []
|
152
|
+
request = InvocationRequest.new(ConcreteInvocation, public_method_name, method_name, args)
|
153
|
+
@service.perform_invocation(request, &block)
|
154
|
+
end
|
144
155
|
end
|
@@ -13,21 +13,20 @@ module Foo
|
|
13
13
|
end
|
14
14
|
|
15
15
|
class FooFullProtocol < AbstractProtocol
|
16
|
-
def
|
17
|
-
|
16
|
+
def self.create_protocol_request(klass, request)
|
17
|
+
protocol = FooFullProtocol.new klass
|
18
|
+
ActionService::Protocol::ProtocolRequest.new(protocol, '', '', '', '')
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
22
|
class FooMinimalProtocol < AbstractProtocol
|
22
|
-
def
|
23
|
-
|
23
|
+
def self.create_protocol_request(klass, request)
|
24
|
+
protocol = FooMinimalProtocol.new klass
|
25
|
+
ActionService::Protocol::ProtocolRequest.new(protocol, '', '', '', '')
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
29
|
class FooMinimalProtocolTwo < AbstractProtocol
|
28
|
-
def request_supported?(request)
|
29
|
-
false
|
30
|
-
end
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
@@ -39,16 +38,16 @@ class ProtocolRegistry
|
|
39
38
|
header_and_body_protocols + body_only_protocols
|
40
39
|
end
|
41
40
|
|
42
|
-
def
|
41
|
+
def protocol_request
|
43
42
|
probe_request_protocol(nil)
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
47
46
|
|
48
|
-
class
|
47
|
+
class TC_ProtocolRegistry < Test::Unit::TestCase
|
49
48
|
def test_registration
|
50
49
|
registry = ProtocolRegistry.new
|
51
50
|
assert(registry.all_protocols.length == 4)
|
52
|
-
assert(registry.
|
51
|
+
assert(registry.protocol_request.protocol.is_a?(Foo::FooFullProtocol))
|
53
52
|
end
|
54
53
|
end
|