Annotation of embedaddon/sqlite3/test/backup_ioerr.test, revision 1.1
1.1 ! misho 1: # 2009 January 30
! 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: # This file implements regression tests for SQLite library. The
! 12: # focus of this file is testing the handling of IO errors by the
! 13: # sqlite3_backup_XXX APIs.
! 14: #
! 15: # $Id: backup_ioerr.test,v 1.3 2009/04/10 18:41:01 danielk1977 Exp $
! 16:
! 17: set testdir [file dirname $argv0]
! 18: source $testdir/tester.tcl
! 19:
! 20: proc data_checksum {db file} {
! 21: $db one "SELECT md5sum(a, b) FROM ${file}.t1"
! 22: }
! 23: proc test_contents {name db1 file1 db2 file2} {
! 24: $db2 eval {select * from sqlite_master}
! 25: $db1 eval {select * from sqlite_master}
! 26: set checksum [data_checksum $db2 $file2]
! 27: uplevel [list do_test $name [list data_checksum $db1 $file1] $checksum]
! 28: }
! 29:
! 30: #--------------------------------------------------------------------
! 31: # This proc creates a database of approximately 290 pages. Depending
! 32: # on whether or not auto-vacuum is configured. Test cases backup_ioerr-1.*
! 33: # verify nothing more than this assumption.
! 34: #
! 35: proc populate_database {db {xtra_large 0}} {
! 36: execsql {
! 37: BEGIN;
! 38: CREATE TABLE t1(a, b);
! 39: INSERT INTO t1 VALUES(1, randstr(1000,1000));
! 40: INSERT INTO t1 SELECT a+ 1, randstr(1000,1000) FROM t1;
! 41: INSERT INTO t1 SELECT a+ 2, randstr(1000,1000) FROM t1;
! 42: INSERT INTO t1 SELECT a+ 4, randstr(1000,1000) FROM t1;
! 43: INSERT INTO t1 SELECT a+ 8, randstr(1000,1000) FROM t1;
! 44: INSERT INTO t1 SELECT a+16, randstr(1000,1000) FROM t1;
! 45: INSERT INTO t1 SELECT a+32, randstr(1000,1000) FROM t1;
! 46: CREATE INDEX i1 ON t1(b);
! 47: COMMIT;
! 48: } $db
! 49: if {$xtra_large} {
! 50: execsql { INSERT INTO t1 SELECT a+64, randstr(1000,1000) FROM t1 } $db
! 51: }
! 52: }
! 53: do_test backup_ioerr-1.1 {
! 54: populate_database db
! 55: set nPage [expr {[file size test.db] / 1024}]
! 56: expr {$nPage>130 && $nPage<160}
! 57: } {1}
! 58: do_test backup_ioerr-1.2 {
! 59: expr {[file size test.db] > $sqlite_pending_byte}
! 60: } {1}
! 61: do_test backup_ioerr-1.3 {
! 62: db close
! 63: forcedelete test.db
! 64: } {}
! 65:
! 66: # Turn off IO error simulation.
! 67: #
! 68: proc clear_ioerr_simulation {} {
! 69: set ::sqlite_io_error_hit 0
! 70: set ::sqlite_io_error_hardhit 0
! 71: set ::sqlite_io_error_pending 0
! 72: set ::sqlite_io_error_persist 0
! 73: }
! 74:
! 75: #--------------------------------------------------------------------
! 76: # The following procedure runs with SQLite's IO error simulation
! 77: # enabled.
! 78: #
! 79: # 1) Start with a reasonably sized database. One that includes the
! 80: # pending-byte (locking) page.
! 81: #
! 82: # 2) Open a backup process. Set the cache-size for the destination
! 83: # database to 10 pages only.
! 84: #
! 85: # 3) Step the backup process N times to partially backup the database
! 86: # file. If an IO error is reported, then the backup process is
! 87: # concluded with a call to backup_finish().
! 88: #
! 89: # If an IO error occurs, verify that:
! 90: #
! 91: # * the call to backup_step() returns an SQLITE_IOERR_XXX error code.
! 92: #
! 93: # * after the failed call to backup_step() but before the call to
! 94: # backup_finish() the destination database handle error code and
! 95: # error message remain unchanged.
! 96: #
! 97: # * the call to backup_finish() returns an SQLITE_IOERR_XXX error code.
! 98: #
! 99: # * following the call to backup_finish(), the destination database
! 100: # handle has been populated with an error code and error message.
! 101: #
! 102: # 4) Write to the database via the source database connection. Check
! 103: # that:
! 104: #
! 105: # * If an IO error occurs while writing the source database, the
! 106: # write operation should report an IO error. The backup should
! 107: # proceed as normal.
! 108: #
! 109: # * If an IO error occurs while updating the backup, the write
! 110: # operation should proceed normally. The error should be reported
! 111: # from the next call to backup_step() (in step 5 of this test
! 112: # procedure).
! 113: #
! 114: # 5) Step the backup process to finish the backup. If an IO error is
! 115: # reported, then the backup process is concluded with a call to
! 116: # backup_finish().
! 117: #
! 118: # Test that if an IO error occurs, or if one occured while updating
! 119: # the backup database during step 4, then the conditions listed
! 120: # under step 3 are all true.
! 121: #
! 122: # 6) Finish the backup process.
! 123: #
! 124: # * If the backup succeeds (backup_finish() returns SQLITE_OK), then
! 125: # the contents of the backup database should match that of the
! 126: # source database.
! 127: #
! 128: # * If the backup fails (backup_finish() returns other than SQLITE_OK),
! 129: # then the contents of the backup database should be as they were
! 130: # before the operation was started.
! 131: #
! 132: # The following factors are varied:
! 133: #
! 134: # * Destination database is initially larger than the source database, OR
! 135: # * Destination database is initially smaller than the source database.
! 136: #
! 137: # * IO errors are transient, OR
! 138: # * IO errors are persistent.
! 139: #
! 140: # * Destination page-size is smaller than the source.
! 141: # * Destination page-size is the same as the source.
! 142: # * Destination page-size is larger than the source.
! 143: #
! 144:
! 145: set iTest 1
! 146: foreach bPersist {0 1} {
! 147: foreach iDestPagesize {512 1024 4096} {
! 148: foreach zSetupBak [list "" {populate_database ddb 1}] {
! 149:
! 150: incr iTest
! 151: set bStop 0
! 152: for {set iError 1} {$bStop == 0} {incr iError} {
! 153: # Disable IO error simulation.
! 154: clear_ioerr_simulation
! 155:
! 156: catch { ddb close }
! 157: catch { sdb close }
! 158: catch { forcedelete test.db }
! 159: catch { forcedelete bak.db }
! 160:
! 161: # Open the source and destination databases.
! 162: sqlite3 sdb test.db
! 163: sqlite3 ddb bak.db
! 164:
! 165: # Step 1: Populate the source and destination databases.
! 166: populate_database sdb
! 167: ddb eval "PRAGMA page_size = $iDestPagesize"
! 168: ddb eval "PRAGMA cache_size = 10"
! 169: eval $zSetupBak
! 170:
! 171: # Step 2: Open the backup process.
! 172: sqlite3_backup B ddb main sdb main
! 173:
! 174: # Enable IO error simulation.
! 175: set ::sqlite_io_error_pending $iError
! 176: set ::sqlite_io_error_persist $bPersist
! 177:
! 178: # Step 3: Partially backup the database. If an IO error occurs, check
! 179: # a few things then skip to the next iteration of the loop.
! 180: #
! 181: set rc [B step 100]
! 182: if {$::sqlite_io_error_hardhit} {
! 183:
! 184: do_test backup_ioerr-$iTest.$iError.1 {
! 185: string match SQLITE_IOERR* $rc
! 186: } {1}
! 187: do_test backup_ioerr-$iTest.$iError.2 {
! 188: list [sqlite3_errcode ddb] [sqlite3_errmsg ddb]
! 189: } {SQLITE_OK {not an error}}
! 190:
! 191: set rc [B finish]
! 192: do_test backup_ioerr-$iTest.$iError.3 {
! 193: string match SQLITE_IOERR* $rc
! 194: } {1}
! 195:
! 196: do_test backup_ioerr-$iTest.$iError.4 {
! 197: sqlite3_errmsg ddb
! 198: } {disk I/O error}
! 199:
! 200: clear_ioerr_simulation
! 201: sqlite3 ddb bak.db
! 202: integrity_check backup_ioerr-$iTest.$iError.5 ddb
! 203:
! 204: continue
! 205: }
! 206:
! 207: # No IO error was encountered during step 3. Check that backup_step()
! 208: # returned SQLITE_OK before proceding.
! 209: do_test backup_ioerr-$iTest.$iError.6 {
! 210: expr {$rc eq "SQLITE_OK"}
! 211: } {1}
! 212:
! 213: # Step 4: Write to the source database.
! 214: set rc [catchsql { UPDATE t1 SET b = randstr(1000,1000) WHERE a < 50 } sdb]
! 215:
! 216: if {[lindex $rc 0] && $::sqlite_io_error_persist==0} {
! 217: # The IO error occured while updating the source database. In this
! 218: # case the backup should be able to continue.
! 219: set rc [B step 5000]
! 220: if { $rc != "SQLITE_IOERR_UNLOCK" } {
! 221: do_test backup_ioerr-$iTest.$iError.7 {
! 222: list [B step 5000] [B finish]
! 223: } {SQLITE_DONE SQLITE_OK}
! 224:
! 225: clear_ioerr_simulation
! 226: test_contents backup_ioerr-$iTest.$iError.8 ddb main sdb main
! 227: integrity_check backup_ioerr-$iTest.$iError.9 ddb
! 228: } else {
! 229: do_test backup_ioerr-$iTest.$iError.10 {
! 230: B finish
! 231: } {SQLITE_IOERR_UNLOCK}
! 232: }
! 233:
! 234: clear_ioerr_simulation
! 235: sqlite3 ddb bak.db
! 236: integrity_check backup_ioerr-$iTest.$iError.11 ddb
! 237:
! 238: continue
! 239: }
! 240:
! 241: # Step 5: Finish the backup operation. If an IO error occurs, check that
! 242: # it is reported correctly and skip to the next iteration of the loop.
! 243: #
! 244: set rc [B step 5000]
! 245: if {$rc != "SQLITE_DONE"} {
! 246: do_test backup_ioerr-$iTest.$iError.12 {
! 247: string match SQLITE_IOERR* $rc
! 248: } {1}
! 249: do_test backup_ioerr-$iTest.$iError.13 {
! 250: list [sqlite3_errcode ddb] [sqlite3_errmsg ddb]
! 251: } {SQLITE_OK {not an error}}
! 252:
! 253: set rc [B finish]
! 254: do_test backup_ioerr-$iTest.$iError.14 {
! 255: string match SQLITE_IOERR* $rc
! 256: } {1}
! 257: do_test backup_ioerr-$iTest.$iError.15 {
! 258: sqlite3_errmsg ddb
! 259: } {disk I/O error}
! 260:
! 261: clear_ioerr_simulation
! 262: sqlite3 ddb bak.db
! 263: integrity_check backup_ioerr-$iTest.$iError.16 ddb
! 264:
! 265: continue
! 266: }
! 267:
! 268: # The backup was successfully completed.
! 269: #
! 270: do_test backup_ioerr-$iTest.$iError.17 {
! 271: list [set rc] [B finish]
! 272: } {SQLITE_DONE SQLITE_OK}
! 273:
! 274: clear_ioerr_simulation
! 275: sqlite3 sdb test.db
! 276: sqlite3 ddb bak.db
! 277:
! 278: test_contents backup_ioerr-$iTest.$iError.18 ddb main sdb main
! 279: integrity_check backup_ioerr-$iTest.$iError.19 ddb
! 280:
! 281: set bStop [expr $::sqlite_io_error_pending<=0]
! 282: }}}}
! 283:
! 284: catch { sdb close }
! 285: catch { ddb close }
! 286: finish_test
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>