libdb/test/sql/bdb_replication.test
2012-11-14 16:35:20 -05:00

1400 lines
34 KiB
Text

#
# 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 regression tests for Berkeley DB specific replication
# simple cases.
#
set testdir [file dirname $argv0]/../../lang/sql/sqlite/test
source $testdir/tester.tcl
source $testdir/../../../../test/sql/bdb_util.tcl
global site1addr site2addr site3addr site1dir site2dir site3dir
# The SQL test system is sequential, but some HA operations like elections
# and client synchronization are parallel operations across more than one
# SQL database/replication site. SQL HA test cases should observe the
# following rules to avoid problems:
# - Wait the appropriate *_delay for replication operations (see below).
# - If you stop and restart one or more sites, you must do an initial
# query on each restarted site to cause it to rejoin the replication
# group. If there is still a master running, a restarted site will
# do a client synchronization. If there is no master, a restarted
# site and all other running sites will perform an election.
# - Any test case that runs an election after initial startup should
# create DB_CONFIG files on all sites that:
# * Set priorities to help make election winner deterministic.
# * Turn off 2SITE_STRICT so that there will not be an excessive
# wait for each site before a quorum is reached.
# * These DB_CONFIG files should usually be created after initial
# startup because during initial startup, turning off 2SITE_STRICT
# on an overloaded or slow machine can cause clients to call their
# own elections instead of finding the initial master.
# Delays are needed in the test to allow time for replication operations
# among different sites:
# replication_delay: Time for master transactions to appear on clients,
# including group membership operations such as
# removing a site.
# client_sync_delay: Time for a client to synchronize with a master
# after client has been shut down.
# election_delay: Time for an election to be held and possibly retried
# after master has been shut down.
set replication_delay 3000
set client_sync_delay 5000
set election_delay 12000
##
## Test cases replication-1.*
## Verify basic replication with a simple 2-site configuration.
##
setup_rep_sites
# Initialize and start replication on master site1.
db eval "
pragma replication_local_site='$site1addr';
"
do_test replication-1.0 {
execsql {
pragma replication_initial_master=on;
pragma replication=on;
} db
} {1 {Replication started}}
# Insert initial data on master.
do_test replication-1.1 {
execsql {
create table reptab (a);
insert into reptab values (1);
select * from reptab;
} db
} {1}
# Initialize and start replication on client site2.
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
"
do_test replication-1.2 {
execsql {
pragma replication=on;
} db2
} {{Replication started}}
after $replication_delay
# Make sure client got initial master insert.
do_test replication-1.3 {
execsql {
select * from reptab;
} db2
} {1}
# Make sure client database is readonly.
do_test replication-1.4 {
catchsql {
insert into reptab values (9999);
} db2
} {1 {attempt to write a readonly database}}
# Insert more data on master.
do_test replication-1.5 {
execsql {
insert into reptab values (2);
select * from reptab order by a;
} db
} {1 2}
after $replication_delay
# Make sure client got additional master data.
do_test replication-1.6 {
execsql {
select * from reptab order by a;
} db2
} {1 2}
# Perform more operations on master.
do_test replication-1.7 {
execsql {
insert into reptab values (3);
update reptab set a = 999 where a = 1;
delete from reptab where a = 2;
select * from reptab order by a;
} db
} {3 999}
after $replication_delay
# Make sure client got additional operations.
do_test replication-1.8 {
execsql {
select * from reptab order by a;
} db2
} {3 999}
# Remove client site2 from master.
do_test replication-1.9 {
set ::DB db2
execsql "pragma replication_remove_site='$site2addr';"
} {{Replication site removed}}
after $replication_delay
set ::DB db
catch {db2 close}
catch {db close}
##
## Test cases replication-2.*
## Verify Use Cases from 5.2 spec.
##
## Cases 2.0.* test Use Case 1: Distributed Read at 3 Sites.
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
create table university (
rank int,
name varchar(75),
domains varchar(75),
country varchar(30),
region varchar(30),
size int,
visibility int,
rich int,
scholar int);
create table country(
country varchar(30),
abbr varchar(10),
Top_100 int,
Top_200 int,
Top_500 int,
Top_1000 int);
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
db3 eval "
pragma replication_local_site='$site3addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
do_test replication-2.0.1 {
execsql {
insert into country values ("Greenland","gl", 0, 0, 0, 2);
insert into university values (26, "University College London",
"ucl.edu", "uk", "Europe", 18, 39, 47, 30);
update country set top_1000 = 1 where abbr = "gl";
select * from country where abbr = "gl";
} db
} {Greenland gl 0 0 0 1}
after $replication_delay
do_test replication-2.0.2 {
execsql {
select * from university where region = "Europe";
select count(*) from country where top_100 > 0;
} db2
} {26 {University College London} ucl.edu uk Europe 18 39 47 30 0}
do_test replication-2.0.3 {
catchsql {
insert into country values ("Antarctica","an", 0, 0, 0, 0);
} db2
} {1 {attempt to write a readonly database}}
catch {db3 close}
catch {db2 close}
catch {db close}
## Cases 2.1.* test Use Case 2: 2-site Failover.
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
create table stock_quote (company_name text(40), price real);
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
# Perform some writes on master.
do_test replication-2.1.1 {
execsql {
insert into stock_quote values ("General Electric", 20.25);
insert into stock_quote values ("Nabisco", 24.75);
insert into stock_quote values ("United Healthcare", 31.00);
update stock_quote set price=25.25 where company_name = "Nabisco";
} db
} {}
after $replication_delay
# Perform reads on client.
do_test replication-2.1.2 {
execsql {
select * from stock_quote where price < 30.00;
select price from stock_quote where company_name = "United Healthcare";
} db2
} {{General Electric} 20.25 Nabisco 25.25 31.0}
# Stop the initial master.
do_test replication-2.1.3 {
catch {db close}
} {0}
after $election_delay
# The remaining client does not accept write operations until the other site
# rejoins the replication group.
do_test replication-2.1.4 {
catchsql {
insert into stock_quote values ("Prudential", 17.25);
} db2
} {1 {attempt to write a readonly database}}
# Restart site, will rejoin replication group. The repmgr will be started.
sqlite3 db $site1dir/rep.db
# Initial query to trigger election and client sync up.
execsql { select * from stock_quote where price < 21.00; } db
after $election_delay
# Assuming the site became master, perform some writes. If it is not the master,
# these writes will not succeed and must be performed at the other site.
do_test replication-2.1.5 {
execsql {
insert into stock_quote values ("Raytheon", 9.25);
insert into stock_quote values ("Cadbury", 7.75);
} db
} {}
after $replication_delay
do_test replication-2.1.6 {
execsql {
select * from stock_quote where price < 21.00;
} db2
} {{General Electric} 20.25 Raytheon 9.25 Cadbury 7.75}
##
## Test cases replication-3.*
## Verify replication pragma syntax and usage.
##
## Cases 3.0.* test replication_local_site by itself and internal host:port
## checking.
setup_rep_sites
do_test replication-3.0.0 {
catchsql {
pragma replication_local_site="badvalue";
} db
} {1 {Format of value must be host:port}}
do_test replication-3.0.1 {
catchsql {
pragma replication_local_site="badvalue";
} db
} {1 {Format of value must be host:port}}
do_test replication-3.0.2 {
catchsql {
pragma replication_local_site=":1234";
} db
} {1 {Format of value must be host:port}}
do_test replication-3.0.3 {
catchsql {
pragma replication_local_site="1234";
} db
} {1 {Format of value must be host:port}}
do_test replication-3.0.4 {
catchsql {
pragma replication_local_site=":";
} db
} {1 {Format of value must be host:port}}
do_test replication-3.0.5 {
execsql {
pragma replication_local_site="testhost:1234";
pragma replication_local_site;
} db
} {testhost:1234 testhost:1234}
## Cases 3.1.* test replication_initial_master by itself.
do_test replication-3.1.0 {
execsql {
pragma replication_initial_master=true;
pragma replication_initial_master;
} db
} {1 1}
do_test replication-3.1.1 {
execsql {
pragma replication_initial_master=false;
pragma replication_initial_master;
} db
} {0 0}
## Cases 3.2.* test replication_remote_site by itself.
setup_rep_sites
do_test replication-3.2.0 {
catchsql {
pragma replication_remote_site="badvalue";
} db
} {1 {Format of value must be host:port}}
do_test replication-3.2.1 {
execsql {
pragma replication_remote_site="testhost2:54321";
pragma replication_remote_site;
} db
} {testhost2:54321 testhost2:54321}
## Cases 3.3.* test interactions between replication pragmas.
setup_rep_sites
do_test replication-3.3.0 {
catchsql {
pragma replication=on;
} db
} {1 {Must specify local site before starting replication}}
db eval "
pragma replication_local_site='$site1addr';
"
do_test replication-3.3.1 {
catchsql {
pragma replication=on;
} db
} {1 {Must either be initial master or specify a remote site}}
catch {db close}
## Cases 3.4.* test replication_remove_site.
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
db3 eval "
pragma replication_local_site='$site3addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
after $replication_delay
## Cases 3.4.0.* remove a remote client site.
do_test replication-3.4.0 {
execsql "pragma replication_remove_site='$site2addr';"
} {{Replication site removed}}
after $replication_delay
## Cases 3.4.1.* remove local client site.
do_test replication-3.4.1 {
set ::DB db3
execsql "pragma replication_remove_site='$site3addr';"
} {{Replication site removed}}
after $replication_delay
set ::DB db
## Cases 3.4.2.* attempt to remove non-existent site (no error).
do_test replication-3.4.2 {
execsql {
pragma replication_remove_site="localhost:1234";
} db
} {{Replication site removed}}
## Cases 3.4.3.* attempt to remove master site (error).
do_test replication-3.4.3 {
catchsql "pragma replication_remove_site='$site1addr';"
} {1 {Replication site not removed}}
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
## Cases 3.4.4.* attempt to remove site before group membership database
## is available (no error).
do_test replication-3.4.4 {
set ::DB db3
execsql "pragma replication_remove_site='$site2addr';"
} {{Replication site removed}}
set ::DB db
## Cases 3.4.5.* test removing and then adding a site back into
## the replication group.
do_test replication-3.4.5.0 {
execsql "pragma replication_remove_site='$site2addr';"
} {{Replication site removed}}
after $replication_delay
db eval "
create table reptab (a);
insert into reptab values (1);
"
after $replication_delay
# Removing a site does not necessarily stop all replication immediately,
# so reptab may or may not exist on db2.
catch {db2 close}
sqlite3 db2 $site2dir/rep.db
after $client_sync_delay
db eval "
insert into reptab values (2);
"
after $replication_delay
# Make sure db2 rejoined the replication group and is caught up.
do_test replication-3.4.5.1 {
execsql {
select * from reptab;
} db2
} {1 2}
## Cases 3.5.* test replication_verbose_output and replication_verbose_file,
## including the immediate effect of turning them on and off.
do_test replication-3.5.0 {
execsql { pragma replication_verbose_output=ON; } db
execsql { pragma replication_verbose_file=sqloutput; } db
} {sqloutput}
catch {db2 close}
catch {db3 close}
catch {db close}
do_test replication-3.5.1 {
expr [file size sqloutput] > 0
} {1}
## Cases 3.6.* test changing replication_local_site after replication is
## started.
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
"
do_test replication-3.6 {
catchsql "
pragma replication_local_site='$site2addr';
"
} {1 {Cannot change local site after replication is turned on}}
catch {db close}
## Cases 3.7.* test running replication pragmas in a database that was
## created without DB_INIT_REP (error).
setup_rep_sites
do_test replication-3.7.0 {
catchsql "pragma replication_remove_site='$site2addr';"
} {1 {Replication site not removed}}
execsql { create table reptab (a); } db
catch {db close}
##
## Test cases replication-4.*
## Verify replication startup, shutdown and election scenarios.
##
## Cases 4.0.* test a 2-site replication group starting up both sites,
## shutting down and restarting the client, and verifying that replication
## continues.
setup_rep_sites
# Initialize and start replication on master site1.
db eval "
pragma replication_local_site='$site1addr';
"
do_test replication-4.0.0 {
execsql {
pragma replication_initial_master=on;
pragma replication=on;
} db
} {1 {Replication started}}
# Initialize and start replication on client site2.
db2 eval "
pragma replication_local_site='$site2addr';
"
db2 eval "
pragma replication_remote_site='$site1addr';
"
do_test replication-4.0.1 {
execsql {
pragma replication=on;
} db2
} {{Replication started}}
# Insert initial data on master.
do_test replication-4.0.2 {
execsql {
create table reptab (a);
insert into reptab values (1);
select * from reptab;
} db
} {1}
after $replication_delay
# Make sure client got initial master insert.
do_test replication-4.0.3 {
execsql {
select * from reptab;
} db2
} {1}
# Shut down and reopen client site.
catch {db2 close}
sqlite3 db2 $site2dir/rep.db
# Insert more data on master.
do_test replication-4.0.4 {
execsql {
insert into reptab values (2);
select * from reptab order by a;
} db
} {1 2}
# Client query to trigger environment open and client synchronization after
# shutdown.
execsql {select * from reptab order by a;} db2
after $client_sync_delay
# Make sure client got additional master data.
do_test replication-4.0.5 {
execsql {
select * from reptab order by a;
} db2
} {1 2}
# Insert more data on master.
do_test replication-4.0.6 {
execsql {
insert into reptab values (3);
select * from reptab order by a;
} db
} {1 2 3}
after $replication_delay
# Make sure client got additional master data.
do_test replication-4.0.7 {
execsql {
select * from reptab order by a;
} db2
} {1 2 3}
catch {db2 close}
catch {db close}
## Cases 4.1.* test a 2-site replication group starting up both sites,
## shutting down first the client then the master and restarting the
## master then the client and verifying that replication continues.
setup_rep_sites
# Initialize and start replication on master site1.
db eval "
pragma replication_local_site='$site1addr';
"
do_test replication-4.1.0 {
execsql {
pragma replication_initial_master=on;
pragma replication=on;
} db
} {1 {Replication started}}
# Initialize and start replication on client site2.
db2 eval "
pragma replication_local_site='$site2addr';
"
db2 eval "
pragma replication_remote_site='$site1addr';
"
do_test replication-4.1.1 {
execsql {
pragma replication=on;
} db2
} {{Replication started}}
# Insert initial data on master.
do_test replication-4.1.2 {
execsql {
create table reptab (a);
insert into reptab values (1);
select * from reptab;
} db
} {1}
after $replication_delay
# Make sure client got initial master insert.
do_test replication-4.1.3 {
execsql {
select * from reptab;
} db2
} {1}
# Set site priorities to make later election winner deterministic.
# Turn off 2site_strict to enable sites to restart and join repgroup
# sequentially after full shutdown, otherwise each initial site will wait
# a very long time for its election until a quorum of sites is available.
file mkdir $site1dir/rep.db-journal
set s1config [open $site1dir/rep.db-journal/DB_CONFIG w]
puts $s1config "rep_set_priority 100"
puts $s1config "rep_set_config db_repmgr_conf_2site_strict off"
close $s1config
file mkdir $site2dir/rep.db-journal
set s2config [open $site2dir/rep.db-journal/DB_CONFIG w]
puts $s2config "rep_set_priority 50"
puts $s2config "rep_set_config db_repmgr_conf_2site_strict off"
close $s2config
# Shut down and reopen master and client sites.
catch {db2 close}
catch {db close}
sqlite3 db $site1dir/rep.db
sqlite3 db2 $site2dir/rep.db
# Execute queries on each site to trigger environment opens after shutdown.
# This will throw the sites into an election.
execsql {select * from reptab order by a;} db
execsql {select * from reptab order by a;} db2
after $election_delay
# Insert more data on master.
do_test replication-4.1.4 {
execsql {
insert into reptab values (2);
select * from reptab order by a;
} db
} {1 2}
after $replication_delay
# Make sure client got additional master data.
do_test replication-4.1.5 {
execsql {
select * from reptab order by a;
} db2
} {1 2}
# Insert more data on master.
do_test replication-4.1.6 {
execsql {
insert into reptab values (3);
select * from reptab order by a;
} db
} {1 2 3}
after $replication_delay
# Make sure client got additional master data.
do_test replication-4.1.7 {
execsql {
select * from reptab order by a;
} db2
} {1 2 3}
catch {db2 close}
catch {db close}
## Cases 4.2.* test a 2-site replication group starting up both sites,
## shutting down first the master then the client and restarting the
## client then the master and verifying that replication continues.
setup_rep_sites
# Initialize and start replication on master site1.
db eval "
pragma replication_local_site='$site1addr';
"
do_test replication-4.2.0 {
execsql {
pragma replication_initial_master=on;
pragma replication=on;
} db
} {1 {Replication started}}
# Initialize and start replication on client site2.
db2 eval "
pragma replication_local_site='$site2addr';
"
db2 eval "
pragma replication_remote_site='$site1addr';
"
do_test replication-4.2.1 {
execsql {
pragma replication=on;
} db2
} {{Replication started}}
# Insert initial data on master.
do_test replication-4.2.2 {
execsql {
create table reptab (a);
insert into reptab values (1);
select * from reptab;
} db
} {1}
after $replication_delay
# Make sure client got initial master insert.
do_test replication-4.2.3 {
execsql {
select * from reptab;
} db2
} {1}
# Set site priorities to make later election winner deterministic.
# Turn off 2site_strict to enable sites to restart and join repgroup
# sequentially after full shutdown, otherwise each initial site will wait
# a very long time for its election until a quorum of sites is available.
file mkdir $site1dir/rep.db-journal
set s1config [open $site1dir/rep.db-journal/DB_CONFIG w]
puts $s1config "rep_set_priority 100"
puts $s1config "rep_set_config db_repmgr_conf_2site_strict off"
close $s1config
file mkdir $site2dir/rep.db-journal
set s2config [open $site2dir/rep.db-journal/DB_CONFIG w]
puts $s2config "rep_set_priority 50"
puts $s2config "rep_set_config db_repmgr_conf_2site_strict off"
close $s2config
# Shut down and reopen master and client sites.
catch {db close}
catch {db2 close}
sqlite3 db $site1dir/rep.db
sqlite3 db2 $site2dir/rep.db
# Execute queries on each site to trigger environment opens after shutdown.
# This will throw the sites into an election.
execsql {select * from reptab order by a;} db
execsql {select * from reptab order by a;} db2
after $election_delay
# Insert more data on master.
do_test replication-4.2.4 {
execsql {
insert into reptab values (2);
select * from reptab order by a;
} db
} {1 2}
after $replication_delay
# Make sure client got additional master data.
do_test replication-4.2.5 {
execsql {
select * from reptab order by a;
} db2
} {1 2}
# Insert more data on master.
do_test replication-4.2.6 {
execsql {
insert into reptab values (3);
select * from reptab order by a;
} db
} {1 2 3}
after $replication_delay
# Make sure client got additional master data.
do_test replication-4.2.7 {
execsql {
select * from reptab order by a;
} db2
} {1 2 3}
catch {db2 close}
catch {db close}
## Cases 4.3.* test that a 2-site replication group, using DB_CONFIG to turn
## off the 2SITE_STRICT setting, can shut down the master and have the client
## take over as master. Verify write operations on the new master and then
## have the original master rejoin as a client.
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
create table reptab(a);
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
execsql { insert into reptab values (1); } db
after $replication_delay
# Set priorities to guarantee initial master will win election when rejoining
# replication group.
set s1config [open $site1dir/rep.db-journal/DB_CONFIG w]
puts $s1config "rep_set_priority 150"
close $s1config
# Shut down master, client won't take over as master.
catch {db close}
after $election_delay
do_test replication-4.3.1 {
catchsql {
insert into reptab values (1);
select * from reptab order by a;
} db2
} {1 {attempt to write a readonly database}}
# Restart master.
sqlite3 db $site1dir/rep.db
execsql {select * from reptab order by a;} db
after $client_sync_delay
# Make sure initial master is still master.
do_test replication-4.3.2 {
execsql {
insert into reptab values (2);
select * from reptab order by a;
} db
} {1 2}
after $replication_delay
# Turn off 2SITE_STRICT on both sites.
set s1config [open $site1dir/rep.db-journal/DB_CONFIG a]
puts $s1config "rep_set_config db_repmgr_conf_2site_strict off"
close $s1config
set s2config [open $site2dir/rep.db-journal/DB_CONFIG a]
puts $s2config "rep_set_config db_repmgr_conf_2site_strict off"
close $s2config
# Shut down both sites.
catch {db close}
catch {db2 close}
# Make sure previous client can now become master.
sqlite3 db2 $site2dir/rep.db
after $election_delay
do_test replication-4.3.3 {
execsql {
insert into reptab values (3);
select * from reptab order by a;
} db2
} {1 2 3}
catch {db2 close}
## Cases 4.4.* test a 3-site replication group that shuts down the initial
## master, verifies that a client takes over as master and then that the
## original master can rejoin as a client. Use DB_CONFIG files to set
## site priorities to determine which client takes over as master.
setup_rep_sites
# Set priority.
file mkdir $site1dir/rep.db-journal
set s1config [open $site1dir/rep.db-journal/DB_CONFIG w]
puts $s1config "rep_set_priority 1"
close $s1config
file mkdir $site2dir/rep.db-journal
set s2config [open $site2dir/rep.db-journal/DB_CONFIG w]
puts $s2config "rep_set_priority 1"
close $s2config
file mkdir $site3dir/rep.db-journal
set s3config [open $site3dir/rep.db-journal/DB_CONFIG w]
puts $s3config "rep_set_priority 100"
close $s3config
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
create table reptab(a);
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
db3 eval "
pragma replication_local_site='$site3addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
after $client_sync_delay
# Shut down master.
catch {db close}
after $election_delay
# Site 3 will be elected as master
do_test replication-4.4.0 {
execsql {
insert into reptab values (1);
select * from reptab order by a;
} db3
} {1}
# Restart previous master as client.
sqlite3 db $site1dir/rep.db
execsql { select * from reptab order by a; } db
after $client_sync_delay
do_test replication-4.4.1 {
catchsql {
insert into reptab values (10);
} db
} {1 {attempt to write a readonly database}}
do_test replication-4.4.2 {
execsql {
select * from reptab order by a;
} db
} {1}
catch {db close}
catch {db2 close}
catch {db3 close}
##
## Test cases replication-5.*
## Verify errors for each SQL operation that can modify the database
## on a replication client.
##
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
create table reptab(a);
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
after $client_sync_delay
do_test replication-5.0 {
catchsql {
create table reptab_tmp as select a from reptab;
} db2
} {1 {attempt to write a readonly database}}
do_test replication-5.1 {
catchsql {
drop table reptab;
} db2
} {1 {attempt to write a readonly database}}
do_test replication-5.2 {
catchsql {
insert into reptab values (1);
} db2
} {1 {attempt to write a readonly database}}
do_test replication-5.3 {
catchsql {
create view testview AS select * from reptab;
} db2
} {1 {attempt to write a readonly database}}
do_test replication-5.4 {
catchsql {
create index testindex on reptab(a);
} db2
} {1 {attempt to write a readonly database}}
do_test replication-5.5 {
catchsql {
CREATE TRIGGER delete_a DELETE ON reptab
BEGIN
INSERT INTO delete_a (a) values (old.a);
END;
} db2
} {1 {attempt to write a readonly database}}
do_test replication-5.6 {
catchsql {
delete from reptab where a=1;
} db2
} {1 {attempt to write a readonly database}}
do_test replication-5.7 {
catchsql {
update reptab set a=2 where rowid = 1;
} db2
} {1 {attempt to write a readonly database}}
catch {db2 close}
catch {db close}
##
## Test cases replication-6.*
## Verify adding replication to an existing database and permanently turning
## off replication.
##
## Cases 6.0.* test turning replication on in an existing database.
setup_rep_sites
# Create database without replication.
do_test replication-6.0.1 {
execsql {
create table reptab(a);
insert into reptab values (1);
select * from reptab;
} db
} {1}
# Turn on replication on existing database.
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
"
# Create client.
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
db3 eval "
pragma replication_local_site='$site3addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
after $client_sync_delay
# Do more operations on the master and ensure replication is occurring.
do_test replication-6.0.2 {
execsql {
insert into reptab values (2);
select * from reptab order by a;
} db
} {1 2}
after $replication_delay
do_test replication-6.0.3 {
execsql {
select * from reptab order by a;
} db2
} {1 2}
do_test replication-6.0.4 {
execsql {
select * from reptab order by a;
} db3
} {1 2}
# Remove db2 from replication group.
do_test replication-6.0.5 {
execsql "pragma replication_remove_site='$site2addr';"
} {{Replication site removed}}
# Turn off replication on db2 client.
do_test replication-6.0.6 {
set ::DB db2
execsql {
pragma replication=OFF;
} db2
} {{Replication stopped}}
set ::DB db
# Do more operations on the master and ensure replication is occurring
# only to db3 remaining client.
do_test replication-6.0.7 {
execsql {
insert into reptab values (3);
select * from reptab order by a;
} db
} {1 2 3}
after $replication_delay
do_test replication-6.0.8 {
execsql {
select * from reptab order by a;
} db2
} {1 2}
do_test replication-6.0.9 {
execsql {
select * from reptab order by a;
} db3
} {1 2 3}
# Make sure db2 is no longer a client and can accept new data.
do_test replication-6.0.10 {
execsql {
insert into reptab values (222);
select * from reptab order by a;
} db2
} {1 2 222}
# Make sure db2 is usable after turning off replication and restarting.
catch {db2 close}
sqlite3 db2 $site2dir/rep.db
do_test replication-6.0.11 {
execsql {
insert into reptab values (223);
select * from reptab order by a;
} db2
} {1 2 222 223}
catch {db3 close}
catch {db2 close}
catch {db close}
## Cases 6.1.* test error paths starting replication on an existing database.
setup_rep_sites
# Create database without replication.
do_test replication-6.1.1 {
execsql {
create table reptab(a);
insert into reptab values (1);
select * from reptab;
} db
} {1}
# Test error when starting without a local site.
do_test replication-6.1.2 {
catchsql {
pragma replication=on;
} db
} {1 {Must specify local site before starting replication}}
# Test turning off replication when it isn't already on.
do_test replication-6.1.3 {
catchsql {
pragma replication=off;
} db
} {1 {Replication is not currently running}}
# Set wrong local site address that will be changed before it is used.
db eval "
pragma replication_local_site='$site2addr';
"
# Test error when not starting as initial master.
do_test replication-6.1.4 {
catchsql {
pragma replication=on;
} db
} {1 {Must be initial master to start replication on an existing database}}
# Change local site address before replication started.
db eval "
pragma replication_local_site='$site1addr';
"
do_test replication-6.1.5 {
execsql {
pragma replication_initial_master=on;
pragma replication=on;
} db
} {1 {Replication started}}
# Test error turning on replication when it is already on.
do_test replication-6.1.6 {
catchsql {
pragma replication=on;
} db
} {1 {Replication is already running}}
# Test error changing local site address after replication started.
do_test replication-6.1.7 {
catchsql "pragma replication_local_site='$site1addr';"
} {1 {Cannot change local site after replication is turned on}}
catch {db close}
##
## Test cases replication-7.*
## Tests for miscellaneous fixes and conditions.
##
## Cases 7.0.* test the error path where the initial election for a
## replication group fails to complete.
setup_rep_sites
# Initialize and start replication on master site1.
db eval "
pragma replication_local_site='$site1addr';
"
do_test replication-7.0.0 {
execsql {
pragma replication_initial_master=on;
pragma replication=on;
} db
} {1 {Replication started}}
# Initialize and start replication on client site2.
db2 eval "
pragma replication_local_site='$site2addr';
"
db2 eval "
pragma replication_remote_site='$site1addr';
"
do_test replication-7.0.1 {
execsql {
pragma replication=on;
} db2
} {{Replication started}}
# Insert initial data on master.
do_test replication-7.0.2 {
execsql {
create table reptab (a);
insert into reptab values (1);
select * from reptab;
} db
} {1}
after $replication_delay
# Make sure client got initial master insert.
do_test replication-7.0.3 {
execsql {
select * from reptab;
} db2
} {1}
# Shut down master and client sites.
catch {db2 close}
catch {db close}
# Set tiny values for election timeout and election retry so that election
# takes minimal time to fail.
file mkdir $site1dir/rep.db-journal
set s1config [open $site1dir/rep.db-journal/DB_CONFIG w]
puts $s1config "rep_set_timeout db_rep_election_timeout 1"
puts $s1config "rep_set_timeout db_rep_election_retry 1"
close $s1config
sqlite3 db $site1dir/rep.db
# Redirect to a file the many expected messages from the election attempt.
set outfile $site1dir/bdbrep.out
execsql "pragma bdbsql_error_file='$outfile';"
# Try and fail to elect a new master without a quorum.
do_test replication-7.0.4 {
catchsql { select * from reptab order by a; } db
} {1 {unable to open database file}}
catch {db close}
## Cases 7.1.* test the error path for an unsuccessful insert on a client
## running alone, and that the master can rejoin the replication group and
## replication can resume afterwards.
setup_rep_sites
db eval "
pragma replication_local_site='$site1addr';
pragma replication_initial_master=ON;
pragma replication=ON;
create table reptab(a);
"
db2 eval "
pragma replication_local_site='$site2addr';
pragma replication_remote_site='$site1addr';
pragma replication=ON;
"
# Shut down master, client cannot take over as master.
catch {db close}
after $election_delay
# Try an unsuccessful write operation on the client.
do_test replication-7.1.1 {
catchsql {
insert into reptab values (999);
} db2
} {1 {attempt to write a readonly database}}
# Make sure a query on the client doesn't crash here.
do_test replication-7.1.2 {
execsql {
select * from reptab order by a;
} db2
} {}
# Restart master.
sqlite3 db $site1dir/rep.db
execsql {select * from reptab order by a;} db
after $election_delay
do_test replication-7.1.3 {
execsql {
insert into reptab values (1);
select * from reptab order by a;
} db
} {1}
after $replication_delay
do_test replication-7.1.4 {
execsql {
select * from reptab order by a;
} db2
} {1}
catch {db2 close}
catch {db close}
finish_test