• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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