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>