actionwebservice 0.5.0 → 0.6.0

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.
Files changed (66) hide show
  1. data/{ChangeLog → CHANGELOG} +20 -0
  2. data/README +45 -1
  3. data/Rakefile +12 -10
  4. data/TODO +8 -9
  5. data/lib/action_web_service.rb +10 -6
  6. data/lib/action_web_service/api.rb +1 -2
  7. data/lib/action_web_service/api/{abstract.rb → base.rb} +14 -71
  8. data/lib/action_web_service/base.rb +0 -3
  9. data/lib/action_web_service/client/base.rb +1 -12
  10. data/lib/action_web_service/client/soap_client.rb +49 -17
  11. data/lib/action_web_service/client/xmlrpc_client.rb +20 -15
  12. data/lib/action_web_service/container.rb +3 -85
  13. data/lib/action_web_service/{api/action_controller.rb → container/action_controller_container.rb} +2 -2
  14. data/lib/action_web_service/container/delegated_container.rb +87 -0
  15. data/lib/action_web_service/container/direct_container.rb +70 -0
  16. data/lib/action_web_service/dispatcher/abstract.rb +100 -102
  17. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +199 -137
  18. data/lib/action_web_service/protocol.rb +1 -1
  19. data/lib/action_web_service/protocol/abstract.rb +14 -112
  20. data/lib/action_web_service/protocol/discovery.rb +37 -0
  21. data/lib/action_web_service/protocol/soap_protocol.rb +32 -458
  22. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +29 -149
  23. data/lib/action_web_service/struct.rb +2 -5
  24. data/lib/action_web_service/test_invoke.rb +130 -0
  25. data/lib/action_web_service/vendor/ws.rb +4 -0
  26. data/lib/action_web_service/vendor/ws/common.rb +8 -0
  27. data/lib/action_web_service/vendor/ws/encoding.rb +3 -0
  28. data/lib/action_web_service/vendor/ws/encoding/abstract.rb +26 -0
  29. data/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb +90 -0
  30. data/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb +53 -0
  31. data/lib/action_web_service/vendor/ws/marshaling.rb +3 -0
  32. data/lib/action_web_service/vendor/ws/marshaling/abstract.rb +17 -0
  33. data/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb +277 -0
  34. data/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb +116 -0
  35. data/lib/action_web_service/vendor/ws/types.rb +162 -0
  36. data/test/abstract_client.rb +8 -11
  37. data/test/abstract_dispatcher.rb +370 -0
  38. data/test/abstract_unit.rb +1 -0
  39. data/test/api_test.rb +18 -1
  40. data/test/apis/auto_load_api.rb +3 -0
  41. data/test/apis/broken_auto_load_api.rb +2 -0
  42. data/test/client_soap_test.rb +16 -3
  43. data/test/client_xmlrpc_test.rb +16 -4
  44. data/test/container_test.rb +28 -8
  45. data/test/dispatcher_action_controller_soap_test.rb +106 -0
  46. data/test/dispatcher_action_controller_xmlrpc_test.rb +44 -0
  47. data/test/gencov +1 -1
  48. data/test/invocation_test.rb +39 -3
  49. data/test/run +4 -4
  50. data/test/test_invoke_test.rb +77 -0
  51. data/test/ws/abstract_encoding.rb +68 -0
  52. data/test/ws/abstract_unit.rb +13 -0
  53. data/test/ws/gencov +3 -0
  54. data/test/ws/run +5 -0
  55. data/test/ws/soap_marshaling_test.rb +91 -0
  56. data/test/ws/soap_rpc_encoding_test.rb +47 -0
  57. data/test/ws/types_test.rb +41 -0
  58. data/test/ws/xmlrpc_encoding_test.rb +34 -0
  59. metadata +48 -19
  60. data/lib/action_web_service/protocol/registry.rb +0 -55
  61. data/lib/action_web_service/support/signature.rb +0 -100
  62. data/test/abstract_soap.rb +0 -58
  63. data/test/dispatcher_action_controller_test.rb +0 -186
  64. data/test/protocol_registry_test.rb +0 -53
  65. data/test/protocol_soap_test.rb +0 -252
  66. data/test/protocol_xmlrpc_test.rb +0 -147
@@ -1,4 +1,5 @@
1
1
  $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib/action_web_service/vendor')
2
3
 
3
4
  require 'test/unit'
4
5
  require 'action_web_service'
@@ -41,7 +41,7 @@ class TC_API < Test::Unit::TestCase
41
41
  assert_equal({:expects=>nil, :returns=>[Integer, [String]]}, API.api_methods[:returns])
42
42
  assert_equal({:expects=>[{:appkey=>Integer}, {:publish=>TrueClass}], :returns=>nil}, API.api_methods[:named_signature])
43
43
  assert_equal({:expects=>[Integer, String, TrueClass], :returns=>nil}, API.api_methods[:string_types])
44
- assert_equal({:expects=>[TrueClass, Bignum, String], :returns=>nil}, API.api_methods[:class_types])
44
+ assert_equal({:expects=>[TrueClass, Integer, String], :returns=>nil}, API.api_methods[:class_types])
45
45
  end
46
46
 
47
47
  def test_not_instantiable
@@ -49,4 +49,21 @@ class TC_API < Test::Unit::TestCase
49
49
  API.new
50
50
  end
51
51
  end
52
+
53
+ def test_api_errors
54
+ assert_raises(ActionWebService::ActionWebServiceError) do
55
+ klass = Class.new(ActionWebService::API::Base) do
56
+ api_method :test, :expects => [ActiveRecord::Base]
57
+ end
58
+ end
59
+ klass = Class.new(ActionWebService::API::Base) do
60
+ allow_active_record_expects true
61
+ api_method :test2, :expects => [ActiveRecord::Base]
62
+ end
63
+ assert_raises(ActionWebService::ActionWebServiceError) do
64
+ klass = Class.new(ActionWebService::API::Base) do
65
+ api_method :test, :invalid => [:int]
66
+ end
67
+ end
68
+ end
52
69
  end
@@ -0,0 +1,3 @@
1
+ class AutoLoadAPI < ActionWebService::API::Base
2
+ api_method :void
3
+ end
@@ -12,10 +12,10 @@ module ClientSoapTest
12
12
  test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
13
13
  test_request.env['HTTP_SOAPACTION'] = req.header['soapaction'][0]
14
14
  test_request.env['RAW_POST_DATA'] = req.body
15
- protocol_request = @controller.protocol_request(test_request)
16
- response = @controller.dispatch_request(protocol_request)
15
+ response = ActionController::TestResponse.new
16
+ @controller.process(test_request, response)
17
17
  res.header['content-type'] = 'text/xml'
18
- res.body = response.raw_body
18
+ res.body = response.body
19
19
  rescue Exception => e
20
20
  $stderr.puts e.message
21
21
  $stderr.puts e.backtrace.join("\n")
@@ -24,10 +24,15 @@ module ClientSoapTest
24
24
 
25
25
  class ClientContainer < ActionController::Base
26
26
  web_client_api :client, :soap, "http://localhost:#{PORT}/client/api", :api => ClientTest::API
27
+ web_client_api :invalid, :null, "", :api => true
27
28
 
28
29
  def get_client
29
30
  client
30
31
  end
32
+
33
+ def get_invalid
34
+ invalid
35
+ end
31
36
  end
32
37
 
33
38
  class SoapServer < ClientTest::AbstractServer
@@ -83,6 +88,7 @@ class TC_ClientSoap < Test::Unit::TestCase
83
88
 
84
89
  def test_client_container
85
90
  assert_equal(50, ClientContainer.new.get_client.client_container)
91
+ assert(ClientContainer.new.get_invalid.nil?)
86
92
  end
87
93
 
88
94
  def test_named_parameters
@@ -90,4 +96,11 @@ class TC_ClientSoap < Test::Unit::TestCase
90
96
  assert(@client.named_parameters("key", 5).nil?)
91
97
  assert_equal(["key", 5], @container.value_named_parameters)
92
98
  end
99
+
100
+ def test_capitalized_method_name
101
+ @container.value_normal = nil
102
+ assert_equal(5, @client.Normal(5, 6))
103
+ assert_equal([5, 6], @container.value_normal)
104
+ @container.value_normal = nil
105
+ end
93
106
  end
@@ -9,12 +9,12 @@ module ClientXmlRpcTest
9
9
  test_request = ActionController::TestRequest.new
10
10
  test_request.request_parameters['action'] = req.path.gsub(/^\//, '').split(/\//)[1]
11
11
  test_request.env['REQUEST_METHOD'] = "POST"
12
- test_request.env['HTTP_CONTENTTYPE'] = 'text/xml'
12
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
13
13
  test_request.env['RAW_POST_DATA'] = req.body
14
- protocol_request = @controller.protocol_request(test_request)
15
- response = @controller.dispatch_request(protocol_request)
14
+ response = ActionController::TestResponse.new
15
+ @controller.process(test_request, response)
16
16
  res.header['content-type'] = 'text/xml'
17
- res.body = response.raw_body
17
+ res.body = response.body
18
18
  rescue Exception => e
19
19
  $stderr.puts e.message
20
20
  $stderr.puts e.backtrace.join("\n")
@@ -89,4 +89,16 @@ class TC_ClientXmlRpc < Test::Unit::TestCase
89
89
  assert_equal(true, @client.named_parameters("xxx", 7))
90
90
  assert_equal(["xxx", 7], @container.value_named_parameters)
91
91
  end
92
+
93
+ def test_exception
94
+ assert_raises(ActionWebService::Client::ClientError) do
95
+ assert(@client.thrower)
96
+ end
97
+ end
98
+
99
+ def test_invalid_signature
100
+ assert_raises(ActionWebService::Client::ClientError) do
101
+ @client.normal
102
+ end
103
+ end
92
104
  end
@@ -1,7 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/abstract_unit'
2
2
 
3
3
  module ContainerTest
4
-
5
4
  $immediate_service = Object.new
6
5
  $deferred_service = Object.new
7
6
 
@@ -22,22 +21,34 @@ module ContainerTest
22
21
 
23
22
  class DirectContainer < ActionController::Base
24
23
  web_service_dispatching_mode :direct
25
- end
24
+ end
25
+
26
+ class InvalidContainer
27
+ include ActionWebService::Container::Direct
28
+ end
26
29
  end
27
30
 
28
31
  class TC_Container < Test::Unit::TestCase
32
+ include ContainerTest
33
+
29
34
  def setup
30
- @delegate_container = ContainerTest::DelegateContainer.new
31
- @direct_container = ContainerTest::DirectContainer.new
35
+ @delegate_container = DelegateContainer.new
36
+ @direct_container = DirectContainer.new
32
37
  end
33
38
 
34
39
  def test_registration
35
- assert(ContainerTest::DelegateContainer.has_web_service?(:immediate_service))
36
- assert(ContainerTest::DelegateContainer.has_web_service?(:deferred_service))
37
- assert(!ContainerTest::DelegateContainer.has_web_service?(:fake_service))
40
+ assert(DelegateContainer.has_web_service?(:immediate_service))
41
+ assert(DelegateContainer.has_web_service?(:deferred_service))
42
+ assert(!DelegateContainer.has_web_service?(:fake_service))
43
+ assert_raises(ActionWebService::Container::Delegated::ContainerError) do
44
+ DelegateContainer.web_service('invalid')
45
+ end
38
46
  end
39
47
 
40
48
  def test_service_object
49
+ assert_raises(ActionWebService::Container::Delegated::ContainerError) do
50
+ @delegate_container.web_service_object(:nonexistent)
51
+ end
41
52
  assert(@delegate_container.flag == true)
42
53
  assert(@delegate_container.web_service_object(:immediate_service) == $immediate_service)
43
54
  assert(@delegate_container.previous_flag.nil?)
@@ -48,6 +59,15 @@ class TC_Container < Test::Unit::TestCase
48
59
  end
49
60
 
50
61
  def test_direct_container
51
- assert(ContainerTest::DirectContainer.web_service_dispatching_mode == :direct)
62
+ assert(DirectContainer.web_service_dispatching_mode == :direct)
63
+ end
64
+
65
+ def test_validity
66
+ assert_raises(ActionWebService::Container::Direct::ContainerError) do
67
+ InvalidContainer.web_service_api :test
68
+ end
69
+ assert_raises(ActionWebService::Container::Direct::ContainerError) do
70
+ InvalidContainer.web_service_api 50.0
71
+ end
52
72
  end
53
73
  end
@@ -0,0 +1,106 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/apis')
2
+ require File.dirname(__FILE__) + '/abstract_dispatcher'
3
+ require 'wsdl/parser'
4
+
5
+ class AutoLoadController < ActionController::Base; end
6
+ class FailingAutoLoadController < ActionController::Base; end
7
+ class BrokenAutoLoadController < ActionController::Base; end
8
+
9
+ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase
10
+ include DispatcherTest
11
+ include DispatcherCommonTests
12
+
13
+ def setup
14
+ @encoder = WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
15
+ @marshaler = WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
16
+ @direct_controller = DirectController.new
17
+ @delegated_controller = DelegatedController.new
18
+ @virtual_controller = VirtualController.new
19
+ end
20
+
21
+ def test_wsdl_generation
22
+ ensure_valid_wsdl_generation DelegatedController.new
23
+ ensure_valid_wsdl_generation DirectController.new
24
+ end
25
+
26
+ def test_wsdl_action
27
+ delegated_types = ensure_valid_wsdl_action DelegatedController.new
28
+ delegated_names = delegated_types.map{|x| x.name.name}
29
+ assert(delegated_names.include?('DispatcherTest..NodeArray'))
30
+ assert(delegated_names.include?('DispatcherTest..Node'))
31
+ direct_types = ensure_valid_wsdl_action DirectController.new
32
+ direct_names = direct_types.map{|x| x.name.name}
33
+ assert(direct_names.include?('DispatcherTest..NodeArray'))
34
+ assert(direct_names.include?('DispatcherTest..Node'))
35
+ assert(direct_names.include?('IntegerArray'))
36
+ end
37
+
38
+ def test_autoloading
39
+ assert(!AutoLoadController.web_service_api.nil?)
40
+ assert(AutoLoadController.web_service_api.has_public_api_method?('Void'))
41
+ assert(FailingAutoLoadController.web_service_api.nil?)
42
+ assert_raises(LoadError, NameError) do
43
+ FailingAutoLoadController.require_web_service_api :blah
44
+ end
45
+ assert_raises(ArgumentError) do
46
+ FailingAutoLoadController.require_web_service_api 50.0
47
+ end
48
+ assert(BrokenAutoLoadController.web_service_api.nil?)
49
+ end
50
+
51
+ protected
52
+ def exception_message(soap_fault_exception)
53
+ soap_fault_exception.detail.cause.message
54
+ end
55
+
56
+ def is_exception?(obj)
57
+ obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && \
58
+ obj.detail.cause.is_a?(Exception)
59
+ end
60
+
61
+ def create_ap_request(container, body, public_method_name, *args)
62
+ test_request = ActionController::TestRequest.new
63
+ test_request.request_parameters['action'] = service_name(container)
64
+ test_request.env['REQUEST_METHOD'] = "POST"
65
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
66
+ test_request.env['HTTP_SOAPACTION'] = "/soap/#{service_name(container)}/#{public_method_name}"
67
+ test_request.env['RAW_POST_DATA'] = body
68
+ test_request
69
+ end
70
+
71
+ def service_name(container)
72
+ container.is_a?(DelegatedController) ? 'test_service' : 'api'
73
+ end
74
+
75
+ def ensure_valid_wsdl_generation(controller)
76
+ wsdl = controller.generate_wsdl
77
+ ensure_valid_wsdl(wsdl)
78
+ end
79
+
80
+ def ensure_valid_wsdl(wsdl)
81
+ definitions = WSDL::Parser.new.parse(wsdl)
82
+ assert(definitions.is_a?(WSDL::Definitions))
83
+ definitions.bindings.each do |binding|
84
+ assert(binding.name.name.index(':').nil?)
85
+ end
86
+ definitions.services.each do |service|
87
+ service.ports.each do |port|
88
+ assert(port.name.name.index(':').nil?)
89
+ end
90
+ end
91
+ types = definitions.collect_complextypes.map{|x| x.name}
92
+ types.each do |type|
93
+ assert(type.namespace == 'urn:ActionWebService')
94
+ end
95
+ definitions.collect_complextypes
96
+ end
97
+
98
+ def ensure_valid_wsdl_action(controller)
99
+ test_request = ActionController::TestRequest.new({ 'action' => 'wsdl' })
100
+ test_request.env['REQUEST_METHOD'] = 'GET'
101
+ test_request.env['HTTP_HOST'] = 'localhost:3000'
102
+ test_response = ActionController::TestResponse.new
103
+ wsdl = controller.process(test_request, test_response).body
104
+ ensure_valid_wsdl(wsdl)
105
+ end
106
+ end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/abstract_dispatcher'
2
+
3
+ class TC_DispatcherActionControllerXmlRpc < Test::Unit::TestCase
4
+ include DispatcherTest
5
+ include DispatcherCommonTests
6
+
7
+ def setup
8
+ @encoder = WS::Encoding::XmlRpcEncoding.new
9
+ @marshaler = WS::Marshaling::XmlRpcMarshaler.new
10
+ @direct_controller = DirectController.new
11
+ @delegated_controller = DelegatedController.new
12
+ @layered_controller = LayeredController.new
13
+ @virtual_controller = VirtualController.new
14
+ end
15
+
16
+ def test_layered_dispatching
17
+ mt_cats = do_method_call(@layered_controller, 'mt.getCategories')
18
+ assert_equal(["mtCat1", "mtCat2"], mt_cats)
19
+ blogger_cats = do_method_call(@layered_controller, 'blogger.getCategories')
20
+ assert_equal(["bloggerCat1", "bloggerCat2"], blogger_cats)
21
+ end
22
+
23
+ protected
24
+ def exception_message(xmlrpc_fault_exception)
25
+ xmlrpc_fault_exception.faultString
26
+ end
27
+
28
+ def is_exception?(obj)
29
+ obj.is_a?(XMLRPC::FaultException)
30
+ end
31
+
32
+ def create_ap_request(container, body, public_method_name, *args)
33
+ test_request = ActionController::TestRequest.new
34
+ test_request.request_parameters['action'] = service_name(container)
35
+ test_request.env['REQUEST_METHOD'] = "POST"
36
+ test_request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
37
+ test_request.env['RAW_POST_DATA'] = body
38
+ test_request
39
+ end
40
+
41
+ def service_name(container)
42
+ container.is_a?(DelegatedController) ? 'test_service' : 'api'
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  #!/bin/sh
2
2
 
3
- rcov -x '.*_test\.rb,rubygems,abstract_,/run' ./run
3
+ rcov -x '.*_test\.rb,rubygems,abstract_,/run,/apis' ./run
@@ -12,23 +12,46 @@ module InvocationTest
12
12
  api_method :only_two
13
13
  end
14
14
 
15
+ class Interceptor
16
+ attr :args
17
+
18
+ def initialize
19
+ @args = nil
20
+ end
21
+
22
+ def intercept(*args)
23
+ @args = args
24
+ end
25
+ end
26
+
27
+ InterceptorClass = Interceptor.new
28
+
15
29
  class Service < ActionWebService::Base
16
30
  web_service_api API
17
31
 
18
32
  before_invocation :intercept_before, :except => [:no_before]
19
33
  after_invocation :intercept_after, :except => [:no_after]
20
- before_invocation :intercept_only, :only => [:only_one, :only_two]
34
+ prepend_after_invocation :intercept_after_first, :except => [:no_after]
35
+ prepend_before_invocation :intercept_only, :only => [:only_one, :only_two]
36
+ after_invocation(:only => [:only_one]) do |*args|
37
+ args[0].instance_variable_set('@block_invoked', args[1])
38
+ end
39
+ after_invocation InterceptorClass, :only => [:only_one]
21
40
 
22
41
  attr_accessor :before_invoked
23
42
  attr_accessor :after_invoked
43
+ attr_accessor :after_first_invoked
24
44
  attr_accessor :only_invoked
45
+ attr_accessor :block_invoked
25
46
  attr_accessor :invocation_result
26
47
 
27
48
  def initialize
28
49
  @before_invoked = nil
29
50
  @after_invoked = nil
51
+ @after_first_invoked = nil
30
52
  @only_invoked = nil
31
53
  @invocation_result = nil
54
+ @block_invoked = nil
32
55
  end
33
56
 
34
57
  def add(a, b)
@@ -69,6 +92,10 @@ module InvocationTest
69
92
  @after_invoked = name
70
93
  @invocation_result = result
71
94
  end
95
+
96
+ def intercept_after_first(name, args, result)
97
+ @after_first_invoked = name
98
+ end
72
99
 
73
100
  def intercept_only(name, args)
74
101
  raise "Interception error" unless name == :only_one || name == :only_two
@@ -94,11 +121,17 @@ class TC_Invocation < Test::Unit::TestCase
94
121
 
95
122
  def test_interceptor_registration
96
123
  assert(InvocationTest::Service.before_invocation_interceptors.length == 2)
97
- assert(InvocationTest::Service.after_invocation_interceptors.length == 1)
124
+ assert(InvocationTest::Service.after_invocation_interceptors.length == 4)
125
+ assert_equal(:intercept_only, InvocationTest::Service.before_invocation_interceptors[0])
126
+ assert_equal(:intercept_after_first, InvocationTest::Service.after_invocation_interceptors[0])
98
127
  end
99
128
 
100
129
  def test_interception
101
- assert(@service.before_invoked.nil? && @service.after_invoked.nil? && @service.only_invoked.nil? && @service.invocation_result.nil?)
130
+ assert(@service.before_invoked.nil?)
131
+ assert(@service.after_invoked.nil?)
132
+ assert(@service.only_invoked.nil?)
133
+ assert(@service.block_invoked.nil?)
134
+ assert(@service.invocation_result.nil?)
102
135
  perform_invocation(:add, 20, 50)
103
136
  assert(@service.before_invoked == :add)
104
137
  assert(@service.after_invoked == :add)
@@ -124,6 +157,7 @@ class TC_Invocation < Test::Unit::TestCase
124
157
  def test_interception_except_conditions
125
158
  perform_invocation(:no_before)
126
159
  assert(@service.before_invoked.nil?)
160
+ assert(@service.after_first_invoked == :no_before)
127
161
  assert(@service.after_invoked == :no_before)
128
162
  assert(@service.invocation_result == 5)
129
163
  @service.before_invoked = @service.after_invoked = @service.invocation_result = nil
@@ -137,6 +171,8 @@ class TC_Invocation < Test::Unit::TestCase
137
171
  assert(@service.only_invoked.nil?)
138
172
  perform_invocation(:only_one)
139
173
  assert(@service.only_invoked == :only_one)
174
+ assert(@service.block_invoked == :only_one)
175
+ assert(InvocationTest::InterceptorClass.args[1] == :only_one)
140
176
  @service.only_invoked = nil
141
177
  perform_invocation(:only_two)
142
178
  assert(@service.only_invoked == :only_two)
data/test/run CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- Dir[File.join(File.dirname(__FILE__), '*_test.rb')].each do |f|
4
- require f
5
- end
2
+ require 'test/unit'
3
+ args = Dir[File.join(File.dirname(__FILE__), '*_test.rb')] + Dir[File.join(File.dirname(__FILE__), 'ws/*_test.rb')]
4
+ (r = Test::Unit::AutoRunner.new(true)).process_args(args)
5
+ exit r.run