Skip to content

Commit dfc4d65

Browse files
author
Shlomi Noach
authored
Merge pull request #185 from github/local-tests
WIP: Local tests
2 parents 56fd82a + b0a2e4c commit dfc4d65

File tree

8 files changed

+254
-0
lines changed

8 files changed

+254
-0
lines changed

doc/local-tests.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Local tests
2+
3+
`gh-ost` is continuously tested in production via `--test-on-replica alter='engine=innodb'`. These tests check the GitHub workload and usage, but not necessarily the general case.
4+
5+
Local tests are an additional layer of tests. They will eventually be part of continuous integration tests.
6+
7+
Local tests test explicit use cases, such as column renames, mix of time zones, special types and alters. Traits of a single test:
8+
9+
- Composed of a single table.
10+
- A single alter.
11+
- By default the alter is `engine=innodb`, but this can be overridden per-test
12+
- Scheduled DML operations, executed via `event_scheduler`.
13+
- `gh-ost` is set to execute and throttle for `5` seconds, at which time all tested DMLs are expected to operate.
14+
- The test requires a replication topology and utilizes `--test-on-replica`
15+
- The test checksums the two tables (original and _ghost_) and expects identical checksum
16+
- By default the test selects all (`*`) columns, but this can be overridden per-test
17+
18+
Tests are found under [localtests](https://github.com/github/gh-ost/tree/master/localtests). A single test is a subdirectory and tests are iterated alphabetically.
19+
20+
New data-integrity, synchronization issues or otherwise concerns are expected to be tested by new test cases.
21+
22+
While this is merged work is still ongoing.

localtests/enum/create.sql

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
drop table if exists gh_ost_test;
2+
create table gh_ost_test (
3+
id int auto_increment,
4+
i int not null,
5+
e enum('red', 'green', 'blue', 'orange') null default null collate 'utf8_bin',
6+
primary key(id)
7+
) auto_increment=1;
8+
9+
drop event if exists gh_ost_test;
10+
delimiter ;;
11+
create event gh_ost_test
12+
on schedule every 1 second
13+
starts current_timestamp
14+
ends current_timestamp + interval 60 second
15+
on completion not preserve
16+
enable
17+
do
18+
begin
19+
insert into gh_ost_test values (null, 11, 'red');
20+
insert into gh_ost_test values (null, 13, 'green');
21+
insert into gh_ost_test values (null, 17, 'blue');
22+
set @last_insert_id := last_insert_id();
23+
update gh_ost_test set e='orange' where id = @last_insert_id;
24+
insert into gh_ost_test values (null, 23, null);
25+
set @last_insert_id := last_insert_id();
26+
update gh_ost_test set i=i+1, e=null where id = @last_insert_id;
27+
end ;;

localtests/enum/extra_args

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--alter="change e e enum('red', 'green', 'blue', 'orange', 'yellow') null default null collate 'utf8_bin'"

localtests/rename/create.sql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
drop table if exists gh_ost_test;
2+
create table gh_ost_test (
3+
id int auto_increment,
4+
c1 int not null,
5+
c2 int not null,
6+
primary key (id)
7+
) auto_increment=1;
8+
9+
drop event if exists gh_ost_test;
10+
delimiter ;;
11+
create event gh_ost_test
12+
on schedule every 1 second
13+
starts current_timestamp
14+
ends current_timestamp + interval 60 second
15+
on completion not preserve
16+
enable
17+
do
18+
begin
19+
insert ignore into gh_ost_test values (1, 11, 23);
20+
insert ignore into gh_ost_test values (2, 13, 23);
21+
insert into gh_ost_test values (null, 17, 23);
22+
set @last_insert_id := last_insert_id();
23+
update gh_ost_test set c1=c1+@last_insert_id, c2=c2+@last_insert_id where id=@last_insert_id order by id desc limit 1;
24+
delete from gh_ost_test where id=1;
25+
delete from gh_ost_test where c1=13; -- id=2
26+
end ;;

localtests/rename/extra_args

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--alter="change column c2 c3 int not null" --approve-renamed-columns

localtests/test.sh

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/bin/bash
2+
3+
# Local integration tests. To be used by CI.
4+
# See https://github.com/github/gh-ost/tree/doc/local-tests.md
5+
#
6+
7+
tests_path=$(dirname $0)
8+
test_logfile=/tmp/gh-ost-test.log
9+
exec_command_file=/tmp/gh-ost-test.bash
10+
11+
master_host=
12+
master_port=
13+
replica_host=
14+
replica_port=
15+
16+
verify_master_and_replica() {
17+
if [ "$(gh-ost-test-mysql-master -e "select 1" -ss)" != "1" ] ; then
18+
echo "Cannot verify gh-ost-test-mysql-master"
19+
exit 1
20+
fi
21+
read master_host master_port <<< $(gh-ost-test-mysql-master -e "select @@hostname, @@port" -ss)
22+
if [ "$(gh-ost-test-mysql-replica -e "select 1" -ss)" != "1" ] ; then
23+
echo "Cannot verify gh-ost-test-mysql-replica"
24+
exit 1
25+
fi
26+
read replica_host replica_port <<< $(gh-ost-test-mysql-replica -e "select @@hostname, @@port" -ss)
27+
}
28+
29+
exec_cmd() {
30+
echo "$@"
31+
command "$@" 1> $test_logfile 2>&1
32+
return $?
33+
}
34+
35+
test_single() {
36+
local test_name
37+
test_name="$1"
38+
39+
echo "Testing: $test_name"
40+
41+
gh-ost-test-mysql-replica -e "start slave"
42+
gh-ost-test-mysql-master test < $tests_path/$test_name/create.sql
43+
44+
extra_args=""
45+
if [ -f $tests_path/$test_name/extra_args ] ; then
46+
extra_args=$(cat $tests_path/$test_name/extra_args)
47+
fi
48+
columns="*"
49+
if [ -f $tests_path/$test_name/test_columns ] ; then
50+
columns=$(cat $tests_path/$test_name/test_columns)
51+
fi
52+
# graceful sleep for replica to catch up
53+
sleep 1
54+
#
55+
cmd="go run go/cmd/gh-ost/main.go \
56+
--user=gh-ost \
57+
--password=gh-ost \
58+
--host=$replica_host \
59+
--port=$replica_port \
60+
--database=test \
61+
--table=gh_ost_test \
62+
--alter='engine=innodb' \
63+
--exact-rowcount \
64+
--switch-to-rbr \
65+
--initially-drop-old-table \
66+
--initially-drop-ghost-table \
67+
--throttle-query='select timestampdiff(second, min(last_update), now()) < 5 from _gh_ost_test_ghc' \
68+
--serve-socket-file=/tmp/gh-ost.test.sock \
69+
--initially-drop-socket-file \
70+
--postpone-cut-over-flag-file=/tmp/gh-ost.postpone.flag \
71+
--test-on-replica \
72+
--default-retries=1 \
73+
--verbose \
74+
--debug \
75+
--stack \
76+
--execute ${extra_args[@]}"
77+
echo $cmd > $exec_command_file
78+
bash $exec_command_file 1> $test_logfile 2>&1
79+
80+
if [ $? -ne 0 ] ; then
81+
echo "ERROR $test_name execution failure. See $test_logfile"
82+
return 1
83+
fi
84+
85+
orig_checksum=$(gh-ost-test-mysql-replica test -e "select ${columns} from gh_ost_test" -ss | md5sum)
86+
ghost_checksum=$(gh-ost-test-mysql-replica test -e "select ${columns} from _gh_ost_test_gho" -ss | md5sum)
87+
88+
if [ "$orig_checksum" != "$ghost_checksum" ] ; then
89+
echo "ERROR $test_name: checksum mismatch"
90+
echo "---"
91+
gh-ost-test-mysql-replica test -e "select ${columns} from gh_ost_test" -ss
92+
echo "---"
93+
gh-ost-test-mysql-replica test -e "select ${columns} from _gh_ost_test_gho" -ss
94+
return 1
95+
fi
96+
}
97+
98+
test_all() {
99+
find $tests_path ! -path . -type d -mindepth 1 -maxdepth 1 | cut -d "/" -f 3 | while read test_name ; do
100+
test_single "$test_name"
101+
if [ $? -ne 0 ] ; then
102+
echo "+ FAIL"
103+
return 1
104+
else
105+
echo "+ pass"
106+
fi
107+
gh-ost-test-mysql-replica -e "start slave"
108+
done
109+
}
110+
111+
verify_master_and_replica
112+
test_all

localtests/tz/create.sql

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
drop table if exists gh_ost_test;
2+
create table gh_ost_test (
3+
id int auto_increment,
4+
i int not null,
5+
ts0 timestamp default current_timestamp,
6+
ts1 timestamp,
7+
ts2 timestamp,
8+
updated tinyint unsigned default 0,
9+
primary key(id),
10+
key i_idx(i)
11+
) auto_increment=1;
12+
13+
drop event if exists gh_ost_test;
14+
delimiter ;;
15+
create event gh_ost_test
16+
on schedule every 1 second
17+
starts current_timestamp
18+
ends current_timestamp + interval 60 second
19+
on completion not preserve
20+
enable
21+
do
22+
begin
23+
insert into gh_ost_test values (null, 11, null, now(), now(), 0);
24+
update gh_ost_test set ts2=now() + interval 10 minute, updated = 1 where i = 11 order by id desc limit 1;
25+
26+
set session time_zone='system';
27+
insert into gh_ost_test values (null, 13, null, now(), now(), 0);
28+
update gh_ost_test set ts2=now() + interval 10 minute, updated = 1 where i = 13 order by id desc limit 1;
29+
30+
set session time_zone='+00:00';
31+
insert into gh_ost_test values (null, 17, null, now(), now(), 0);
32+
update gh_ost_test set ts2=now() + interval 10 minute, updated = 1 where i = 17 order by id desc limit 1;
33+
34+
set session time_zone='-03:00';
35+
insert into gh_ost_test values (null, 19, null, now(), now(), 0);
36+
update gh_ost_test set ts2=now() + interval 10 minute, updated = 1 where i = 19 order by id desc limit 1;
37+
38+
set session time_zone='+05:00';
39+
insert into gh_ost_test values (null, 23, null, now(), now(), 0);
40+
update gh_ost_test set ts2=now() + interval 10 minute, updated = 1 where i = 23 order by id desc limit 1;
41+
end ;;

localtests/unsigned/create.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
drop table if exists gh_ost_test;
2+
create table gh_ost_test (
3+
id int auto_increment,
4+
i int not null,
5+
bi bigint not null,
6+
iu int unsigned not null,
7+
biu bigint unsigned not null,
8+
primary key(id)
9+
) auto_increment=1;
10+
11+
drop event if exists gh_ost_test;
12+
delimiter ;;
13+
create event gh_ost_test
14+
on schedule every 1 second
15+
starts current_timestamp
16+
ends current_timestamp + interval 60 second
17+
on completion not preserve
18+
enable
19+
do
20+
begin
21+
insert into gh_ost_test values (null, -2147483647, -9223372036854775807, 4294967295, 18446744073709551615);
22+
set @last_insert_id := cast(last_insert_id() as signed);
23+
update gh_ost_test set i=-2147483647+@last_insert_id, bi=-9223372036854775807+@last_insert_id, iu=4294967295-@last_insert_id, biu=18446744073709551615-@last_insert_id where id < @last_insert_id order by id desc limit 1;
24+
end ;;

0 commit comments

Comments
 (0)