The first assert() added in [0ebc65481f4a3e79] is not necessarily true in a
[sqlite.git] / test / avfs.test
blobffd6b309fc80254ef7bcbb57e76e016e17fc757c
1 # 2021-03-06
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
11 # TESTRUNNER: shell
12
13 # This file implements tests for the appendvfs extension.
15 # Tests performed:
16 # avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file.
17 # avfs-1.1. Test that the DB can be read with correct content upon reopen.
18 # avfs-1.2. Test that an appendvfs DB can be added to a simple text file.
19 # avfs-1.3. Test that the DB can be read with correct content upon reopen.
20 # avfs-1.4. Test that appended DB is aligned to default page boundary.
21 # avfs-2.1. Test that the simple text file retains its initial text.
22 # avfs-3.1. Test that the appendvfs can grow and shrink, remaining intact.
23 # avfs-3.2. Test that appendvfs is intact after grow/shrink/close/reopen.
24 # avfs-3.3. Test that appendvfs can grow by many pages and be written.
25 # avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
26 # avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
27 # avfs-4.1. Test shell's ability to append to a non-appendvfs file.
28 # avfs-4.2. Test shell's ability to append to empty or nonexistent file.
29 # avfs-4.3. Test shell's ability to reopen and alter an appendvfs file.
30 # avfs-5.1. Test appendvfs refusal to open too-tiny DB appended onto ZLF.
31 # avfs-5.2. Test appendvfs refusal to open too-tiny DB appended on other.
32 # ...
33 # (more to come)
35 set testdir [file dirname $argv0]
36 source $testdir/tester.tcl
37 set ::testprefix avfs
39 # Do not attempt this test if SQLITE_OMIT_VIRTUALTABLE is defined. 
41 ifcapable !vtab {
42   finish_test
43   return
46 set CLI [test_find_cli]
47 db close
48 # forcedelete test.db
50 load_static_extension db appendvfs
52 set ::fa avfs.adb
53 set ::fza avfs.sdb
54 forcedelete $::fa $::fza
55 set ::result {}
57 proc shellDoesAr {} {
58   set shdo "sh_app1.sql"
59   forcedelete $shdo
60   set fd [open $shdo w]
61   puts $fd ".help\n.q"
62   close $fd
63   set res [catchcmd "-batch -cmd \".read $shdo\""]
64   return [regexp {^.archive} [lindex $res 1]]
67 set ::vf "&vfs=apndvfs"
69 # Return file offset of appendvfs portion of a file, or {} if none such.
70 proc fosAvfs {fname} {
71   if {[file size $fname] < 25} {
72     return {}
73   }
74   if {[catch {set fd [open $fname rb]}]} {
75     return {}
76   }
77   seek $fd -25 end
78   set am [read $fd 17]
79   set ao [read $fd 8]
80   close $fd
81   if {$am ne "Start-Of-SQLite3-"} {
82     return {}
83   }
84   binary scan $ao "W" rvo
85   return $rvo
88 do_test 1.0 {
89   set results {}
90   set out [open $::fza wb]
91   close $out
92   sqlite3 adb "file:$::fza?mode=rwc$::vf" -uri 1
93   adb eval {
94     PRAGMA page_size=1024;
95     PRAGMA cache_size=10;
96     CREATE TABLE t1(a TEXT);
97     INSERT INTO t1 VALUES ('dog'),('cat');
98     SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
99   } { lappend results $pets }
100   adb close
101   lappend results [fosAvfs $fza]
102   set ::result [join $results " | "]
103 } {cat,dog | 0}
105 do_test 1.1 {
106   set results {}
107   sqlite3 adb "file:$::fza?mode=rw$::vf" -uri 1
108   adb eval {
109     SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
110   } { lappend results $pets }
111   adb close
112   set ::result [join $results " | "]
113 } {dog,cat}
115 do_test 1.2 {
116   set results {}
117   set out [open $::fa wb]
118   set ::tlo { "Just some text," "and more text," "ending at 3 lines." }
119   puts $out [join $::tlo "\n"]
120   close $out
121   set adbSz [file size $::fa]
122   sqlite3 adb "file:$::fa?mode=rwc$::vf" -uri 1
123   adb eval {
124     PRAGMA auto_vacuum = 0;
125     PRAGMA page_size=512;
126     PRAGMA cache_size=0;
127     CREATE TABLE t1(a TEXT);
128     INSERT INTO t1 VALUES ('dog'),('cat'),('pig');
129     SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
130   } { lappend results $pets }
131   adb close
132   set adaSz [file size $::fa]
133   lappend results "Bytes before/after $adbSz/$adaSz"
134   set ::result [join $results " | "]
135 } {cat,dog,pig | Bytes before/after 50/5145}
137 do_test 1.3 {
138   set results {}
139   sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
140   adb eval {
141     SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
142   } { lappend results $pets }
143   adb close
144   set ::result [join $results " | "]
145 } {pig,dog,cat}
147 do_test 1.4 {
148   set ::result [fosAvfs $fa]
149 } {4096}
151 do_test 2.1 {
152   set in [open $::fa r]
153   set tli {}
154   for {set i [llength $::tlo]} {$i > 0} {incr i -1} {
155     lappend tli [gets $in]
156   }
157   close $in
158   if { [join $tli ":"] ne [join $::tlo ":"] } {
159     set ::result "Appendee changed."
160   } else {
161     set ::result "Appendee intact."
162   }
163 } {Appendee intact.}
165 # Set of repeatable random integers for a couple tests.
166 set ::nrint 50000
167 proc rint {v} {
168   return [::tcl::mathfunc::int [expr $v * 100000]]
170 array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]]
171 for {set i 1} {$i < $::nrint} {incr i} {
172   set ::randints($i) [rint [::tcl::mathfunc::rand]]
175 do_test 3.1 {
176   set results {}
177   sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
178   adb eval {
179     DROP TABLE t1;
180     PRAGMA cache_size=10;
181     CREATE TABLE ri (i INTEGER);
182     BEGIN;
183   }
184   for {set i 0} {$i < $::nrint} {incr i} {
185     set r $::randints($i)
186     set s $::randints([incr i])
187     set t $::randints([incr i])
188     set u $::randints([incr i])
189     set v $::randints([incr i])
190     adb eval {
191       INSERT INTO ri VALUES ($r),($s),($t),($u),($v)
192     }
193   }
194   adb eval {
195     COMMIT;
196     SELECT integrity_check as ic FROM pragma_integrity_check();
197   } { lappend results $ic }
198   set adbSz [file size $::fa]
199   set qr {}
200   adb eval {
201     SELECT count(*) as ic FROM ri;
202     DELETE FROM ri WHERE (i % 50) <> 25;
203     SELECT integrity_check as ic FROM pragma_integrity_check();
204     VACUUM;
205     SELECT integrity_check as ic FROM pragma_integrity_check();
206     SELECT count(*) as ic FROM ri;
207   } { lappend qr $ic }
208   adb close
209   set adaSz [file size $::fa]
210   set adba [expr ($adbSz + 0.1)/$adaSz]
211   # lappend results $adba
212   set results [concat $results [lrange $qr 0 2]]
213   lappend results [expr {$adba > 10.0}]
214   set ::result [join $results " | "]
215 } "ok | $::nrint | ok | ok | 1"
217 do_test 3.2 {
218   set results {}
219   sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
220   adb eval {
221     SELECT integrity_check as ic FROM pragma_integrity_check();
222   } { lappend results $ic }
223   adb close
224   set ::result [join $results " | "]
225 } {ok}
227 # avfs-3.3. Test that appendvfs can grow by many pages and be written.
228 do_test 3.3 {
229   set results {}
230   sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
231   set npages 300
232   adb eval { BEGIN }
233   while {$npages > 0} {
234     adb eval { INSERT INTO ri VALUES (randomblob(1500)) }
235     incr npages -1
236   }
237   adb eval { COMMIT }
238   adb eval {
239     SELECT integrity_check as ic FROM pragma_integrity_check();
240   } { lappend results $ic }
241   adb close
242   set adaSzr [expr [file size $::fa] / 300.0 / 1500 ]
243   set okSzr [expr $adaSzr > 1.0 && $adaSzr < 1.3 ]
244   lappend results $okSzr
245   set ::result [join $results " | "]
246 } {ok | 1}
248 # avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
249 do_test 3.4 {
250   set results {}
251   sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
252   adb eval {
253     SELECT integrity_check as ic FROM pragma_integrity_check();
254   } { lappend results $ic }
255   adb close
256   set ::result $ic
257 } {ok}
259 # avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
260 do_test 3.5 {
261   set results {}
262   set adbsz [file size $::fa]
263   sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
264   adb eval {
265     DELETE FROM ri WHERE rowid % 8 <> 0;
266     SELECT integrity_check as ic FROM pragma_integrity_check();
267     VACUUM;
268     SELECT integrity_check as ic FROM pragma_integrity_check();
269   } { lappend results $ic }
270   adb close
271   set adasz [file size $::fa]
272   lappend results [expr {$adbsz/$adasz > 5}]
273   sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
274   adb eval {
275     SELECT integrity_check as ic FROM pragma_integrity_check();
276   } { lappend results $ic }
277   adb close
278   set ::result [join $results " | "]
279 } {ok | ok | 1 | ok}
281 set ::cliDoesAr [shellDoesAr]
283 do_test 4.1 {
284   set shdo "sh_app1.sql"
285   set shod "sh_app1.adb"
286   forcedelete $shdo $shod
287   set ofd [open $shdo w]
288   if {$::cliDoesAr} {
289     puts $ofd ".ar -c"
290   } else {
291     puts $ofd "pragma page_size=512;"
292     puts $ofd "create table sqlar (a);"
293   }
294   puts $ofd ".tables"
295   puts $ofd ".q"
296   close $ofd
297   set ofd [open $shod wb]
298   puts $ofd "Some text."
299   close $ofd
300   set res [catchcmd "-append -batch -init $shdo $shod" ""]
301   lappend res [fosAvfs $shod]
302   forcedelete $shdo $shod
303   set ::result [join $res " | "]
304 } {0 | sqlar | 4096}
306 do_test 4.2 {
307   set shdo "sh_app1.sql"
308   set shod "sh_app1.adb"
309   forcedelete $shdo $shod
310   set ofd [open $shdo w]
311   if {$::cliDoesAr} {
312     puts $ofd ".ar -c"
313   } else {
314     puts $ofd "pragma page_size=512;"
315     puts $ofd "create table sqlar (a);"
316   }
317   puts $ofd ".tables"
318   puts $ofd ".q"
319   close $ofd
320   set ofd [open $shod wb]
321   close $ofd
322   set res [catchcmd "-append -batch -init $shdo $shod" ""]
323   lappend res [fosAvfs $shod]
324   forcedelete $shdo ; # Leave $shod for next test.
325   set ::result [join $res " | "]
326 } {0 | sqlar | 0}
328 do_test 4.3 {
329   set shdo "sh_app1.sql"
330   set shod "sh_app1.adb" ; # Same as test 4.2, reusing ADB.
331   forcedelete $shdo
332   set ofd [open $shdo w]
333   if {$::cliDoesAr} {
334     puts $ofd ".ar -u $shdo"
335     puts $ofd "select count(*) from sqlar where name = '$shdo';"
336   } else {
337     puts $ofd "insert into sqlar values (1);"
338     puts $ofd "select count(*) from sqlar;"
339   }
340   puts $ofd ".q"
341   close $ofd
342   set res [catchcmd "-append -batch -init $shdo $shod" ""]
343   sqlite3 adb "file:$shod?mode=rw$::vf" -uri 1
344   adb eval {
345     SELECT count(*) as n FROM sqlar
346   } { lappend res $n }
347   adb close
348   forcedelete $shdo $shod;
349   set ::result [join $res " | "]
350 } {0 | 1 | 1}
352 do_test 5.1 {
353   set fake "faketiny.sdb"
354   forcedelete $fake
355   set ofd [open $fake wb]
356   puts -nonewline $ofd "SQLite format 3"
357   puts -nonewline $ofd [binary format "c" 0]
358   puts -nonewline $ofd "Start-Of-SQLite3-"
359   puts -nonewline $ofd [binary format "W" 0]
360   close $ofd
361   if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
362     set res "Open failed."
363   } else {
364     adb close
365     set res "Opened when should not."
366   }
367   forcedelete $fake
368   set ::result $res
369 } {Open failed.}
371 do_test 5.2 {
372   set fake "faketiny.sdb"
373   forcedelete $fake
374   set ofd [open $fake wb]
375   set fakeAppendee "Dog ate my homework.\n"
376   puts -nonewline $ofd $fakeAppendee
377   puts -nonewline $ofd "SQLite format 3"
378   puts -nonewline $ofd [binary format "c" 0]
379   puts -nonewline $ofd "Start-Of-SQLite3-"
380   puts -nonewline $ofd [binary format "W" [string length $fakeAppendee]]
381   close $ofd
382   if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
383     set res "Open failed."
384   } else {
385     adb close
386     set res "Opened when should not."
387   }
388   forcedelete $fake
389   set ::result $res
390 } {Open failed.}
392 forcedelete $::fa $::fza
394 unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::nrint ::cliDoesAr
396 finish_test