require File.dirname(__FILE__) + '/abstract_unit'
module DispatcherTest
class Node < ActiveRecord::Base
def initialize(*args)
super(*args)
@new_record = false
end
class << self
def name
"DispatcherTest::Node"
end
def columns(*args)
[
ActiveRecord::ConnectionAdapters::Column.new('id', 0, 'int'),
ActiveRecord::ConnectionAdapters::Column.new('name', nil, 'string'),
ActiveRecord::ConnectionAdapters::Column.new('description', nil, 'string'),
]
end
def connection
self
end
end
end
class Person < ActionWebService::Struct
member :id, :int
member :name, :string
end
class API < ActionWebService::API::Base
api_method :add, :expects => [:int, :int], :returns => [:int]
api_method :interceptee
api_method :struct_return, :returns => [[Node]]
api_method :void
end
class DirectAPI < ActionWebService::API::Base
api_method :add, :expects => [{:a=>:int}, {:b=>:int}], :returns => [:int]
api_method :before_filtered
api_method :after_filtered, :returns => [[:int]]
api_method :struct_return, :returns => [[Node]]
api_method :base_struct_return, :returns => [[Person]]
api_method :thrower
api_method :void
end
class VirtualAPI < ActionWebService::API::Base
default_api_method :fallback
end
class Service < ActionWebService::Base
web_service_api API
before_invocation :do_intercept, :only => [:interceptee]
attr :added
attr :intercepted
attr :void_called
def initialize
@void_called = false
end
def add(a, b)
@added = a + b
end
def interceptee
@intercepted = false
end
def struct_return
n1 = Node.new('id' => 1, 'name' => 'node1', 'description' => 'Node 1')
n2 = Node.new('id' => 2, 'name' => 'node2', 'description' => 'Node 2')
[n1, n2]
end
def void(*args)
@void_called = args
end
def do_intercept(name, args)
[false, "permission denied"]
end
end
class MTAPI < ActionWebService::API::Base
inflect_names false
api_method :getCategories, :returns => [[:string]]
end
class BloggerAPI < ActionWebService::API::Base
inflect_names false
api_method :getCategories, :returns => [[:string]]
end
class MTService < ActionWebService::Base
web_service_api MTAPI
def getCategories
["mtCat1", "mtCat2"]
end
end
class BloggerService < ActionWebService::Base
web_service_api BloggerAPI
def getCategories
["bloggerCat1", "bloggerCat2"]
end
end
class AbstractController < ActionController::Base
def generate_wsdl
to_wsdl
end
end
class DelegatedController < AbstractController
web_service_dispatching_mode :delegated
web_service(:test_service) { @service ||= Service.new; @service }
end
class LayeredController < AbstractController
web_service_dispatching_mode :layered
web_service(:mt) { @mt_service ||= MTService.new; @mt_service }
web_service(:blogger) { @blogger_service ||= BloggerService.new; @blogger_service }
end
class DirectController < AbstractController
web_service_api DirectAPI
web_service_dispatching_mode :direct
before_filter :alwaysfail, :only => [:before_filtered]
after_filter :alwaysok, :only => [:after_filtered]
attr :added
attr :before_filter_called
attr :before_filter_target_called
attr :after_filter_called
attr :after_filter_target_called
attr :void_called
def initialize
@before_filter_called = false
@before_filter_target_called = false
@after_filter_called = false
@after_filter_target_called = false
@void_called = false
end
def add
@added = @params['a'] + @params['b']
end
def before_filtered
@before_filter_target_called = true
end
def after_filtered
@after_filter_target_called = true
[5, 6, 7]
end
def thrower
raise "Hi, I'm an exception"
end
def struct_return
n1 = Node.new('id' => 1, 'name' => 'node1', 'description' => 'Node 1')
n2 = Node.new('id' => 2, 'name' => 'node2', 'description' => 'Node 2')
[n1, n2]
end
def base_struct_return
p1 = Person.new('id' => 1, 'name' => 'person1')
p2 = Person.new('id' => 2, 'name' => 'person2')
[p1, p2]
end
def void
@void_called = @method_params
end
protected
def alwaysfail
@before_filter_called = true
false
end
def alwaysok
@after_filter_called = true
end
end
class VirtualController < AbstractController
web_service_api VirtualAPI
def fallback
"fallback!"
end
end
end
module DispatcherCommonTests
def test_direct_dispatching
assert_equal(70, do_method_call(@direct_controller, 'Add', 20, 50))
assert_equal(70, @direct_controller.added)
assert(@direct_controller.void_called == false)
case @encoder
when WS::Encoding::SoapRpcEncoding
assert(do_method_call(@direct_controller, 'Void', 3, 4, 5).nil?)
when WS::Encoding::XmlRpcEncoding
assert(do_method_call(@direct_controller, 'Void', 3, 4, 5) == true)
end
assert(@direct_controller.void_called == [])
result = do_method_call(@direct_controller, 'BaseStructReturn')
case @encoder
when WS::Encoding::SoapRpcEncoding
assert(result[0].is_a?(DispatcherTest::Person))
assert(result[1].is_a?(DispatcherTest::Person))
when WS::Encoding::XmlRpcEncoding
assert(result[0].is_a?(Hash))
assert(result[1].is_a?(Hash))
end
end
def test_direct_entrypoint
assert(@direct_controller.respond_to?(:api))
end
def test_virtual_dispatching
assert_equal("fallback!", do_method_call(@virtual_controller, 'VirtualOne'))
assert_equal("fallback!", do_method_call(@virtual_controller, 'VirtualTwo'))
end
def test_direct_filtering
assert_equal(false, @direct_controller.before_filter_called)
assert_equal(false, @direct_controller.before_filter_target_called)
do_method_call(@direct_controller, 'BeforeFiltered')
assert_equal(true, @direct_controller.before_filter_called)
assert_equal(false, @direct_controller.before_filter_target_called)
assert_equal(false, @direct_controller.after_filter_called)
assert_equal(false, @direct_controller.after_filter_target_called)
assert_equal([5, 6, 7], do_method_call(@direct_controller, 'AfterFiltered'))
assert_equal(true, @direct_controller.after_filter_called)
assert_equal(true, @direct_controller.after_filter_target_called)
end
def test_delegated_dispatching
assert_equal(130, do_method_call(@delegated_controller, 'Add', 50, 80))
service = @delegated_controller.web_service_object(:test_service)
assert_equal(130, service.added)
@delegated_controller.web_service_exception_reporting = true
assert(service.intercepted.nil?)
result = do_method_call(@delegated_controller, 'Interceptee')
assert(service.intercepted.nil?)
assert(is_exception?(result))
assert_match(/permission denied/, exception_message(result))
result = do_method_call(@delegated_controller, 'NonExistentMethod')
assert(is_exception?(result))
assert_match(/NonExistentMethod/, exception_message(result))
assert(service.void_called == false)
case @encoder
when WS::Encoding::SoapRpcEncoding
assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5).nil?)
when WS::Encoding::XmlRpcEncoding
assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5) == true)
end
assert(service.void_called == [])
end
def test_garbage_request
[@direct_controller, @delegated_controller].each do |controller|
controller.class.web_service_exception_reporting = true
send_garbage_request = lambda do
request = create_ap_request(controller, 'invalid request body', 'xxx')
response = ActionController::TestResponse.new
controller.process(request, response)
# puts response.body
assert(response.headers['Status'] =~ /^500/)
end
send_garbage_request.call
controller.class.web_service_exception_reporting = false
send_garbage_request.call
end
end
def test_exception_marshaling
@direct_controller.web_service_exception_reporting = true
result = do_method_call(@direct_controller, 'Thrower')
assert(is_exception?(result))
assert_equal("Hi, I'm an exception", exception_message(result))
@direct_controller.web_service_exception_reporting = false
result = do_method_call(@direct_controller, 'Thrower')
assert(exception_message(result) != "Hi, I'm an exception")
end
def test_ar_struct_return
[@direct_controller, @delegated_controller].each do |controller|
result = do_method_call(controller, 'StructReturn')
case @encoder
when WS::Encoding::SoapRpcEncoding
assert(result[0].is_a?(DispatcherTest::Node))
assert(result[1].is_a?(DispatcherTest::Node))
assert_equal('node1', result[0].name)
assert_equal('node2', result[1].name)
when WS::Encoding::XmlRpcEncoding
assert(result[0].is_a?(Hash))
assert(result[1].is_a?(Hash))
assert_equal('node1', result[0]['name'])
assert_equal('node2', result[1]['name'])
end
end
end
protected
def service_name(container)
raise NotImplementedError
end
def exception_message(obj)
raise NotImplementedError
end
def is_exception?(obj)
raise NotImplementedError
end
def do_method_call(container, public_method_name, *params)
mode = container.web_service_dispatching_mode
case mode
when :direct
api = container.class.web_service_api
when :delegated
api = container.web_service_object(service_name(container)).class.web_service_api
when :layered
service_name = nil
if public_method_name =~ /^([^\.]+)\.(.*)$/
service_name = $1
end
api = container.web_service_object(service_name.to_sym).class.web_service_api
end
info = api.api_methods[method_name] || {}
params = params.dup
((info[:expects] || []) + (info[:returns] || [])).each do |spec|
@marshaler.register_type(spec)
end
expects = info[:expects]
(0..(params.length-1)).each do |i|
type_binding = @marshaler.register_type(expects ? expects[i] : params[i].class)
info = WS::ParamInfo.create(expects ? expects[i] : params[i].class, type_binding, i)
params[i] = @marshaler.marshal(WS::Param.new(params[i], info))
end
body = @encoder.encode_rpc_call(public_method_name, params)
# puts body
ap_request = create_ap_request(container, body, public_method_name, *params)
ap_response = ActionController::TestResponse.new
container.process(ap_request, ap_response)
# puts ap_response.body
public_method_name, return_value = @encoder.decode_rpc_response(ap_response.body)
@marshaler.unmarshal(return_value).value
end
end