test/test_database.rb in extralite-2.5 vs test/test_database.rb in extralite-2.6
- old
+ new
@@ -894,10 +894,57 @@
assert_equal [], db.query('select * from foo')
assert_kind_of RuntimeError, exception
assert_equal 'bar', exception.message
end
+
+ def test_database_transaction_rollback!
+ db = Extralite::Database.new(':memory:')
+ db.execute('create table foo(x)')
+
+ exception = nil
+ begin
+ db.transaction do
+ db.execute('insert into foo values (42)')
+ db.rollback!
+ end
+ rescue => e
+ exception = e
+ end
+
+ assert_equal [], db.query('select * from foo')
+ assert_nil exception
+ end
+
+ def test_database_savepoint
+ db = Extralite::Database.new(':memory:')
+ db.execute('create table foo(x)')
+
+ db.transaction do
+ assert_equal [], db.query('select * from foo')
+
+ db.execute('insert into foo values (42)')
+ assert_equal [42], db.query_single_column('select x from foo')
+
+ db.savepoint(:a)
+
+ db.execute('insert into foo values (43)')
+ assert_equal [42, 43], db.query_single_column('select x from foo')
+
+ db.savepoint(:b)
+
+ db.execute('insert into foo values (44)')
+ assert_equal [42, 43, 44], db.query_single_column('select x from foo')
+
+ db.rollback_to(:b)
+ assert_equal [42, 43], db.query_single_column('select x from foo')
+
+ db.release(:a)
+
+ assert_equal [42, 43], db.query_single_column('select x from foo')
+ end
+ end
end
class ScenarioTest < MiniTest::Test
def setup
@fn = Tempfile.new('extralite_scenario_test').path
@@ -1051,11 +1098,11 @@
db = Extralite::Database.new(tmp_fn)
assert_equal [[1, 2, 3], [4, 5, 6]], db.query_ary('select * from t')
end
end
-class GVLReleaseThresholdTest < Minitest::Test
+class ConcurrencyTest < Minitest::Test
def setup
@sql = <<~SQL
WITH RECURSIVE r(i) AS (
VALUES(0)
UNION ALL
@@ -1145,9 +1192,162 @@
assert_raises(ArgumentError) { db.gvl_release_threshold = :foo }
db.gvl_release_threshold = nil
assert_equal 1000, db.gvl_release_threshold
+ end
+
+ def test_progress_handler_simple
+ db = Extralite::Database.new(':memory:')
+
+ buf = []
+ db.on_progress(1) { buf << :progress }
+
+ result = db.query_single_row('select 1 as a, 2 as b, 3 as c')
+ assert_equal({ a: 1, b: 2, c: 3 }, result)
+ assert_in_range 5..7, buf.size
+
+ buf = []
+ db.on_progress(2) { buf << :progress }
+
+ result = db.query_single_row('select 1 as a, 2 as b, 3 as c')
+ assert_equal({ a: 1, b: 2, c: 3 }, result)
+ assert_in_range 2..4, buf.size
+ end
+
+ LONG_QUERY = <<~SQL
+ WITH RECURSIVE
+ fibo (curr, next)
+ AS
+ ( SELECT 1,1
+ UNION ALL
+ SELECT next, curr + next FROM fibo
+ LIMIT 10000000 )
+ SELECT curr, next FROM fibo LIMIT 1 OFFSET 10000000-1;
+ SQL
+
+ def test_progress_handler_timeout_interrupt
+ db = Extralite::Database.new(':memory:')
+ t0 = Time.now
+ db.on_progress(1000) do
+ Thread.pass
+ db.interrupt if Time.now - t0 >= 0.2
+ end
+
+ q = db.prepare(LONG_QUERY)
+ result = nil
+ err = nil
+ begin
+ result = q.next
+ rescue => e
+ err = e
+ end
+ t1 = Time.now
+
+ assert_nil result
+ assert_equal 1, ((t1 - t0) * 5).round.to_i
+ assert_kind_of Extralite::InterruptError, err
+
+ # try a second time, just to make sure no undefined state is left behind
+ t0 = Time.now
+ q = db.prepare(LONG_QUERY)
+ result = nil
+ err = nil
+ begin
+ result = q.next
+ rescue => e
+ err = e
+ end
+ t1 = Time.now
+
+ assert_nil result
+ assert_equal 1, ((t1 - t0) * 5).round.to_i
+ assert_kind_of Extralite::InterruptError, err
+ end
+
+ class CustomTimeoutError < RuntimeError
+ end
+
+ def test_progress_handler_timeout_raise
+ db = Extralite::Database.new(':memory:')
+ t0 = Time.now
+ db.on_progress(1000) do
+ Thread.pass
+ raise CustomTimeoutError if Time.now - t0 >= 0.2
+ end
+
+ q = db.prepare(LONG_QUERY)
+ result = nil
+ err = nil
+ begin
+ result = q.next
+ rescue => e
+ err = e
+ end
+ t1 = Time.now
+
+ assert_nil result
+ assert_equal 1, ((t1 - t0) * 5).round.to_i
+ assert_kind_of CustomTimeoutError, err
+
+ # try a second time, just to make sure no undefined state is left behind
+ t0 = Time.now
+ q = db.prepare(LONG_QUERY)
+ result = nil
+ err = nil
+ begin
+ result = q.next
+ rescue => e
+ err = e
+ end
+ t1 = Time.now
+
+ assert_nil result
+ assert_equal 1, ((t1 - t0) * 5).round.to_i
+ assert_kind_of CustomTimeoutError, err
+ end
+
+ def test_progress_handler_busy_timeout
+ fn = Tempfile.new('extralite_test_progress_handler_busy_timeout').path
+ db1 = Extralite::Database.new(fn)
+ db2 = Extralite::Database.new(fn)
+
+ db1.query('begin exclusive')
+ assert_raises(Extralite::BusyError) { db2.query('begin exclusive') }
+
+ t0 = Time.now
+ db2.on_progress(1000) do
+ Thread.pass
+ raise CustomTimeoutError if Time.now - t0 >= 0.2
+ end
+
+ result = nil
+ err = nil
+ begin
+ result = db2.execute('begin exclusive')
+ rescue => e
+ err = e
+ end
+ t1 = Time.now
+
+ assert_nil result
+ assert_equal 1, ((t1 - t0) * 5).round.to_i
+ assert_kind_of CustomTimeoutError, err
+
+ # Try a second time, to ensure no undefined state remains behind
+ t0 = Time.now
+ result = nil
+ err = nil
+ begin
+ result = db2.execute('begin exclusive')
+ rescue => e
+ err = e
+ end
+ t1 = Time.now
+
+ assert_nil result
+ assert_equal 1, ((t1 - t0) * 5).round.to_i
+ assert_kind_of CustomTimeoutError, err
end
end
class RactorTest < Minitest::Test
def test_ractor_simple