actionwebservice 0.8.1 → 0.9.1

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