blob: 2ebd608baafa13a17579995d47701b47609db86b [file] [log] [blame]
larrybrb47e4c22021-03-08 14:32:26 +00001# 2021-03-06
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# This file implements tests for the appendvfs extension.
13#
14# Tests performed:
larrybrddf49722021-03-08 20:13:43 +000015# avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file.
larrybrb47e4c22021-03-08 14:32:26 +000016# 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.
larrybrddf49722021-03-08 20:13:43 +000019# avfs-1.4. Test that appended DB is aligned to default page boundary.
larrybrb47e4c22021-03-08 14:32:26 +000020# 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.
larrybr5cad1782021-03-16 06:41:51 +000023# 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.
larrybrb47e4c22021-03-08 14:32:26 +000026# 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.
larrybrddf49722021-03-08 20:13:43 +000029# 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.
larrybrb47e4c22021-03-08 14:32:26 +000031# ...
32# (more to come)
33
34set testdir [file dirname $argv0]
35source $testdir/tester.tcl
36set ::testprefix avfs
danba34b792021-03-10 17:43:18 +000037
38# Do not attempt this test if SQLITE_OMIT_VIRTUALTABLE is defined.
39#
40ifcapable !vtab {
41 finish_test
42 return
43}
44
larrybrb47e4c22021-03-08 14:32:26 +000045set CLI [test_find_cli]
46db close
larrybrc5edbd12021-03-10 06:06:16 +000047# forcedelete test.db
larrybrb47e4c22021-03-08 14:32:26 +000048
49load_static_extension db appendvfs
50
51set ::fa avfs.adb
52set ::fza avfs.sdb
53forcedelete $::fa $::fza
54set ::result {}
55
larrybrc5edbd12021-03-10 06:06:16 +000056proc 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]]
64}
65
larrybrb47e4c22021-03-08 14:32:26 +000066set ::vf "&vfs=apndvfs"
67
68# Return file offset of appendvfs portion of a file, or {} if none such.
69proc 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
85}
86
87do_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}
103
104do_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}
113
114do_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 {
danbc3c4e02021-03-10 15:10:20 +0000123 PRAGMA auto_vacuum = 0;
larrybrb47e4c22021-03-08 14:32:26 +0000124 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}
135
136do_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
larrybrb47e4c22021-03-08 14:32:26 +0000143 set ::result [join $results " | "]
larrybrddf49722021-03-08 20:13:43 +0000144} {pig,dog,cat}
145
146do_test 1.4 {
147 set ::result [fosAvfs $fa]
148} {4096}
larrybrb47e4c22021-03-08 14:32:26 +0000149
150do_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.}
163
164# Set of repeatable random integers for a couple tests.
larrybr5cad1782021-03-16 06:41:51 +0000165set ::nrint 50000
larrybrb47e4c22021-03-08 14:32:26 +0000166proc rint {v} {
167 return [::tcl::mathfunc::int [expr $v * 100000]]
168}
169array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]]
larrybr5cad1782021-03-16 06:41:51 +0000170for {set i 1} {$i < $::nrint} {incr i} {
larrybrb47e4c22021-03-08 14:32:26 +0000171 set ::randints($i) [rint [::tcl::mathfunc::rand]]
172}
173
174do_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 }
larrybr5cad1782021-03-16 06:41:51 +0000183 for {set i 0} {$i < $::nrint} {incr i} {
larrybrb47e4c22021-03-08 14:32:26 +0000184 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]
larrybr5cad1782021-03-16 06:41:51 +0000210 # lappend results $adba
larrybrb47e4c22021-03-08 14:32:26 +0000211 set results [concat $results [lrange $qr 0 2]]
larrybr5cad1782021-03-16 06:41:51 +0000212 lappend results [expr {$adba > 10.0}]
larrybrb47e4c22021-03-08 14:32:26 +0000213 set ::result [join $results " | "]
larrybr5cad1782021-03-16 06:41:51 +0000214} "ok | $::nrint | ok | ok | 1"
larrybrb47e4c22021-03-08 14:32:26 +0000215
216do_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}
225
larrybr5cad1782021-03-16 06:41:51 +0000226# avfs-3.3. Test that appendvfs can grow by many pages and be written.
227do_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}
246
247# avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
248do_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}
257
258# avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
259do_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}
279
larrybrc5edbd12021-03-10 06:06:16 +0000280set ::cliDoesAr [shellDoesAr]
281
larrybrb47e4c22021-03-08 14:32:26 +0000282do_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]
larrybrc5edbd12021-03-10 06:06:16 +0000287 if {$::cliDoesAr} {
288 puts $ofd ".ar -c"
289 } else {
290 puts $ofd "pragma page_size=512;"
291 puts $ofd "create table sqlar (a);"
292 }
larrybrb47e4c22021-03-08 14:32:26 +0000293 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}
304
305do_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]
larrybrc5edbd12021-03-10 06:06:16 +0000310 if {$::cliDoesAr} {
311 puts $ofd ".ar -c"
312 } else {
313 puts $ofd "pragma page_size=512;"
314 puts $ofd "create table sqlar (a);"
315 }
larrybrb47e4c22021-03-08 14:32:26 +0000316 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}
326
327do_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]
larrybrc5edbd12021-03-10 06:06:16 +0000332 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 }
larrybrb47e4c22021-03-08 14:32:26 +0000339 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}
350
larrybrddf49722021-03-08 20:13:43 +0000351do_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.}
369
370do_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.}
390
larrybrb47e4c22021-03-08 14:32:26 +0000391forcedelete $::fa $::fza
392
larrybr5cad1782021-03-16 06:41:51 +0000393unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::nrint ::cliDoesAr
larrybrb47e4c22021-03-08 14:32:26 +0000394
395finish_test