Vaguely humorous Test::Unit problem (long)


#1

Hi everybody,

I have a problem I can’t figure out. I’ve created a test class using
Test::Unit::TestCase. One of the test cases is failing, but if I
comment out the passing one, the failing one passes. Moreover, if I
rename the failing test to something preceeding the passing one in
alphabetical order, it passes.

The issue is a bit complicated, however. I’ll post some code, then
explain it.

require ‘drb’
require ‘test/unit’
require ‘…/lib/classes/Config.rb’
require ‘…/lib/classes/Service.rb’

class TestService < Test::Unit::TestCase

def test_statistics # fails, unless named e.g. test_astatistics
message = {:data => [1,1,1], :mixin => :statistics}.to_config
config = {:url => ‘druby://localhost:9001’,}.to_config

remote_service = Service.new(config)
DRb.start_service()
service = DRbObject.new(nil, config.url)
assert_equal([:statistics, 1, 0], service.process(message))

end

def test_service_drb # Always passes.
message = {:data => 1, :mixin => :trivial}.to_config
config = {:url => ‘druby://localhost:9000’,}.to_config

remote_service = Service.new(config)
DRb.start_service()
service = DRbObject.new(nil, config.url)
assert_equal(service.process(message),1)

end
end

EOC

Note that outside of the message and config objects, and parameters to
assert_equal, the code is identical.

The Hash.to_config method turns hash keys into attr_reader’s and hash
values into the reader’s return value. The new object’s class is
Config.

Oh, right, I should explain what a Service object is. First off,
Service.new(config) takes in a Config object. It also starts a DRb
server with the line:

DRb.start_service(@config.url, self)

service.process is harder to explain. Essentially, Service objects
are servers that dynamically change how they process data depending on
the type of data they recieve. I implemented this idea using mixins
and a stable public API. So for each call of
service.process(message), the Service object checks the value of
config.mixin, compares it to the currently loaded module, and requires
and includes it if they differ. Then it calls the run(message.data)
method, which is implemented by the mixed in module. The Service
class:

class Service

def initialize(config)
@mixin = “”
@config = config
DRb.start_service(@config.url, self)
end

def process(message)
new_mixin = message.mixin
unless @mixin == new_mixin
require “…/lib/services/#{new_mixin.to_s.capitalize}.rb”
self.class.class_eval(“include #{new_mixin.to_s.capitalize}” )
@mixin = new_mixin
end
self.run(message.data)
end
end

EOC

Little help?
Thanks,
Alex


#2

You’re calling DRb.start_service a lot. In my experience, this can lead
to
problems. Try adding DRb.stop_service in #teardown.


#3

On Jun 26, 1:13 pm, removed_email_address@domain.invalid wrote:

def test_service_stat # fails
end
Statistics::run(data). Is DRb threaded? Could this be a race
condition in DRb and not my code? (I can’t see how it would by a bug
in my code)

My mistake. DRb is obviously threaded. I meant to ask if Test::Unit
is threaded, and if there might be a race condition there.

Alex


#4

On Jun 26, 12:57 am, Sylvain J. removed_email_address@domain.invalid
wrote:

You’re calling DRb.start_service a lot. In my experience, this can lead to
problems. Try adding DRb.stop_service in #teardown.

Sylvain J.

Well, I refactored the tests so that Drb.start_service is only called
once. I still get the name dependent failure.

require ‘drb’
require ‘test/unit’
require ‘…/lib/classes/Config.rb’
require ‘…/lib/classes/Service.rb’

class TestService < Test::Unit::TestCase

@@config = {:url => ‘druby://localhost:9001’,}.to_config
@@remote_service = Service.new(@@config) # calls DRb.service_start

def test_service_stat # fails
message = {:data => [1,1,1], :mixin => :statistics}.to_config
service = DRbObject.new(nil, @@config.url)
assert_equal([:statistics, 1, 0], service.process(message))
end

def test_service_trivial
message = {:data => 1, :mixin => :trivial}.to_config
service = DRbObject.new(nil, @@config.url)
assert_equal(service.process(message),1)
end
end

EOC

One thing I forgot to mention is that test_service_statistics fails
with:

<[:statistics, 1, 0]> expected but was
<[1, 1, 1]>

which means that it was actually using Trivial::run(data) instead of
Statistics::run(data). Is DRb threaded? Could this be a race
condition in DRb and not my code? (I can’t see how it would by a bug
in my code)

Thanks,
Alex