Home | History | Annotate | Download | only in test
      1 # 2011 March 28
      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 #
     12 
     13 set testdir [file dirname $argv0]
     14 source $testdir/tester.tcl
     15 source $testdir/lock_common.tcl
     16 source $testdir/malloc_common.tcl
     17 
     18 if {[llength [info commands test_syscall]]==0} {
     19   finish_test
     20   return
     21 } 
     22 
     23 set testprefix sysfault
     24 
     25 set FAULTSIM(vfsfault-transient) [list             \
     26   -injectinstall   vfsfault_install                \
     27   -injectstart     vfsfault_injectstart_t          \
     28   -injectstop      vfsfault_injectstop             \
     29   -injecterrlist   {}                              \
     30   -injectuninstall {test_syscall uninstall}        \
     31 ]
     32 set FAULTSIM(vfsfault-persistent) [list            \
     33   -injectinstall   vfsfault_install                \
     34   -injectstart     vfsfault_injectstart_p          \
     35   -injectstop      vfsfault_injectstop             \
     36   -injecterrlist   {}                              \
     37   -injectuninstall {test_syscall uninstall}        \
     38 ]
     39 
     40 proc vfsfault_injectstart_t {iFail} { test_syscall fault $iFail 0 }
     41 proc vfsfault_injectstart_p {iFail} { test_syscall fault $iFail 1 }
     42 proc vfsfault_injectstop    {}      { test_syscall fault }
     43 
     44 faultsim_save_and_close
     45 
     46 
     47 set open_and_write_body {
     48   sqlite3 db test.db
     49   db eval {
     50     CREATE TABLE t1(a, b);
     51     INSERT INTO t1 VALUES(1, 2);
     52     PRAGMA journal_mode = WAL;
     53     INSERT INTO t1 VALUES(3, 4);
     54     SELECT * FROM t1;
     55     CREATE TEMP TABLE t2(x);
     56     INSERT INTO t2 VALUES('y');
     57   }
     58 }
     59 
     60 proc vfsfault_install {} { test_syscall install {open getcwd} }
     61 do_faultsim_test 1 -faults vfsfault-* -prep {
     62   faultsim_restore
     63 } -body $open_and_write_body -test {
     64   faultsim_test_result {0 {wal 1 2 3 4}}       \
     65     {1 {unable to open database file}}         \
     66     {1 {attempt to write a readonly database}}
     67 }
     68 
     69 #-------------------------------------------------------------------------
     70 # Errors in the fstat() function when opening and writing a file. Cases
     71 # where fstat() fails and sets errno to ENOMEM and EOVERFLOW are both
     72 # tested. EOVERFLOW is interpreted as meaning that a file on disk is
     73 # too large to be opened by the OS.
     74 #
     75 foreach {tn errno errlist} {
     76   1 ENOMEM       {{disk I/O error}}
     77   2 EOVERFLOW    {{disk I/O error} {large file support is disabled}}
     78 } {
     79   proc vfsfault_install {} { test_syscall install fstat }
     80   set errs [list]
     81   foreach e $errlist { lappend errs [list 1 $e] }
     82   do_faultsim_test 1.2.$tn -faults vfsfault-* -prep {
     83     faultsim_restore
     84   } -body "
     85     test_syscall errno fstat $errno
     86     $open_and_write_body 
     87   " -test "
     88     faultsim_test_result {0 {wal 1 2 3 4}} $errs
     89   "
     90 }
     91 
     92 #-------------------------------------------------------------------------
     93 # Various errors in locking functions. 
     94 #
     95 foreach vfs {unix unix-excl} {
     96   foreach {tn errno errlist} {
     97     1 EAGAIN       {{database is locked} {disk I/O error}}
     98     2 ETIMEDOUT    {{database is locked} {disk I/O error}}
     99     3 EBUSY        {{database is locked} {disk I/O error}}
    100     4 EINTR        {{database is locked} {disk I/O error}}
    101     5 ENOLCK       {{database is locked} {disk I/O error}}
    102     6 EACCES       {{database is locked} {disk I/O error}}
    103     7 EPERM        {{access permission denied} {disk I/O error}}
    104     8 EDEADLK      {{disk I/O error}}
    105     9 ENOMEM       {{disk I/O error}}
    106   } {
    107     proc vfsfault_install {} { test_syscall install fcntl }
    108     set errs [list]
    109     foreach e $errlist { lappend errs [list 1 $e] }
    110   
    111     set body [string map [list %VFS% $vfs] {
    112       sqlite3 db test.db
    113       db eval {
    114         CREATE TABLE t1(a, b);
    115         INSERT INTO t1 VALUES(1, 2);
    116       }
    117       set fd [open test.db-journal w]
    118       puts $fd "hello world"
    119       close $fd
    120       sqlite3 db test.db -vfs %VFS%
    121       db eval {
    122         SELECT * FROM t1;
    123       }
    124     }]
    125   
    126     do_faultsim_test 1.3.$vfs.$tn -faults vfsfault-* -prep {
    127       faultsim_restore
    128     } -body "
    129       test_syscall errno fcntl $errno
    130       $body
    131     " -test "
    132       faultsim_test_result {0 {1 2}} $errs
    133     "
    134   }
    135 }
    136 
    137 #-------------------------------------------------------------------------
    138 # Check that a single EINTR error does not affect processing.
    139 #
    140 proc vfsfault_install {} { 
    141   test_syscall reset
    142   test_syscall install {open ftruncate close read pread pread64 write fallocate}
    143 }
    144 
    145 forcedelete test.db test.db2
    146 sqlite3 db test.db
    147 do_test 2.setup {
    148   execsql {
    149     CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
    150     INSERT INTO t1 VALUES('abc', 'def', 'ghi');
    151     ATTACH 'test.db2' AS 'aux';
    152     CREATE TABLE aux.t2(x);
    153     INSERT INTO t2 VALUES(1);
    154   }
    155   faultsim_save_and_close
    156 } {}
    157 
    158 do_faultsim_test 2.1 -faults vfsfault-transient -prep {
    159   catch { db close }
    160   faultsim_restore
    161 } -body {
    162   test_syscall errno open      EINTR
    163   test_syscall errno ftruncate EINTR
    164   test_syscall errno close     EINTR
    165   test_syscall errno read      EINTR
    166   test_syscall errno pread     EINTR
    167   test_syscall errno pread64   EINTR
    168   test_syscall errno write     EINTR
    169   test_syscall errno fallocate EINTR
    170 
    171   sqlite3 db test.db
    172   file_control_chunksize_test db main 8192
    173 
    174   set res [db eval {
    175     ATTACH 'test.db2' AS 'aux';
    176     SELECT * FROM t1;
    177     PRAGMA journal_mode = truncate;
    178     BEGIN;
    179       INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
    180       INSERT INTO t1 VALUES(randomblob(10000), 0, 0);
    181       UPDATE t2 SET x = 2;
    182     COMMIT;
    183     DELETE FROM t1 WHERE length(a)>3;
    184     SELECT * FROM t1;
    185     SELECT * FROM t2;
    186   }]
    187   db close
    188   set res
    189 } -test {
    190   faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}}
    191 }
    192 
    193 do_faultsim_test 2.2 -faults vfsfault-* -prep {
    194   catch { db close }
    195   faultsim_restore
    196 } -body {
    197   sqlite3 db test.db
    198   set res [db eval {
    199     ATTACH 'test.db2' AS 'aux';
    200     SELECT * FROM t1;
    201     PRAGMA journal_mode = truncate;
    202     BEGIN;
    203       INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
    204       UPDATE t2 SET x = 2;
    205     COMMIT;
    206     SELECT * FROM t1;
    207     SELECT * FROM t2;
    208   }]
    209   db close
    210   set res
    211 } -test {
    212   faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}} \
    213     {1 {unable to open database file}}                                      \
    214     {1 {unable to open database: test.db2}}                                 \
    215     {1 {attempt to write a readonly database}}                              \
    216     {1 {disk I/O error}}                                                  
    217 }
    218 
    219 #-------------------------------------------------------------------------
    220 
    221 proc vfsfault_install {} { 
    222   test_syscall reset
    223   test_syscall install {fstat fallocate}
    224 }
    225 do_faultsim_test 3 -faults vfsfault-* -prep {
    226   faultsim_delete_and_reopen
    227   file_control_chunksize_test db main 8192
    228   execsql {
    229     CREATE TABLE t1(a, b);
    230     BEGIN;
    231       SELECT * FROM t1;
    232   }
    233 } -body {
    234   test_syscall errno fstat     EIO
    235   test_syscall errno fallocate EIO
    236 
    237   execsql {
    238     INSERT INTO t1 VALUES(randomblob(10000), randomblob(10000));
    239     SELECT length(a) + length(b) FROM t1;
    240     COMMIT;
    241   }
    242 } -test {
    243   faultsim_test_result {0 20000}
    244 }
    245 
    246 finish_test
    247 
    248