From a4bc123f832b2636f5240c150c9a7f8d6fadab05 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 1 Jun 2010 17:46:38 +0000 Subject: [PATCH] Change the OOM and IO error test cases in walfault.test so that each test case runs both types of error simulation. FossilOrigin-Name: b627e1536822bb7e3ef91867661a53be0efc13ef --- manifest | 14 ++-- manifest.uuid | 2 +- test/malloc_common.tcl | 144 +++++++++++++++++++++++++++++++++++++---- test/walfault.test | 86 +++++++++++++++++------- 4 files changed, 204 insertions(+), 42 deletions(-) diff --git a/manifest b/manifest index 9824a84442..4cee35672f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Delay\sthe\sdecision\sto\srestart\sthe\slog\sfile\suntil\sdata\sis\sactually\sready\sto\sbe\swritten\sto\sthe\slog\sfile\s(instead\sof\sat\sthe\sstart\sof\sa\swrite\stransaction). -D 2010-06-01T15:44:57 +C Change\sthe\sOOM\sand\sIO\serror\stest\scases\sin\swalfault.test\sso\sthat\seach\stest\scase\sruns\sboth\stypes\sof\serror\ssimulation. +D 2010-06-01T17:46:38 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -506,7 +506,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9 -F test/malloc_common.tcl d92de40a5583f977a7c1bd3a25d8f66d75e55263 +F test/malloc_common.tcl 7d2478b7f084afd8cb14b1121097ea3d989216b3 F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498 F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217 @@ -767,7 +767,7 @@ F test/walbak.test e7650a26eb4b8abeca9b145b1af1e63026dde432 F test/walcksum.test 4efa8fb88c32bed8288ea4385a9cc113a5c8f0bf F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f F test/walcrash2.test 14585ad1a2c85da2de721caa3b4deeea55213008 -F test/walfault.test 690350d02057409b695a3694f048780f2c5e21f4 +F test/walfault.test c3c5478d23742ef887bec54fe7de9b0c1de07e1e F test/walhook.test 67e675127f4acb72f061a12667ce6e5460b06b78 F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048 F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933 @@ -815,7 +815,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 1d3e569e59ba89cc167f0a48951ecd82f10322ba -R b704a2554ef7915333dfdde871fa034e +P b1abfaaf5309cc0d0dda4fb2c237862c8cf83261 +R 0d10d60aa1f988cbb877d394e9ed3639 U dan -Z 3d2943f29bb11a4315abddbe2964e6d2 +Z c5ae99887497d633a8a1fd47de534f18 diff --git a/manifest.uuid b/manifest.uuid index 798ada6560..dde174137c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b1abfaaf5309cc0d0dda4fb2c237862c8cf83261 \ No newline at end of file +b627e1536822bb7e3ef91867661a53be0efc13ef \ No newline at end of file diff --git a/test/malloc_common.tcl b/test/malloc_common.tcl index 992f545f29..057cf7c412 100644 --- a/test/malloc_common.tcl +++ b/test/malloc_common.tcl @@ -23,6 +23,105 @@ ifcapable builtin_test { return 0 } + +#-------------------------------------------------------------------------- +# Usage do_faultsim_test NAME ?OPTIONS...? +# +# -faults List of fault types to simulate. +# +# -prep Script to execute before -body. +# +# -body Script to execute (with fault injection). +# +# -test Script to execute after -body. +# +proc do_faultsim_test {name args} { + set DEFAULT(-faults) [list \ + oom-transient oom-persistent \ + ioerr-transient ioerr-persistent \ + ] + set DEFAULT(-prep) "" + set DEFAULT(-body) "" + set DEFAULT(-test) "" + + array set O [array get DEFAULT] + array set O $args + foreach o [array names O] { + if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" } + } + + set A(oom-transient) [list \ + -injectstart {oom_injectstart 0} \ + -injectstop oom_injectstop \ + -injecterrlist {{1 {out of memory}}} \ + ] + set A(oom-persistent) [list \ + -injectstart {oom_injectstart 1000000} \ + -injectstop oom_injectstop \ + -injecterrlist {{1 {out of memory}}} \ + ] + + set A(ioerr-transient) [list \ + -injectstart {ioerr_injectstart 0} \ + -injectstop ioerr_injectstop \ + -injecterrlist {{1 {disk I/O error}}} \ + ] + + set A(ioerr-persistent) [list \ + -injectstart {ioerr_injectstart 1} \ + -injectstop ioerr_injectstop \ + -injecterrlist {{1 {disk I/O error}}} \ + ] + + foreach f $O(-faults) { + if {[info exists A($f)]==0} { error "unknown fault: $f" } + } + set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)] + foreach f $O(-faults) { + eval do_one_faultsim_test "$name-$f" $A($f) $testspec + } +} + +#------------------------------------------------------------------------- +# Procedures to save and restore the current file-system state: +# +# faultsim_save_and_close +# faultsim_restore_and_reopen +# +proc faultsim_save_and_close {} { + foreach {a => b} { + test.db => testX.db + test.db-wal => testX.db-wal + test.db-journal => testX.db-journal + } { + if {[file exists $a]} { + file copy -force $a $b + } else { + file delete -force $b + } + } + catch { db close } + return "" +} +proc faultsim_restore_and_reopen {} { + catch { db close } + foreach {a => b} { + testX.db => test.db + testX.db-wal => test.db-wal + testX.db-journal => test.db-journal + } { + if {[file exists $a]} { + file copy -force $a $b + } else { + file delete -force $b + } + } + sqlite3 db test.db + sqlite3_extended_result_codes db 1 + sqlite3_db_config_lookaside db 0 0 0 +} + + # The following procs are used as [do_faultsim_test] when injecting OOM # faults into test cases. # @@ -33,19 +132,35 @@ proc oom_injectstop {} { sqlite3_memdebug_fail -1 } -# This command is only useful when used by the -test script of a -# [do_faultsim_test] test case. +proc ioerr_injectstart {persist iFail} { + set ::sqlite_io_error_persist $persist + set ::sqlite_io_error_pending $iFail +} +proc ioerr_injectstop {} { + set sv $::sqlite_io_error_hit + set ::sqlite_io_error_persist 0 + set ::sqlite_io_error_pending 0 + set ::sqlite_io_error_hardhit 0 + set ::sqlite_io_error_hit 0 + set ::sqlite_io_error_pending 0 + return $sv +} + +# This command is not called directly. It is used by the +# [faultsim_test_result] command created by [do_faultsim_test] and used +# by -test scripts. # -proc faultsim_test_result {args} { +proc faultsim_test_result_int {args} { upvar testrc testrc testresult testresult testnfail testnfail set t [list $testrc $testresult] - set r [concat $args [list {1 {out of memory}}]] + set r $args if { ($testnfail==0 && $t != [lindex $r 0]) || [lsearch $r $t]<0 } { error "nfail=$testnfail rc=$testrc result=$testresult" } } -# Usage do_faultsim_test NAME ?OPTIONS...? +#-------------------------------------------------------------------------- +# Usage do_one_faultsim_test NAME ?OPTIONS...? # # The first argument, , is used as a prefix of the test names # taken by tests executed by this command. Options are as follows. All @@ -55,19 +170,23 @@ proc faultsim_test_result {args} { # # -injectstop Script to disable fault-injection. # +# -injecterrlist List of generally acceptable test results (i.e. error +# messages). Example: [list {1 {out of memory}}] +# # -prep Script to execute before -body. # # -body Script to execute (with fault injection). # # -test Script to execute after -body. # -proc do_faultsim_test {testname args} { +proc do_one_faultsim_test {testname args} { - set DEFAULT(-injectstart) {oom_injectstart 0} - set DEFAULT(-injectstop) {oom_injectstop} - set DEFAULT(-prep) "" - set DEFAULT(-body) "" - set DEFAULT(-test) "" + set DEFAULT(-injectstart) {oom_injectstart 0} + set DEFAULT(-injectstop) {oom_injectstop} + set DEFAULT(-injecterrlist) [list {1 {out of memory}}] + set DEFAULT(-prep) "" + set DEFAULT(-body) "" + set DEFAULT(-test) "" array set O [array get DEFAULT] array set O $args @@ -76,6 +195,9 @@ proc do_faultsim_test {testname args} { } proc faultsim_test_proc {testrc testresult testnfail} $O(-test) + proc faultsim_test_result {args} " + uplevel faultsim_test_result_int \$args [list $O(-injecterrlist)] + " set stop 0 for {set iFail 1} {!$stop} {incr iFail} { diff --git a/test/walfault.test b/test/walfault.test index 3b0395e05f..05b26dad6d 100644 --- a/test/walfault.test +++ b/test/walfault.test @@ -19,10 +19,20 @@ source $testdir/malloc_common.tcl ifcapable !wal {finish_test ; return } -do_faultsim_test walfault-oom-1 -prep { - catch { db close } +#------------------------------------------------------------------------- +# This test case, walfault-1-*, simulates faults while executing a +# +# PRAGMA journal_mode = WAL; +# +# statement immediately after creating a new database. +# +do_test walfault-1-pre-1 { + db close file delete -force test.db test.db-wal test.db-journal - sqlite3 db test.db + faultsim_save_and_close +} {} +do_faultsim_test walfault-1 -prep { + faultsim_restore_and_reopen } -body { db eval { PRAGMA main.journal_mode = WAL } } -test { @@ -49,7 +59,12 @@ do_faultsim_test walfault-oom-1 -prep { if { $testrc==0 && $jm!="wal" } { error "Journal mode is not WAL" } } -do_malloc_test walfault-oom-2 -tclprep { +#-------------------------------------------------------------------------- +# Test case walfault-2-* tests fault injection during recovery of a +# short WAL file (a dozen frames or thereabouts). +# +do_test walfault-2-pre-1 { + sqlite3 db test.db execsql { PRAGMA journal_mode = WAL; BEGIN; @@ -62,29 +77,54 @@ do_malloc_test walfault-oom-2 -tclprep { INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; INSERT INTO x SELECT randomblob(100), randomblob(100) FROM x; } - file copy -force test.db testX.db - file copy -force test.db-wal testX.db-wal - db close - file rename -force testX.db test.db - file rename -force testX.db-wal test.db-wal + execsql { + SELECT count(*) FROM x + } +} {8} +do_test walfault-2-pre-2 { + faultsim_save_and_close + faultsim_restore_and_reopen + execsql { SELECT count(*) FROM x } +} {8} +do_faultsim_test walfault-2 -prep { + faultsim_restore_and_reopen +} -body { + execsql { SELECT count(*) FROM x } +} -test { + # Test that all the rows in the WAL were recovered. + faultsim_test_result {0 8} + + # Run the integrity_check to make sure nothing strange has occurred. + set ic [db eval { PRAGMA integrity_check }] + if {$ic != "ok"} { error "Integrity check: $ic" } +} + +#-------------------------------------------------------------------------- +# Test fault injection while writing and checkpointing a small WAL file. +# +do_test walfault-3-pre-1 { sqlite3 db test.db - sqlite3_extended_result_codes db 1 - sqlite3_db_config_lookaside db 0 0 0 -} -sqlbody { - SELECT count(*) FROM x; -} + execsql { + PRAGMA auto_vacuum = 1; + PRAGMA journal_mode = WAL; + CREATE TABLE abc(a PRIMARY KEY); + INSERT INTO abc VALUES(randomblob(1500)); + } + db close + faultsim_save_and_close +} {} -do_ioerr_test walfault-ioerr-1 -sqlprep { - PRAGMA auto_vacuum = 1; - PRAGMA journal_mode = WAL; - CREATE TABLE abc(a PRIMARY KEY); - INSERT INTO abc VALUES(randomblob(1500)); -} -sqlbody { - DELETE FROM abc; - PRAGMA wal_checkpoint; +do_faultsim_test walfault-3 -prep { + faultsim_restore_and_reopen +} -body { + db eval { + DELETE FROM abc; + PRAGMA wal_checkpoint; + } +} -test { + faultsim_test_result {0 {}} } -catch {db close} # A [testvfs] callback for the VFS created by [do_shmfault_test]. This # callback injects SQLITE_IOERR faults into methods for which an entry