/ Check-in [0e1d20df]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add test infrastructure (and some tests) to inject faults into os_unix.c using the new xSetSystemCall interface.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0e1d20dfaeea5ab285d16aa4b8f02b61b1d2bc10
User & Date: dan 2011-03-28 19:10:07
Context
2011-03-29
01:47
Fix the documentation for the sqlite3_column_*_name() functions to describe that the information can be invalidated when a prepared statement is reprepared by the first invocation of an sqlite3_step() for a particular execution cycle. check-in: 7270f80a user: drh tags: trunk
2011-03-28
19:10
Add test infrastructure (and some tests) to inject faults into os_unix.c using the new xSetSystemCall interface. check-in: 0e1d20df user: dan tags: trunk
2011-03-24
17:43
Minor change to sqlite3Utf8Read() to make consistent with READ_UTF8() usage and avoid implementation defined usages of <<. Added some additional UTF-8 test cases. check-in: 7173b392 user: shaneh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to main.mk.

   249    249     $(TOP)/src/test_pcache.c \
   250    250     $(TOP)/src/test_quota.c \
   251    251     $(TOP)/src/test_rtree.c \
   252    252     $(TOP)/src/test_schema.c \
   253    253     $(TOP)/src/test_server.c \
   254    254     $(TOP)/src/test_stat.c \
   255    255     $(TOP)/src/test_superlock.c \
          256  +  $(TOP)/src/test_syscall.c \
   256    257     $(TOP)/src/test_tclvar.c \
   257    258     $(TOP)/src/test_thread.c \
   258    259     $(TOP)/src/test_vfs.c \
   259    260     $(TOP)/src/test_wsd.c
   260    261   
   261    262   #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
   262    263   #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c

Changes to src/tclsqlite.c.

  3577   3577       extern int Sqlitetestintarray_Init(Tcl_Interp*);
  3578   3578       extern int Sqlitetestvfs_Init(Tcl_Interp *);
  3579   3579       extern int SqlitetestStat_Init(Tcl_Interp*);
  3580   3580       extern int Sqlitetestrtree_Init(Tcl_Interp*);
  3581   3581       extern int Sqlitequota_Init(Tcl_Interp*);
  3582   3582       extern int Sqlitemultiplex_Init(Tcl_Interp*);
  3583   3583       extern int SqliteSuperlock_Init(Tcl_Interp*);
         3584  +    extern int SqlitetestSyscall_Init(Tcl_Interp*);
  3584   3585   
  3585   3586   #ifdef SQLITE_ENABLE_ZIPVFS
  3586   3587       extern int Zipvfs_Init(Tcl_Interp*);
  3587   3588       Zipvfs_Init(interp);
  3588   3589   #endif
  3589   3590   
  3590   3591       Sqliteconfig_Init(interp);
................................................................................
  3614   3615       Sqlitetestintarray_Init(interp);
  3615   3616       Sqlitetestvfs_Init(interp);
  3616   3617       SqlitetestStat_Init(interp);
  3617   3618       Sqlitetestrtree_Init(interp);
  3618   3619       Sqlitequota_Init(interp);
  3619   3620       Sqlitemultiplex_Init(interp);
  3620   3621       SqliteSuperlock_Init(interp);
         3622  +    SqlitetestSyscall_Init(interp);
  3621   3623   
  3622   3624       Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0);
  3623   3625   
  3624   3626   #ifdef SQLITE_SSE
  3625   3627       Sqlitetestsse_Init(interp);
  3626   3628   #endif
  3627   3629     }

Added src/test_syscall.c.

            1  +/*
            2  +** 2011 March 28
            3  +**
            4  +** The author disclaims copyright to this source code.  In place of
            5  +** a legal notice, here is a blessing:
            6  +**
            7  +**    May you do good and not evil.
            8  +**    May you find forgiveness for yourself and forgive others.
            9  +**    May you share freely, never taking more than you give.
           10  +**
           11  +*************************************************************************
           12  +**
           13  +** The code in this file implements a Tcl interface used to test error
           14  +** handling in the os_unix.c module. Wrapper functions that support fault
           15  +** injection are registered as the low-level OS functions using the 
           16  +** xSetSystemCall() method of the VFS. The Tcl interface is as follows:
           17  +**
           18  +**
           19  +**   test_syscall install LIST
           20  +**     Install wrapper functions for all system calls in argument LIST.
           21  +**     LIST must be a list consisting of zero or more of the following
           22  +**     literal values:
           23  +**
           24  +**         open        close      access   getcwd   stat      fstat    
           25  +**         ftruncate   fcntl      read     pread    pread64   write
           26  +**         pwrite      pwrite64   fchmod   fallocate
           27  +**
           28  +**   test_syscall uninstall
           29  +**     Uninstall all wrapper functions.
           30  +**
           31  +**   test_syscall fault ?COUNT PERSIST?
           32  +**     If [test_syscall fault] is invoked without the two arguments, fault
           33  +**     injection is disabled. Otherwise, fault injection is configured to
           34  +**     cause a failure on the COUNT'th next call to a system call with a
           35  +**     wrapper function installed. A COUNT value of 1 means fail the next
           36  +**     system call. 
           37  +** 
           38  +**     Argument PERSIST is interpreted as a boolean. If true, the all
           39  +**     system calls following the initial failure also fail. Otherwise, only
           40  +**     the single transient failure is injected.
           41  +**
           42  +**   test_syscall errno CALL ERRNO
           43  +**     Set the value that the global "errno" is set to following a fault
           44  +**     in call CALL. Argument CALL must be one of the system call names
           45  +**     listed above (under [test_syscall install]). ERRNO is a symbolic
           46  +**     name (i.e. "EACCES"). Not all errno codes are supported. Add extra
           47  +**     to the aErrno table in function test_syscall_errno() below as 
           48  +**     required.
           49  +*/
           50  +
           51  +#include "sqlite3.h"
           52  +#include "tcl.h"
           53  +#include <stdlib.h>
           54  +#include <string.h>
           55  +#include <assert.h>
           56  +
           57  +#ifdef SQLITE_OS_UNIX
           58  +
           59  +#include <sys/types.h>
           60  +#include <errno.h>
           61  +
           62  +static struct TestSyscallGlobal {
           63  +  int bPersist;                   /* 1 for persistent errors, 0 for transient */
           64  +  int nCount;                     /* Fail after this many more calls */
           65  +  int nFail;                      /* Number of failures that have occurred */
           66  +} gSyscall = { 0, 0 };
           67  +
           68  +static int ts_open(const char *, int, int);
           69  +static int ts_close(int fd);
           70  +static int ts_access(const char *zPath, int mode);
           71  +static char *ts_getcwd(char *zPath, size_t nPath);
           72  +static int ts_stat(const char *zPath, struct stat *p);
           73  +static int ts_fstat(int fd, struct stat *p);
           74  +static int ts_ftruncate(int fd, off_t n);
           75  +static int ts_fcntl(int fd, int cmd, ... );
           76  +static int ts_read(int fd, void *aBuf, size_t nBuf);
           77  +static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
           78  +static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off);
           79  +static int ts_write(int fd, const void *aBuf, size_t nBuf);
           80  +static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
           81  +static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off);
           82  +static int ts_fchmod(int fd, mode_t mode);
           83  +static int ts_fallocate(int fd, off_t off, off_t len);
           84  +
           85  +
           86  +struct TestSyscallArray {
           87  +  const char *zName;
           88  +  sqlite3_syscall_ptr xTest;
           89  +  sqlite3_syscall_ptr xOrig;
           90  +  int default_errno;              /* Default value for errno following errors */
           91  +  int custom_errno;               /* Current value for errno if error */
           92  +} aSyscall[] = {
           93  +  /*  0 */ { "open",      (sqlite3_syscall_ptr)ts_open,      0, EACCES, 0 },
           94  +  /*  1 */ { "close",     (sqlite3_syscall_ptr)ts_close,     0, 0, 0 },
           95  +  /*  2 */ { "access",    (sqlite3_syscall_ptr)ts_access,    0, 0, 0 },
           96  +  /*  3 */ { "getcwd",    (sqlite3_syscall_ptr)ts_getcwd,    0, 0, 0 },
           97  +  /*  4 */ { "stat",      (sqlite3_syscall_ptr)ts_stat,      0, 0, 0 },
           98  +  /*  5 */ { "fstat",     (sqlite3_syscall_ptr)ts_fstat,     0, 0, 0 },
           99  +  /*  6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, 0, 0 },
          100  +  /*  7 */ { "fcntl",     (sqlite3_syscall_ptr)ts_fcntl,     0, 0, 0 },
          101  +  /*  8 */ { "read",      (sqlite3_syscall_ptr)ts_read,      0, 0, 0 },
          102  +  /*  9 */ { "pread",     (sqlite3_syscall_ptr)ts_pread,     0, 0, 0 },
          103  +  /* 10 */ { "pread64",   (sqlite3_syscall_ptr)ts_pread64,   0, 0, 0 },
          104  +  /* 11 */ { "write",     (sqlite3_syscall_ptr)ts_write,     0, 0, 0 },
          105  +  /* 12 */ { "pwrite",    (sqlite3_syscall_ptr)ts_pwrite,    0, 0, 0 },
          106  +  /* 13 */ { "pwrite64",  (sqlite3_syscall_ptr)ts_pwrite64,  0, 0, 0 },
          107  +  /* 14 */ { "fchmod",    (sqlite3_syscall_ptr)ts_fchmod,    0, 0, 0 },
          108  +  /* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 },
          109  +           { 0, 0, 0, 0, 0 }
          110  +};
          111  +
          112  +#define orig_open      ((int(*)(const char *, int, int))aSyscall[0].xOrig)
          113  +#define orig_close     ((int(*)(int))aSyscall[1].xOrig)
          114  +#define orig_access    ((int(*)(const char*,int))aSyscall[2].xOrig)
          115  +#define orig_getcwd    ((char*(*)(char*,size_t))aSyscall[3].xOrig)
          116  +#define orig_stat      ((int(*)(const char*,struct stat*))aSyscall[4].xOrig)
          117  +#define orig_fstat     ((int(*)(int,struct stat*))aSyscall[5].xOrig)
          118  +#define orig_ftruncate ((int(*)(int,off_t))aSyscall[6].xOrig)
          119  +#define orig_fcntl     ((int(*)(int,int,...))aSyscall[7].xOrig)
          120  +#define orig_read      ((ssize_t(*)(int,void*,size_t))aSyscall[8].xOrig)
          121  +#define orig_pread     ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].xOrig)
          122  +#define orig_pread64   ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].xOrig)
          123  +#define orig_write     ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig)
          124  +#define orig_pwrite    ((ssize_t(*)(int,const void*,size_t,off_t))\
          125  +                       aSyscall[12].xOrig)
          126  +#define orig_pwrite64  ((ssize_t(*)(int,const void*,size_t,off_t))\
          127  +                       aSyscall[13].xOrig)
          128  +#define orig_fchmod    ((int(*)(int,mode_t))aSyscall[14].xOrig)
          129  +#define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
          130  +
          131  +
          132  +/*
          133  +** This function is called exactly once from within each invocation of a
          134  +** system call wrapper in this file. It returns 1 if the function should
          135  +** fail, or 0 if it should succeed.
          136  +*/
          137  +static int tsIsFail(void){
          138  +  gSyscall.nCount--;
          139  +  if( gSyscall.nCount==0 || (gSyscall.nFail && gSyscall.bPersist) ){
          140  +    gSyscall.nFail++;
          141  +    return 1;
          142  +  }
          143  +  return 0;
          144  +}
          145  +
          146  +/*
          147  +** Return the current error-number value for function zFunc. zFunc must be
          148  +** the name of a system call in the aSyscall[] table.
          149  +**
          150  +** Usually, the current error-number is the value that errno should be set
          151  +** to if the named system call fails. The exception is "fallocate". See 
          152  +** comments above the implementation of ts_fallocate() for details.
          153  +*/
          154  +static int tsErrno(const char *zFunc){
          155  +  int i;
          156  +  int nFunc = strlen(zFunc);
          157  +  for(i=0; aSyscall[i].zName; i++){
          158  +    if( strlen(aSyscall[i].zName)!=nFunc ) continue;
          159  +    if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
          160  +    return aSyscall[i].custom_errno;
          161  +  }
          162  +
          163  +  assert(0);
          164  +  return 0;
          165  +}
          166  +
          167  +/*
          168  +** A wrapper around tsIsFail(). If tsIsFail() returns non-zero, set the
          169  +** value of errno before returning.
          170  +*/ 
          171  +static int tsIsFailErrno(const char *zFunc){
          172  +  if( tsIsFail() ){
          173  +    errno = tsErrno(zFunc);
          174  +    return 1;
          175  +  }
          176  +  return 0;
          177  +}
          178  +
          179  +/*
          180  +** A wrapper around open().
          181  +*/
          182  +static int ts_open(const char *zFile, int flags, int mode){
          183  +  if( tsIsFailErrno("open") ){
          184  +    return -1;
          185  +  }
          186  +  return orig_open(zFile, flags, mode);
          187  +}
          188  +
          189  +/*
          190  +** A wrapper around close().
          191  +*/
          192  +static int ts_close(int fd){
          193  +  if( tsIsFail() ){
          194  +    return -1;
          195  +  }
          196  +  return orig_close(fd);
          197  +}
          198  +
          199  +/*
          200  +** A wrapper around access().
          201  +*/
          202  +static int ts_access(const char *zPath, int mode){
          203  +  if( tsIsFail() ){
          204  +    return -1;
          205  +  }
          206  +  return orig_access(zPath, mode);
          207  +}
          208  +
          209  +/*
          210  +** A wrapper around getcwd().
          211  +*/
          212  +static char *ts_getcwd(char *zPath, size_t nPath){
          213  +  if( tsIsFail() ){
          214  +    return NULL;
          215  +  }
          216  +  return orig_getcwd(zPath, nPath);
          217  +}
          218  +
          219  +/*
          220  +** A wrapper around stat().
          221  +*/
          222  +static int ts_stat(const char *zPath, struct stat *p){
          223  +  if( tsIsFail() ){
          224  +    return -1;
          225  +  }
          226  +  return orig_stat(zPath, p);
          227  +}
          228  +
          229  +/*
          230  +** A wrapper around fstat().
          231  +*/
          232  +static int ts_fstat(int fd, struct stat *p){
          233  +  if( tsIsFail() ){
          234  +    return -1;
          235  +  }
          236  +  return orig_fstat(fd, p);
          237  +}
          238  +
          239  +/*
          240  +** A wrapper around ftruncate().
          241  +*/
          242  +static int ts_ftruncate(int fd, off_t n){
          243  +  if( tsIsFail() ){
          244  +    return -1;
          245  +  }
          246  +  return orig_ftruncate(fd, n);
          247  +}
          248  +
          249  +/*
          250  +** A wrapper around fcntl().
          251  +*/
          252  +static int ts_fcntl(int fd, int cmd, ... ){
          253  +  va_list ap;
          254  +  void *pArg;
          255  +  if( tsIsFail() ){
          256  +    return -1;
          257  +  }
          258  +  va_start(ap, cmd);
          259  +  pArg = va_arg(ap, void *);
          260  +  return orig_fcntl(fd, cmd, pArg);
          261  +}
          262  +
          263  +/*
          264  +** A wrapper around read().
          265  +*/
          266  +static int ts_read(int fd, void *aBuf, size_t nBuf){
          267  +  if( tsIsFail() ){
          268  +    return -1;
          269  +  }
          270  +  return orig_read(fd, aBuf, nBuf);
          271  +}
          272  +
          273  +/*
          274  +** A wrapper around pread().
          275  +*/
          276  +static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
          277  +  if( tsIsFail() ){
          278  +    return -1;
          279  +  }
          280  +  return orig_pread(fd, aBuf, nBuf, off);
          281  +}
          282  +
          283  +/*
          284  +** A wrapper around pread64().
          285  +*/
          286  +static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){
          287  +  if( tsIsFail() ){
          288  +    return -1;
          289  +  }
          290  +  return orig_pread64(fd, aBuf, nBuf, off);
          291  +}
          292  +
          293  +/*
          294  +** A wrapper around write().
          295  +*/
          296  +static int ts_write(int fd, const void *aBuf, size_t nBuf){
          297  +  if( tsIsFail() ){
          298  +    return -1;
          299  +  }
          300  +  return orig_write(fd, aBuf, nBuf);
          301  +}
          302  +
          303  +/*
          304  +** A wrapper around pwrite().
          305  +*/
          306  +static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
          307  +  if( tsIsFail() ){
          308  +    return -1;
          309  +  }
          310  +  return orig_pwrite(fd, aBuf, nBuf, off);
          311  +}
          312  +
          313  +/*
          314  +** A wrapper around pwrite64().
          315  +*/
          316  +static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){
          317  +  if( tsIsFail() ){
          318  +    return -1;
          319  +  }
          320  +  return orig_pwrite64(fd, aBuf, nBuf, off);
          321  +}
          322  +
          323  +/*
          324  +** A wrapper around fchmod().
          325  +*/
          326  +static int ts_fchmod(int fd, mode_t mode){
          327  +  if( tsIsFail() ){
          328  +    return -1;
          329  +  }
          330  +  return orig_fchmod(fd, mode);
          331  +}
          332  +
          333  +/*
          334  +** A wrapper around fallocate().
          335  +**
          336  +** SQLite assumes that the fallocate() function is compatible with
          337  +** posix_fallocate(). According to the Linux man page (2009-09-30):
          338  +**
          339  +**   posix_fallocate() returns  zero on success, or an error number on
          340  +**   failure. Note that errno is not set.
          341  +*/
          342  +static int ts_fallocate(int fd, off_t off, off_t len){
          343  +  if( tsIsFail() ){
          344  +    return tsErrno("fallocate");
          345  +  }
          346  +  return orig_fallocate(fd, off, len);
          347  +}
          348  +
          349  +static int test_syscall_install(
          350  +  void * clientData,
          351  +  Tcl_Interp *interp,
          352  +  int objc,
          353  +  Tcl_Obj *CONST objv[]
          354  +){
          355  +  sqlite3_vfs *pVfs; 
          356  +  int nElem;
          357  +  int i;
          358  +  Tcl_Obj **apElem;
          359  +
          360  +  if( objc!=3 ){
          361  +    Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL-LIST");
          362  +    return TCL_ERROR;
          363  +  }
          364  +  if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
          365  +    return TCL_ERROR;
          366  +  }
          367  +  pVfs = sqlite3_vfs_find(0);
          368  +
          369  +  for(i=0; i<nElem; i++){
          370  +    int iCall;
          371  +    int rc = Tcl_GetIndexFromObjStruct(interp, 
          372  +        apElem[i], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
          373  +    );
          374  +    if( rc ) return rc;
          375  +    if( aSyscall[iCall].xOrig==0 ){
          376  +      aSyscall[iCall].xOrig = pVfs->xGetSystemCall(pVfs, aSyscall[iCall].zName);
          377  +      pVfs->xSetSystemCall(pVfs, aSyscall[iCall].zName, aSyscall[iCall].xTest);
          378  +    }
          379  +    aSyscall[iCall].custom_errno = aSyscall[iCall].default_errno;
          380  +  }
          381  +
          382  +  return TCL_OK;
          383  +}
          384  +
          385  +static int test_syscall_uninstall(
          386  +  void * clientData,
          387  +  Tcl_Interp *interp,
          388  +  int objc,
          389  +  Tcl_Obj *CONST objv[]
          390  +){
          391  +  sqlite3_vfs *pVfs; 
          392  +  int i;
          393  +
          394  +  if( objc!=2 ){
          395  +    Tcl_WrongNumArgs(interp, 2, objv, "");
          396  +    return TCL_ERROR;
          397  +  }
          398  +
          399  +  pVfs = sqlite3_vfs_find(0);
          400  +  for(i=0; aSyscall[i].zName; i++){
          401  +    if( aSyscall[i].xOrig ){
          402  +      pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, aSyscall[i].xOrig);
          403  +      aSyscall[i].xOrig = 0;
          404  +    }
          405  +  }
          406  +  return TCL_OK;
          407  +}
          408  +
          409  +static int test_syscall_fault(
          410  +  void * clientData,
          411  +  Tcl_Interp *interp,
          412  +  int objc,
          413  +  Tcl_Obj *CONST objv[]
          414  +){
          415  +  int nCount = 0;
          416  +  int bPersist = 0;
          417  +
          418  +  if( objc!=2 && objc!=4 ){
          419  +    Tcl_WrongNumArgs(interp, 2, objv, "?COUNT PERSIST?");
          420  +    return TCL_ERROR;
          421  +  }
          422  +
          423  +  if( objc==4 ){
          424  +    if( Tcl_GetIntFromObj(interp, objv[2], &nCount)
          425  +     || Tcl_GetBooleanFromObj(interp, objv[3], &bPersist)
          426  +    ){
          427  +      return TCL_ERROR;
          428  +    }
          429  +  }
          430  +
          431  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(gSyscall.nFail));
          432  +  gSyscall.nCount = nCount;
          433  +  gSyscall.bPersist = bPersist;
          434  +  gSyscall.nFail = 0;
          435  +  return TCL_OK;
          436  +}
          437  +
          438  +static int test_syscall_errno(
          439  +  void * clientData,
          440  +  Tcl_Interp *interp,
          441  +  int objc,
          442  +  Tcl_Obj *CONST objv[]
          443  +){
          444  +  int iCall;
          445  +  int iErrno;
          446  +  int rc;
          447  +
          448  +  struct Errno {
          449  +    const char *z;
          450  +    int i;
          451  +  } aErrno[] = {
          452  +    { "EACCES", EACCES },
          453  +    { 0, 0 }
          454  +  };
          455  +
          456  +  if( objc!=4 ){
          457  +    Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL ERRNO");
          458  +    return TCL_ERROR;
          459  +  }
          460  +
          461  +  rc = Tcl_GetIndexFromObjStruct(interp, 
          462  +      objv[2], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
          463  +  );
          464  +  if( rc!=TCL_OK ) return rc;
          465  +  rc = Tcl_GetIndexFromObjStruct(interp, 
          466  +      objv[3], aErrno, sizeof(aErrno[0]), "errno", 0, &iErrno
          467  +  );
          468  +  if( rc!=TCL_OK ) return rc;
          469  +
          470  +  aSyscall[iCall].custom_errno = aErrno[iErrno].i;
          471  +  return TCL_OK;
          472  +}
          473  +
          474  +static int test_syscall(
          475  +  void * clientData,
          476  +  Tcl_Interp *interp,
          477  +  int objc,
          478  +  Tcl_Obj *CONST objv[]
          479  +){
          480  +  struct SyscallCmd {
          481  +    const char *zName;
          482  +    Tcl_ObjCmdProc *xCmd;
          483  +  } aCmd[] = {
          484  +    { "fault",     test_syscall_fault },
          485  +    { "install",   test_syscall_install },
          486  +    { "uninstall", test_syscall_uninstall },
          487  +    { "errno",     test_syscall_errno },
          488  +    { 0, 0 }
          489  +  };
          490  +  int iCmd;
          491  +  int rc;
          492  +
          493  +  if( objc<2 ){
          494  +    Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
          495  +    return TCL_ERROR;
          496  +  }
          497  +  rc = Tcl_GetIndexFromObjStruct(interp, 
          498  +      objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd
          499  +  );
          500  +  if( rc!=TCL_OK ) return rc;
          501  +  return aCmd[iCmd].xCmd(clientData, interp, objc, objv);
          502  +}
          503  +
          504  +int SqlitetestSyscall_Init(Tcl_Interp *interp){
          505  +  struct SyscallCmd {
          506  +    const char *zName;
          507  +    Tcl_ObjCmdProc *xCmd;
          508  +  } aCmd[] = {
          509  +    { "test_syscall",     test_syscall},
          510  +  };
          511  +  int i;
          512  +
          513  +  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
          514  +    Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xCmd, 0, 0);
          515  +  }
          516  +  return TCL_OK;
          517  +}
          518  +#else
          519  +int SqlitetestSyscall_Init(Tcl_Interp *interp){
          520  +  return TCL_OK;
          521  +}
          522  +#endif
          523  +

Changes to test/malloc_common.tcl.

   113    113   proc do_faultsim_test {name args} {
   114    114     global FAULTSIM
   115    115     
   116    116     set DEFAULT(-faults)        [array names FAULTSIM]
   117    117     set DEFAULT(-prep)          ""
   118    118     set DEFAULT(-body)          ""
   119    119     set DEFAULT(-test)          ""
   120         -  set DEFAULT(-install)          ""
   121         -  set DEFAULT(-uninstall)          ""
          120  +  set DEFAULT(-install)       ""
          121  +  set DEFAULT(-uninstall)     ""
   122    122   
   123    123     fix_testname name
   124    124   
   125    125     array set O [array get DEFAULT]
   126    126     array set O $args
   127    127     foreach o [array names O] {
   128    128       if {[info exists DEFAULT($o)]==0} { error "unknown option: $o" }

Added test/sysfault.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  +proc vfsfault_install {} { 
           47  +  test_syscall install {open getcwd}
           48  +}
           49  +
           50  +do_faultsim_test 1 -faults vfsfault-* -prep {
           51  +  faultsim_restore
           52  +} -body {
           53  +  sqlite3 db test.db
           54  +  db eval {
           55  +    CREATE TABLE t1(a, b);
           56  +    INSERT INTO t1 VALUES(1, 2);
           57  +    PRAGMA journal_mode = WAL;
           58  +    INSERT INTO t1 VALUES(3, 4);
           59  +    SELECT * FROM t1;
           60  +    CREATE TEMP TABLE t2(x);
           61  +    INSERT INTO t2 VALUES('y');
           62  +  }
           63  +} -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  +finish_test
           70  +