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 13set testdir [file dirname $argv0] 14source $testdir/tester.tcl 15source $testdir/lock_common.tcl 16source $testdir/malloc_common.tcl 17 18if {[llength [info commands test_syscall]]==0} { 19 finish_test 20 return 21} 22 23set testprefix sysfault 24 25set 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] 32set 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 40proc vfsfault_injectstart_t {iFail} { test_syscall fault $iFail 0 } 41proc vfsfault_injectstart_p {iFail} { test_syscall fault $iFail 1 } 42proc vfsfault_injectstop {} { test_syscall fault } 43 44faultsim_save_and_close 45 46 47set 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 60proc vfsfault_install {} { test_syscall install {open getcwd} } 61do_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# 75foreach {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# 95foreach 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# 140proc vfsfault_install {} { 141 test_syscall reset 142 test_syscall install {open ftruncate close read pread pread64 write fallocate} 143} 144 145forcedelete test.db test.db2 146sqlite3 db test.db 147do_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 158do_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 193do_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 221proc vfsfault_install {} { 222 test_syscall reset 223 test_syscall install {fstat fallocate} 224} 225do_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 246finish_test 247 248