aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionwebservice/CHANGELOG4
-rw-r--r--actionwebservice/TODO3
-rw-r--r--actionwebservice/lib/action_web_service/dispatcher/abstract.rb8
-rw-r--r--actionwebservice/lib/action_web_service/test_invoke.rb130
-rw-r--r--actionwebservice/test/dispatcher_action_controller_soap_test.rb2
-rw-r--r--actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb2
-rw-r--r--actionwebservice/test/test_invoke_test.rb77
7 files changed, 223 insertions, 3 deletions
diff --git a/actionwebservice/CHANGELOG b/actionwebservice/CHANGELOG
index f823c293ba..5dbae2ff88 100644
--- a/actionwebservice/CHANGELOG
+++ b/actionwebservice/CHANGELOG
@@ -1,5 +1,9 @@
*0.6.0* (Unreleased)
+* Add action_controller/test_invoke, used for integrating AWS with the Rails testing infrastructure
+
+* Allow passing through options to the SOAP RPC driver for the SOAP client
+
* Make the SOAP WS marshaler use #columns to decide which fields to marshal as well, avoids providing attributes brought in by associations
* Add <tt>ActionWebService::API::Base.allow_active_record_expects</tt> option, with a default of false. Setting this to true will allow specifying ActiveRecord::Base model classes in <tt>:expects</tt>. API writers should take care to validate the received ActiveRecord model objects when turning it on, and/or have an authentication mechanism in place to reduce the security risk.
diff --git a/actionwebservice/TODO b/actionwebservice/TODO
index 55c484b775..87d2a62c08 100644
--- a/actionwebservice/TODO
+++ b/actionwebservice/TODO
@@ -1,11 +1,12 @@
= 0.7.0
+ - WS Test Integration
- WS Scaffolding
- WS Generators
- - WS Test Integration
= 0.8.0
- Consumption of WSDL services
= Refactoring
+ - Port dispatcher tests to use test_invoke
- Don't have clean way to go from SOAP Class object to the xsd:NAME type
string -- NaHi possibly looking at remedying this situation
diff --git a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
index 641f291533..1df03d1777 100644
--- a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
+++ b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
@@ -12,6 +12,14 @@ module ActionWebService # :nodoc:
base.send(:include, ActionWebService::Dispatcher::InstanceMethods)
end
+ def self.layered_service_name(public_method_name) # :nodoc:
+ if public_method_name =~ /^([^\.]+)\.(.*)$/
+ $1
+ else
+ nil
+ end
+ end
+
module InstanceMethods # :nodoc:
private
def invoke_web_service_request(protocol_request)
diff --git a/actionwebservice/lib/action_web_service/test_invoke.rb b/actionwebservice/lib/action_web_service/test_invoke.rb
new file mode 100644
index 0000000000..44601c1c11
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/test_invoke.rb
@@ -0,0 +1,130 @@
+require 'test/unit'
+
+module Test
+ module Unit
+ class TestCase # :nodoc:
+ private
+ # invoke the specified API method
+ def invoke_direct(method_name, *args)
+ prepare_request('api', 'api', method_name, *args)
+ @controller.process(@request, @response)
+ decode_rpc_response
+ end
+ alias_method :invoke, :invoke_direct
+
+ # invoke the specified API method on the specified service
+ def invoke_delegated(service_name, method_name, *args)
+ prepare_request(service_name.to_s, service_name, method_name, *args)
+ @controller.process(@request, @response)
+ decode_rpc_response
+ end
+
+ # invoke the specified layered API method on the correct service
+ def invoke_layered(service_name, method_name, *args)
+ if protocol == :soap
+ raise "SOAP protocol support for :layered dispatching mode is not available"
+ end
+ prepare_request('api', service_name, method_name, *args)
+ @controller.process(@request, @response)
+ decode_rpc_response
+ end
+
+ # ---------------------- internal ---------------------------
+
+ def prepare_request(action, service_name, api_method_name, *args)
+ @request.request_parameters['action'] = action
+ @request.env['REQUEST_METHOD'] = 'POST'
+ @request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
+ @request.env['RAW_POST_DATA'] = encode_rpc_call(service_name, api_method_name, *args)
+ case protocol
+ when :soap
+ soap_action = "/#{@controller.controller_name}/#{service_name}/#{public_method_name(service_name, api_method_name)}"
+ @request.env['HTTP_SOAPACTION'] = soap_action
+ when :xmlrpc
+ @request.env.delete('HTTP_SOAPACTION')
+ end
+ end
+
+ def encode_rpc_call(service_name, api_method_name, *args)
+ case @controller.web_service_dispatching_mode
+ when :direct
+ api = @controller.class.web_service_api
+ when :delegated, :layered
+ api = @controller.web_service_object(service_name.to_sym).class.web_service_api
+ end
+ info = api.api_methods[api_method_name.to_sym]
+ ((info[:expects] || []) + (info[:returns] || [])).each do |spec|
+ marshaler.register_type spec
+ end
+ expects = info[:expects]
+ args = args.dup
+ (0..(args.length-1)).each do |i|
+ type_binding = marshaler.register_type(expects ? expects[i] : args[i].class)
+ info = WS::ParamInfo.create(expects ? expects[i] : args[i].class, type_binding, i)
+ args[i] = marshaler.marshal(WS::Param.new(args[i], info))
+ end
+ encoder.encode_rpc_call(public_method_name(service_name, api_method_name), args)
+ end
+
+ def decode_rpc_response
+ public_method_name, return_value = encoder.decode_rpc_response(@response.body)
+ result = marshaler.unmarshal(return_value).value
+ unless @return_exceptions
+ exception = is_exception?(result)
+ raise exception if exception
+ end
+ result
+ end
+
+ def public_method_name(service_name, api_method_name)
+ public_name = service_api(service_name).public_api_method_name(api_method_name)
+ if @controller.web_service_dispatching_mode == :layered
+ '%s.%s' % [service_name.to_s, public_name]
+ else
+ public_name
+ end
+ end
+
+ def service_api(service_name)
+ case @controller.web_service_dispatching_mode
+ when :direct
+ @controller.class.web_service_api
+ when :delegated, :layered
+ @controller.web_service_object(service_name.to_sym).class.web_service_api
+ end
+ end
+
+ def protocol
+ @protocol ||= :soap
+ end
+
+ def marshaler
+ case protocol
+ when :soap
+ @soap_marshaler ||= WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
+ when :xmlrpc
+ @xmlrpc_marshaler ||= WS::Marshaling::XmlRpcMarshaler.new
+ end
+ end
+
+ def encoder
+ case protocol
+ when :soap
+ @soap_encoder ||= WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
+ when :xmlrpc
+ @xmlrpc_encoder ||= WS::Encoding::XmlRpcEncoding.new
+ end
+ end
+
+ def is_exception?(obj)
+ case protocol
+ when :soap
+ (obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
+ obj.detail.cause.is_a?(Exception)) ? obj.detail.cause : nil
+ when :xmlrpc
+ obj.is_a?(XMLRPC::FaultException) ? obj : nil
+ end
+ end
+ end
+ end
+end
diff --git a/actionwebservice/test/dispatcher_action_controller_soap_test.rb b/actionwebservice/test/dispatcher_action_controller_soap_test.rb
index 6d50bbba8a..dd945972d6 100644
--- a/actionwebservice/test/dispatcher_action_controller_soap_test.rb
+++ b/actionwebservice/test/dispatcher_action_controller_soap_test.rb
@@ -62,7 +62,7 @@ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase
test_request = ActionController::TestRequest.new
test_request.request_parameters['action'] = service_name(container)
test_request.env['REQUEST_METHOD'] = "POST"
- test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
test_request.env['HTTP_SOAPACTION'] = "/soap/#{service_name(container)}/#{public_method_name}"
test_request.env['RAW_POST_DATA'] = body
test_request
diff --git a/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb b/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb
index 87677dec3e..81ada70c9e 100644
--- a/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb
+++ b/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb
@@ -33,7 +33,7 @@ class TC_DispatcherActionControllerXmlRpc < Test::Unit::TestCase
test_request = ActionController::TestRequest.new
test_request.request_parameters['action'] = service_name(container)
test_request.env['REQUEST_METHOD'] = "POST"
- test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
test_request.env['RAW_POST_DATA'] = body
test_request
end
diff --git a/actionwebservice/test/test_invoke_test.rb b/actionwebservice/test/test_invoke_test.rb
new file mode 100644
index 0000000000..cbfde9c3df
--- /dev/null
+++ b/actionwebservice/test/test_invoke_test.rb
@@ -0,0 +1,77 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+require 'action_web_service/test_invoke'
+
+class TestInvokeAPI < ActionWebService::API::Base
+ api_method :add, :expects => [:int, :int], :returns => [:int]
+end
+
+class TestInvokeService < ActionWebService::Base
+ web_service_api TestInvokeAPI
+
+ attr :invoked
+
+ def add(a, b)
+ @invoked = true
+ a + b
+ end
+end
+
+class TestController < ActionController::Base
+ def rescue_action(e); raise e; end
+end
+
+class TestInvokeDirectController < TestController
+ web_service_api TestInvokeAPI
+
+ attr :invoked
+
+ def add
+ @invoked = true
+ @method_params[0] + @method_params[1]
+ end
+end
+
+class TestInvokeDelegatedController < TestController
+ web_service_dispatching_mode :delegated
+ web_service :service, TestInvokeService.new
+end
+
+class TestInvokeLayeredController < TestController
+ web_service_dispatching_mode :layered
+ web_service :one, TestInvokeService.new
+ web_service :two, TestInvokeService.new
+end
+
+class TestInvokeTest < Test::Unit::TestCase
+ def setup
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ end
+
+ def test_direct_add
+ @controller = TestInvokeDirectController.new
+ assert_equal nil, @controller.invoked
+ result = invoke :add, 25, 25
+ assert_equal 50, result
+ assert_equal true, @controller.invoked
+ end
+
+ def test_delegated_add
+ @controller = TestInvokeDelegatedController.new
+ assert_equal nil, @controller.web_service_object(:service).invoked
+ result = invoke_delegated :service, :add, 100, 50
+ assert_equal 150, result
+ assert_equal true, @controller.web_service_object(:service).invoked
+ end
+
+ def test_layered_add
+ @protocol = :xmlrpc
+ @controller = TestInvokeLayeredController.new
+ [:one, :two].each do |service|
+ assert_equal nil, @controller.web_service_object(service).invoked
+ result = invoke_layered service, :add, 200, -50
+ assert_equal 150, result
+ assert_equal true, @controller.web_service_object(service).invoked
+ end
+ end
+end