diff options
Diffstat (limited to 'ext/rbu/rbu12.test')
-rw-r--r-- | ext/rbu/rbu12.test | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/ext/rbu/rbu12.test b/ext/rbu/rbu12.test new file mode 100644 index 0000000..7816bfe --- /dev/null +++ b/ext/rbu/rbu12.test @@ -0,0 +1,234 @@ +# 2015 February 16 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source $testdir/tester.tcl +source $testdir/lock_common.tcl +set ::testprefix rbu12 + +set setup_sql { + DROP TABLE IF EXISTS xx; + DROP TABLE IF EXISTS xy; + CREATE TABLE xx(a, b, c PRIMARY KEY); + INSERT INTO xx VALUES(1, 2, 3); + CREATE TABLE xy(a, b, c PRIMARY KEY); + + ATTACH 'rbu.db' AS rbu; + DROP TABLE IF EXISTS data_xx; + CREATE TABLE rbu.data_xx(a, b, c, rbu_control); + INSERT INTO data_xx VALUES(4, 5, 6, 0); + INSERT INTO data_xx VALUES(7, 8, 9, 0); + CREATE TABLE rbu.data_xy(a, b, c, rbu_control); + INSERT INTO data_xy VALUES(10, 11, 12, 0); + DETACH rbu; +} + +do_multiclient_test tn { + + # Initialize a target (test.db) and rbu (rbu.db) database. + # + forcedelete rbu.db + sql1 $setup_sql + + # Using connection 2, open a read transaction on the target database. + # RBU will still be able to generate "test.db-oal", but it will not be + # able to rename it to "test.db-wal". + # + do_test 1.$tn.1 { + sql2 { BEGIN; SELECT * FROM xx; } + } {1 2 3} + do_test 1.$tn.2 { + sqlite3rbu rbu test.db rbu.db + while 1 { + set res [rbu step] + if {$res!="SQLITE_OK"} break + } + set res + } {SQLITE_BUSY} + + do_test 1.$tn.3 { sql2 { SELECT * FROM xx; } } {1 2 3} + do_test 1.$tn.4 { sql2 { SELECT * FROM xy; } } {} + do_test 1.$tn.5 { + list [file exists test.db-wal] [file exists test.db-oal] + } {0 1} + do_test 1.$tn.6 { sql2 COMMIT } {} + + # The rbu object that hit the SQLITE_BUSY error above cannot be reused. + # It is stuck in a permanent SQLITE_BUSY state at this point. + # + do_test 1.$tn.7 { rbu step } {SQLITE_BUSY} + do_test 1.$tn.8 { + list [catch { rbu close } msg] $msg + } {1 SQLITE_BUSY} + + do_test 1.$tn.9.1 { sql2 { BEGIN EXCLUSIVE } } {} + do_test 1.$tn.9.2 { + sqlite3rbu rbu test.db rbu.db + rbu step + } {SQLITE_BUSY} + do_test 1.$tn.9.3 { + list [catch { rbu close } msg] $msg + } {1 {SQLITE_BUSY - database is locked}} + do_test 1.$tn.9.4 { sql2 COMMIT } {} + + sqlite3rbu rbu test.db rbu.db + do_test 1.$tn.10.1 { sql2 { BEGIN EXCLUSIVE } } {} + do_test 1.$tn.10.2 { + rbu step + } {SQLITE_BUSY} + do_test 1.$tn.10.3 { + list [catch { rbu close } msg] $msg + } {1 SQLITE_BUSY} + do_test 1.$tn.10.4 { sql2 COMMIT } {} + + # A new rbu object can finish the work though. + # + do_test 1.$tn.11 { + sqlite3rbu rbu test.db rbu.db + rbu step + } {SQLITE_OK} + do_test 1.$tn.12 { + list [file exists test.db-wal] [file exists test.db-oal] + } {1 0} + do_test 1.$tn.13 { + while 1 { + set res [rbu step] + if {$res!="SQLITE_OK"} break + } + set res + } {SQLITE_DONE} + + do_test 1.$tn.14 { + rbu close + } {SQLITE_DONE} +} + +do_multiclient_test tn { + + # Initialize a target (test.db) and rbu (rbu.db) database. + # + forcedelete rbu.db + sql1 $setup_sql + + do_test 2.$tn.1 { + sqlite3rbu rbu test.db rbu.db + while {[file exists test.db-wal]==0} { + if {[rbu step]!="SQLITE_OK"} {error "problem here...."} + } + rbu close + } {SQLITE_OK} + + + do_test 2.$tn.2 { sql2 { BEGIN IMMEDIATE } } {} + + do_test 2.$tn.3 { + sqlite3rbu rbu test.db rbu.db + rbu step + } {SQLITE_BUSY} + + do_test 2.$tn.4 { list [catch { rbu close } msg] $msg } {1 SQLITE_BUSY} + + do_test 2.$tn.5 { + sql2 { SELECT * FROM xx ; COMMIT } + } {1 2 3 4 5 6 7 8 9} + + do_test 2.$tn.6 { + sqlite3rbu rbu test.db rbu.db + rbu step + rbu close + } {SQLITE_OK} + + do_test 2.$tn.7 { sql2 { BEGIN EXCLUSIVE } } {} + + do_test 2.$tn.8 { + sqlite3rbu rbu test.db rbu.db + rbu step + } {SQLITE_BUSY} + do_test 2.$tn.9 { list [catch { rbu close } msg] $msg } {1 SQLITE_BUSY} + do_test 2.$tn.10 { + sql2 { SELECT * FROM xx ; COMMIT } + } {1 2 3 4 5 6 7 8 9} + + do_test 2.$tn.11 { + sqlite3rbu rbu test.db rbu.db + while {[rbu step]=="SQLITE_OK"} {} + rbu close + } {SQLITE_DONE} + +} + +#------------------------------------------------------------------------- +# Test that "PRAGMA data_version" works when an RBU client writes the +# database. +# +do_multiclient_test tn { + + # Initialize a target (test.db) and rbu (rbu.db) database. + # + forcedelete rbu.db + sql1 $setup_sql + + # Check the initial database contains table "xx" with a single row. + # Also save the current values of "PRAGMA data-version" for [db1] + # and [db2]. + # + do_test 2.$tn.1 { + list [sql1 { SELECT count(*) FROM xx }] [sql2 { SELECT count(*) FROM xx }] + } {1 1} + set V1 [sql1 {PRAGMA data_version}] + set V2 [sql2 {PRAGMA data_version}] + + # Check the values of data-version have not magically changed. + # + do_test 2.$tn.2 { + list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}] + } [list $V1 $V2] + + # Start stepping the RBU. From the point of view of [db1] and [db2], the + # data-version values remain unchanged until the database contents are + # modified. At which point the values are incremented. + # + sqlite3rbu rbu test.db rbu.db + set x 0 + while {[db one {SELECT count(*) FROM xx}]==1} { + do_test 2.$tn.3.[incr x] { + list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}] + } [list $V1 $V2] + rbu step + } + do_test 2.$tn.5.1 { expr {$V1 < [sql1 {PRAGMA data_version}]} } 1 + do_test 2.$tn.5.2 { expr {$V2 < [sql2 {PRAGMA data_version}]} } 1 + + # Check the db contents is as expected. + # + do_test 2.$tn.4 { + list [sql1 {SELECT count(*) FROM xx}] [sql2 {SELECT count(*) FROM xx}] + } {3 3} + + set V1 [sql1 {PRAGMA data_version}] + set V2 [sql2 {PRAGMA data_version}] + + # Finish applying the RBU (i.e. do the incremental checkpoint). Check that + # this does not cause the data-version values to change. + # + while {[rbu step]=="SQLITE_OK"} { } + rbu close + + do_test 2.$tn.6 { + list [sql1 {PRAGMA data_version}] [sql2 {PRAGMA data_version}] + } [list $V1 $V2] + +} + +finish_test |