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