1# 2018 March 14
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.
12#
13
14if {![info exists testdir]} {
15  set testdir [file join [file dirname [info script]] .. .. test]
16}
17source [file join [file dirname [info script]] session_common.tcl]
18source $testdir/tester.tcl
19ifcapable !session {finish_test; return}
20
21set testprefix sessionrebase
22
23set ::lConflict [list]
24proc xConflict {args} {
25  set res [lindex $::lConflict 0]
26  set ::lConflict [lrange $::lConflict 1 end]
27  return $res
28}
29
30#-------------------------------------------------------------------------
31# The following test cases - 1.* - test that the rebase blobs output by
32# sqlite3_changeset_apply_v2 look correct in some simple cases. The blob
33# is itself a changeset, containing records determined as follows:
34#
35#   * For each conflict resolved with REPLACE, the rebase blob contains
36#     a DELETE record. All fields other than the PK fields are undefined.
37#
38#   * For each conflict resolved with OMIT, the rebase blob contains an
39#     INSERT record. For an INSERT or UPDATE operation, the indirect flag
40#     is clear and all updated fields are defined. For a DELETE operation,
41#     the indirect flag is set and all non-PK fields left undefined.
42#
43proc do_apply_v2_test {tn sql modsql conflict_handler res} {
44
45  execsql BEGIN
46  sqlite3session S db main
47  S attach *
48  execsql $sql
49  set changeset [S changeset]
50  S delete
51  execsql ROLLBACK
52
53  execsql BEGIN
54  execsql $modsql
55  set ::lConflict $conflict_handler
56  set blob [sqlite3changeset_apply_v2 db $changeset xConflict]
57  execsql ROLLBACK
58
59  uplevel [list do_test $tn [list changeset_to_list $blob] [list {*}$res]]
60}
61
62do_execsql_test 1.0 {
63  CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
64  INSERT INTO t1 VALUES(1, 'value A');
65}
66
67do_apply_v2_test 1.1.1 {
68  UPDATE t1 SET b = 'value B' WHERE a=1;
69} {
70  UPDATE t1 SET b = 'value C' WHERE a=1;
71} {
72  OMIT
73} {
74  {INSERT t1 0 X. {} {i 1 t {value B}}}
75}
76do_apply_v2_test 1.1.2 {
77  UPDATE t1 SET b = 'value B' WHERE a=1;
78} {
79  UPDATE t1 SET b = 'value C' WHERE a=1;
80} {
81  REPLACE
82} {
83  {DELETE t1 0 X. {i 1 {} {}} {}}
84}
85
86do_apply_v2_test 1.2.1 {
87  INSERT INTO t1 VALUES(2, 'first');
88} {
89  INSERT INTO t1 VALUES(2, 'second');
90} {
91  OMIT
92} {
93  {INSERT t1 0 X. {} {i 2 t first}}
94}
95do_apply_v2_test 1.2.2 {
96  INSERT INTO t1 VALUES(2, 'first');
97} {
98  INSERT INTO t1 VALUES(2, 'second');
99} {
100  REPLACE
101} {
102  {DELETE t1 0 X. {i 2 {} {}} {}}
103}
104
105do_apply_v2_test 1.3.1 {
106  DELETE FROM t1 WHERE a=1;
107} {
108  UPDATE t1 SET b='value D' WHERE a=1;
109} {
110  OMIT
111} {
112  {INSERT t1 1 X. {} {i 1 {} {}}}
113}
114do_apply_v2_test 1.3.2 {
115  DELETE FROM t1 WHERE a=1;
116} {
117  UPDATE t1 SET b='value D' WHERE a=1;
118} {
119  REPLACE
120} {
121  {DELETE t1 0 X. {i 1 {} {}} {}}
122}
123
124#-------------------------------------------------------------------------
125# Test cases 2.* - simple tests of rebasing actual changesets.
126#
127#    2.1.1 - 1u2u1r
128#    2.1.2 - 1u2u2r
129#    2.1.3 - 1d2d
130#    2.1.4 - 1d2u1r
131#    2.1.5 - 1d2u2r !!
132#    2.1.6 - 1u2d1r
133
134proc xConflictAbort {args} {
135  return "ABORT"
136}
137
138# Take a copy of database test.db in file test.db2. Execute $sql1
139# against test.db and $sql2 against test.db2. Capture a changeset
140# for each. Then send the test.db2 changeset to test.db and apply
141# it with the conflict handlers in $conflict_handler. Patch the
142# test.db changeset and then execute it against test.db2. Test that
143# the two databases come out the same.
144#
145proc do_rebase_test {tn sql1 sql2 conflict_handler {testsql ""} {testres ""}} {
146
147  forcedelete test.db2 test.db2-journal test.db2-wal
148  forcecopy test.db test.db2
149  sqlite3 db2 test.db2
150
151  db eval BEGIN
152
153  sqlite3session S1 db main
154  S1 attach *
155  execsql $sql1 db
156  set c1 [S1 changeset]
157  S1 delete
158
159  sqlite3session S2 db2 main
160  S2 attach *
161  execsql $sql2 db2
162  set c2 [S2 changeset]
163  S2 delete
164
165  set ::lConflict $conflict_handler
166  set rebase [sqlite3changeset_apply_v2 db $c2 xConflict]
167  #puts [changeset_to_list $rebase]
168
169  sqlite3rebaser_create R
170  R configure $rebase
171  set c1r [R rebase $c1]
172  R delete
173  #puts [changeset_to_list $c1r]
174
175  sqlite3changeset_apply_v2 db2 $c1r xConflictAbort
176
177  uplevel [list do_test $tn.1 [list compare_db db db2] {}]
178  db2 close
179
180  if {$testsql!=""} {
181    uplevel [list do_execsql_test $tn.2 $testsql $testres]
182  }
183
184  db eval ROLLBACK
185}
186
187reset_db
188do_execsql_test 2.1.0 {
189  CREATE TABLE t1 (a INTEGER PRIMARY KEY, b TEXT);
190  INSERT INTO t1 VALUES(1, 'one');
191  INSERT INTO t1 VALUES(2, 'two');
192  INSERT INTO t1 VALUES(3, 'three');
193}
194do_rebase_test 2.1.1 {
195  UPDATE t1 SET b = 'two.1' WHERE a=2;
196} {
197  UPDATE t1 SET b = 'two.2' WHERE a=2;
198} {
199  OMIT
200} { SELECT * FROM t1 } {1 one 2 two.1 3 three}
201
202do_rebase_test 2.1.2 {
203  UPDATE t1 SET b = 'two.1' WHERE a=2;
204} {
205  UPDATE t1 SET b = 'two.2' WHERE a=2;
206} {
207  REPLACE
208} { SELECT * FROM t1 } {1 one 2 two.2 3 three}
209
210do_rebase_test 2.1.3 {
211  DELETE FROM t1 WHERE a=3;
212} {
213  DELETE FROM t1 WHERE a=3;
214} {
215  OMIT
216} { SELECT * FROM t1 } {1 one 2 two}
217
218do_rebase_test 2.1.4 {
219  DELETE FROM t1 WHERE a=1;
220} {
221  UPDATE t1 SET b='one.2' WHERE a=1
222} {
223  OMIT
224} { SELECT * FROM t1 } {2 two 3 three}
225
226#do_rebase_test 2.1.5 {
227  #DELETE FROM t1 WHERE a=1;
228#} {
229  #UPDATE t1 SET b='one.2' WHERE a=1
230#} {
231  #REPLACE
232#} { SELECT * FROM t1 } {2 two 3 three}
233
234do_rebase_test 2.1.6 {
235  UPDATE t1 SET b='three.1' WHERE a=3;
236} {
237  DELETE FROM t1 WHERE a=3;
238} {
239  OMIT
240} { SELECT * FROM t1 } {1 one 2 two 3 three.1}
241
242do_rebase_test 2.1.7 {
243  UPDATE t1 SET b='three.1' WHERE a=3;
244} {
245  DELETE FROM t1 WHERE a=3;
246} {
247  REPLACE
248} { SELECT * FROM t1 } {1 one 2 two}
249
250finish_test
251
252