# -*- encoding: binary -*- $stdout.sync = $stderr.sync = true require 'test/unit' require 'tempfile' $-w = true require 'tdb' class Test_TDB_MT < Test::Unit::TestCase def setup @tdb = @tmp = nil @start_pid = $$ end def teardown return if @start_pid != $$ @tmp.close! if @tmp.respond_to?(:close!) @tdb.close if @tdb && ! @tdb.closed? end def test_make_threadsafe @tdb = TDB.new(nil) assert_kind_of TDB, @tdb assert ! @tdb.threadsafe? assert_nothing_raised { @tdb.threadsafe! } assert @tdb.threadsafe? @tdb.each { |k,v| assert_equal v, @tdb[k] } end def test_init_threadsafe @tdb = TDB.new(nil, :threadsafe => true) assert @tdb.threadsafe? @tdb.close @tdb = TDB.new(nil, :threadsafe => false) assert ! @tdb.threadsafe? @tdb.close @tdb = TDB.new(nil) assert ! @tdb.threadsafe? @tdb.close end def test_thread_safe_torture_test @tdb = TDB.new(nil) assert_nothing_raised { @tdb.threadsafe! } pid = fork do Thread.abort_on_exception = true threads = [] blob = 'foo' * 1000 nr = 10000 t = Thread.new do while true Thread.pass @tdb.to_a end end threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } } threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } } threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } } threads << Thread.new { nr.times { |i| @tdb[i.to_s] = blob } } threads << t t.kill threads.each { |t| t.join } end _, status = Process.waitpid2(pid) assert status.success?, status.inspect end def test_check_methods m = TDB.instance_methods.sort m -= Object.instance_methods m -= Enumerable.instance_methods m.map! { |x| x.to_sym } mt = TDB::MT.instance_methods.sort m -= [ :threadsafe! ] m += [ :include?, :member? ] m.sort! unwrapped = ( (m - mt) | (mt - m)).uniq assert unwrapped.empty?, "unwrapped methods: #{unwrapped.inspect}" @tdb = TDB.new(nil) respond_to?(:refute_match) and m.each { |meth| refute_match(/\bTDB::MT\b/, @tdb.method(meth).to_s) } @tdb.threadsafe! m.each { |meth| assert_match(/\bTDB::MT\b/, @tdb.method(meth).to_s) } end end