summaryrefslogtreecommitdiffstats
path: root/test/multiplex3.test
blob: 31883501639750e7c280b54d93a5d3734850386c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# 2011 December 13
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains tests for error (IO, OOM etc.) handling when using
# the multiplexor extension with 8.3 filenames.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix multiplex3

ifcapable !8_3_names {
  puts -nonewline "SQLite compiled without SQLITE_ENABLE_8_3_NAMES. "
  puts            "Skipping tests multiplex3-*."
  finish_test
  return
}

db close
sqlite3_shutdown
sqlite3_config_uri 1
autoinstall_test_functions

sqlite3_multiplex_initialize "" 1

proc destroy_vfs_stack {} {
  generic_unregister stack
  sqlite3_multiplex_shutdown
}

proc multiplex_delete_db {} {
  forcedelete test.db
  for {set i 1} {$i <= 1000} {incr i} {
    forcedelete test.[format %03d $i]
  }
}

# Procs to save and restore the current muliplexed database.
#
proc multiplex_save_db {} {
  foreach f [glob -nocomplain sv_test.*] { forcedelete $f }
  foreach f [glob -nocomplain test.*]    { forcecopy $f "sv_$f" }
}
proc multiplex_restore_db {} {
  foreach f [glob -nocomplain test.*]    {forcedelete $f}
  foreach f [glob -nocomplain sv_test.*] {forcecopy $f [string range $f 3 end]} }

proc setup_and_save_db {} {
  multiplex_delete_db
  sqlite3 db file:test.db?8_3_names=1
  sqlite3_multiplex_control db main chunk_size [expr 256*1024]
  execsql {
    CREATE TABLE t1(a PRIMARY KEY, b);
    INSERT INTO t1 VALUES(randomblob(15), randomblob(2000));
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --   2
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --   4
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --   8
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --  16
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --  32
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --  64
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    -- 128
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    -- 256
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    -- 512
  }
  set ::cksum1 [execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a}]
  db close
  multiplex_save_db
}

do_test 1.0 { setup_and_save_db } {}
do_faultsim_test 1 -prep {
  multiplex_restore_db
  sqlite3 db file:test.db?8_3_names=1
  sqlite3_multiplex_control db main chunk_size [expr 256*1024]
  execsql { PRAGMA journal_mode = truncate }
  execsql { PRAGMA synchronous = off }
} -body {
  execsql {
    UPDATE t1 SET a=randomblob(12), b=randomblob(1500) WHERE (rowid%32)=0
  }
} -test {
  faultsim_test_result {0 {}}
  if {$testrc!=0} {
    set cksum2 [execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a}]
    if {$cksum2 != $::cksum1} { error "data mismatch" }
  }
}

#-------------------------------------------------------------------------
# The following tests verify that hot-journal rollback works. As follows:
#
#   1. Create a large database.
#   2. Set the pager cache to be very small.
#   3. Open a transaction. 
#   4. Run the following 100 times:
#      a. Update a row.
#      b. Copy all files on disk to a new db location, including the journal.
#      c. Verify that the new db can be opened and that the content matches
#         the database created in step 1 (proving the journal was rolled
#         back).

do_test 2.0 { 
  setup_and_save_db
  multiplex_restore_db
  sqlite3 db file:test.db?8_3_names=1
  execsql { PRAGMA cache_size = 10 }
  execsql { BEGIN }
} {}

for {set iTest 1} {$iTest<=100} {incr iTest} {
  do_test 2.$iTest {
    execsql { 
      UPDATE t1 SET a=randomblob(12), b=randomblob(1400) WHERE rowid=5*$iTest
    }
    foreach f [glob -nocomplain test.*] {forcecopy $f "xx_$f"}
    sqlite3 db2 file:xx_test.db?8_3_names=1
    execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a} db2
  } $::cksum1

  db2 close
}
catch { db close }


do_test 3.0 { setup_and_save_db } {}
do_faultsim_test 3 -faults ioerr-trans* -prep {

  forcedelete test2.db
  set fd [open test2.wal w]
  seek $fd 4095
  puts -nonewline $fd x
  close $fd

  multiplex_restore_db
  sqlite3 db file:test.db?8_3_names=1
  sqlite3 db2 file:test2.db?8_3_names=1
  sqlite3_multiplex_control db main chunk_size [expr 256*1024]
  sqlite3_multiplex_control db2 main chunk_size [expr 256*1024]
} -body {
  sqlite3_backup B db2 main db main
  B step 100000
  set rc [B finish]
  if { [string match SQLITE_IOERR_* $rc] } {error "disk I/O error"}
  set rc
} -test {
  faultsim_test_result {0 SQLITE_OK}
  if {$testrc==0} {
    set cksum2 [execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a} db2]
    if {$cksum2 != $::cksum1} { error "data mismatch" }
  }
  catch { B finish }
  catch { db close }
  catch { db2 close }
}

catch { db close }
sqlite3_multiplex_shutdown
finish_test