larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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: |
larrybr | ddf4972 | 2021-03-08 20:13:43 +0000 | [diff] [blame] | 15 | # avfs-1.0. Test that an appendvfs DB can be added to an empty (ZLF) file. |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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. |
larrybr | ddf4972 | 2021-03-08 20:13:43 +0000 | [diff] [blame] | 19 | # avfs-1.4. Test that appended DB is aligned to default page boundary. |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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. |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 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. |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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. |
larrybr | ddf4972 | 2021-03-08 20:13:43 +0000 | [diff] [blame] | 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. |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 31 | # ... |
| 32 | # (more to come) |
| 33 | |
| 34 | set testdir [file dirname $argv0] |
| 35 | source $testdir/tester.tcl |
| 36 | set ::testprefix avfs |
dan | ba34b79 | 2021-03-10 17:43:18 +0000 | [diff] [blame] | 37 | |
| 38 | # Do not attempt this test if SQLITE_OMIT_VIRTUALTABLE is defined. |
| 39 | # |
| 40 | ifcapable !vtab { |
| 41 | finish_test |
| 42 | return |
| 43 | } |
| 44 | |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 45 | set CLI [test_find_cli] |
| 46 | db close |
larrybr | c5edbd1 | 2021-03-10 06:06:16 +0000 | [diff] [blame] | 47 | # forcedelete test.db |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 48 | |
| 49 | load_static_extension db appendvfs |
| 50 | |
| 51 | set ::fa avfs.adb |
| 52 | set ::fza avfs.sdb |
| 53 | forcedelete $::fa $::fza |
| 54 | set ::result {} |
| 55 | |
larrybr | c5edbd1 | 2021-03-10 06:06:16 +0000 | [diff] [blame] | 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]] |
| 64 | } |
| 65 | |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 66 | set ::vf "&vfs=apndvfs" |
| 67 | |
| 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 |
| 85 | } |
| 86 | |
| 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} |
| 103 | |
| 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} |
| 113 | |
| 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 { |
dan | bc3c4e0 | 2021-03-10 15:10:20 +0000 | [diff] [blame] | 123 | PRAGMA auto_vacuum = 0; |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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} |
| 135 | |
| 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 |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 143 | set ::result [join $results " | "] |
larrybr | ddf4972 | 2021-03-08 20:13:43 +0000 | [diff] [blame] | 144 | } {pig,dog,cat} |
| 145 | |
| 146 | do_test 1.4 { |
| 147 | set ::result [fosAvfs $fa] |
| 148 | } {4096} |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 149 | |
| 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.} |
| 163 | |
| 164 | # Set of repeatable random integers for a couple tests. |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 165 | set ::nrint 50000 |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 166 | proc rint {v} { |
| 167 | return [::tcl::mathfunc::int [expr $v * 100000]] |
| 168 | } |
| 169 | array set ::randints [list 0 [rint [::tcl::mathfunc::srand 0]]] |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 170 | for {set i 1} {$i < $::nrint} {incr i} { |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 171 | set ::randints($i) [rint [::tcl::mathfunc::rand]] |
| 172 | } |
| 173 | |
| 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 | } |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 183 | for {set i 0} {$i < $::nrint} {incr i} { |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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] |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 210 | # lappend results $adba |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 211 | set results [concat $results [lrange $qr 0 2]] |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 212 | lappend results [expr {$adba > 10.0}] |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 213 | set ::result [join $results " | "] |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 214 | } "ok | $::nrint | ok | ok | 1" |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 215 | |
| 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} |
| 225 | |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 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} |
| 246 | |
| 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} |
| 257 | |
| 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} |
| 279 | |
larrybr | c5edbd1 | 2021-03-10 06:06:16 +0000 | [diff] [blame] | 280 | set ::cliDoesAr [shellDoesAr] |
| 281 | |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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] |
larrybr | c5edbd1 | 2021-03-10 06:06:16 +0000 | [diff] [blame] | 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 | } |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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} |
| 304 | |
| 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] |
larrybr | c5edbd1 | 2021-03-10 06:06:16 +0000 | [diff] [blame] | 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 | } |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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} |
| 326 | |
| 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] |
larrybr | c5edbd1 | 2021-03-10 06:06:16 +0000 | [diff] [blame] | 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 | } |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 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} |
| 350 | |
larrybr | ddf4972 | 2021-03-08 20:13:43 +0000 | [diff] [blame] | 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.} |
| 369 | |
| 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.} |
| 390 | |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 391 | forcedelete $::fa $::fza |
| 392 | |
larrybr | 5cad178 | 2021-03-16 06:41:51 +0000 | [diff] [blame] | 393 | unset -nocomplain ::fa ::fza ::tlo ::result ::randints ::nrint ::cliDoesAr |
larrybr | b47e4c2 | 2021-03-08 14:32:26 +0000 | [diff] [blame] | 394 | |
| 395 | finish_test |