CoolFace
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
backup_ioerr.test287 linesDownload Raw Back to test
1# 2009 January 302#3# The author disclaims copyright to this source code.  In place of4# 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.  The12# focus of this file is testing the handling of IO errors by the13# sqlite3_backup_XXX APIs.14#15# $Id: backup_ioerr.test,v 1.3 2009/04/10 18:41:01 danielk1977 Exp $16 17set testdir [file dirname $argv0]18source $testdir/tester.tcl19 20proc data_checksum {db file} { 21  $db one "SELECT md5sum(a, b) FROM ${file}.t1" 22}23proc 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. Depending32# on whether or not auto-vacuum is configured. Test cases backup_ioerr-1.*33# verify nothing more than this assumption.34#35proc 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  } $db49  if {$xtra_large} {50    execsql { INSERT INTO t1 SELECT a+64, randstr(1000,1000) FROM t1 } $db51  }52}53do_test backup_ioerr-1.1 {54  populate_database db55  set nPage [expr {[file size test.db] / 1024}]56  expr {$nPage>130 && $nPage<160}57} {1}58do_test backup_ioerr-1.2 {59  expr {[file size test.db] > $sqlite_pending_byte}60} {1}61do_test backup_ioerr-1.3 {62  db close63  forcedelete test.db64} {}65 66# Turn off IO error simulation.67#68proc clear_ioerr_simulation {} {69  set ::sqlite_io_error_hit 070  set ::sqlite_io_error_hardhit 071  set ::sqlite_io_error_pending 072  set ::sqlite_io_error_persist 073}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 the80#      pending-byte (locking) page.81#82#   2) Open a backup process. Set the cache-size for the destination83#      database to 10 pages only.84#85#   3) Step the backup process N times to partially backup the database86#      file. If an IO error is reported, then the backup process is87#      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 to94#        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 database100#        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, the106#        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 reported111#        from the next call to backup_step() (in step 5 of this test112#        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 occurred while updating119#      the backup database during step 4, then the conditions listed120#      under step 3 are all true.121#122#   6) Finish the backup process.123#124#   * If the backup succeeds (backup_finish() returns SQLITE_OK), then125#     the contents of the backup database should match that of the126#     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, OR135#   * Destination database is initially smaller than the source database.136#137#   * IO errors are transient, OR138#   * 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 145set iTest 1146foreach bPersist {0 1} {147foreach iDestPagesize {512 1024 4096} {148foreach zSetupBak [list "" {populate_database ddb 1}] {149 150  incr iTest151  set bStop 0152for {set iError 1} {$bStop == 0} {incr iError} {153  # Disable IO error simulation.154  clear_ioerr_simulation155 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.db163  sqlite3 ddb bak.db164 165  # Step 1: Populate the source and destination databases.166  populate_database sdb167  ddb eval "PRAGMA page_size = $iDestPagesize"168  ddb eval "PRAGMA cache_size = 10"169  eval $zSetupBak170 171  # Step 2: Open the backup process.172  sqlite3_backup B ddb main sdb main173 174  # Enable IO error simulation.175  set ::sqlite_io_error_pending $iError176  set ::sqlite_io_error_persist $bPersist177 178  # Step 3: Partially backup the database. If an IO error occurs, check179  # 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* $rc186    } {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* $rc194    } {1}195 196    do_test backup_ioerr-$iTest.$iError.4 {197      sqlite3_errmsg ddb198    } {disk I/O error}199 200    clear_ioerr_simulation201    sqlite3 ddb bak.db202    integrity_check backup_ioerr-$iTest.$iError.5 ddb203 204    continue205  }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 occurred while updating the source database. In this218    # 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_simulation226      test_contents backup_ioerr-$iTest.$iError.8 ddb main sdb main227      integrity_check backup_ioerr-$iTest.$iError.9 ddb228    } else {229      do_test backup_ioerr-$iTest.$iError.10 {230        B finish231      } {SQLITE_IOERR_UNLOCK}232    }233 234    clear_ioerr_simulation235    sqlite3 ddb bak.db236    integrity_check backup_ioerr-$iTest.$iError.11 ddb237 238    continue239  }240 241  # Step 5: Finish the backup operation. If an IO error occurs, check that242  # 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* $rc248    } {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* $rc256    } {1}257    do_test backup_ioerr-$iTest.$iError.15 {258      sqlite3_errmsg ddb259    } {disk I/O error}260 261    clear_ioerr_simulation262    sqlite3 ddb bak.db263    integrity_check backup_ioerr-$iTest.$iError.16 ddb264 265    continue266  }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_simulation275  sqlite3 sdb test.db276  sqlite3 ddb bak.db277 278  test_contents backup_ioerr-$iTest.$iError.18 ddb main sdb main279  integrity_check backup_ioerr-$iTest.$iError.19 ddb280 281  set bStop [expr $::sqlite_io_error_pending<=0]282}}}}283 284catch { sdb close }285catch { ddb close }286finish_test287