1 # 2008 January 8 2 # 3 # The author disclaims copyright to this source code. In place of 4 # a legal notice, here is a blessing: 5 # 6 # May you do good and not evil. 7 # May you find forgiveness for yourself and forgive others. 8 # May you share freely, never taking more than you give. 9 # 10 #*********************************************************************** 11 # 12 # This file contains additional tests to verify that SQLite database 13 # file survive a power loss or OS crash. 14 # 15 # $Id: crash4.test,v 1.3 2008/01/16 17:46:38 drh Exp $ 16 17 set testdir [file dirname $argv0] 18 source $testdir/tester.tcl 19 20 ifcapable !crashtest { 21 finish_test 22 return 23 } 24 25 26 # A sequence of SQL commands: 27 # 28 set sql_cmd_list { 29 {CREATE TABLE a(id INTEGER, name CHAR(50))} 30 {INSERT INTO a(id,name) VALUES(1,'one')} 31 {INSERT INTO a(id,name) VALUES(2,'two')} 32 {INSERT INTO a(id,name) VALUES(3,'three')} 33 {INSERT INTO a(id,name) VALUES(4,'four')} 34 {INSERT INTO a(id,name) VALUES(5,'five')} 35 {INSERT INTO a(id,name) VALUES(6,'six')} 36 {INSERT INTO a(id,name) VALUES(7,'seven')} 37 {INSERT INTO a(id,name) VALUES(8,'eight')} 38 {INSERT INTO a(id,name) VALUES(9,'nine')} 39 {INSERT INTO a(id,name) VALUES(10,'ten')} 40 {UPDATE A SET name='new text for row 3' WHERE id=3} 41 } 42 43 # Assume that a database is created by evaluating the SQL statements 44 # in $sql_cmd_list. Compute a set of checksums that capture the state 45 # of the database after each statement. Also include a checksum for 46 # the state of the database prior to any of these statements. 47 # 48 set crash4_cksum_set {} 49 lappend crash4_cksum_set [allcksum db] 50 foreach cmd $sql_cmd_list { 51 db eval $cmd 52 lappend crash4_cksum_set [allcksum db] 53 } 54 55 # Run the sequence of SQL statements shown above repeatedly. 56 # Close and reopen the database right before the UPDATE statement. 57 # On each repetition, introduce database corruption typical of 58 # what might be seen in a power loss or OS crash. 59 # 60 # Slowly increase the delay before the crash, repeating the test 61 # over and over. Stop testing when the entire sequence of SQL 62 # statements runs to completing without hitting the crash. 63 # 64 for {set cnt 1; set fin 0} {!$fin} {incr cnt} { 65 db close 66 file delete -force test.db test.db-journal 67 do_test crash4-1.$cnt.1 { 68 set seed [expr {int(abs(rand()*10000))}] 69 set delay [expr {int($cnt/50)+1}] 70 set file [expr {($cnt&1)?"test.db":"test.db-journal"}] 71 set c [crashsql -delay $delay -file $file -seed $seed -tclbody { 72 db eval {CREATE TABLE a(id INTEGER, name CHAR(50))} 73 db eval {INSERT INTO a(id,name) VALUES(1,'one')} 74 db eval {INSERT INTO a(id,name) VALUES(2,'two')} 75 db eval {INSERT INTO a(id,name) VALUES(3,'three')} 76 db eval {INSERT INTO a(id,name) VALUES(4,'four')} 77 db eval {INSERT INTO a(id,name) VALUES(5,'five')} 78 db eval {INSERT INTO a(id,name) VALUES(6,'six')} 79 db eval {INSERT INTO a(id,name) VALUES(7,'seven')} 80 db eval {INSERT INTO a(id,name) VALUES(8,'eight')} 81 db eval {INSERT INTO a(id,name) VALUES(9,'nine')} 82 db eval {INSERT INTO a(id,name) VALUES(10,'ten')} 83 db close 84 sqlite3 db test.db 85 db eval {UPDATE A SET name='new text for row 3' WHERE id=3} 86 db close 87 } {}] 88 if {$c==[list 0 {}]} { 89 set ::fin 1 90 set c [list 1 {child process exited abnormally}] 91 } 92 set c 93 } {1 {child process exited abnormally}} 94 sqlite3 db test.db 95 integrity_check crash4-1.$cnt.2 96 do_test crash4-1.$cnt.3 { 97 set x [lsearch $::crash4_cksum_set [allcksum db]] 98 expr {$x>=0} 99 } {1} 100 } 101 102 finish_test 103