396 lines
11 KiB
Plaintext
396 lines
11 KiB
Plaintext
# 2021-03-06
|
|
#
|
|
# 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 implements tests for the appendvfs extension.
|
|
#
|
|
# Tests performed:
|
|
# avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file.
|
|
# avfs-1.1. Test that the DB can be read with correct content upon reopen.
|
|
# avfs-1.2. Test that an appendvfs DB can be added to a simple text file.
|
|
# avfs-1.3. Test that the DB can be read with correct content upon reopen.
|
|
# avfs-1.4. Test that appended DB is aligned to default page boundary.
|
|
# avfs-2.1. Test that the simple text file retains its initial text.
|
|
# avfs-3.1. Test that the appendvfs can grow and shrink, remaining intact.
|
|
# avfs-3.2. Test that appendvfs is intact after grow/shrink/close/reopen.
|
|
# avfs-3.3. Test that appendvfs can grow by many pages and be written.
|
|
# avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
|
|
# avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
|
|
# avfs-4.1. Test shell's ability to append to a non-appendvfs file.
|
|
# avfs-4.2. Test shell's ability to append to empty or nonexistent file.
|
|
# avfs-4.3. Test shell's ability to reopen and alter an appendvfs file.
|
|
# avfs-5.1. Test appendvfs refusal to open too-tiny DB appended onto ZLF.
|
|
# avfs-5.2. Test appendvfs refusal to open too-tiny DB appended on other.
|
|
# ...
|
|
# (more to come)
|
|
|
|
set testdir [file dirname $argv0]
|
|
source $testdir/tester.tcl
|
|
set ::testprefix avfs
|
|
|
|
# Do not attempt this test if SQLITE_OMIT_VIRTUALTABLE is defined.
|
|
#
|
|
ifcapable !vtab {
|
|
finish_test
|
|
return
|
|
}
|
|
|
|
set CLI [test_find_cli]
|
|
db close
|
|
# forcedelete test.db
|
|
|
|
load_static_extension db appendvfs
|
|
|
|
set ::fa avfs.adb
|
|
set ::fza avfs.sdb
|
|
forcedelete $::fa $::fza
|
|
set ::result {}
|
|
|
|
proc shellDoesAr {} {
|
|
set shdo "sh_app1.sql"
|
|
forcedelete $shdo
|
|
set fd [open $shdo w]
|
|
puts $fd ".help\n.q"
|
|
close $fd
|
|
set res [catchcmd "-batch -cmd \".read $shdo\""]
|
|
return [regexp {^.archive} [lindex $res 1]]
|
|
}
|
|
|
|
set ::vf "&vfs=apndvfs"
|
|
|
|
# Return file offset of appendvfs portion of a file, or {} if none such.
|
|
proc fosAvfs {fname} {
|
|
if {[file size $fname] < 25} {
|
|
return {}
|
|
}
|
|
if {[catch {set fd [open $fname rb]}]} {
|
|
return {}
|
|
}
|
|
seek $fd -25 end
|
|
set am [read $fd 17]
|
|
set ao [read $fd 8]
|
|
close $fd
|
|
if {$am ne "Start-Of-SQLite3-"} {
|
|
return {}
|
|
}
|
|
binary scan $ao "W" rvo
|
|
return $rvo
|
|
}
|
|
|
|
do_test 1.0 {
|
|
set results {}
|
|
set out [open $::fza wb]
|
|
close $out
|
|
sqlite3 adb "file:$::fza?mode=rwc$::vf" -uri 1
|
|
adb eval {
|
|
PRAGMA page_size=1024;
|
|
PRAGMA cache_size=10;
|
|
CREATE TABLE t1(a TEXT);
|
|
INSERT INTO t1 VALUES ('dog'),('cat');
|
|
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
|
|
} { lappend results $pets }
|
|
adb close
|
|
lappend results [fosAvfs $fza]
|
|
set ::result [join $results " | "]
|
|
} {cat,dog | 0}
|
|
|
|
do_test 1.1 {
|
|
set results {}
|
|
sqlite3 adb "file:$::fza?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
|
|
} { lappend results $pets }
|
|
adb close
|
|
set ::result [join $results " | "]
|
|
} {dog,cat}
|
|
|
|
do_test 1.2 {
|
|
set results {}
|
|
set out [open $::fa wb]
|
|
set ::tlo { "Just some text," "and more text," "ending at 3 lines." }
|
|
puts $out [join $::tlo "\n"]
|
|
close $out
|
|
set adbSz [file size $::fa]
|
|
sqlite3 adb "file:$::fa?mode=rwc$::vf" -uri 1
|
|
adb eval {
|
|
PRAGMA auto_vacuum = 0;
|
|
PRAGMA page_size=512;
|
|
PRAGMA cache_size=0;
|
|
CREATE TABLE t1(a TEXT);
|
|
INSERT INTO t1 VALUES ('dog'),('cat'),('pig');
|
|
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a);
|
|
} { lappend results $pets }
|
|
adb close
|
|
set adaSz [file size $::fa]
|
|
lappend results "Bytes before/after $adbSz/$adaSz"
|
|
set ::result [join $results " | "]
|
|
} {cat,dog,pig | Bytes before/after 50/5145}
|
|
|
|
do_test 1.3 {
|
|
set results {}
|
|
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
SELECT group_concat(a) as pets FROM (SELECT a FROM t1 ORDER BY a DESC);
|
|
} { lappend results $pets }
|
|
adb close
|
|
set ::result [join $results " | "]
|
|
} {pig,dog,cat}
|
|
|
|
do_test 1.4 {
|
|
set ::result [fosAvfs $fa]
|
|
} {4096}
|
|
|
|
do_test 2.1 {
|
|
set in [open $::fa r]
|
|
set tli {}
|
|
for {set i [llength $::tlo]} {$i > 0} {incr i -1} {
|
|
lappend tli [gets $in]
|
|
}
|
|
close $in
|
|
if { [join $tli ":"] ne [join $::tlo ":"] } {
|
|
set ::result "Appendee changed."
|
|
} else {
|
|
set ::result "Appendee intact."
|
|
}
|
|
} {Appendee intact.}
|
|
|
|
# Set of repeatable random integers for a couple tests.
|
|
set ::nrint 50000
|
|
proc rint {v} {
|
|
return [::tcl::mathfunc::int [expr $v * 100000]]
|
|
}
|
|
array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]]
|
|
for {set i 1} {$i < $::nrint} {incr i} {
|
|
set ::randints($i) [rint [::tcl::mathfunc::rand]]
|
|
}
|
|
|
|
do_test 3.1 {
|
|
set results {}
|
|
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
DROP TABLE t1;
|
|
PRAGMA cache_size=10;
|
|
CREATE TABLE ri (i INTEGER);
|
|
BEGIN;
|
|
}
|
|
for {set i 0} {$i < $::nrint} {incr i} {
|
|
set r $::randints($i)
|
|
set s $::randints([incr i])
|
|
set t $::randints([incr i])
|
|
set u $::randints([incr i])
|
|
set v $::randints([incr i])
|
|
adb eval {
|
|
INSERT INTO ri VALUES ($r),($s),($t),($u),($v)
|
|
}
|
|
}
|
|
adb eval {
|
|
COMMIT;
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
} { lappend results $ic }
|
|
set adbSz [file size $::fa]
|
|
set qr {}
|
|
adb eval {
|
|
SELECT count(*) as ic FROM ri;
|
|
DELETE FROM ri WHERE (i % 50) <> 25;
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
VACUUM;
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
SELECT count(*) as ic FROM ri;
|
|
} { lappend qr $ic }
|
|
adb close
|
|
set adaSz [file size $::fa]
|
|
set adba [expr ($adbSz + 0.1)/$adaSz]
|
|
# lappend results $adba
|
|
set results [concat $results [lrange $qr 0 2]]
|
|
lappend results [expr {$adba > 10.0}]
|
|
set ::result [join $results " | "]
|
|
} "ok | $::nrint | ok | ok | 1"
|
|
|
|
do_test 3.2 {
|
|
set results {}
|
|
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
} { lappend results $ic }
|
|
adb close
|
|
set ::result [join $results " | "]
|
|
} {ok}
|
|
|
|
# avfs-3.3. Test that appendvfs can grow by many pages and be written.
|
|
do_test 3.3 {
|
|
set results {}
|
|
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
|
set npages 300
|
|
adb eval { BEGIN }
|
|
while {$npages > 0} {
|
|
adb eval { INSERT INTO ri VALUES (randomblob(1500)) }
|
|
incr npages -1
|
|
}
|
|
adb eval { COMMIT }
|
|
adb eval {
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
} { lappend results $ic }
|
|
adb close
|
|
set adaSzr [expr [file size $::fa] / 300.0 / 1500 ]
|
|
set okSzr [expr $adaSzr > 1.0 && $adaSzr < 1.3 ]
|
|
lappend results $okSzr
|
|
set ::result [join $results " | "]
|
|
} {ok | 1}
|
|
|
|
# avfs-3.4. Test that grown appendvfs can be reopened and appear intact.
|
|
do_test 3.4 {
|
|
set results {}
|
|
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
} { lappend results $ic }
|
|
adb close
|
|
set ::result $ic
|
|
} {ok}
|
|
|
|
# avfs-3.5. Test that much grown appendvfs can shrink and reopen intact.
|
|
do_test 3.5 {
|
|
set results {}
|
|
set adbsz [file size $::fa]
|
|
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
DELETE FROM ri WHERE rowid % 8 <> 0;
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
VACUUM;
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
} { lappend results $ic }
|
|
adb close
|
|
set adasz [file size $::fa]
|
|
lappend results [expr {$adbsz/$adasz > 5}]
|
|
sqlite3 adb "file:$::fa?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
SELECT integrity_check as ic FROM pragma_integrity_check();
|
|
} { lappend results $ic }
|
|
adb close
|
|
set ::result [join $results " | "]
|
|
} {ok | ok | 1 | ok}
|
|
|
|
set ::cliDoesAr [shellDoesAr]
|
|
|
|
do_test 4.1 {
|
|
set shdo "sh_app1.sql"
|
|
set shod "sh_app1.adb"
|
|
forcedelete $shdo $shod
|
|
set ofd [open $shdo w]
|
|
if {$::cliDoesAr} {
|
|
puts $ofd ".ar -c"
|
|
} else {
|
|
puts $ofd "pragma page_size=512;"
|
|
puts $ofd "create table sqlar (a);"
|
|
}
|
|
puts $ofd ".tables"
|
|
puts $ofd ".q"
|
|
close $ofd
|
|
set ofd [open $shod wb]
|
|
puts $ofd "Some text."
|
|
close $ofd
|
|
set res [catchcmd "-append -batch -init $shdo $shod" ""]
|
|
lappend res [fosAvfs $shod]
|
|
forcedelete $shdo $shod
|
|
set ::result [join $res " | "]
|
|
} {0 | sqlar | 4096}
|
|
|
|
do_test 4.2 {
|
|
set shdo "sh_app1.sql"
|
|
set shod "sh_app1.adb"
|
|
forcedelete $shdo $shod
|
|
set ofd [open $shdo w]
|
|
if {$::cliDoesAr} {
|
|
puts $ofd ".ar -c"
|
|
} else {
|
|
puts $ofd "pragma page_size=512;"
|
|
puts $ofd "create table sqlar (a);"
|
|
}
|
|
puts $ofd ".tables"
|
|
puts $ofd ".q"
|
|
close $ofd
|
|
set ofd [open $shod wb]
|
|
close $ofd
|
|
set res [catchcmd "-append -batch -init $shdo $shod" ""]
|
|
lappend res [fosAvfs $shod]
|
|
forcedelete $shdo ; # Leave $shod for next test.
|
|
set ::result [join $res " | "]
|
|
} {0 | sqlar | 0}
|
|
|
|
do_test 4.3 {
|
|
set shdo "sh_app1.sql"
|
|
set shod "sh_app1.adb" ; # Same as test 4.2, reusing ADB.
|
|
forcedelete $shdo
|
|
set ofd [open $shdo w]
|
|
if {$::cliDoesAr} {
|
|
puts $ofd ".ar -u $shdo"
|
|
puts $ofd "select count(*) from sqlar where name = '$shdo';"
|
|
} else {
|
|
puts $ofd "insert into sqlar values (1);"
|
|
puts $ofd "select count(*) from sqlar;"
|
|
}
|
|
puts $ofd ".q"
|
|
close $ofd
|
|
set res [catchcmd "-append -batch -init $shdo $shod" ""]
|
|
sqlite3 adb "file:$shod?mode=rw$::vf" -uri 1
|
|
adb eval {
|
|
SELECT count(*) as n FROM sqlar
|
|
} { lappend res $n }
|
|
adb close
|
|
forcedelete $shdo $shod;
|
|
set ::result [join $res " | "]
|
|
} {0 | 1 | 1}
|
|
|
|
do_test 5.1 {
|
|
set fake "faketiny.sdb"
|
|
forcedelete $fake
|
|
set ofd [open $fake wb]
|
|
puts -nonewline $ofd "SQLite format 3"
|
|
puts -nonewline $ofd [binary format "c" 0]
|
|
puts -nonewline $ofd "Start-Of-SQLite3-"
|
|
puts -nonewline $ofd [binary format "W" 0]
|
|
close $ofd
|
|
if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
|
|
set res "Open failed."
|
|
} else {
|
|
adb close
|
|
set res "Opened when should not."
|
|
}
|
|
forcedelete $fake
|
|
set ::result $res
|
|
} {Open failed.}
|
|
|
|
do_test 5.2 {
|
|
set fake "faketiny.sdb"
|
|
forcedelete $fake
|
|
set ofd [open $fake wb]
|
|
set fakeAppendee "Dog ate my homework.\n"
|
|
puts -nonewline $ofd $fakeAppendee
|
|
puts -nonewline $ofd "SQLite format 3"
|
|
puts -nonewline $ofd [binary format "c" 0]
|
|
puts -nonewline $ofd "Start-Of-SQLite3-"
|
|
puts -nonewline $ofd [binary format "W" [string length $fakeAppendee]]
|
|
close $ofd
|
|
if {[catch {sqlite3 adb "file:$fake?mode=rw$::vf" -uri 1}]} {
|
|
set res "Open failed."
|
|
} else {
|
|
adb close
|
|
set res "Opened when should not."
|
|
}
|
|
forcedelete $fake
|
|
set ::result $res
|
|
} {Open failed.}
|
|
|
|
forcedelete $::fa $::fza
|
|
|
|
unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::nrint ::cliDoesAr
|
|
|
|
finish_test
|