Annotation of embedaddon/sqlite3/test/backup_ioerr.test, revision 1.1.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>