321 lines
6.5 KiB
Ruby
321 lines
6.5 KiB
Ruby
|
#!/usr/bin/env ruby
|
||
|
#
|
||
|
|
||
|
$LOAD_PATH.unshift("lib")
|
||
|
$LOAD_PATH.unshift("test")
|
||
|
|
||
|
require 'madeleine'
|
||
|
require 'test/unit'
|
||
|
|
||
|
|
||
|
class Append
|
||
|
def initialize(value)
|
||
|
@value = value
|
||
|
end
|
||
|
|
||
|
def execute(system)
|
||
|
system << @value
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
module TestUtils
|
||
|
def delete_directory(directory_name)
|
||
|
return unless File.exists?(directory_name)
|
||
|
Dir.foreach(directory_name) do |file|
|
||
|
next if file == "."
|
||
|
next if file == ".."
|
||
|
assert(File.delete(directory_name + File::SEPARATOR + file) == 1,
|
||
|
"Unable to delete #{file}")
|
||
|
end
|
||
|
Dir.delete(directory_name)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
class SnapshotMadeleineTest < Test::Unit::TestCase
|
||
|
include TestUtils
|
||
|
|
||
|
def teardown
|
||
|
delete_directory(persistence_base)
|
||
|
end
|
||
|
|
||
|
def persistence_base
|
||
|
"closing-test"
|
||
|
end
|
||
|
|
||
|
def test_closing
|
||
|
madeleine = SnapshotMadeleine.new(persistence_base) { "hello" }
|
||
|
madeleine.close
|
||
|
assert_raises(RuntimeError) do
|
||
|
madeleine.execute_command(Append.new("world"))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class NumberedFileTest < Test::Unit::TestCase
|
||
|
|
||
|
def test_main
|
||
|
target = Madeleine::NumberedFile.new(File::SEPARATOR + "foo", "bar", 321)
|
||
|
assert_equal(File::SEPARATOR + "foo" + File::SEPARATOR +
|
||
|
"000000000000000000321.bar",
|
||
|
target.name)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
class LoggerTest < Test::Unit::TestCase
|
||
|
include TestUtils
|
||
|
|
||
|
def teardown
|
||
|
delete_directory("whoah")
|
||
|
end
|
||
|
|
||
|
def test_creation
|
||
|
@log = Object.new
|
||
|
def @log.store(command)
|
||
|
unless defined? @commands
|
||
|
@commands = []
|
||
|
end
|
||
|
@commands << command
|
||
|
end
|
||
|
def @log.commands
|
||
|
@commands
|
||
|
end
|
||
|
|
||
|
log_factory = self
|
||
|
target = Madeleine::Logger.new("whoah", log_factory)
|
||
|
target.store(:foo)
|
||
|
assert(@log.commands.include?(:foo))
|
||
|
end
|
||
|
|
||
|
# Self-shunt
|
||
|
def create_log(directory_name)
|
||
|
@log
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class CommandVerificationTest < Test::Unit::TestCase
|
||
|
|
||
|
def teardown
|
||
|
Dir.delete("foo")
|
||
|
end
|
||
|
|
||
|
def test_broken_command
|
||
|
target = SnapshotMadeleine.new("foo") { :a_system }
|
||
|
assert_raises(Madeleine::InvalidCommandException) do
|
||
|
target.execute_command(:not_a_command)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
class CustomMarshallerTest < Test::Unit::TestCase
|
||
|
include TestUtils
|
||
|
|
||
|
def teardown
|
||
|
delete_directory(prevalence_base)
|
||
|
end
|
||
|
|
||
|
def prevalence_base
|
||
|
"custom-marshaller-test"
|
||
|
end
|
||
|
|
||
|
def madeleine_class
|
||
|
SnapshotMadeleine
|
||
|
end
|
||
|
|
||
|
def test_changing_marshaller
|
||
|
@log = ""
|
||
|
marshaller = self
|
||
|
target = madeleine_class.new(prevalence_base, marshaller) { "hello world" }
|
||
|
target.take_snapshot
|
||
|
assert_equal("dump ", @log)
|
||
|
target = nil
|
||
|
|
||
|
madeleine_class.new(prevalence_base, marshaller) { flunk() }
|
||
|
assert_equal("dump load ", @log)
|
||
|
end
|
||
|
|
||
|
def load(io)
|
||
|
@log << "load "
|
||
|
assert_equal("dump data", io.read())
|
||
|
end
|
||
|
|
||
|
def dump(system, io)
|
||
|
@log << "dump "
|
||
|
assert_equal("hello world", system)
|
||
|
io.write("dump data")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
class ErrorRaisingCommand
|
||
|
def execute(system)
|
||
|
raise "this is an exception from a command"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class ErrorHandlingTest < Test::Unit::TestCase
|
||
|
include TestUtils
|
||
|
|
||
|
def teardown
|
||
|
delete_directory(prevalence_base)
|
||
|
end
|
||
|
|
||
|
def prevalence_base
|
||
|
"error-handling-base"
|
||
|
end
|
||
|
|
||
|
def test_exception_in_command
|
||
|
madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" }
|
||
|
assert_raises(RuntimeError) do
|
||
|
madeleine.execute_command(ErrorRaisingCommand.new)
|
||
|
end
|
||
|
madeleine.close
|
||
|
madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" }
|
||
|
madeleine.close
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class QueryTest < Test::Unit::TestCase
|
||
|
include TestUtils
|
||
|
|
||
|
def teardown
|
||
|
delete_directory(prevalence_base)
|
||
|
end
|
||
|
|
||
|
def prevalence_base
|
||
|
"query-base"
|
||
|
end
|
||
|
|
||
|
def test_querying
|
||
|
madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" }
|
||
|
query = Object.new
|
||
|
def query.execute(system)
|
||
|
system.size
|
||
|
end
|
||
|
# 'query' is an un-marshallable singleton, so we implicitly test
|
||
|
# that querys aren't stored.
|
||
|
assert_equal(5, madeleine.execute_query(query))
|
||
|
# TODO: assert that no logging was done
|
||
|
# TODO: assert that lock was held
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
class TimeOptimizingLoggerTest < Test::Unit::TestCase
|
||
|
include TestUtils
|
||
|
|
||
|
def setup
|
||
|
@target = Madeleine::Logger.new("some_directory", self)
|
||
|
@log = []
|
||
|
def @log.store(command)
|
||
|
self << command
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def teardown
|
||
|
delete_directory("some_directory")
|
||
|
end
|
||
|
|
||
|
def test_optimizing_ticks
|
||
|
assert_equal(0, @log.size)
|
||
|
@target.store(Madeleine::Clock::Tick.new(Time.at(3)))
|
||
|
assert_equal(0, @log.size)
|
||
|
@target.store(Madeleine::Clock::Tick.new(Time.at(22)))
|
||
|
assert_equal(0, @log.size)
|
||
|
@target.store(Addition.new(100))
|
||
|
assert_kind_of(Madeleine::Clock::Tick, @log[0])
|
||
|
assert_equal(22, value_of_tick(@log[0]))
|
||
|
assert_equal(100, @log[1].value)
|
||
|
assert_equal(2, @log.size)
|
||
|
end
|
||
|
|
||
|
def value_of_tick(tick)
|
||
|
@clock = Object.new
|
||
|
def @clock.forward_to(time)
|
||
|
@value = time.to_i
|
||
|
end
|
||
|
def @clock.value
|
||
|
@value
|
||
|
end
|
||
|
tick.execute(self)
|
||
|
@clock.value
|
||
|
end
|
||
|
|
||
|
# Self-shunt
|
||
|
def create_log(directory_name)
|
||
|
assert_equal("some_directory", directory_name)
|
||
|
@log
|
||
|
end
|
||
|
|
||
|
# Self-shunt
|
||
|
def clock
|
||
|
@clock
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
class SharedLockQueryTest < Test::Unit::TestCase
|
||
|
include TestUtils
|
||
|
|
||
|
def prevalence_base
|
||
|
"shared_lock_test"
|
||
|
end
|
||
|
|
||
|
def teardown
|
||
|
delete_directory(prevalence_base)
|
||
|
end
|
||
|
|
||
|
def test_query
|
||
|
madeleine = SnapshotMadeleine.new(prevalence_base) { "hello" }
|
||
|
lock = Object.new
|
||
|
madeleine.instance_eval { @lock = lock } # FIXME: The horror, the horror
|
||
|
|
||
|
$shared = false
|
||
|
$was_shared = false
|
||
|
def lock.synchronize_shared(&block)
|
||
|
$shared = true
|
||
|
block.call
|
||
|
$shared = false
|
||
|
end
|
||
|
query = Object.new
|
||
|
def query.execute(system)
|
||
|
$was_shared = $shared
|
||
|
end
|
||
|
madeleine.execute_query(query)
|
||
|
assert($was_shared)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
suite = Test::Unit::TestSuite.new("Madeleine")
|
||
|
|
||
|
suite << SnapshotMadeleineTest.suite
|
||
|
suite << NumberedFileTest.suite
|
||
|
require 'test_command_log'
|
||
|
suite << CommandLogTest.suite
|
||
|
suite << LoggerTest.suite
|
||
|
suite << CommandVerificationTest.suite
|
||
|
suite << CustomMarshallerTest.suite
|
||
|
suite << ErrorHandlingTest.suite
|
||
|
suite << QueryTest.suite
|
||
|
suite << TimeOptimizingLoggerTest.suite
|
||
|
suite << SharedLockQueryTest.suite
|
||
|
require 'test_executer'
|
||
|
suite << ExecuterTest.suite
|
||
|
|
||
|
require 'test_clocked'
|
||
|
add_clocked_tests(suite)
|
||
|
require 'test_automatic'
|
||
|
add_automatic_tests(suite)
|
||
|
require 'test_persistence'
|
||
|
add_persistence_tests(suite)
|
||
|
require 'test_platforms'
|
||
|
add_platforms_tests(suite)
|
||
|
require 'test_zmarshal'
|
||
|
add_zmarshal_tests(suite)
|
||
|
|
||
|
require 'test/unit/ui/console/testrunner'
|
||
|
Test::Unit::UI::Console::TestRunner.run(suite)
|