xref: /sqlite-3.40.0/test/avfs.test (revision bc3c4e08)
1# 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:
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-4.1. Test shell's ability to append to a non-appendvfs file.
24# avfs-4.2. Test shell's ability to append to empty or nonexistent file.
25# avfs-4.3. Test shell's ability to reopen and alter an appendvfs file.
26# avfs-5.1. Test appendvfs refusal to open too-tiny DB appended onto ZLF.
27# avfs-5.2. Test appendvfs refusal to open too-tiny DB appended on other.
28# ...
29# (more to come)
30
31set testdir [file dirname $argv0]
32source $testdir/tester.tcl
33set ::testprefix avfs
34set CLI [test_find_cli]
35db close
36# forcedelete test.db
37
38load_static_extension db appendvfs
39
40set ::fa avfs.adb
41set ::fza avfs.sdb
42forcedelete $::fa $::fza
43set ::result {}
44
45proc shellDoesAr {} {
46  set shdo "sh_app1.sql"
47  forcedelete $shdo
48  set fd [open $shdo w]
49  puts $fd ".help\n.q"
50  close $fd
51  set res [catchcmd "-batch -cmd \".read $shdo\""]
52  return [regexp {^.archive} [lindex $res 1]]
53}
54
55set ::vf "&vfs=apndvfs"
56
57# Return file offset of appendvfs portion of a file, or {} if none such.
58proc fosAvfs {fname} {
59  if {[file size $fname] < 25} {
60    return {}
61  }
62  if {[catch {set fd [open $fname rb]}]} {
63    return {}
64  }
65  seek $fd -25 end
66  set am [read $fd 17]
67  set ao [read $fd 8]
68  close $fd
69  if {$am ne "Start-Of-SQLite3-"} {
70    return {}
71  }
72  binary scan $ao "W" rvo
73  return $rvo
74}
75
76do_test 1.0 {
77  set results {}
78  set out [open $::fza wb]
79  close $out
80  sqlite3 adb "file:$::fza?mode=rwc$::vf" -uri 1
81  adb eval {
82    PRAGMA page_size=1024;
83    PRAGMA cache_size=10;
84    CREATE TABLE t1(a TEXT);
85    INSERT INTO t1 VALUES ('dog'),('cat');
86    SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
87  } { lappend results $pets }
88  adb close
89  lappend results [fosAvfs $fza]
90  set ::result [join $results " | "]
91} {cat,dog | 0}
92
93do_test 1.1 {
94  set results {}
95  sqlite3 adb "file:$::fza?mode=rw$::vf" -uri 1
96  adb eval {
97    SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
98  } { lappend results $pets }
99  adb close
100  set ::result [join $results " | "]
101} {dog,cat}
102
103do_test 1.2 {
104  set results {}
105  set out [open $::fa wb]
106  set ::tlo { "Just some text," "and more text," "ending at 3 lines." }
107  puts $out [join $::tlo "\n"]
108  close $out
109  set adbSz [file size $::fa]
110  sqlite3 adb "file:$::fa?mode=rwc$::vf" -uri 1
111  adb eval {
112    PRAGMA auto_vacuum = 0;
113    PRAGMA page_size=512;
114    PRAGMA cache_size=0;
115    CREATE TABLE t1(a TEXT);
116    INSERT INTO t1 VALUES ('dog'),('cat'),('pig');
117    SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
118  } { lappend results $pets }
119  adb close
120  set adaSz [file size $::fa]
121  lappend results "Bytes before/after $adbSz/$adaSz"
122  set ::result [join $results " | "]
123} {cat,dog,pig | Bytes before/after 50/5145}
124
125do_test 1.3 {
126  set results {}
127  sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
128  adb eval {
129    SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
130  } { lappend results $pets }
131  adb close
132  set ::result [join $results " | "]
133} {pig,dog,cat}
134
135do_test 1.4 {
136  set ::result [fosAvfs $fa]
137} {4096}
138
139do_test 2.1 {
140  set in [open $::fa r]
141  set tli {}
142  for {set i [llength $::tlo]} {$i > 0} {incr i -1} {
143    lappend tli [gets $in]
144  }
145  close $in
146  if { [join $tli ":"] ne [join $::tlo ":"] } {
147    set ::result "Appendee changed."
148  } else {
149    set ::result "Appendee intact."
150  }
151} {Appendee intact.}
152
153# Set of repeatable random integers for a couple tests.
154proc rint {v} {
155  return [::tcl::mathfunc::int [expr $v * 100000]]
156}
157array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]]
158for {set i 1} {$i < 10000} {incr i} {
159  set ::randints($i) [rint [::tcl::mathfunc::rand]]
160}
161
162do_test 3.1 {
163  set results {}
164  sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
165  adb eval {
166    DROP TABLE t1;
167    PRAGMA cache_size=10;
168    CREATE TABLE ri (i INTEGER);
169    BEGIN;
170  }
171  for {set i 0} {$i < 10000} {incr i} {
172    set r $::randints($i)
173    set s $::randints([incr i])
174    set t $::randints([incr i])
175    set u $::randints([incr i])
176    set v $::randints([incr i])
177    adb eval {
178      INSERT INTO ri VALUES ($r),($s),($t),($u),($v)
179    }
180  }
181  adb eval {
182    COMMIT;
183    SELECT integrity_check as ic FROM pragma_integrity_check();
184  } { lappend results $ic }
185  set adbSz [file size $::fa]
186  set qr {}
187  adb eval {
188    SELECT count(*) as ic FROM ri;
189    DELETE FROM ri WHERE (i % 50) <> 25;
190    SELECT integrity_check as ic FROM pragma_integrity_check();
191    VACUUM;
192    SELECT integrity_check as ic FROM pragma_integrity_check();
193    SELECT count(*) as ic FROM ri;
194  } { lappend qr $ic }
195  adb close
196  set adaSz [file size $::fa]
197  set adba [expr ($adbSz + 0.1)/$adaSz]
198  # lappend results $adbSz $adaSz
199  set results [concat $results [lrange $qr 0 2]]
200  lappend results [expr {$adba > 10.0 && $adba < 20.0}]
201  set ::result [join $results " | "]
202} {ok | 10000 | ok | ok | 1}
203
204do_test 3.2 {
205  set results {}
206  sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
207  adb eval {
208    SELECT integrity_check as ic FROM pragma_integrity_check();
209  } { lappend results $ic }
210  adb close
211  set ::result [join $results " | "]
212} {ok}
213
214set ::cliDoesAr [shellDoesAr]
215
216do_test 4.1 {
217  set shdo "sh_app1.sql"
218  set shod "sh_app1.adb"
219  forcedelete $shdo $shod
220  set ofd [open $shdo w]
221  if {$::cliDoesAr} {
222    puts $ofd ".ar -c"
223  } else {
224    puts $ofd "pragma page_size=512;"
225    puts $ofd "create table sqlar (a);"
226  }
227  puts $ofd ".tables"
228  puts $ofd ".q"
229  close $ofd
230  set ofd [open $shod wb]
231  puts $ofd "Some text."
232  close $ofd
233  set res [catchcmd "-append -batch -init $shdo $shod" ""]
234  lappend res [fosAvfs $shod]
235  forcedelete $shdo $shod
236  set ::result [join $res " | "]
237} {0 | sqlar | 4096}
238
239do_test 4.2 {
240  set shdo "sh_app1.sql"
241  set shod "sh_app1.adb"
242  forcedelete $shdo $shod
243  set ofd [open $shdo w]
244  if {$::cliDoesAr} {
245    puts $ofd ".ar -c"
246  } else {
247    puts $ofd "pragma page_size=512;"
248    puts $ofd "create table sqlar (a);"
249  }
250  puts $ofd ".tables"
251  puts $ofd ".q"
252  close $ofd
253  set ofd [open $shod wb]
254  close $ofd
255  set res [catchcmd "-append -batch -init $shdo $shod" ""]
256  lappend res [fosAvfs $shod]
257  forcedelete $shdo ; # Leave $shod for next test.
258  set ::result [join $res " | "]
259} {0 | sqlar | 0}
260
261do_test 4.3 {
262  set shdo "sh_app1.sql"
263  set shod "sh_app1.adb" ; # Same as test 4.2, reusing ADB.
264  forcedelete $shdo
265  set ofd [open $shdo w]
266  if {$::cliDoesAr} {
267    puts $ofd ".ar -u $shdo"
268    puts $ofd "select count(*) from sqlar where name = '$shdo';"
269  } else {
270    puts $ofd "insert into sqlar values (1);"
271    puts $ofd "select count(*) from sqlar;"
272  }
273  puts $ofd ".q"
274  close $ofd
275  set res [catchcmd "-append -batch -init $shdo $shod" ""]
276  sqlite3 adb "file:$shod?mode=rw$::vf" -uri 1
277  adb eval {
278    SELECT count(*) as n FROM sqlar
279  } { lappend res $n }
280  adb close
281  forcedelete $shdo $shod;
282  set ::result [join $res " | "]
283} {0 | 1 | 1}
284
285do_test 5.1 {
286  set fake "faketiny.sdb"
287  forcedelete $fake
288  set ofd [open $fake wb]
289  puts -nonewline $ofd "SQLite format 3"
290  puts -nonewline $ofd [binary format "c" 0]
291  puts -nonewline $ofd "Start-Of-SQLite3-"
292  puts -nonewline $ofd [binary format "W" 0]
293  close $ofd
294  if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
295    set res "Open failed."
296  } else {
297    adb close
298    set res "Opened when should not."
299  }
300  forcedelete $fake
301  set ::result $res
302} {Open failed.}
303
304do_test 5.2 {
305  set fake "faketiny.sdb"
306  forcedelete $fake
307  set ofd [open $fake wb]
308  set fakeAppendee "Dog ate my homework.\n"
309  puts -nonewline $ofd $fakeAppendee
310  puts -nonewline $ofd "SQLite format 3"
311  puts -nonewline $ofd [binary format "c" 0]
312  puts -nonewline $ofd "Start-Of-SQLite3-"
313  puts -nonewline $ofd [binary format "W" [string length $fakeAppendee]]
314  close $ofd
315  if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
316    set res "Open failed."
317  } else {
318    adb close
319    set res "Opened when should not."
320  }
321  forcedelete $fake
322  set ::result $res
323} {Open failed.}
324
325forcedelete $::fa $::fza
326
327unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::cliDoesAr
328
329finish_test
330