diff options
Diffstat (limited to 'test/crash3.test')
-rw-r--r-- | test/crash3.test | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/test/crash3.test b/test/crash3.test new file mode 100644 index 0000000..7958af9 --- /dev/null +++ b/test/crash3.test @@ -0,0 +1,190 @@ +# 2007 August 23 +# +# 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. +# +#*********************************************************************** +# +# This file contains tests that verify that SQLite can correctly rollback +# databases after crashes when using the special IO modes triggered +# by device IOCAP flags. +# +# $Id: crash3.test,v 1.4 2008/07/12 14:52:20 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !crashtest { + finish_test + return +} + +proc do_test2 {name tcl res1 res2} { + set script [subst -nocommands { + do_test $name { + set res1 {$res1} + set res2 {$res2} + set res [eval {$tcl}] + if {[set res] eq [set res1] || [set res] eq [set res2]} { + set res "{[set res1]} or {[set res2]}" + } + set res + } {{$res1} or {$res2}} + }] + uplevel $script +} + +# This block tests crash-recovery when the IOCAP_ATOMIC flags is set. +# +# Each iteration of the following loop sets up the database to contain +# the following schema and data: +# +# CREATE TABLE abc(a, b, c); +# INSERT INTO abc VALUES(1, 2, 3); +# +# Then execute the SQL statement, scheduling a crash for part-way through +# the first sync() of either the database file or the journal file (often +# the journal file is not required - meaning no crash occurs). +# +# After the crash (or absence of a crash), open the database and +# verify that: +# +# * The integrity check passes, and +# * The contents of table abc is either {1 2 3} or the value specified +# to the right of the SQL statement below. +# +# The procedure is repeated 10 times for each SQL statement. Five times +# with the crash scheduled for midway through the first journal sync (if +# any), and five times with the crash midway through the database sync. +# +set tn 1 +foreach {sql res2} [list \ + {INSERT INTO abc VALUES(4, 5, 6)} {1 2 3 4 5 6} \ + {DELETE FROM abc} {} \ + {INSERT INTO abc SELECT * FROM abc} {1 2 3 1 2 3} \ + {UPDATE abc SET a = 2} {2 2 3} \ + {INSERT INTO abc VALUES(4, 5, randstr(1000,1000))} {n/a} \ + {CREATE TABLE def(d, e, f)} {n/a} \ +] { + for {set ii 0} {$ii < 10} {incr ii} { + + db close + forcedelete test.db test.db-journal + sqlite3 db test.db + do_test crash3-1.$tn.1 { + execsql { + PRAGMA page_size = 1024; + BEGIN; + CREATE TABLE abc(a, b, c); + INSERT INTO abc VALUES(1, 2, 3); + COMMIT; + } + } {} + db close + + set crashfile test.db + if {($ii%2)==0} { append crashfile -journal } + set rand "SELECT randstr($tn,$tn);" + do_test crash3-1.$tn.2 [subst { + crashsql -file $crashfile -char atomic {$rand $sql} + sqlite3 db test.db + execsql { PRAGMA integrity_check; } + }] {ok} + + do_test2 crash3-1.$tn.3 { + execsql { SELECT * FROM abc } + } {1 2 3} $res2 + + incr tn + } +} + +# This block tests both the IOCAP_SEQUENTIAL and IOCAP_SAFE_APPEND flags. +# +db close +forcedelete test.db test.db-journal +sqlite3 db test.db +do_test crash3-2.0 { + execsql { + BEGIN; + CREATE TABLE abc(a PRIMARY KEY, b, c); + CREATE TABLE def(d PRIMARY KEY, e, f); + PRAGMA default_cache_size = 10; + INSERT INTO abc VALUES(randstr(10,1000),randstr(10,1000),randstr(10,1000)); + INSERT INTO abc + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; + INSERT INTO abc + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; + INSERT INTO abc + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; + INSERT INTO abc + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; + INSERT INTO abc + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; + INSERT INTO abc + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc; + COMMIT; + } +} {} + +set tn 1 +foreach {::crashfile ::delay ::char} { + test.db 1 sequential + test.db 1 safe_append + test.db-journal 1 sequential + test.db-journal 1 safe_append + test.db-journal 2 safe_append + test.db-journal 2 sequential + test.db-journal 3 sequential + test.db-journal 3 safe_append +} { + for {set ii 0} {$ii < 100} {incr ii} { + set ::SQL [subst { + SELECT randstr($ii,$ii+10); + BEGIN; + DELETE FROM abc WHERE random()%5; + INSERT INTO abc + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) + FROM abc + WHERE (random()%5)==0; + DELETE FROM def WHERE random()%5; + INSERT INTO def + SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) + FROM def + WHERE (random()%5)==0; + COMMIT; + }] + + do_test crash3-2.$tn.$ii { + crashsql -file $::crashfile -delay $::delay -char $::char $::SQL + db close + sqlite3 db test.db + execsql {PRAGMA integrity_check} + } {ok} + } + incr tn +} + +# The following block tests an interaction between IOCAP_ATOMIC and +# IOCAP_SEQUENTIAL. At one point, if both flags were set, small +# journal files that contained only a single page, but were required +# for some other reason (i.e. nTrunk) were not being written to +# disk. +# +for {set ii 0} {$ii < 10} {incr ii} { + db close + forcedelete test.db test.db-journal + crashsql -file test.db -char {sequential atomic} { + CREATE TABLE abc(a, b, c); + } + sqlite3 db test.db + do_test crash3-3.$ii { + execsql {PRAGMA integrity_check} + } {ok} +} + +finish_test |