test/test.rb in daybreak-0.1.3 vs test/test.rb in daybreak-0.2.0
- old
+ new
@@ -1,130 +1,324 @@
+require 'minitest/autorun'
+require 'minitest/benchmark'
+
require 'set'
-begin
- require 'simplecov'
- SimpleCov.start
- SimpleCov.command_name "Unit tests"
-rescue Exception => ex
- puts "No coverage report generated: #{ex.message}"
-end
-
require File.expand_path(File.dirname(__FILE__)) + '/test_helper.rb'
-describe "database functions" do
+describe Daybreak::DB do
before do
@db = Daybreak::DB.new DB_PATH
end
- it "should insert" do
+ it 'should insert' do
@db[1] = 1
assert_equal @db[1], 1
assert @db.has_key?(1)
@db[1] = '2'
assert_equal @db[1], '2'
assert_equal @db.length, 1
end
- it "should persist values" do
- @db.set('1', '4', true)
- @db.set('4', '1', true)
+ it 'should persist values' do
+ @db['1'] = '4'
+ @db['4'] = '1'
+ @db.sync
assert_equal @db['1'], '4'
db2 = Daybreak::DB.new DB_PATH
assert_equal db2['1'], '4'
assert_equal db2['4'], '1'
- db2.close!
+ db2.close
end
- it "should compact cleanly" do
+ it 'should persist after clear' do
+ @db['1'] = 'xy'
+ @db.clear
+ @db['1'] = '4'
+ @db['4'] = '1'
+ @db.close
+
+ @db = Daybreak::DB.new DB_PATH
+ assert_equal @db['1'], '4'
+ assert_equal @db['4'], '1'
+ end
+
+ it 'should persist after compact' do
+ @db['1'] = 'xy'
+ @db['1'] = 'z'
+ @db.compact
+ @db['1'] = '4'
+ @db['4'] = '1'
+ @db.close
+
+ @db = Daybreak::DB.new DB_PATH
+ assert_equal @db['1'], '4'
+ assert_equal @db['4'], '1'
+ end
+
+ it 'should reload database file in sync after compact' do
+ db = Daybreak::DB.new DB_PATH
+
+ @db['1'] = 'xy'
+ @db['1'] = 'z'
+ @db.compact
+ @db['1'] = '4'
+ @db['4'] = '1'
+ @db.flush
+
+ db.sync
+ assert_equal db['1'], '4'
+ assert_equal db['4'], '1'
+ db.close
+ end
+
+ it 'should reload database file in sync after clear' do
+ db = Daybreak::DB.new DB_PATH
+
+ @db['1'] = 'xy'
+ @db['1'] = 'z'
+ @db.clear
+ @db['1'] = '4'
+ @db['4'] = '1'
+ @db.flush
+
+ db.sync
+ assert_equal db['1'], '4'
+ assert_equal db['4'], '1'
+ db.close
+ end
+
+ it 'should compact cleanly' do
@db[1] = 1
@db[1] = 1
- @db.flush!
+ @db.sync
+
size = File.stat(DB_PATH).size
- @db.compact!
+ @db.compact
assert_equal @db[1], 1
assert size > File.stat(DB_PATH).size
end
- it "should allow for default values" do
- default_db = Daybreak::DB.new(DB_PATH, 0)
+ it 'should allow for default values' do
+ default_db = Daybreak::DB.new(DB_PATH, :default => 0)
assert_equal default_db[1], 0
default_db[1] = 1
assert_equal default_db[1], 1
+ default_db.close
end
- it "should handle default values that are procs" do
+ it 'should handle default values that are procs' do
db = Daybreak::DB.new(DB_PATH) {|key| Set.new }
assert db['foo'].is_a? Set
+ db.close
end
- it "should be able to sync competing writes" do
+ it 'should be able to sync competing writes' do
@db.set! '1', 4
db2 = Daybreak::DB.new DB_PATH
db2.set! '1', 5
- @db.read!
+ @db.sync
assert_equal @db['1'], 5
+ db2.close
end
- it "should be able to handle another process's call to compact" do
- 20.times {|i| @db.set i, i, true }
+ it 'should be able to handle another process\'s call to compact' do
+ @db.lock { 20.times {|i| @db[i] = i } }
db2 = Daybreak::DB.new DB_PATH
- 20.times {|i| @db.set i, i + 1, true }
- @db.compact!
- db2.read!
- assert_equal 20, db2['19']
+ @db.lock { 20.times {|i| @db[i] = i } }
+ @db.compact
+ db2.sync
+ assert_equal 19, db2['19']
+ db2.close
end
- it "can empty the database" do
+ it 'can empty the database' do
20.times {|i| @db[i] = i }
- @db.empty!
+ @db.clear
db2 = Daybreak::DB.new DB_PATH
assert_equal nil, db2['19']
+ db2.close
end
- it "should compact subclassed dbs" do
- class StringDB < Daybreak::DB
- def serialize(it)
- it.to_s
- end
-
- def parse(it)
- it
- end
- end
-
- db = StringDB.new 'string.db'
- db[1] = 'one'
- db[2] = 'two'
- db.delete 2
- db.compact!
- assert_equal db[1], 'one'
- assert_equal db[2], nil
- db.empty!
- db.close!
- end
-
- it "should handle deletions" do
+ it 'should handle deletions' do
@db[1] = 'one'
@db[2] = 'two'
- @db.delete 'two'
+ @db.delete! 'two'
assert !@db.has_key?('two')
assert_equal @db['two'], nil
db2 = Daybreak::DB.new DB_PATH
assert !db2.has_key?('two')
assert_equal db2['two'], nil
+ db2.close
end
- it "should close and reopen the file when clearing the database" do
+ it 'should close and reopen the file when clearing the database' do
begin
1000.times {@db.clear}
rescue
flunk
end
end
+ it 'should have threadsafe lock' do
+ @db[1] = 0
+ inc = proc { 1000.times { @db.lock { @db[1] += 1 } } }
+ a = Thread.new &inc
+ b = Thread.new &inc
+ a.join
+ b.join
+ assert_equal @db[1], 2000
+ end
+
+ it 'should synchronize across processes' do
+ @db[1] = 0
+ @db.flush
+ @db.close
+ begin
+ a = fork do
+ db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ db.lock { db[1] += 1 }
+ db["a#{i}"] = i
+ sleep 0.01 if i % 100 == 0
+ end
+ db.close
+ end
+ b = fork do
+ db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ db.lock { db[1] += 1 }
+ db["b#{i}"] = i
+ sleep 0.01 if i % 100 == 0
+ end
+ db.close
+ end
+ Process.wait a
+ Process.wait b
+ @db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ assert_equal @db["a#{i}"], i
+ assert_equal @db["b#{i}"], i
+ end
+ assert_equal @db[1], 2000
+ rescue NotImplementedError
+ warn 'fork is not available: skipping multiprocess test'
+ @db = Daybreak::DB.new DB_PATH
+ end
+ end
+
+ it 'should synchronize across threads' do
+ @db[1] = 0
+ @db.flush
+ @db.close
+ a = Thread.new do
+ db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ db.lock { db[1] += 1 }
+ db["a#{i}"] = i
+ sleep 0.01 if i % 100 == 0
+ end
+ db.close
+ end
+ b = Thread.new do
+ db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ db.lock { db[1] += 1 }
+ db["b#{i}"] = i
+ sleep 0.01 if i % 100 == 0
+ end
+ db.close
+ end
+ a.join
+ b.join
+ @db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ assert_equal @db["a#{i}"], i
+ assert_equal @db["b#{i}"], i
+ end
+ assert_equal @db[1], 2000
+ end
+
+ it 'should support background compaction' do
+ @db[1] = 0
+ @db.flush
+ @db.close
+ stop = false
+ a = Thread.new do
+ db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ db.lock { db[1] += 1 }
+ db["a#{i}"] = i
+ sleep 0.01 if i % 100 == 0
+ end
+ db.close
+ end
+ b = Thread.new do
+ db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ db.lock { db[1] += 1 }
+ db["b#{i}"] = i
+ sleep 0.01 if i % 100 == 0
+ end
+ db.close
+ end
+ c = Thread.new do
+ db = Daybreak::DB.new DB_PATH
+ db.compact until stop
+ db.close
+ end
+ d = Thread.new do
+ db = Daybreak::DB.new DB_PATH
+ db.compact until stop
+ db.close
+ end
+ stop = true
+ a.join
+ b.join
+ c.join
+ d.join
+ @db = Daybreak::DB.new DB_PATH
+ 1000.times do |i|
+ assert_equal @db["a#{i}"], i
+ assert_equal @db["b#{i}"], i
+ end
+ assert_equal @db[1], 2000
+ end
+
+ it 'should support compact in lock' do
+ @db[1] = 2
+ @db.lock do
+ @db[1] = 2
+ @db.compact
+ end
+ end
+
+ it 'should support clear in lock' do
+ @db[1] = 2
+ @db.lock do
+ @db[1] = 2
+ @db.clear
+ end
+ end
+
+ it 'should support flush in lock' do
+ @db[1] = 2
+ @db.lock do
+ @db[1] = 2
+ @db.flush
+ end
+ end
+
+ it 'should support set! in lock' do
+ @db[1] = 2
+ @db.lock do
+ @db.set!(1, 2)
+ end
+ end
+
after do
- @db.empty!
- @db.close!
+ @db.clear
+ @db.close
end
end