/ Check-in [f5df83fd]
Login

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

Overview
Comment:Add tests to pager1.test and pagerfault.test.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: f5df83fd875073eee8e2269e87e2a8c9c7abc981
User & Date: dan 2010-06-19 17:26:37
Context
2010-06-19
18:12
Change the name of IOCAP_SAFE_DELETE to IOCAP_UNDELETABLE_WHEN_OPEN. Have the xDeviceCharacteristics() method of the win32 VFS return this flag. check-in: 5a5ff4e3 user: dan tags: experimental
17:26
Add tests to pager1.test and pagerfault.test. check-in: f5df83fd user: dan tags: experimental
11:30
Add tests to pager1.test and pagerfault.test. check-in: 58c0b5bf user: dan tags: experimental
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/test_vfs.c.

    55     55     int isNoshm;
    56     56   
    57     57     int mask;
    58     58     int iIoerrCnt;
    59     59     int ioerr;
    60     60     int nIoerrFail;
    61     61   
           62  +  int iFullCnt;
           63  +  int fullerr;
           64  +  int nFullFail;
           65  +
    62     66     int iDevchar;
    63     67     int iSectorsize;
    64     68   };
    65     69   
    66     70   /*
    67     71   ** The Testvfs.mask variable is set to a combination of the following.
    68     72   ** If a bit is clear in Testvfs.mask, then calls made by SQLite to the 
................................................................................
   189    193         return 1;
   190    194       }
   191    195     }
   192    196   
   193    197     return 0;
   194    198   }
   195    199   
          200  +static int tvfsInjectIoerr(Testvfs *p){
          201  +  int ret = 0;
          202  +  if( p->ioerr ){
          203  +    p->iIoerrCnt--;
          204  +    if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
          205  +      ret = 1;
          206  +      p->nIoerrFail++;
          207  +    }
          208  +  }
          209  +  return ret;
          210  +}
          211  +
          212  +static int tvfsInjectFullerr(Testvfs *p){
          213  +  int ret = 0;
          214  +  if( p->fullerr ){
          215  +    p->iFullCnt--;
          216  +    if( p->iFullCnt<=0 ){
          217  +      ret = 1;
          218  +      p->nFullFail++;
          219  +    }
          220  +  }
          221  +  return ret;
          222  +}
          223  +
   196    224   
   197    225   static void tvfsExecTcl(
   198    226     Testvfs *p, 
   199    227     const char *zMethod,
   200    228     Tcl_Obj *arg1,
   201    229     Tcl_Obj *arg2,
   202    230     Tcl_Obj *arg3
................................................................................
   298    326   
   299    327     if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){
   300    328       tvfsExecTcl(p, "xWrite", 
   301    329           Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
   302    330       );
   303    331       tvfsResultCode(p, &rc);
   304    332     }
          333  +
          334  +  if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;
   305    335     
   306    336     if( rc==SQLITE_OK ){
   307    337       rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst);
   308    338     }
   309    339     return rc;
   310    340   }
   311    341   
................................................................................
   360    390   
   361    391       tvfsExecTcl(p, "xSync", 
   362    392           Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId,
   363    393           Tcl_NewStringObj(zFlags, -1)
   364    394       );
   365    395       tvfsResultCode(p, &rc);
   366    396     }
          397  +
          398  +  if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL;
   367    399   
   368    400     if( rc==SQLITE_OK ){
   369    401       rc = sqlite3OsSync(pFd->pReal, flags);
   370    402     }
   371    403   
   372    404     return rc;
   373    405   }
................................................................................
   599    631   /*
   600    632   ** Return the current time as a Julian Day number in *pTimeOut.
   601    633   */
   602    634   static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
   603    635     return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
   604    636   }
   605    637   
   606         -static int tvfsInjectIoerr(Testvfs *p){
   607         -  int ret = 0;
   608         -  if( p->ioerr ){
   609         -    p->iIoerrCnt--;
   610         -    if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){
   611         -      ret = 1;
   612         -      p->nIoerrFail++;
   613         -    }
   614         -  }
   615         -  return ret;
   616         -}
   617         -
   618    638   static int tvfsShmOpen(
   619    639     sqlite3_file *pFileDes
   620    640   ){
   621    641     Testvfs *p;
   622    642     int rc = SQLITE_OK;             /* Return code */
   623    643     TestvfsBuffer *pBuffer;         /* Buffer to open connection to */
   624    644     TestvfsFile *pFd;               /* The testvfs file structure */
................................................................................
   828    848     int objc,
   829    849     Tcl_Obj *CONST objv[]
   830    850   ){
   831    851     Testvfs *p = (Testvfs *)cd;
   832    852   
   833    853     enum DB_enum { 
   834    854       CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, 
   835         -    CMD_DEVCHAR, CMD_SECTORSIZE
          855  +    CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR
   836    856     };
   837    857     struct TestvfsSubcmd {
   838    858       char *zName;
   839    859       enum DB_enum eCmd;
   840    860     } aSubcmd[] = {
   841    861       { "shm",        CMD_SHM        },
   842    862       { "delete",     CMD_DELETE     },
   843    863       { "filter",     CMD_FILTER     },
   844    864       { "ioerr",      CMD_IOERR      },
          865  +    { "fullerr",    CMD_FULLERR    },
   845    866       { "script",     CMD_SCRIPT     },
   846    867       { "devchar",    CMD_DEVCHAR    },
   847    868       { "sectorsize", CMD_SECTORSIZE },
   848    869       { 0, 0 }
   849    870     };
   850    871     int i;
   851    872     
................................................................................
   973    994         }
   974    995   
   975    996         Tcl_ResetResult(interp);
   976    997         if( p->pScript ) Tcl_SetObjResult(interp, p->pScript);
   977    998   
   978    999         break;
   979   1000       }
         1001  +
         1002  +    /*
         1003  +    ** TESTVFS fullerr ?IFAIL?
         1004  +    **
         1005  +    **   Where IFAIL is an integer.
         1006  +    */
         1007  +    case CMD_FULLERR: {
         1008  +      int iRet = p->nFullFail;
         1009  +
         1010  +      p->nFullFail = 0;
         1011  +      p->fullerr = 0;
         1012  +      p->iFullCnt = 0;
         1013  +
         1014  +      if( objc==3 ){
         1015  +        int iCnt;
         1016  +        if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt) ){
         1017  +          return TCL_ERROR;
         1018  +        }
         1019  +        p->fullerr = (iCnt>0);
         1020  +        p->iFullCnt = iCnt;
         1021  +      }else if( objc!=2 ){
         1022  +        Tcl_AppendResult(interp, "Bad args", 0);
         1023  +        return TCL_ERROR;
         1024  +      }
         1025  +
         1026  +      Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet));
         1027  +      break;
         1028  +    }
   980   1029   
   981   1030       /*
   982   1031       ** TESTVFS ioerr ?IFAIL PERSIST?
   983   1032       **
   984   1033       **   Where IFAIL is an integer and PERSIST is boolean.
   985   1034       */
   986   1035       case CMD_IOERR: {

Changes to test/malloc_common.tcl.

    44     44     -injecterrlist {{1 {disk I/O error}}}    \
    45     45   ]
    46     46   set FAULTSIM(ioerr-persistent) [list       \
    47     47     -injectstart   {ioerr_injectstart 1}     \
    48     48     -injectstop    ioerr_injectstop          \
    49     49     -injecterrlist {{1 {disk I/O error}}}    \
    50     50   ]
           51  +
           52  +# SQLITE_FULL errors (always persistent):
           53  +#
           54  +set FAULTSIM(full) [list                   \
           55  +  -injectinstall   fullerr_injectinstall   \
           56  +  -injectstart     fullerr_injectstart     \
           57  +  -injectstop      fullerr_injectstop      \
           58  +  -injecterrlist   {{1 {database or disk is full}}} \
           59  +  -injectuninstall fullerr_injectuninstall \
           60  +]
    51     61   
    52     62   # Transient and persistent SHM errors:
    53     63   #
    54     64   set FAULTSIM(shmerr-transient) [list       \
    55     65     -injectinstall   shmerr_injectinstall    \
    56     66     -injectstart     {shmerr_injectstart 0}  \
    57     67     -injectstop      shmerr_injectstop       \
................................................................................
   172    182     set ::sqlite_io_error_persist 0
   173    183     set ::sqlite_io_error_pending 0
   174    184     set ::sqlite_io_error_hardhit 0
   175    185     set ::sqlite_io_error_hit     0
   176    186     set ::sqlite_io_error_pending 0
   177    187     return $sv
   178    188   }
          189  +
   179    190   
   180    191   # The following procs are used as [do_one_faultsim_test] callbacks when 
   181    192   # injecting shared-memory related error faults into test cases.
   182    193   #
   183    194   proc shmerr_injectinstall {} {
   184    195     testvfs shmfault -default true
   185    196   }
................................................................................
   190    201   }
   191    202   proc shmerr_injectstart {persist iFail} {
   192    203     shmfault ioerr $iFail $persist
   193    204   }
   194    205   proc shmerr_injectstop {} {
   195    206     shmfault ioerr 0 0
   196    207   }
          208  +
          209  +proc fullerr_injectinstall {} {
          210  +  testvfs shmfault -default true
          211  +}
          212  +proc fullerr_injectuninstall {} {
          213  +  catch {db  close}
          214  +  catch {db2 close}
          215  +  shmfault delete
          216  +}
          217  +proc fullerr_injectstart {iFail} {
          218  +  shmfault full $iFail
          219  +}
          220  +proc fullerr_injectstop {} {
          221  +  shmfault full 0
          222  +}
          223  +
   197    224   
   198    225   # This command is not called directly. It is used by the 
   199    226   # [faultsim_test_result] command created by [do_faultsim_test] and used
   200    227   # by -test scripts.
   201    228   #
   202    229   proc faultsim_test_result_int {args} {
   203    230     upvar testrc testrc testresult testresult testnfail testnfail

Changes to test/pager1.test.

    22     22   #
    23     23   # pager1-3.*: Savepoint related tests.
    24     24   #
    25     25   # pager1-4.*: Hot-journal related tests.
    26     26   #
    27     27   # pager1-5.*: Cases related to multi-file commits.
    28     28   #
           29  +# pager1-6.*: Cases related to "PRAGMA max_page_count"
           30  +#
    29     31   
    30     32   proc do_execsql_test {testname sql result} {
    31     33     uplevel do_test $testname [list "execsql {$sql}"] [list $result]
    32     34   }
    33     35   proc do_catchsql_test {testname sql result} {
    34     36     uplevel do_test $testname [list "catchsql {$sql}"] [list $result]
    35     37   }
................................................................................
   217    219   set otn 0
   218    220   testvfs tv -default 1
   219    221   foreach code [list {
   220    222     set s 512
   221    223   } {
   222    224     set s 1024
   223    225     set sql { PRAGMA journal_mode = memory }
          226  +} {
          227  +  set s 1024
          228  +  set sql { 
          229  +    PRAGMA journal_mode = memory;
          230  +    PRAGMA locking_mode = exclusive;
          231  +  }
   224    232   } {
   225    233     set s 2048
   226    234     tv devchar safe_append
   227    235   } {
   228    236     set s 4096
   229    237   } {
   230    238     set s 4096
................................................................................
   445    453       hexio_write test.db-journal $ofst [format %.8x $value]
   446    454       execsql { SELECT * FROM t1 }
   447    455     } $result
   448    456   }
   449    457   db close
   450    458   
   451    459   #-------------------------------------------------------------------------
          460  +# The following tests deal with multi-file commits.
          461  +#
          462  +# pager1-5.1.*: The case where a multi-file cannot be committed because
          463  +#               another connection is holding a SHARED lock on one of the
          464  +#               files. After the SHARED lock is removed, the COMMIT succeeds.
          465  +#
          466  +# pager1-5.2.*: Multi-file commits with journal_mode=memory.
          467  +#
          468  +# pager1-5.3.*: Multi-file commits with journal_mode=memory.
          469  +#
          470  +# pager1-5.4.*: Check that with synchronous=normal, the master-journal file
          471  +#               name is added to a journal file immediately after the last
          472  +#               journal record. But with synchronous=full, extra unused space
          473  +#               is allocated between the last journal record and the 
          474  +#               master-journal file name so that the master-journal file
          475  +#               name does not lie on the same sector as the last journal file
          476  +#               record.
          477  +#
          478  +# pager1-5.5.*: 
          479  +#
          480  +do_test pager1-5.1.1 {
          481  +  faultsim_delete_and_reopen
          482  +  execsql {
          483  +    ATTACH 'test.db2' AS aux;
          484  +    CREATE TABLE t1(a, b);
          485  +    CREATE TABLE aux.t2(a, b);
          486  +    INSERT INTO t1 VALUES(17, 'Lenin');
          487  +    INSERT INTO t1 VALUES(22, 'Stalin');
          488  +    INSERT INTO t1 VALUES(53, 'Khrushchev');
          489  +  }
          490  +} {}
          491  +do_test pager1-5.1.2 {
          492  +  execsql {
          493  +    BEGIN;
          494  +      INSERT INTO t1 VALUES(64, 'Brezhnev');
          495  +      INSERT INTO t2 SELECT * FROM t1;
          496  +  }
          497  +  sqlite3 db2 test.db2
          498  +  execsql {
          499  +    BEGIN;
          500  +      SELECT * FROM t2;
          501  +  } db2
          502  +} {}
          503  +do_test pager1-5.1.3 {
          504  +  catchsql COMMIT
          505  +} {1 {database is locked}}
          506  +do_test pager1-5.1.4 {
          507  +  execsql COMMIT db2
          508  +  execsql COMMIT
          509  +  execsql { SELECT * FROM t2 } db2
          510  +} {17 Lenin 22 Stalin 53 Khrushchev 64 Brezhnev}
          511  +do_test pager1-5.1.5 {
          512  +  db2 close
          513  +} {}
          514  +
          515  +do_test pager1-5.2.1 {
          516  +  execsql {
          517  +    PRAGMA journal_mode = memory;
          518  +    BEGIN;
          519  +      INSERT INTO t1 VALUES(84, 'Andropov');
          520  +      INSERT INTO t2 VALUES(84, 'Andropov');
          521  +    COMMIT;
          522  +  }
          523  +} {memory}
          524  +do_test pager1-5.3.1 {
          525  +  execsql {
          526  +    PRAGMA journal_mode = off;
          527  +    BEGIN;
          528  +      INSERT INTO t1 VALUES(85, 'Gorbachev');
          529  +      INSERT INTO t2 VALUES(85, 'Gorbachev');
          530  +    COMMIT;
          531  +  }
          532  +} {off}
          533  +
          534  +do_test pager1-5.4.1 {
          535  +  db close
          536  +  testvfs tv
          537  +  sqlite3 db test.db -vfs tv
          538  +  execsql { ATTACH 'test.db2' AS aux }
          539  +
          540  +  tv filter xDelete
          541  +  tv script max_journal_size
          542  +  tv sectorsize 512
          543  +  set ::max_journal 0
          544  +  proc max_journal_size {method args} {
          545  +    set sz 0
          546  +    catch { set sz [file size test.db-journal] }
          547  +    if {$sz > $::max_journal} {
          548  +      set ::max_journal $sz
          549  +    }
          550  +    return SQLITE_OK
          551  +  }
          552  +  execsql {
          553  +    PRAGMA journal_mode = DELETE;
          554  +    PRAGMA synchronous = NORMAL;
          555  +    BEGIN;
          556  +      INSERT INTO t1 VALUES(85, 'Gorbachev');
          557  +      INSERT INTO t2 VALUES(85, 'Gorbachev');
          558  +    COMMIT;
          559  +  }
          560  +  set ::max_journal
          561  +} [expr 2615+[string length [pwd]]]
          562  +do_test pager1-5.4.2 {
          563  +  set ::max_journal 0
          564  +  execsql {
          565  +    PRAGMA synchronous = full;
          566  +    BEGIN;
          567  +      DELETE FROM t1 WHERE b = 'Lenin';
          568  +      DELETE FROM t2 WHERE b = 'Lenin';
          569  +    COMMIT;
          570  +  }
          571  +  set ::max_journal
          572  +} [expr 3111+[string length [pwd]]]
          573  +db close
          574  +tv delete
          575  +
          576  +do_test pager1-5.5.1 {
          577  +  sqlite3 db test.db
          578  +  execsql { 
          579  +    ATTACH 'test.db2' AS aux;
          580  +    PRAGMA journal_mode = PERSIST;
          581  +    CREATE TABLE t3(a, b);
          582  +    INSERT INTO t3 SELECT randomblob(1500), randomblob(1500) FROM t1;
          583  +    UPDATE t3 SET b = randomblob(1500);
          584  +  }
          585  +  expr [file size test.db-journal] > 15000
          586  +} {1}
          587  +do_test pager1-5.5.2 {
          588  +  execsql {
          589  +    PRAGMA synchronous = full;
          590  +    BEGIN;
          591  +      DELETE FROM t1 WHERE b = 'Stalin';
          592  +      DELETE FROM t2 WHERE b = 'Stalin';
          593  +    COMMIT;
          594  +  }
          595  +  file size test.db-journal
          596  +} {0}
          597  +
          598  +
          599  +#-------------------------------------------------------------------------
          600  +# The following tests work with "PRAGMA max_page_count"
   452    601   #
          602  +do_test pager1-6.1 {
          603  +  faultsim_delete_and_reopen
          604  +  execsql {
          605  +    PRAGMA max_page_count = 10;
          606  +    CREATE TABLE t2(a, b);
          607  +    CREATE TABLE t3(a, b);
          608  +    CREATE TABLE t4(a, b);
          609  +    CREATE TABLE t5(a, b);
          610  +    CREATE TABLE t6(a, b);
          611  +    CREATE TABLE t7(a, b);
          612  +    CREATE TABLE t8(a, b);
          613  +    CREATE TABLE t9(a, b);
          614  +    CREATE TABLE t10(a, b);
          615  +  }
          616  +} {10}
          617  +do_test pager1-6.2 {
          618  +  catchsql {
          619  +    CREATE TABLE t11(a, b);
          620  +  }
          621  +} {1 {database or disk is full}}
   453    622   
   454    623   finish_test
   455    624   

Changes to test/pagerfault.test.

   175    175   } -test {
   176    176     faultsim_test_result {0 z}
   177    177     faultsim_integrity_check
   178    178   }
   179    179   
   180    180   #-------------------------------------------------------------------------
   181    181   # Test fault-injection as part of a commit when using journal_mode=PERSIST.
          182  +# Three different cases:
          183  +#
          184  +#    pagerfault-5.1: With no journal_size_limit configured.
          185  +#    pagerfault-5.2: With a journal_size_limit configured.
          186  +#    pagerfault-5.4: Multi-file transaction. One connection has a 
          187  +#                    journal_size_limit of 0, the other has no limit.
   182    188   #
   183    189   do_test pagerfault-5-pre1 {
   184    190     faultsim_delete_and_reopen
   185    191     db func a_string a_string
   186    192     execsql {
   187    193       CREATE TABLE t1(a UNIQUE, b UNIQUE);
   188    194       INSERT INTO t1 VALUES(a_string(200), a_string(300));
................................................................................
   210    216     }
   211    217   } -body {
   212    218     execsql { INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1 }
   213    219   } -test {
   214    220     faultsim_test_result {0 {}}
   215    221     faultsim_integrity_check
   216    222   }
   217         -
   218    223   do_faultsim_test pagerfault-5.3 -prep {
   219    224     faultsim_restore_and_reopen
   220    225     db func a_string a_string
   221    226     file delete -force test2.db test2.db-journal test2.db-wal
   222    227     execsql { 
   223    228       PRAGMA journal_mode = PERSIST;
   224    229       ATTACH 'test2.db' AS aux;
................................................................................
   231    236         INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1;
   232    237         CREATE TABLE aux.t2 AS SELECT * FROM t1;
   233    238       COMMIT;
   234    239     }
   235    240   } -test {
   236    241     faultsim_test_result {0 {}}
   237    242   }
          243  +
          244  +# The following was an attempt to get a bitvec malloc to fail. Didn't work.
          245  +#
          246  +# do_test pagerfault-6-pre1 {
          247  +#   faultsim_delete_and_reopen
          248  +#   execsql {
          249  +#     CREATE TABLE t1(x, y, UNIQUE(x, y));
          250  +#     INSERT INTO t1 VALUES(1, randomblob(1501));
          251  +#     INSERT INTO t1 VALUES(2, randomblob(1502));
          252  +#     INSERT INTO t1 VALUES(3, randomblob(1503));
          253  +#     INSERT INTO t1 VALUES(4, randomblob(1504));
          254  +#     INSERT INTO t1 
          255  +#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
          256  +#     INSERT INTO t1 
          257  +#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
          258  +#     INSERT INTO t1 
          259  +#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
          260  +#     INSERT INTO t1 
          261  +#       SELECT x, randomblob(1500+oid+(SELECT max(oid) FROM t1)) FROM t1;
          262  +#   }
          263  +#   faultsim_save_and_close
          264  +# } {}
          265  +# do_faultsim_test pagerfault-6 -prep {
          266  +#   faultsim_restore_and_reopen
          267  +# } -body {
          268  +#   execsql { 
          269  +#     BEGIN;
          270  +#       UPDATE t1 SET x=x+4 WHERE x=1;
          271  +#       SAVEPOINT one;
          272  +#         UPDATE t1 SET x=x+4 WHERE x=2;
          273  +#         SAVEPOINT three;
          274  +#           UPDATE t1 SET x=x+4 WHERE x=3;
          275  +#           SAVEPOINT four;
          276  +#             UPDATE t1 SET x=x+4 WHERE x=4;
          277  +#         RELEASE three;
          278  +#     COMMIT;
          279  +#     SELECT DISTINCT x FROM t1;
          280  +#   }
          281  +# } -test {
          282  +#   faultsim_test_result {0 {5 6 7 8}}
          283  +#   faultsim_integrity_check
          284  +# }
   238    285   
   239    286   finish_test

Changes to test/permutations.test.

   166    166   } 
   167    167   
   168    168   test_suite "coverage-pager" -description {
   169    169     Coverage tests for file pager.c.
   170    170   } -files {
   171    171     pager1.test
   172    172     pagerfault.test
          173  +  journal2.test
   173    174   } 
   174    175   
   175    176   
   176    177   lappend ::testsuitelist xxx
   177    178   #-------------------------------------------------------------------------
   178    179   # Define the permutation test suites:
   179    180   #