actionwebservice 0.8.1 → 0.9.1

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 CHANGED
@@ -1,3 +1,23 @@
1
+ *0.9.1* (October 19th, 2005)
2
+
3
+ * Upgraded to Action Pack 1.10.1 and Active Record 1.12.1
4
+
5
+
6
+ *0.9.0* (October 16th, 2005)
7
+
8
+ * Fix invalid XML request generation bug in test_invoke [Ken Barker]
9
+
10
+ * Add XML-RPC 'system.multicall' support #1941 [jbonnar]
11
+
12
+ * Fix duplicate XSD entries for custom types shared across delegated/layered services #1729 [Tyler Kovacs]
13
+
14
+ * Allow multiple invocations in the same test method #1720 [dkhawk]
15
+
16
+ * Added ActionWebService::API::Base.soap_client and ActionWebService::API::Base.xmlrpc_client helper methods to create the internal clients for an API, useful for testing from ./script/console
17
+
18
+ * ActionWebService now always returns UTF-8 responses.
19
+
20
+
1
21
  *0.8.1* (11 July, 2005)
2
22
 
3
23
  * Fix scaffolding for Action Pack controller changes
data/README CHANGED
@@ -215,6 +215,25 @@ custom types and message definition types:
215
215
  The default namespace used is 'urn:ActionWebService', if you don't supply
216
216
  one.
217
217
 
218
+
219
+ == ActionWebService and UTF-8
220
+
221
+ If you're going to be sending back strings containing non-ASCII UTF-8
222
+ characters using the <tt>:string</tt> data type, you need to make sure that
223
+ Ruby is using UTF-8 as the default encoding for its strings.
224
+
225
+ The default in Ruby to use US-ASCII encoding for strings, which causes a string
226
+ validation check in the Ruby SOAP library to fail and your string to be sent
227
+ back as a Base-64 value, which may confuse clients that expected strings
228
+ because of the WSDL.
229
+
230
+ Two ways of doing setting the default string encoding are:
231
+
232
+ * Start Ruby using the <tt>-Ku</tt> command-line option to the Ruby executable
233
+ * Set the <tt>$KCODE</tt> flag in <tt>config/environment.rb</tt> to the
234
+ string <tt>'UTF8'</tt>
235
+
236
+
218
237
  == Testing your APIs
219
238
 
220
239
 
data/Rakefile CHANGED
@@ -6,10 +6,11 @@ require 'rake/packagetask'
6
6
  require 'rake/gempackagetask'
7
7
  require 'rake/contrib/rubyforgepublisher'
8
8
  require 'fileutils'
9
+ require File.join(File.dirname(__FILE__), 'lib', 'action_web_service', 'version')
9
10
 
10
11
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
11
12
  PKG_NAME = 'actionwebservice'
12
- PKG_VERSION = '0.8.1' + PKG_BUILD
13
+ PKG_VERSION = ActionWebService::Version::STRING + PKG_BUILD
13
14
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
14
15
  PKG_DESTINATION = ENV["RAILS_PKG_DESTINATION"] || "../#{PKG_NAME}"
15
16
 
@@ -62,9 +63,9 @@ spec = Gem::Specification.new do |s|
62
63
  s.rubyforge_project = "aws"
63
64
  s.homepage = "http://www.rubyonrails.org"
64
65
 
65
- s.add_dependency('actionpack', '= 1.9.1' + PKG_BUILD)
66
- s.add_dependency('activerecord', '= 1.11.1' + PKG_BUILD)
67
- s.add_dependency('activesupport', '= 1.1.1' + PKG_BUILD)
66
+ s.add_dependency('actionpack', '= 1.10.1' + PKG_BUILD)
67
+ s.add_dependency('activerecord', '= 1.12.1' + PKG_BUILD)
68
+ s.add_dependency('activesupport', '= 1.2.1' + PKG_BUILD)
68
69
 
69
70
  s.has_rdoc = true
70
71
  s.requirements << 'none'
@@ -16,11 +16,10 @@ module ActionWebService # :nodoc:
16
16
  private
17
17
  def invoke_web_service_request(protocol_request)
18
18
  invocation = web_service_invocation(protocol_request)
19
- case web_service_dispatching_mode
20
- when :direct
21
- web_service_direct_invoke(invocation)
22
- when :delegated, :layered
23
- web_service_delegated_invoke(invocation)
19
+ if invocation.is_a?(Array) && protocol_request.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol)
20
+ xmlrpc_multicall_invoke(invocation)
21
+ else
22
+ web_service_invoke(invocation)
24
23
  end
25
24
  end
26
25
 
@@ -47,10 +46,47 @@ module ActionWebService # :nodoc:
47
46
  if cancellation_reason
48
47
  raise(DispatcherError, "request canceled: #{cancellation_reason}")
49
48
  end
49
+ return_value
50
+ end
51
+
52
+ def web_service_invoke(invocation)
53
+ case web_service_dispatching_mode
54
+ when :direct
55
+ return_value = web_service_direct_invoke(invocation)
56
+ when :delegated, :layered
57
+ return_value = web_service_delegated_invoke(invocation)
58
+ end
50
59
  web_service_create_response(invocation.protocol, invocation.protocol_options, invocation.api, invocation.api_method, return_value)
51
60
  end
61
+
62
+ def xmlrpc_multicall_invoke(invocations)
63
+ responses = []
64
+ invocations.each do |invocation|
65
+ if invocation.is_a?(Hash)
66
+ responses << invocation
67
+ next
68
+ end
69
+ begin
70
+ case web_service_dispatching_mode
71
+ when :direct
72
+ return_value = web_service_direct_invoke(invocation)
73
+ when :delegated, :layered
74
+ return_value = web_service_delegated_invoke(invocation)
75
+ end
76
+ api_method = invocation.api_method
77
+ if invocation.api.has_api_method?(api_method.name)
78
+ return_value = api_method.cast_returns(return_value)
79
+ end
80
+ responses << [return_value]
81
+ rescue Exception => e
82
+ responses << { 'faultCode' => 3, 'faultString' => e.message }
83
+ end
84
+ end
85
+ invocation = invocations[0]
86
+ invocation.protocol.encode_response('system.multicall', responses, nil, invocation.protocol_options)
87
+ end
52
88
 
53
- def web_service_invocation(request)
89
+ def web_service_invocation(request, level = 0)
54
90
  public_method_name = request.method_name
55
91
  invocation = Invocation.new
56
92
  invocation.protocol = request.protocol
@@ -70,6 +106,32 @@ module ActionWebService # :nodoc:
70
106
  end
71
107
  end
72
108
  end
109
+ if invocation.protocol.is_a? Protocol::XmlRpc::XmlRpcProtocol
110
+ if public_method_name == 'multicall' && invocation.service_name == 'system'
111
+ if level > 0
112
+ raise(DispatcherError, "Recursive system.multicall invocations not allowed")
113
+ end
114
+ multicall = request.method_params.dup
115
+ unless multicall.is_a?(Array) && multicall[0].is_a?(Array)
116
+ raise(DispatcherError, "Malformed multicall (expected array of Hash elements)")
117
+ end
118
+ multicall = multicall[0]
119
+ return multicall.map do |item|
120
+ raise(DispatcherError, "Multicall elements must be Hash") unless item.is_a?(Hash)
121
+ raise(DispatcherError, "Multicall elements must contain a 'methodName' key") unless item.has_key?('methodName')
122
+ method_name = item['methodName']
123
+ params = item.has_key?('params') ? item['params'] : []
124
+ multicall_request = request.dup
125
+ multicall_request.method_name = method_name
126
+ multicall_request.method_params = params
127
+ begin
128
+ web_service_invocation(multicall_request, level + 1)
129
+ rescue Exception => e
130
+ {'faultCode' => 4, 'faultMessage' => e.message}
131
+ end
132
+ end
133
+ end
134
+ end
73
135
  case web_service_dispatching_mode
74
136
  when :direct
75
137
  invocation.api = self.class.web_service_api
@@ -195,7 +195,7 @@ module ActionWebService # :nodoc:
195
195
  custom_types = []
196
196
  apis.values.each do |api, bindings|
197
197
  bindings.each do |b|
198
- custom_types << b
198
+ custom_types << b unless custom_types.include?(b)
199
199
  end
200
200
  end
201
201
 
@@ -347,29 +347,32 @@ module ActionWebService # :nodoc:
347
347
 
348
348
  def register_api(api, marshaler)
349
349
  bindings = {}
350
- traverse_custom_types(api, marshaler) do |binding|
350
+ traverse_custom_types(api, marshaler, bindings) do |binding|
351
351
  bindings[binding] = nil unless bindings.has_key?(binding)
352
352
  element_binding = binding.element_binding
353
- bindings[binding.element_binding] = nil if element_binding && !bindings.has_key?(element_binding)
353
+ bindings[element_binding] = nil if element_binding && !bindings.has_key?(element_binding)
354
354
  end
355
355
  bindings.keys
356
356
  end
357
357
 
358
- def traverse_custom_types(api, marshaler, &block)
358
+ def traverse_custom_types(api, marshaler, bindings, &block)
359
359
  api.api_methods.each do |name, method|
360
360
  expects, returns = method.expects, method.returns
361
- expects.each{ |type| traverse_type(marshaler, type, &block) if type.custom? } if expects
362
- returns.each{ |type| traverse_type(marshaler, type, &block) if type.custom? } if returns
361
+ expects.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if expects
362
+ returns.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if returns
363
363
  end
364
364
  end
365
365
 
366
- def traverse_type(marshaler, type, &block)
367
- yield marshaler.register_type(type)
366
+ def traverse_type(marshaler, type, bindings, &block)
367
+ binding = marshaler.register_type(type)
368
+ return if bindings.has_key?(binding)
369
+ bindings[binding] = nil
370
+ yield binding
368
371
  if type.array?
369
372
  yield marshaler.register_type(type.element_type)
370
373
  type = type.element_type
371
374
  end
372
- type.each_member{ |name, type| traverse_type(marshaler, type, &block) } if type.structured?
375
+ type.each_member{ |name, type| traverse_type(marshaler, type, bindings, &block) } if type.structured?
373
376
  end
374
377
  end
375
378
  end
@@ -41,7 +41,7 @@ module ActionWebService # :nodoc:
41
41
 
42
42
  class Request # :nodoc:
43
43
  attr :protocol
44
- attr :method_name
44
+ attr_accessor :method_name
45
45
  attr_accessor :method_params
46
46
  attr :service_name
47
47
  attr_accessor :api
@@ -1,7 +1,16 @@
1
1
  require 'action_web_service/protocol/soap_protocol/marshaler'
2
2
  require 'soap/streamHandler'
3
+ require 'action_web_service/client/soap_client'
3
4
 
4
5
  module ActionWebService # :nodoc:
6
+ module API # :nodoc:
7
+ class Base # :nodoc:
8
+ def self.soap_client(endpoint_uri, options={})
9
+ ActionWebService::Client::Soap.new self, endpoint_uri, options
10
+ end
11
+ end
12
+ end
13
+
5
14
  module Protocol # :nodoc:
6
15
  module Soap # :nodoc:
7
16
  def self.included(base)
@@ -11,7 +20,8 @@ module ActionWebService # :nodoc:
11
20
  end
12
21
 
13
22
  class SoapProtocol < AbstractProtocol # :nodoc:
14
- DefaultEncoding = 'utf-8'
23
+ AWSEncoding = 'UTF-8'
24
+ XSDEncoding = 'UTF8'
15
25
 
16
26
  attr :marshaler
17
27
 
@@ -27,10 +37,10 @@ module ActionWebService # :nodoc:
27
37
  def decode_action_pack_request(action_pack_request)
28
38
  return nil unless soap_action = has_valid_soap_action?(action_pack_request)
29
39
  service_name = action_pack_request.parameters['action']
30
- charset = parse_charset(action_pack_request.env['HTTP_CONTENT_TYPE'])
40
+ input_encoding = parse_charset(action_pack_request.env['HTTP_CONTENT_TYPE'])
31
41
  protocol_options = {
32
42
  :soap_action => soap_action,
33
- :charset => charset
43
+ :charset => input_encoding
34
44
  }
35
45
  decode_request(action_pack_request.raw_post, service_name, protocol_options)
36
46
  end
@@ -42,8 +52,7 @@ module ActionWebService # :nodoc:
42
52
  end
43
53
 
44
54
  def decode_request(raw_request, service_name, protocol_options={})
45
- charset = protocol_options[:charset] || DefaultEncoding
46
- envelope = SOAP::Processor.unmarshal(raw_request, :charset => charset)
55
+ envelope = SOAP::Processor.unmarshal(raw_request, :charset => protocol_options[:charset])
47
56
  unless envelope
48
57
  raise ProtocolError, "Failed to parse SOAP request message"
49
58
  end
@@ -109,8 +118,17 @@ module ActionWebService # :nodoc:
109
118
  end
110
119
  end
111
120
  envelope = create_soap_envelope(response)
112
- charset = protocol_options[:charset] || DefaultEncoding
113
- Response.new(SOAP::Processor.marshal(envelope, :charset => charset), "text/xml; charset=#{charset}", return_value)
121
+
122
+ # FIXME: This is not thread-safe, but StringFactory_ in SOAP4R only
123
+ # reads target encoding from the XSD::Charset.encoding variable.
124
+ # This is required to ensure $KCODE strings are converted
125
+ # correctly to UTF-8 for any values of $KCODE.
126
+ previous_encoding = XSD::Charset.encoding
127
+ XSD::Charset.encoding = XSDEncoding
128
+ response_body = SOAP::Processor.marshal(envelope, :charset => AWSEncoding)
129
+ XSD::Charset.encoding = previous_encoding
130
+
131
+ Response.new(response_body, "text/xml; charset=#{AWSEncoding}", return_value)
114
132
  end
115
133
 
116
134
  def protocol_client(api, protocol_name, endpoint_uri, options={})
@@ -138,20 +156,20 @@ module ActionWebService # :nodoc:
138
156
  soap_action
139
157
  end
140
158
 
159
+ def create_soap_envelope(body)
160
+ header = SOAP::SOAPHeader.new
161
+ body = SOAP::SOAPBody.new(body)
162
+ SOAP::SOAPEnvelope.new(header, body)
163
+ end
164
+
141
165
  def parse_charset(content_type)
142
- return DefaultEncoding if content_type.nil?
166
+ return AWSEncoding if content_type.nil?
143
167
  if /^text\/xml(?:\s*;\s*charset=([^"]+|"[^"]+"))$/i =~ content_type
144
168
  $1
145
169
  else
146
- DefaultEncoding
170
+ AWSEncoding
147
171
  end
148
172
  end
149
-
150
- def create_soap_envelope(body)
151
- header = SOAP::SOAPHeader.new
152
- body = SOAP::SOAPBody.new(body)
153
- SOAP::SOAPEnvelope.new(header, body)
154
- end
155
173
  end
156
174
  end
157
175
  end
@@ -1,4 +1,5 @@
1
1
  require 'xmlrpc/marshal'
2
+ require 'action_web_service/client/xmlrpc_client'
2
3
 
3
4
  module XMLRPC # :nodoc:
4
5
  class FaultException # :nodoc:
@@ -7,6 +8,14 @@ module XMLRPC # :nodoc:
7
8
  end
8
9
 
9
10
  module ActionWebService # :nodoc:
11
+ module API # :nodoc:
12
+ class Base # :nodoc:
13
+ def self.xmlrpc_client(endpoint_uri, options={})
14
+ ActionWebService::Client::XmlRpc.new self, endpoint_uri, options
15
+ end
16
+ end
17
+ end
18
+
10
19
  module Protocol # :nodoc:
11
20
  module XmlRpc # :nodoc:
12
21
  def self.included(base)
@@ -40,7 +40,7 @@ module ActionWebService
40
40
  # can then be used as the entry point for invoking API methods from a web browser.
41
41
  def web_service_scaffold(action_name)
42
42
  add_template_helper(Helpers)
43
- module_eval <<-END, __FILE__, __LINE__
43
+ module_eval <<-"end_eval", __FILE__, __LINE__
44
44
  def #{action_name}
45
45
  if request.method == :get
46
46
  setup_invocation_assigns
@@ -112,8 +112,17 @@ module ActionWebService
112
112
  def render_invocation_scaffold(action)
113
113
  customized_template = "\#{self.class.controller_path}/#{action_name}/\#{action}"
114
114
  default_template = scaffold_path(action)
115
- @content_for_layout = template_exists?(customized_template) ? @template.render_file(customized_template) : @template.render_file(default_template, false)
116
- self.active_layout ? render_file(self.active_layout, "200 OK", true) : render_file(scaffold_path("layout"))
115
+ if template_exists?(customized_template)
116
+ content = @template.render_file(customized_template)
117
+ else
118
+ content = @template.render_file(default_template, false)
119
+ end
120
+ @template.instance_variable_set("@content_for_layout", content)
121
+ if self.active_layout.nil?
122
+ render_file(scaffold_path("layout"))
123
+ else
124
+ render_file(self.active_layout, "200 OK", true)
125
+ end
117
126
  end
118
127
 
119
128
  def scaffold_path(template_name)
@@ -159,7 +168,7 @@ module ActionWebService
159
168
  rescue_action(exception)
160
169
  true
161
170
  end
162
- END
171
+ end_eval
163
172
  end
164
173
  end
165
174
 
@@ -29,6 +29,7 @@ module Test # :nodoc:
29
29
  # ---------------------- internal ---------------------------
30
30
 
31
31
  def prepare_request(action, service_name, api_method_name, *args)
32
+ @request.recycle!
32
33
  @request.request_parameters['action'] = action
33
34
  @request.env['REQUEST_METHOD'] = 'POST'
34
35
  @request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
@@ -81,7 +82,7 @@ module Test # :nodoc:
81
82
 
82
83
  def protocol
83
84
  if @protocol.nil?
84
- @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.new(@controller)
85
+ @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.create(@controller)
85
86
  else
86
87
  case @protocol
87
88
  when :xmlrpc
@@ -0,0 +1,9 @@
1
+ module ActionWebService
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 9
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -4,6 +4,7 @@ require 'stringio'
4
4
  class ActionController::Base; def rescue_action(e) raise e end; end
5
5
 
6
6
  module DispatcherTest
7
+ Utf8String = "One World Caf\303\251"
7
8
  WsdlNamespace = 'http://rubyonrails.com/some/namespace'
8
9
 
9
10
  class Node < ActiveRecord::Base
@@ -58,6 +59,7 @@ module DispatcherTest
58
59
  api_method :hash_struct_return, :returns => [[Person]]
59
60
  api_method :thrower
60
61
  api_method :void
62
+ api_method :test_utf8, :returns => [:string]
61
63
  api_method :hex, :expects => [:base64], :returns => [:string]
62
64
  api_method :unhex, :expects => [:string], :returns => [:base64]
63
65
  end
@@ -105,11 +107,15 @@ module DispatcherTest
105
107
  class MTAPI < ActionWebService::API::Base
106
108
  inflect_names false
107
109
  api_method :getCategories, :returns => [[:string]]
110
+ api_method :bool, :returns => [:bool]
111
+ api_method :alwaysFail
108
112
  end
109
113
 
110
114
  class BloggerAPI < ActionWebService::API::Base
111
115
  inflect_names false
112
116
  api_method :getCategories, :returns => [[:string]]
117
+ api_method :str, :expects => [:int], :returns => [:string]
118
+ api_method :alwaysFail
113
119
  end
114
120
 
115
121
  class MTService < ActionWebService::Base
@@ -118,6 +124,14 @@ module DispatcherTest
118
124
  def getCategories
119
125
  ["mtCat1", "mtCat2"]
120
126
  end
127
+
128
+ def bool
129
+ 'y'
130
+ end
131
+
132
+ def alwaysFail
133
+ raise "MT AlwaysFail"
134
+ end
121
135
  end
122
136
 
123
137
  class BloggerService < ActionWebService::Base
@@ -126,6 +140,17 @@ module DispatcherTest
126
140
  def getCategories
127
141
  ["bloggerCat1", "bloggerCat2"]
128
142
  end
143
+
144
+ def str(int)
145
+ unless int.is_a?(Integer)
146
+ raise "Not an integer!"
147
+ end
148
+ 500 + int
149
+ end
150
+
151
+ def alwaysFail
152
+ raise "Blogger AlwaysFail"
153
+ end
129
154
  end
130
155
 
131
156
  class AbstractController < ActionController::Base
@@ -223,6 +248,10 @@ module DispatcherTest
223
248
  @void_called = @method_params
224
249
  end
225
250
 
251
+ def test_utf8
252
+ Utf8String
253
+ end
254
+
226
255
  def hex(s)
227
256
  return s.unpack("H*")[0]
228
257
  end
@@ -398,12 +427,6 @@ module DispatcherCommonTests
398
427
  raise NotImplementedError
399
428
  end
400
429
 
401
- def update_request(ap_request)
402
- end
403
-
404
- def check_response(ap_response)
405
- end
406
-
407
430
  def protocol
408
431
  @protocol
409
432
  end
@@ -439,8 +462,8 @@ module DispatcherCommonTests
439
462
  public_method_name = real_method_name
440
463
  request_env['HTTP_SOAPACTION'] = "/soap/#{service_name}/#{real_method_name}"
441
464
  end
442
- api = container.web_service_object(service_name.to_sym).class.web_service_api
443
- method = api.public_api_method_instance(real_method_name)
465
+ api = container.web_service_object(service_name.to_sym).class.web_service_api rescue nil
466
+ method = api.public_api_method_instance(real_method_name) rescue nil
444
467
  service_name = self.service_name(container)
445
468
  end
446
469
  protocol.register_api(api)
@@ -453,11 +476,10 @@ module DispatcherCommonTests
453
476
  # puts body
454
477
  ap_request = protocol.encode_action_pack_request(service_name, public_method_name, body, :request_class => ActionController::TestRequest)
455
478
  ap_request.env.update(request_env)
456
- update_request(ap_request)
457
479
  ap_response = ActionController::TestResponse.new
458
480
  container.process(ap_request, ap_response)
459
481
  # puts ap_response.body
460
- check_response(ap_response)
482
+ @response_body = ap_response.body
461
483
  public_method_name, return_value = protocol.decode_response(ap_response.body)
462
484
  unless is_exception?(return_value) || virtual
463
485
  return_value = method.cast_returns(return_value)
@@ -67,16 +67,25 @@ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase
67
67
  assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats)
68
68
  end
69
69
 
70
- protected
71
- def update_request(ap_request)
72
- ap_request.env.update('HTTP_CONTENT_TYPE' => 'text/xml; charset=us-ascii')
73
- end
74
-
75
- def check_response(ap_response)
76
- assert_equal 'text/xml; charset=us-ascii', ap_response.headers['Content-Type']
77
- assert_match /xml.*?encoding="us-ascii"/, ap_response.body
78
- end
70
+ def test_utf8
71
+ @direct_controller.web_service_exception_reporting = true
72
+ $KCODE = 'u'
73
+ assert_equal(Utf8String, do_method_call(@direct_controller, 'TestUtf8'))
74
+ retval = SOAP::Processor.unmarshal(@response_body).body.response
75
+ assert retval.is_a?(SOAP::SOAPString)
76
+
77
+ # If $KCODE is not set to UTF-8, any strings with non-ASCII UTF-8 data
78
+ # will be sent back as base64 by SOAP4R. By the time we get it here though,
79
+ # it will be decoded back into a string. So lets read the base64 value
80
+ # from the message body directly.
81
+ $KCODE = 'NONE'
82
+ do_method_call(@direct_controller, 'TestUtf8')
83
+ retval = SOAP::Processor.unmarshal(@response_body).body.response
84
+ assert retval.is_a?(SOAP::SOAPBase64)
85
+ assert_equal "T25lIFdvcmxkIENhZsOp", retval.data.to_s
86
+ end
79
87
 
88
+ protected
80
89
  def exception_message(soap_fault_exception)
81
90
  soap_fault_exception.detail.cause.message
82
91
  end
@@ -19,6 +19,29 @@ class TC_DispatcherActionControllerXmlRpc < Test::Unit::TestCase
19
19
  assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats)
20
20
  end
21
21
 
22
+ def test_multicall
23
+ response = do_method_call(@layered_controller, 'system.multicall', [
24
+ {'methodName' => 'mt.getCategories'},
25
+ {'methodName' => 'blogger.getCategories'},
26
+ {'methodName' => 'mt.bool'},
27
+ {'methodName' => 'blogger.str', 'params' => ['2000']},
28
+ {'methodName' => 'mt.alwaysFail'},
29
+ {'methodName' => 'blogger.alwaysFail'},
30
+ {'methodName' => 'mt.blah'},
31
+ {'methodName' => 'blah.blah'}
32
+ ])
33
+ assert_equal [
34
+ [["mtCat1", "mtCat2"]],
35
+ [["bloggerCat1", "bloggerCat2"]],
36
+ [true],
37
+ ["2500"],
38
+ {"faultCode" => 3, "faultString" => "MT AlwaysFail"},
39
+ {"faultCode" => 3, "faultString" => "Blogger AlwaysFail"},
40
+ {"faultCode" => 4, "faultMessage" => "no such method 'blah' on API DispatcherTest::MTAPI"},
41
+ {"faultCode" => 4, "faultMessage" => "no such web service 'blah'"}
42
+ ], response
43
+ end
44
+
22
45
  protected
23
46
  def exception_message(xmlrpc_fault_exception)
24
47
  xmlrpc_fault_exception.faultString
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: actionwebservice
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.8.1
7
- date: 2005-07-11
6
+ version: 0.9.1
7
+ date: 2005-10-19
8
8
  summary: Web service support for Action Pack.
9
9
  require_paths:
10
10
  - lib
@@ -72,6 +72,7 @@ files:
72
72
  - lib/action_web_service/support
73
73
  - lib/action_web_service/templates
74
74
  - lib/action_web_service/test_invoke.rb
75
+ - lib/action_web_service/version.rb
75
76
  - lib/action_web_service/client/base.rb
76
77
  - lib/action_web_service/client/soap_client.rb
77
78
  - lib/action_web_service/client/xmlrpc_client.rb
@@ -129,7 +130,7 @@ dependencies:
129
130
  -
130
131
  - "="
131
132
  - !ruby/object:Gem::Version
132
- version: 1.9.1
133
+ version: 1.10.1
133
134
  version:
134
135
  - !ruby/object:Gem::Dependency
135
136
  name: activerecord
@@ -139,7 +140,7 @@ dependencies:
139
140
  -
140
141
  - "="
141
142
  - !ruby/object:Gem::Version
142
- version: 1.11.1
143
+ version: 1.12.1
143
144
  version:
144
145
  - !ruby/object:Gem::Dependency
145
146
  name: activesupport
@@ -149,5 +150,5 @@ dependencies:
149
150
  -
150
151
  - "="
151
152
  - !ruby/object:Gem::Version
152
- version: 1.1.1
153
+ version: 1.2.1
153
154
  version: