| Index: third_party/sqlite/sqlite-src-3080704/test/backup_ioerr.test
|
| diff --git a/third_party/sqlite/sqlite-src-3080704/test/backup_ioerr.test b/third_party/sqlite/sqlite-src-3080704/test/backup_ioerr.test
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ca3fd3240d778d1b6fd19b59a66ffcf7a66b9f78
|
| --- /dev/null
|
| +++ b/third_party/sqlite/sqlite-src-3080704/test/backup_ioerr.test
|
| @@ -0,0 +1,286 @@
|
| +# 2009 January 30
|
| +#
|
| +# The author disclaims copyright to this source code. In place of
|
| +# a legal notice, here is a blessing:
|
| +#
|
| +# May you do good and not evil.
|
| +# May you find forgiveness for yourself and forgive others.
|
| +# May you share freely, never taking more than you give.
|
| +#
|
| +#***********************************************************************
|
| +# This file implements regression tests for SQLite library. The
|
| +# focus of this file is testing the handling of IO errors by the
|
| +# sqlite3_backup_XXX APIs.
|
| +#
|
| +# $Id: backup_ioerr.test,v 1.3 2009/04/10 18:41:01 danielk1977 Exp $
|
| +
|
| +set testdir [file dirname $argv0]
|
| +source $testdir/tester.tcl
|
| +
|
| +proc data_checksum {db file} {
|
| + $db one "SELECT md5sum(a, b) FROM ${file}.t1"
|
| +}
|
| +proc test_contents {name db1 file1 db2 file2} {
|
| + $db2 eval {select * from sqlite_master}
|
| + $db1 eval {select * from sqlite_master}
|
| + set checksum [data_checksum $db2 $file2]
|
| + uplevel [list do_test $name [list data_checksum $db1 $file1] $checksum]
|
| +}
|
| +
|
| +#--------------------------------------------------------------------
|
| +# This proc creates a database of approximately 290 pages. Depending
|
| +# on whether or not auto-vacuum is configured. Test cases backup_ioerr-1.*
|
| +# verify nothing more than this assumption.
|
| +#
|
| +proc populate_database {db {xtra_large 0}} {
|
| + execsql {
|
| + BEGIN;
|
| + CREATE TABLE t1(a, b);
|
| + INSERT INTO t1 VALUES(1, randstr(1000,1000));
|
| + INSERT INTO t1 SELECT a+ 1, randstr(1000,1000) FROM t1;
|
| + INSERT INTO t1 SELECT a+ 2, randstr(1000,1000) FROM t1;
|
| + INSERT INTO t1 SELECT a+ 4, randstr(1000,1000) FROM t1;
|
| + INSERT INTO t1 SELECT a+ 8, randstr(1000,1000) FROM t1;
|
| + INSERT INTO t1 SELECT a+16, randstr(1000,1000) FROM t1;
|
| + INSERT INTO t1 SELECT a+32, randstr(1000,1000) FROM t1;
|
| + CREATE INDEX i1 ON t1(b);
|
| + COMMIT;
|
| + } $db
|
| + if {$xtra_large} {
|
| + execsql { INSERT INTO t1 SELECT a+64, randstr(1000,1000) FROM t1 } $db
|
| + }
|
| +}
|
| +do_test backup_ioerr-1.1 {
|
| + populate_database db
|
| + set nPage [expr {[file size test.db] / 1024}]
|
| + expr {$nPage>130 && $nPage<160}
|
| +} {1}
|
| +do_test backup_ioerr-1.2 {
|
| + expr {[file size test.db] > $sqlite_pending_byte}
|
| +} {1}
|
| +do_test backup_ioerr-1.3 {
|
| + db close
|
| + forcedelete test.db
|
| +} {}
|
| +
|
| +# Turn off IO error simulation.
|
| +#
|
| +proc clear_ioerr_simulation {} {
|
| + set ::sqlite_io_error_hit 0
|
| + set ::sqlite_io_error_hardhit 0
|
| + set ::sqlite_io_error_pending 0
|
| + set ::sqlite_io_error_persist 0
|
| +}
|
| +
|
| +#--------------------------------------------------------------------
|
| +# The following procedure runs with SQLite's IO error simulation
|
| +# enabled.
|
| +#
|
| +# 1) Start with a reasonably sized database. One that includes the
|
| +# pending-byte (locking) page.
|
| +#
|
| +# 2) Open a backup process. Set the cache-size for the destination
|
| +# database to 10 pages only.
|
| +#
|
| +# 3) Step the backup process N times to partially backup the database
|
| +# file. If an IO error is reported, then the backup process is
|
| +# concluded with a call to backup_finish().
|
| +#
|
| +# If an IO error occurs, verify that:
|
| +#
|
| +# * the call to backup_step() returns an SQLITE_IOERR_XXX error code.
|
| +#
|
| +# * after the failed call to backup_step() but before the call to
|
| +# backup_finish() the destination database handle error code and
|
| +# error message remain unchanged.
|
| +#
|
| +# * the call to backup_finish() returns an SQLITE_IOERR_XXX error code.
|
| +#
|
| +# * following the call to backup_finish(), the destination database
|
| +# handle has been populated with an error code and error message.
|
| +#
|
| +# 4) Write to the database via the source database connection. Check
|
| +# that:
|
| +#
|
| +# * If an IO error occurs while writing the source database, the
|
| +# write operation should report an IO error. The backup should
|
| +# proceed as normal.
|
| +#
|
| +# * If an IO error occurs while updating the backup, the write
|
| +# operation should proceed normally. The error should be reported
|
| +# from the next call to backup_step() (in step 5 of this test
|
| +# procedure).
|
| +#
|
| +# 5) Step the backup process to finish the backup. If an IO error is
|
| +# reported, then the backup process is concluded with a call to
|
| +# backup_finish().
|
| +#
|
| +# Test that if an IO error occurs, or if one occurred while updating
|
| +# the backup database during step 4, then the conditions listed
|
| +# under step 3 are all true.
|
| +#
|
| +# 6) Finish the backup process.
|
| +#
|
| +# * If the backup succeeds (backup_finish() returns SQLITE_OK), then
|
| +# the contents of the backup database should match that of the
|
| +# source database.
|
| +#
|
| +# * If the backup fails (backup_finish() returns other than SQLITE_OK),
|
| +# then the contents of the backup database should be as they were
|
| +# before the operation was started.
|
| +#
|
| +# The following factors are varied:
|
| +#
|
| +# * Destination database is initially larger than the source database, OR
|
| +# * Destination database is initially smaller than the source database.
|
| +#
|
| +# * IO errors are transient, OR
|
| +# * IO errors are persistent.
|
| +#
|
| +# * Destination page-size is smaller than the source.
|
| +# * Destination page-size is the same as the source.
|
| +# * Destination page-size is larger than the source.
|
| +#
|
| +
|
| +set iTest 1
|
| +foreach bPersist {0 1} {
|
| +foreach iDestPagesize {512 1024 4096} {
|
| +foreach zSetupBak [list "" {populate_database ddb 1}] {
|
| +
|
| + incr iTest
|
| + set bStop 0
|
| +for {set iError 1} {$bStop == 0} {incr iError} {
|
| + # Disable IO error simulation.
|
| + clear_ioerr_simulation
|
| +
|
| + catch { ddb close }
|
| + catch { sdb close }
|
| + catch { forcedelete test.db }
|
| + catch { forcedelete bak.db }
|
| +
|
| + # Open the source and destination databases.
|
| + sqlite3 sdb test.db
|
| + sqlite3 ddb bak.db
|
| +
|
| + # Step 1: Populate the source and destination databases.
|
| + populate_database sdb
|
| + ddb eval "PRAGMA page_size = $iDestPagesize"
|
| + ddb eval "PRAGMA cache_size = 10"
|
| + eval $zSetupBak
|
| +
|
| + # Step 2: Open the backup process.
|
| + sqlite3_backup B ddb main sdb main
|
| +
|
| + # Enable IO error simulation.
|
| + set ::sqlite_io_error_pending $iError
|
| + set ::sqlite_io_error_persist $bPersist
|
| +
|
| + # Step 3: Partially backup the database. If an IO error occurs, check
|
| + # a few things then skip to the next iteration of the loop.
|
| + #
|
| + set rc [B step 100]
|
| + if {$::sqlite_io_error_hardhit} {
|
| +
|
| + do_test backup_ioerr-$iTest.$iError.1 {
|
| + string match SQLITE_IOERR* $rc
|
| + } {1}
|
| + do_test backup_ioerr-$iTest.$iError.2 {
|
| + list [sqlite3_errcode ddb] [sqlite3_errmsg ddb]
|
| + } {SQLITE_OK {not an error}}
|
| +
|
| + set rc [B finish]
|
| + do_test backup_ioerr-$iTest.$iError.3 {
|
| + string match SQLITE_IOERR* $rc
|
| + } {1}
|
| +
|
| + do_test backup_ioerr-$iTest.$iError.4 {
|
| + sqlite3_errmsg ddb
|
| + } {disk I/O error}
|
| +
|
| + clear_ioerr_simulation
|
| + sqlite3 ddb bak.db
|
| + integrity_check backup_ioerr-$iTest.$iError.5 ddb
|
| +
|
| + continue
|
| + }
|
| +
|
| + # No IO error was encountered during step 3. Check that backup_step()
|
| + # returned SQLITE_OK before proceding.
|
| + do_test backup_ioerr-$iTest.$iError.6 {
|
| + expr {$rc eq "SQLITE_OK"}
|
| + } {1}
|
| +
|
| + # Step 4: Write to the source database.
|
| + set rc [catchsql { UPDATE t1 SET b = randstr(1000,1000) WHERE a < 50 } sdb]
|
| +
|
| + if {[lindex $rc 0] && $::sqlite_io_error_persist==0} {
|
| + # The IO error occurred while updating the source database. In this
|
| + # case the backup should be able to continue.
|
| + set rc [B step 5000]
|
| + if { $rc != "SQLITE_IOERR_UNLOCK" } {
|
| + do_test backup_ioerr-$iTest.$iError.7 {
|
| + list [B step 5000] [B finish]
|
| + } {SQLITE_DONE SQLITE_OK}
|
| +
|
| + clear_ioerr_simulation
|
| + test_contents backup_ioerr-$iTest.$iError.8 ddb main sdb main
|
| + integrity_check backup_ioerr-$iTest.$iError.9 ddb
|
| + } else {
|
| + do_test backup_ioerr-$iTest.$iError.10 {
|
| + B finish
|
| + } {SQLITE_IOERR_UNLOCK}
|
| + }
|
| +
|
| + clear_ioerr_simulation
|
| + sqlite3 ddb bak.db
|
| + integrity_check backup_ioerr-$iTest.$iError.11 ddb
|
| +
|
| + continue
|
| + }
|
| +
|
| + # Step 5: Finish the backup operation. If an IO error occurs, check that
|
| + # it is reported correctly and skip to the next iteration of the loop.
|
| + #
|
| + set rc [B step 5000]
|
| + if {$rc != "SQLITE_DONE"} {
|
| + do_test backup_ioerr-$iTest.$iError.12 {
|
| + string match SQLITE_IOERR* $rc
|
| + } {1}
|
| + do_test backup_ioerr-$iTest.$iError.13 {
|
| + list [sqlite3_errcode ddb] [sqlite3_errmsg ddb]
|
| + } {SQLITE_OK {not an error}}
|
| +
|
| + set rc [B finish]
|
| + do_test backup_ioerr-$iTest.$iError.14 {
|
| + string match SQLITE_IOERR* $rc
|
| + } {1}
|
| + do_test backup_ioerr-$iTest.$iError.15 {
|
| + sqlite3_errmsg ddb
|
| + } {disk I/O error}
|
| +
|
| + clear_ioerr_simulation
|
| + sqlite3 ddb bak.db
|
| + integrity_check backup_ioerr-$iTest.$iError.16 ddb
|
| +
|
| + continue
|
| + }
|
| +
|
| + # The backup was successfully completed.
|
| + #
|
| + do_test backup_ioerr-$iTest.$iError.17 {
|
| + list [set rc] [B finish]
|
| + } {SQLITE_DONE SQLITE_OK}
|
| +
|
| + clear_ioerr_simulation
|
| + sqlite3 sdb test.db
|
| + sqlite3 ddb bak.db
|
| +
|
| + test_contents backup_ioerr-$iTest.$iError.18 ddb main sdb main
|
| + integrity_check backup_ioerr-$iTest.$iError.19 ddb
|
| +
|
| + set bStop [expr $::sqlite_io_error_pending<=0]
|
| +}}}}
|
| +
|
| +catch { sdb close }
|
| +catch { ddb close }
|
| +finish_test
|
|
|