blob: 1aa5179add413a033abd1af58ed95fa56b16e0be [file] [log] [blame]
dan8311c472010-08-19 11:05:53 +00001# 2010 August 19
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# This file implements regression tests for SQLite library. The
12# focus of this file is testing that the current version of SQLite
13# is capable of reading and writing databases created by previous
14# versions, and vice-versa.
15#
16# To use this test, old versions of the testfixture process should be
17# copied into the working directory alongside the new version. The old
18# versions should be named "testfixtureXXX" (or testfixtureXXX.exe on
19# windows), where XXX can be any string.
20#
21# This test file uses the tcl code for controlling a second testfixture
22# process located in lock_common.tcl. See the commments in lock_common.tcl
23# for documentation of the available commands.
24#
25
26set testdir [file dirname $argv0]
27source $testdir/tester.tcl
28source $testdir/lock_common.tcl
29source $testdir/malloc_common.tcl
dana35dafc2010-08-19 15:11:34 +000030db close
dan8311c472010-08-19 11:05:53 +000031
32# Search for binaries to test against. Any executable files that match
33# our naming convention are assumed to be testfixture binaries to test
34# against.
35#
36set binaries [list]
dana35dafc2010-08-19 15:11:34 +000037set pattern "[file tail [info nameofexec]]*"
dan8311c472010-08-19 11:05:53 +000038foreach file [glob $pattern] {
39 if {[file executable $file]} {lappend binaries $file}
40}
41if {[llength $binaries]==0} {
42 puts "WARNING: No binaries to test against. No tests have been run."
43 finish_test
44 return
45}
46proc get_version {binary} {
47 set chan [launch_testfixture $binary]
48 set v [testfixture $chan { sqlite3 -version }]
49 close $chan
50 set v
51}
52foreach bin $binaries {
53 puts "Testing against $bin - version [get_version $bin]"
54}
55
dana35dafc2010-08-19 15:11:34 +000056proc do_backcompat_test {rv bin1 bin2 script} {
dan8311c472010-08-19 11:05:53 +000057
dana35dafc2010-08-19 15:11:34 +000058 file delete -force test.db
59
60 if {$bin1 != ""} { set ::bc_chan1 [launch_testfixture $bin1] }
61 set ::bc_chan2 [launch_testfixture $bin2]
dan8311c472010-08-19 11:05:53 +000062
63 if { $rv } {
dan8311c472010-08-19 11:05:53 +000064 proc code2 {tcl} { uplevel #0 $tcl }
dana35dafc2010-08-19 15:11:34 +000065 if {$bin1 != ""} { proc code2 {tcl} { testfixture $::bc_chan1 $tcl } }
66 proc code1 {tcl} { testfixture $::bc_chan2 $tcl }
dan8311c472010-08-19 11:05:53 +000067 } else {
68 proc code1 {tcl} { uplevel #0 $tcl }
dana35dafc2010-08-19 15:11:34 +000069 if {$bin1 != ""} { proc code1 {tcl} { testfixture $::bc_chan1 $tcl } }
70 proc code2 {tcl} { testfixture $::bc_chan2 $tcl }
dan8311c472010-08-19 11:05:53 +000071 }
72
73 proc sql1 sql { code1 [list db eval $sql] }
74 proc sql2 sql { code2 [list db eval $sql] }
75
dan8311c472010-08-19 11:05:53 +000076 code1 { sqlite3 db test.db }
77 code2 { sqlite3 db test.db }
78
79 uplevel $script
80
81 catch { code1 { db close } }
82 catch { code2 { db close } }
dana35dafc2010-08-19 15:11:34 +000083 catch { close $::bc_chan2 }
84 catch { close $::bc_chan1 }
dan8311c472010-08-19 11:05:53 +000085}
86
87array set ::incompatible [list]
88proc do_allbackcompat_test {script} {
89
90 foreach bin $::binaries {
91 set nErr [set_test_counter errors]
92 foreach dir {0 1} {
93
danfc5026d2010-08-19 15:48:47 +000094 set bintag [string map {testfixture {}} $bin]
95 if {$bintag == ""} {set bintag self}
96 set ::bcname ".$bintag.$dir."
dan8311c472010-08-19 11:05:53 +000097
98 rename do_test _do_test
99 proc do_test {nm sql res} {
100 set nm [regsub {\.} $nm $::bcname]
101 uplevel [list _do_test $nm $sql $res]
102 }
103
dana35dafc2010-08-19 15:11:34 +0000104 do_backcompat_test $dir {} $bin $script
dan8311c472010-08-19 11:05:53 +0000105
106 rename do_test {}
107 rename _do_test do_test
108 }
109 if { $nErr < [set_test_counter errors] } {
110 set ::incompatible([get_version $bin]) 1
111 }
112 }
113}
114
115proc read_file {zFile} {
116 set zData {}
dan9ab7fe82010-08-19 17:16:11 +0000117 if {[file exists $zFile]} {
dan8311c472010-08-19 11:05:53 +0000118 set fd [open $zFile]
119 fconfigure $fd -translation binary -encoding binary
dan9ab7fe82010-08-19 17:16:11 +0000120
121 if {[file size $zFile]<=$::sqlite_pending_byte || $zFile != "test.db"} {
122 set zData [read $fd]
123 } else {
124 set zData [read $fd $::sqlite_pending_byte]
125 append zData [string repeat x 512]
126 seek $fd [expr $::sqlite_pending_byte+512] start
127 append zData [read $fd]
128 }
129
dan8311c472010-08-19 11:05:53 +0000130 close $fd
131 }
132 return $zData
133}
134proc write_file {zFile zData} {
135 set fd [open $zFile w]
136 fconfigure $fd -translation binary -encoding binary
137 puts -nonewline $fd $zData
138 close $fd
139}
140proc read_file_system {} {
141 set ret [list]
142 foreach f {test.db test.db-journal test.db-wal} { lappend ret [read_file $f] }
143 set ret
144}
145proc write_file_system {data} {
146 foreach f {test.db test.db-journal test.db-wal} d $data {
147 if {[string length $d] == 0} {
148 file delete -force $f
149 } else {
150 write_file $f $d
151 }
152 }
153}
154
155#-------------------------------------------------------------------------
156# Actual tests begin here.
157#
danfc5026d2010-08-19 15:48:47 +0000158# This first block of tests checks to see that the same database and
159# journal files can be used by old and new versions. WAL and wal-index
160# files are tested separately below.
161#
dan8311c472010-08-19 11:05:53 +0000162do_allbackcompat_test {
163
164 # Test that database files are backwards compatible.
165 #
166 do_test backcompat-1.1.1 { sql1 {
167 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
168 INSERT INTO t1 VALUES('abc', 'def');
169 } } {}
170 do_test backcompat-1.1.2 { sql2 { SELECT * FROM t1; } } {abc def}
171 do_test backcompat-1.1.3 { sql2 { INSERT INTO t1 VALUES('ghi', 'jkl'); } } {}
172 do_test backcompat-1.1.4 { sql1 { SELECT * FROM t1; } } {abc def ghi jkl}
173 do_test backcompat-1.1.5 { sql1 { PRAGMA integrity_check } } {ok}
174 do_test backcompat-1.1.6 { sql2 { PRAGMA integrity_check } } {ok}
175
176 # Test that one version can roll back a hot-journal file left in the
177 # file-system by the other version.
178 #
dana35dafc2010-08-19 15:11:34 +0000179 # Each test case is named "backcompat-1.X...", where X is either 0 or
180 # 1. If it is 0, then the current version creates a journal file that
181 # the old versions try to read. Otherwise, if X is 1, then the old version
182 # creates the journal file and we try to read it with the current version.
183 #
dan8311c472010-08-19 11:05:53 +0000184 do_test backcompat-1.2.1 { sql1 {
185 PRAGMA cache_size = 10;
186 BEGIN;
187 INSERT INTO t1 VALUES(randomblob(400), randomblob(400));
188 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
189 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
190 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
191 INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM t1;
192 COMMIT;
193 } } {}
194 set cksum1 [sql1 {SELECT md5sum(a), md5sum(b) FROM t1}]
195 set cksum2 [sql2 {SELECT md5sum(a), md5sum(b) FROM t1}]
196 do_test backcompat-1.2.2 [list string compare $cksum1 $cksum2] 0
197
198 do_test backcompat-1.2.3 { sql1 {
199 BEGIN;
200 UPDATE t1 SET a = randomblob(500);
201 } } {}
202 set data [read_file_system]
dana35dafc2010-08-19 15:11:34 +0000203
204 set f "test.db-journal[incr x]"
205 file copy -force test.db-journal $f
206
dan8311c472010-08-19 11:05:53 +0000207 do_test backcompat-1.2.4 { sql1 { COMMIT } } {}
208
209 set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
210 do_test backcompat-1.2.5 [list set {} $same] 0
211
dana35dafc2010-08-19 15:11:34 +0000212 code1 { db close }
213 code2 { db close }
dan8311c472010-08-19 11:05:53 +0000214 write_file_system $data
dana35dafc2010-08-19 15:11:34 +0000215 code1 { sqlite3 db test.db }
216 code2 { sqlite3 db test.db }
217
dan8311c472010-08-19 11:05:53 +0000218 set same [expr {[sql2 {SELECT md5sum(a), md5sum(b) FROM t1}] == $cksum2}]
219 do_test backcompat-1.2.6 [list set {} $same] 1
220
dana35dafc2010-08-19 15:11:34 +0000221 do_test backcompat-1.2.7 { sql1 { PRAGMA integrity_check } } {ok}
dan8311c472010-08-19 11:05:53 +0000222 do_test backcompat-1.2.8 { sql2 { PRAGMA integrity_check } } {ok}
223}
dan8311c472010-08-19 11:05:53 +0000224foreach k [lsort [array names ::incompatible]] {
danfc5026d2010-08-19 15:48:47 +0000225 puts "ERROR: Detected journal incompatibility with version $k"
226}
227unset ::incompatible
228
229
230#-------------------------------------------------------------------------
231# Test that WAL and wal-index files may be shared between different
232# SQLite versions.
233#
234do_allbackcompat_test {
235 if {[code1 {sqlite3 -version}] >= "3.7.0"
236 && [code2 {sqlite3 -version}] >= "3.7.0"
237 } {
238
239 do_test backcompat-2.1.1 { sql1 {
240 PRAGMA journal_mode = WAL;
241 CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
242 INSERT INTO t1 VALUES('I', 1);
243 INSERT INTO t1 VALUES('II', 2);
244 INSERT INTO t1 VALUES('III', 3);
245 SELECT * FROM t1;
246 } } {wal I 1 II 2 III 3}
247 do_test backcompat-2.1.2 { sql2 {
248 SELECT * FROM t1;
249 } } {I 1 II 2 III 3}
250
251 set data [read_file_system]
252 code1 {db close}
253 code2 {db close}
254 write_file_system $data
255 code1 {sqlite3 db test.db}
256 code2 {sqlite3 db test.db}
257
258 # The WAL file now in the file-system was created by the [code1]
259 # process. Check that the [code2] process can recover the log.
260 #
261 do_test backcompat-2.1.3 { sql2 {
262 SELECT * FROM t1;
263 } } {I 1 II 2 III 3}
264 do_test backcompat-2.1.4 { sql1 {
265 SELECT * FROM t1;
266 } } {I 1 II 2 III 3}
267 }
dan8311c472010-08-19 11:05:53 +0000268}
269
270finish_test