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