github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/tests/validator_basic/run.sh (about)

     1  #!/bin/bash
     2  
     3  set -eu
     4  
     5  cur=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
     6  source $cur/../_utils/test_prepare
     7  WORK_DIR=$TEST_DIR/$TEST_NAME
     8  
     9  db_name=$TEST_NAME
    10  
    11  function get_gtid_executed() {
    12  	gtid_executed=$(echo "show master status;" | MYSQL_PWD=123456 mysql -uroot -h$1 -P$2 | awk 'FNR == 2 {print $3}')
    13  	echo $gtid_executed
    14  }
    15  
    16  function prepare_dm_and_source() {
    17  	cleanup_process $*
    18  	cleanup_data $db_name
    19  	cleanup_data_upstream $db_name
    20  
    21  	run_sql_file $cur/data/db1.prepare.sql $MYSQL_HOST1 $MYSQL_PORT1 $MYSQL_PASSWORD1
    22  
    23  	run_dm_master $WORK_DIR/master $MASTER_PORT $cur/conf/dm-master.toml
    24  	check_rpc_alive $cur/../bin/check_master_online 127.0.0.1:$MASTER_PORT
    25  
    26  	run_dm_worker $WORK_DIR/worker1 $WORKER1_PORT $cur/conf/dm-worker1.toml
    27  	check_rpc_alive $cur/../bin/check_worker_online 127.0.0.1:$WORKER1_PORT
    28  	# source 1 should be bound to worker 1
    29  	dmctl_operate_source create $cur/conf/source1.yaml $SOURCE_ID1
    30  
    31  	run_dm_worker $WORK_DIR/worker2 $WORKER2_PORT $cur/conf/dm-worker2.toml
    32  	check_rpc_alive $cur/../bin/check_worker_online 127.0.0.1:$WORKER2_PORT
    33  }
    34  
    35  function prepare_for_standalone_test() {
    36  	prepare_dm_and_source
    37  	dmctl_start_task_standalone $cur/conf/dm-task-standalone.yaml --remove-meta
    38  
    39  	# sync-diff seems cannot handle float/double well, will skip it here
    40  }
    41  
    42  function trigger_checkpoint_flush() {
    43  	sleep 1.5
    44  	run_sql_source1 "alter table $db_name.t1 comment 'a';" # force flush checkpoint
    45  }
    46  
    47  function restore_timezone() {
    48  	echo "restore time_zone"
    49  	run_sql_source1 "set global time_zone = SYSTEM"
    50  	run_sql_tidb "set global time_zone = SYSTEM"
    51  }
    52  
    53  function restore_on_case_exit() {
    54  	echo "restore config"
    55  	mv $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
    56  	mv $cur/conf/source1.yaml.bak $cur/conf/source1.yaml
    57  
    58  	restore_timezone
    59  }
    60  
    61  function test_validator_together_with_task() {
    62  	enable_gtid=$1
    63  	enable_relay=$2
    64  	# clear fail point
    65  	export GO_FAILPOINTS=""
    66  	echo "--> full mode, check we validate different data types(gtid=$enable_gtid, relay=$enable_relay)"
    67  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
    68  	cp $cur/conf/source1.yaml.bak $cur/conf/source1.yaml
    69  	sed -i 's/enable-gtid: false/enable-gtid: '$enable_gtid'/g' $cur/conf/source1.yaml
    70  	sed -i 's/enable-relay: false/enable-relay: '$enable_relay'/g' $cur/conf/source1.yaml
    71  	prepare_for_standalone_test
    72  	# key=6, mysql store as 1.2345679e+17, but in tidb it's 1.23457e17
    73  	# so will fail in current compare rule
    74  	# note: key=1 has the same condition, but it's not validated, since it's migrated in full phase.
    75  	run_sql_file $cur/data/db1.increment.sql $MYSQL_HOST1 $MYSQL_PORT1 $MYSQL_PASSWORD1
    76  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
    77  		"config source $SOURCE_ID1" \
    78  		"enable-gtid: $enable_gtid" 1 \
    79  		"enable-relay: $enable_relay" 1
    80  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
    81  		"validation status test" \
    82  		"\"processedRowsStatus\": \"insert\/update\/delete: 6\/1\/1\"" 1 \
    83  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
    84  		"new\/ignored\/resolved: 1\/0\/0" 1
    85  	run_sql_tidb "SELECT count(*) from $db_name.t1_down"
    86  	check_contains "count(*): 6"
    87  }
    88  
    89  function test_start_validator_on_the_fly_prepare() {
    90  	enable_gtid=$1
    91  	enable_relay=$2
    92  	# clear fail point
    93  	export GO_FAILPOINTS=""
    94  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
    95  	cp $cur/conf/source1.yaml.bak $cur/conf/source1.yaml
    96  	sed -i 's/enable-gtid: false/enable-gtid: '$enable_gtid'/g' $cur/conf/source1.yaml
    97  	sed -i 's/enable-relay: false/enable-relay: '$enable_relay'/g' $cur/conf/source1.yaml
    98  	run_sql_source1 "flush binary logs"
    99  	sleep 1
   100  	run_sql_source1 "purge binary logs before now()"
   101  	prepare_dm_and_source
   102  	dmctl_start_task_standalone $cur/conf/dm-task-standalone-no-validator.yaml --remove-meta
   103  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   104  		"config source $SOURCE_ID1" \
   105  		"enable-gtid: $enable_gtid" 1 \
   106  		"enable-relay: $enable_relay" 1
   107  	run_sql_source1 "insert into $db_name.t1(id, name) values(2,'b'), (3, 'c')"
   108  	run_sql_source1 "delete from $db_name.t1 where id=1"
   109  	trigger_checkpoint_flush
   110  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   111  		"query-status test" \
   112  		"\"synced\": true" 1
   113  	check_sync_diff $WORK_DIR $cur/conf/diff_config.toml
   114  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   115  		"validation status test" \
   116  		"validator not found for task" 1
   117  }
   118  
   119  function test_start_validator_on_the_fly() {
   120  	enable_gtid=$1
   121  	enable_relay=$2
   122  	echo "--> start validator on the fly, validate from current syncer progress(gtid=$enable_gtid, relay=$enable_relay)"
   123  	test_start_validator_on_the_fly_prepare $enable_gtid $enable_relay
   124  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   125  		"validation start test" \
   126  		"\"result\": true" 1
   127  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   128  		"validation status test" \
   129  		"\"processedRowsStatus\": \"insert\/update\/delete: 0\/0\/0\"" 1
   130  	run_sql_source1 "insert into $db_name.t1(id, name) values(4,'d'), (5, 'e')"
   131  	run_sql_source1 "update $db_name.t1 set name='bb' where id=2"
   132  	run_sql_source1 "delete from $db_name.t1 where id=3"
   133  	trigger_checkpoint_flush
   134  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   135  		"validation status test" \
   136  		"\"processedRowsStatus\": \"insert\/update\/delete: 2\/1\/1\"" 1 \
   137  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   138  		"new\/ignored\/resolved: 0\/0\/0" 1
   139  	check_sync_diff $WORK_DIR $cur/conf/diff_config.toml
   140  }
   141  
   142  function test_start_validator_with_time_smaller_than_min_binlog_pos() {
   143  	enable_gtid=$1
   144  	echo "--> start validator from time < min mysql binlog pos(gtid=$enable_gtid)"
   145  	test_start_validator_on_the_fly_prepare $enable_gtid false
   146  	run_sql_source1 "insert into $db_name.t1(id, name) values(4,'d'), (5, 'e')"
   147  	run_sql_source1 "update $db_name.t1 set name='bb' where id=2"
   148  	run_sql_source1 "delete from $db_name.t1 where id=3"
   149  	trigger_checkpoint_flush
   150  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   151  		"query-status test" \
   152  		"\"synced\": true" 1
   153  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   154  		"validation start --start-time '$(($(date "+%Y") - 2))-01-01 00:00:00' test" \
   155  		"\"result\": true" 1
   156  	trigger_checkpoint_flush
   157  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   158  		"validation status test" \
   159  		"\"processedRowsStatus\": \"insert\/update\/delete: 5\/1\/2\"" 1 \
   160  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   161  		"new\/ignored\/resolved: 0\/0\/0" 1
   162  	check_sync_diff $WORK_DIR $cur/conf/diff_config.toml
   163  }
   164  
   165  function test_start_validator_with_time_in_range_of_binlog_pos() {
   166  	enable_gtid=$1
   167  	echo "--> start validator from time which is in range of mysql binlog(gtid=$enable_gtid)"
   168  	test_start_validator_on_the_fly_prepare $enable_gtid false
   169  	run_sql_source1 "insert into $db_name.t1(id, name) values(4,'d'), (5, 'e')"
   170  	run_sql_source1 "update $db_name.t1 set name='bb' where id=2"
   171  	run_sql_source1 "delete from $db_name.t1 where id=3"
   172  	run_sql_source1 "insert into $db_name.t1(id, name) values(100,'d'), (101, 'e')"
   173  	sleep 2
   174  	start_time="$(TZ='UTC-2' date '+%Y-%m-%d %T')" # TZ=UTC-2 means +02:00
   175  	run_sql_source1 "insert into $db_name.t1(id, name) values(200,'d'), (201, 'e')"
   176  	run_sql_source1 "delete from $db_name.t1 where id=200"
   177  	run_sql_source1 "update $db_name.t1 set name='dd' where id=100"
   178  	run_sql_source1 "insert into $db_name.t1(id, name) values(300,'d')"
   179  	run_sql_source1 "update $db_name.t1 set name='ee' where id=101"
   180  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   181  		"validation start --start-time '$start_time' test" \
   182  		"\"result\": true" 1
   183  	trigger_checkpoint_flush
   184  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   185  		"validation status test" \
   186  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/2\/1\"" 1 \
   187  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   188  		"new\/ignored\/resolved: 0\/0\/0" 1
   189  	check_sync_diff $WORK_DIR $cur/conf/diff_config.toml
   190  }
   191  
   192  function run_standalone() {
   193  	#
   194  	# we have set row-error-delay and meta-flush-interval small enough for cases below,
   195  	# but it maybe unstable if validator reached progress of syncer before the last ddl,
   196  	# and then validator start to mark failed rows as error. So we may have more errors
   197  	# than expected.
   198  	#
   199  
   200  	# backup it, will change it in the following case
   201  	cp $cur/conf/dm-task-standalone.yaml $cur/conf/dm-task-standalone.yaml.bak
   202  	cp $cur/conf/source1.yaml $cur/conf/source1.yaml.bak
   203  
   204  	trap restore_on_case_exit EXIT
   205  
   206  	# use different timezone for upstream and tidb
   207  	run_sql_source1 "set global time_zone = '+02:00'"
   208  	run_sql_source1 "SELECT cast(TIMEDIFF(NOW(6), UTC_TIMESTAMP(6)) as time) time"
   209  	check_contains "time: 02:00:00"
   210  	run_sql_tidb "set global time_zone = '+06:00'"
   211  	run_sql_tidb "SELECT cast(TIMEDIFF(NOW(6), UTC_TIMESTAMP(6)) as time) time"
   212  	check_contains "time: 06:00:00"
   213  
   214  	# validator is started together with task
   215  	test_validator_together_with_task false false
   216  	test_validator_together_with_task false true
   217  	test_validator_together_with_task true false
   218  	test_validator_together_with_task true true
   219  
   220  	echo "--> fast mode, check we validate different data types"
   221  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
   222  	sed -i 's/    mode: full/    mode: fast/' $cur/conf/dm-task-standalone.yaml
   223  	prepare_for_standalone_test
   224  	# in fast mode we don't check col by col, so key=6 will pass
   225  	run_sql_file $cur/data/db1.increment.sql $MYSQL_HOST1 $MYSQL_PORT1 $MYSQL_PASSWORD1
   226  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   227  		"validation status test" \
   228  		"\"processedRowsStatus\": \"insert\/update\/delete: 6\/1\/1\"" 1 \
   229  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   230  		"new\/ignored\/resolved: 0\/0\/0" 1
   231  	run_sql_tidb "SELECT count(*) from $db_name.t1_down"
   232  	check_contains "count(*): 6"
   233  
   234  	echo "--> check we can catch inconsistent rows: full mode"
   235  	# skip incremental rows with id <= 5
   236  	export GO_FAILPOINTS='github.com/pingcap/tiflow/dm/syncer/SkipDML=return(5)'
   237  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
   238  	prepare_for_standalone_test
   239  	run_sql_file $cur/data/db1.increment.sql $MYSQL_HOST1 $MYSQL_PORT1 $MYSQL_PASSWORD1
   240  	# 6 inconsistent rows:
   241  	# insert of id = 3, 4, 5 are skipped.
   242  	# insert & update of id = 2 are merged and skipped
   243  	# delete of id = 1 are skipped
   244  	# id = 6, float precision problem, so inconsistent
   245  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   246  		"validation status test" \
   247  		"\"processedRowsStatus\": \"insert\/update\/delete: 6\/1\/1\"" 1 \
   248  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   249  		"new\/ignored\/resolved: 6\/0\/0" 1
   250  	run_sql_tidb "SELECT count(*) from $db_name.t1_down"
   251  	check_contains "count(*): 3"
   252  
   253  	echo "--> check we can catch inconsistent rows: fast mode"
   254  	# skip incremental rows with id <= 5
   255  	export GO_FAILPOINTS='github.com/pingcap/tiflow/dm/syncer/SkipDML=return(5)'
   256  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
   257  	sed -i 's/    mode: full/    mode: fast/' $cur/conf/dm-task-standalone.yaml
   258  	prepare_for_standalone_test
   259  	run_sql_file $cur/data/db1.increment.sql $MYSQL_HOST1 $MYSQL_PORT1 $MYSQL_PASSWORD1
   260  	# 5 inconsistent rows, nearly same as previous test, but id = 6 success in fast mode
   261  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   262  		"validation status test" \
   263  		"\"processedRowsStatus\": \"insert\/update\/delete: 6\/1\/1\"" 1 \
   264  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   265  		"new\/ignored\/resolved: 5\/0\/0" 1
   266  	run_sql_tidb "SELECT count(*) from $db_name.t1_down"
   267  	check_contains "count(*): 3"
   268  
   269  	echo "--> check update pk(split into insert and delete)"
   270  	run_sql_source1 "update $db_name.t1 set id=100 where id=7"
   271  	trigger_checkpoint_flush
   272  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   273  		"validation status test" \
   274  		"\"processedRowsStatus\": \"insert\/update\/delete: 7\/1\/2\"" 1 \
   275  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   276  		"new\/ignored\/resolved: 5\/0\/0" 1
   277  	run_sql_tidb "SELECT count(*) from $db_name.t1_down"
   278  	check_contains "count(*): 3"
   279  
   280  	echo "--> check validator panic and we can catch it"
   281  	export GO_FAILPOINTS='github.com/pingcap/tiflow/dm/syncer/ValidatorPanic=panic("validator panic")'
   282  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
   283  	prepare_for_standalone_test
   284  	run_sql_file $cur/data/db1.increment.sql $MYSQL_HOST1 $MYSQL_PORT1 $MYSQL_PASSWORD1
   285  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   286  		"validation status test" \
   287  		"validator panic" 1
   288  
   289  	echo "--> check validator worker panic and we can catch it"
   290  	# panic 1 times
   291  	export GO_FAILPOINTS='github.com/pingcap/tiflow/dm/syncer/ValidatorWorkerPanic=1*panic("validator worker panic")'
   292  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
   293  	prepare_for_standalone_test
   294  	run_sql_file $cur/data/db1.increment.sql $MYSQL_HOST1 $MYSQL_PORT1 $MYSQL_PASSWORD1
   295  	sleep 5
   296  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   297  		"validation status test" \
   298  		"validator worker panic" 1
   299  
   300  	# in real world panic, we cannot restart just like this, this case only makes sure worker panic doesn't
   301  	# mess status of validator up
   302  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   303  		"validation start test" \
   304  		"\"result\": true" 1
   305  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   306  		"validation status test" \
   307  		"\"processedRowsStatus\": \"insert\/update\/delete: 6\/1\/1\"" 1 \
   308  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   309  		"new\/ignored\/resolved: 1\/0\/0" 1
   310  	run_sql_tidb "SELECT count(*) from $db_name.t1_down"
   311  	check_contains "count(*): 6"
   312  
   313  	echo "--> check validator stop when pending row size too large"
   314  	# skip incremental rows with id <= 5
   315  	export GO_FAILPOINTS='github.com/pingcap/tiflow/dm/syncer/SkipDML=return(5)'
   316  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
   317  	sed -i 's/row-error-delay: .*$/row-error-delay: 30m/' $cur/conf/dm-task-standalone.yaml
   318  	sed -i 's/max-pending-row-size: .*$/max-pending-row-size: 20/' $cur/conf/dm-task-standalone.yaml
   319  	prepare_for_standalone_test
   320  	run_sql_source1 "create table $db_name.t1_large_col(id int primary key, c varchar(100))"
   321  	run_sql_source1 "insert into $db_name.t1_large_col values(1, 'this-text-is-more-than-20-bytes')"
   322  	trigger_checkpoint_flush
   323  	# since multiple worker may send this error, there should be at least one "too much pending data" error
   324  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   325  		"validation status test" \
   326  		"\"stage\": \"Stopped\"" 1 \
   327  		"too much pending data, stop validator" 1+ \
   328  		"\"processedRowsStatus\": \"insert\/update\/delete: 1\/0\/0\"" 1 \
   329  		"pendingRowsStatus\": \"insert\/update\/delete: 1\/0\/0" 1 \
   330  		"new\/ignored\/resolved: 0\/0\/0" 1
   331  
   332  	echo "--> check validator stop when pending row count too many"
   333  	# skip incremental rows with id <= 5
   334  	export GO_FAILPOINTS='github.com/pingcap/tiflow/dm/syncer/SkipDML=return(5)'
   335  	cp $cur/conf/dm-task-standalone.yaml.bak $cur/conf/dm-task-standalone.yaml
   336  	sed -i 's/row-error-delay: .*$/row-error-delay: 30m/' $cur/conf/dm-task-standalone.yaml
   337  	sed -i 's/max-pending-row-count: .*$/max-pending-row-count: 2/' $cur/conf/dm-task-standalone.yaml
   338  	prepare_for_standalone_test
   339  	run_sql_source1 "create table $db_name.t1_large_col(id int primary key)"
   340  	run_sql_source1 "insert into $db_name.t1_large_col values(1)"
   341  	run_sql_source1 "insert into $db_name.t1_large_col values(2)"
   342  	run_sql_source1 "insert into $db_name.t1_large_col values(3)"
   343  	trigger_checkpoint_flush
   344  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   345  		"validation status test" \
   346  		"\"stage\": \"Stopped\"" 1 \
   347  		"too much pending data, stop validator" 1+ \
   348  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/0\/0\"" 1 \
   349  		"pendingRowsStatus\": \"insert\/update\/delete: 3\/0\/0" 1 \
   350  		"new\/ignored\/resolved: 0\/0\/0" 1
   351  
   352  	test_start_validator_on_the_fly false false
   353  	test_start_validator_on_the_fly false true
   354  	test_start_validator_on_the_fly true false
   355  	test_start_validator_on_the_fly true true
   356  
   357  	test_start_validator_with_time_smaller_than_min_binlog_pos false
   358  	test_start_validator_with_time_smaller_than_min_binlog_pos true
   359  
   360  	test_start_validator_with_time_in_range_of_binlog_pos false
   361  	test_start_validator_with_time_in_range_of_binlog_pos true
   362  
   363  	echo "--> start validator from time > max mysql binlog pos"
   364  	test_start_validator_on_the_fly_prepare false false
   365  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   366  		"validation start --start-time '$(($(date "+%Y") + 2))-01-01 00:00:00' test" \
   367  		"\"result\": true" 1
   368  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   369  		"validation status test" \
   370  		"is too late, no binlog location matches it" 1 \
   371  		"\"stage\": \"Stopped\"" 1 \
   372  		"\"processedRowsStatus\": \"insert\/update\/delete: 0\/0\/0\"" 1 \
   373  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   374  		"new\/ignored\/resolved: 0\/0\/0" 1
   375  }
   376  
   377  function validate_table_with_different_pk() {
   378  	export GO_FAILPOINTS=""
   379  
   380  	# int type uk already tested in run_standalone, so not test it here
   381  	echo "--> single varchar col pk"
   382  	prepare_for_standalone_test
   383  	run_sql_source1 "create table $db_name.t2(c1 varchar(10) primary key, c2 varchar(10))"
   384  	run_sql_source1 "insert into $db_name.t2 values('a', NULL), ('b', 'b'), ('c', 'c')"
   385  	run_sql_source1 "update $db_name.t2 set c2='bb' where c1='b'"
   386  	run_sql_source1 "update $db_name.t2 set c2='cc' where c1='c'"
   387  	run_sql_source1 "delete from $db_name.t2 where c1='a'"
   388  	trigger_checkpoint_flush
   389  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   390  		"validation status test" \
   391  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/2\/1\"" 1 \
   392  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   393  		"new\/ignored\/resolved: 0\/0\/0" 1
   394  	run_sql_tidb "SELECT count(*) from $db_name.t2"
   395  	check_contains "count(*): 2"
   396  
   397  	echo "--> single datetime col pk"
   398  	prepare_for_standalone_test
   399  	run_sql_source1 "create table $db_name.t2(c1 datetime primary key, c2 varchar(10))"
   400  	run_sql_source1 "insert into $db_name.t2 values('2022-01-01 00:00:00', NULL), ('2022-01-01 00:00:01', 'b'), ('2022-01-01 00:00:02', 'c')"
   401  	run_sql_source1 "update $db_name.t2 set c2='bb' where c1='2022-01-01 00:00:01'"
   402  	run_sql_source1 "update $db_name.t2 set c2='cc' where c1='2022-01-01 00:00:02'"
   403  	run_sql_source1 "delete from $db_name.t2 where c1='2022-01-01 00:00:00'"
   404  	trigger_checkpoint_flush
   405  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   406  		"validation status test" \
   407  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/2\/1\"" 1 \
   408  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   409  		"new\/ignored\/resolved: 0\/0\/0" 1
   410  	run_sql_tidb "SELECT count(*) from $db_name.t2"
   411  	check_contains "count(*): 2"
   412  
   413  	echo "--> compound pk (datetime, timestamp, int, varchar)"
   414  	prepare_for_standalone_test
   415  	run_sql_source1 "create table $db_name.t2(c1 datetime, c2 timestamp DEFAULT CURRENT_TIMESTAMP, c3 int, c4 varchar(10), c5 int, primary key(c1, c2, c3, c4))"
   416  	run_sql_source1 "insert into $db_name.t2 values('2022-01-01 00:00:00', '2022-01-01 00:00:00', 1, 'a', 1)"
   417  	run_sql_source1 "insert into $db_name.t2 values('2022-01-01 00:00:00', '2022-01-01 00:00:00', 1, 'b', 2)"
   418  	run_sql_source1 "insert into $db_name.t2 values('2022-01-01 00:00:00', '2012-12-01 00:00:00', 1, 'a', 3)"
   419  	run_sql_source1 "insert into $db_name.t2 values('2012-12-01 00:00:00', '2022-01-01 00:00:00', 1, 'a', 4)"
   420  	run_sql_source1 "update $db_name.t2 set c5=11 where c1='2022-01-01 00:00:00'" # update 3 rows
   421  	run_sql_source1 "update $db_name.t2 set c5=22 where c2='2012-12-01 00:00:00'" # update 1 row
   422  	run_sql_source1 "delete from $db_name.t2 where c4='a'"                        # delete 3 row
   423  	trigger_checkpoint_flush
   424  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   425  		"validation status test" \
   426  		"\"processedRowsStatus\": \"insert\/update\/delete: 4\/4\/3\"" 1 \
   427  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   428  		"new\/ignored\/resolved: 0\/0\/0" 1
   429  	run_sql_tidb "SELECT count(*) from $db_name.t2"
   430  	check_contains "count(*): 1"
   431  }
   432  
   433  function test_unsupported_table_status() {
   434  	export GO_FAILPOINTS=""
   435  
   436  	echo "--> table without primary key"
   437  	prepare_for_standalone_test
   438  	run_sql_source1 "create table $db_name.t2(c1 int)"
   439  	run_sql_source1 "insert into $db_name.t2 values(1)"
   440  	trigger_checkpoint_flush
   441  	# skipped row is not add to processed rows
   442  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   443  		"validation status test" \
   444  		"\"processedRowsStatus\": \"insert\/update\/delete: 0\/0\/0\"" 1 \
   445  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   446  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   447  		"\"stage\": \"Running\"" 1 \
   448  		"\"stage\": \"Stopped\"" 1 \
   449  		"no primary key" 1
   450  	run_sql_tidb "SELECT count(*) from $db_name.t2"
   451  	check_contains "count(*): 1"
   452  
   453  	echo "--> table is deleted on downstream"
   454  	prepare_dm_and_source
   455  	run_sql_source1 "reset master"
   456  	dmctl_start_task_standalone $cur/conf/dm-task-standalone-no-validator.yaml --remove-meta
   457  	run_sql_source1 "create table $db_name.t2(c1 int primary key, c2 int, c3 int)"
   458  	run_sql_source1 "insert into $db_name.t2 values(1, 1, 1)"
   459  	run_sql_source1 "insert into $db_name.t2 values(2, 2, 2)"
   460  	run_sql_source1 "drop table $db_name.t2"
   461  	trigger_checkpoint_flush
   462  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   463  		"query-status test" \
   464  		"\"synced\": true" 1
   465  	run_sql_tidb "select count(*) from information_schema.tables where TABLE_SCHEMA='${db_name}' and TABLE_NAME = 't2'"
   466  	check_contains "count(*): 0"
   467  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   468  		"validation start --start-time '$(($(date "+%Y") - 2))-01-01 00:00:00' test" \
   469  		"\"result\": true" 1
   470  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   471  		"validation status test" \
   472  		"\"processedRowsStatus\": \"insert\/update\/delete: 0\/0\/0\"" 1 \
   473  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   474  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   475  		"\"stage\": \"Running\"" 1 \
   476  		"\"stage\": \"Stopped\"" 1 \
   477  		"table is not synced or dropped" 1
   478  
   479  	echo "--> table in schema-tracker has less column than binlog"
   480  	prepare_dm_and_source
   481  	run_sql_source1 "reset master"
   482  	dmctl_start_task_standalone $cur/conf/dm-task-standalone-no-validator.yaml --remove-meta
   483  	run_sql_source1 "create table $db_name.t2(c1 int primary key, c2 int, c3 int)"
   484  	run_sql_source1 "insert into $db_name.t2 values(1, 1, 1)"
   485  	run_sql_source1 "alter table $db_name.t2 drop column c3"
   486  	run_sql_source1 "insert into $db_name.t2 values(2, 2)"
   487  	trigger_checkpoint_flush
   488  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   489  		"query-status test" \
   490  		"\"synced\": true" 1
   491  	run_sql_tidb "SELECT count(*) from $db_name.t2"
   492  	check_contains "count(*): 2"
   493  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   494  		"validation start --start-time '$(($(date "+%Y") - 2))-01-01 00:00:00' test" \
   495  		"\"result\": true" 1
   496  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   497  		"validation status test" \
   498  		"\"processedRowsStatus\": \"insert\/update\/delete: 0\/0\/0\"" 1 \
   499  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   500  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   501  		"\"stage\": \"Running\"" 1 \
   502  		"\"stage\": \"Stopped\"" 1 \
   503  		"binlog has more columns than current table" 1
   504  
   505  	echo "--> pk column of downstream table not in range of binlog column"
   506  	prepare_dm_and_source
   507  	run_sql_source1 "reset master"
   508  	dmctl_start_task_standalone $cur/conf/dm-task-standalone-no-validator.yaml --remove-meta
   509  	run_sql_source1 "create table $db_name.t2(c1 int)"
   510  	run_sql_source1 "insert into $db_name.t2 values(1)"
   511  	run_sql_source1 "alter table $db_name.t2 add column c2 int default 1"
   512  	run_sql_source1 "alter table $db_name.t2 add primary key(c2)"
   513  	run_sql_source1 "insert into $db_name.t2 values(2, 2)"
   514  	trigger_checkpoint_flush
   515  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   516  		"query-status test" \
   517  		"\"synced\": true" 1
   518  	run_sql_tidb "SELECT count(*) from $db_name.t2"
   519  	check_contains "count(*): 2"
   520  	run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   521  		"validation start --start-time '$(($(date "+%Y") - 2))-01-01 00:00:00' test" \
   522  		"\"result\": true" 1
   523  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   524  		"validation status test" \
   525  		"\"processedRowsStatus\": \"insert\/update\/delete: 0\/0\/0\"" 1 \
   526  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   527  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   528  		"\"stage\": \"Running\"" 1 \
   529  		"\"stage\": \"Stopped\"" 1 \
   530  		"primary key column of downstream table out of range of binlog event row" 1
   531  }
   532  
   533  function stopped_validator_fail_over() {
   534  	export GO_FAILPOINTS=""
   535  
   536  	echo "--> stopped validator fail over"
   537  	# skip incremental rows with c1 <= 1
   538  	export GO_FAILPOINTS='github.com/pingcap/tiflow/dm/syncer/SkipDML=return(1)'
   539  	prepare_for_standalone_test
   540  	run_sql_source1 "create table $db_name.t2(c1 int primary key, c2 int)"
   541  	run_sql_source1 "insert into $db_name.t2 values(1, 1), (2, 2), (3, 3)"
   542  	run_sql_source1 "update $db_name.t2 set c2=11 where c2=1"
   543  	run_sql_source1 "update $db_name.t2 set c2=22 where c2=2"
   544  	run_sql_source1 "delete from $db_name.t2 where c1=3"
   545  	trigger_checkpoint_flush
   546  	# skipped row is not add to processed rows
   547  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   548  		"validation status test" \
   549  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/2\/1\"" 1 \
   550  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   551  		"new\/ignored\/resolved: 1\/0\/0" 1 \
   552  		"\"stage\": \"Running\"" 2
   553  	# make sure validator checkpoint is flushed
   554  	sleep 1 # wait for the min flush interval
   555  	trigger_checkpoint_flush
   556  	run_sql_tidb_with_retry "select concat_ws('/', procd_ins, procd_upd, procd_del) processed
   557  														from dm_meta.test_validator_checkpoint where source='mysql-replica-01'" \
   558  		"processed: 3/2/1"
   559  	run_sql_tidb_with_retry "select count(1) cnt
   560  														from dm_meta.test_validator_error_change where source='mysql-replica-01'" \
   561  		"cnt: 1"
   562  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   563  		"validation stop test" \
   564  		"\"result\": true" 1
   565  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   566  		"validation status test" \
   567  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/2\/1\"" 1 \
   568  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   569  		"new\/ignored\/resolved: 1\/0\/0" 1 \
   570  		"\"stage\": \"Running\"" 1 \
   571  		"\"stage\": \"Stopped\"" 1
   572  	# source1 is bound to worker1, so source1 will be bound to worker2. see prepare_dm_and_source
   573  	kill_process worker1
   574  	# stopped task fail over, processed row status and table status is not loaded into memory, so they're zero
   575  	# but we can see errors, since it's loaded from db all the time
   576  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   577  		"validation status test" \
   578  		"\"processedRowsStatus\": \"insert\/update\/delete: 0\/0\/0\"" 1 \
   579  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   580  		"new\/ignored\/resolved: 1\/0\/0" 1 \
   581  		"\"stage\": \"Running\"" 0 \
   582  		"\"stage\": \"Stopped\"" 1
   583  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   584  		"validation show-error --error all test" \
   585  		"\"result\": true" 1 \
   586  		"\"id\": \"1\"" 1
   587  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   588  		"validation start test" \
   589  		"\"result\": true" 1
   590  	run_sql_source1 "insert into $db_name.t2 values(4, 4), (5, 5), (6, 6)"
   591  	run_sql_source1 "update $db_name.t2 set c2=55 where c2=5"
   592  	trigger_checkpoint_flush
   593  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   594  		"validation status test" \
   595  		"\"processedRowsStatus\": \"insert\/update\/delete: 6\/3\/1\"" 1 \
   596  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   597  		"new\/ignored\/resolved: 1\/0\/0" 1 \
   598  		"\"stage\": \"Running\"" 2
   599  }
   600  
   601  # some events are filtered in syncer, validator should filter them too.
   602  # validator only support below 3 filter.
   603  function test_data_filter() {
   604  	export GO_FAILPOINTS=""
   605  
   606  	echo "--> filter online ddl shadow table"
   607  	prepare_dm_and_source
   608  	dmctl_start_task_standalone $cur/conf/test-filter.yaml --remove-meta
   609  	run_sql_source1 "create table $db_name.t2(id int primary key)"
   610  	run_sql_source1 "insert into $db_name.t2 values(1), (2), (3)"
   611  	run_sql_source1 "create table $db_name._t_gho(id int primary key)"
   612  	run_sql_source1 "insert into $db_name._t_gho values(1), (2), (3)"
   613  	trigger_checkpoint_flush
   614  	# skipped table has no table status, so number of running = 2
   615  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   616  		"validation status test" \
   617  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/0\/0\"" 1 \
   618  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   619  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   620  		"\"stage\": \"Running\"" 2
   621  
   622  	echo "--> filter by ba list"
   623  	run_sql_source1 "create table $db_name.x1(id int primary key)"
   624  	run_sql_source1 "insert into $db_name.x1 values(1), (2), (3)"
   625  	trigger_checkpoint_flush
   626  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   627  		"query-status test" \
   628  		"\"synced\": true" 1
   629  	# skipped table has no table status, so number of running is still 2
   630  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   631  		"validation status test" \
   632  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/0\/0\"" 1 \
   633  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   634  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   635  		"\"stage\": \"Running\"" 2
   636  
   637  	echo "--> filter by filter-rules"
   638  	run_sql_source1 "create table $db_name.t_filter_del(id int primary key, val int)"
   639  	run_sql_source1 "insert into $db_name.t_filter_del values(1, 1), (2, 2), (3, 3), (4, 4)"
   640  	run_sql_source1 "update $db_name.t_filter_del set val=11 where id=1"
   641  	run_sql_source1 "update $db_name.t_filter_del set val=22 where id=2"
   642  	run_sql_source1 "delete from $db_name.t_filter_del where id in (1, 2, 3)"
   643  	trigger_checkpoint_flush
   644  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   645  		"query-status test" \
   646  		"\"synced\": true" 1
   647  	run_sql_tidb "SELECT count(*) from $db_name.t_filter_del"
   648  	check_contains "count(*): 4"
   649  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   650  		"validation status test" \
   651  		"\"processedRowsStatus\": \"insert\/update\/delete: 7\/2\/0\"" 1 \
   652  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   653  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   654  		"\"stage\": \"Running\"" 3
   655  }
   656  
   657  function test_validation_syncer_stopped() {
   658  	echo "--> validate when syncer is stopped"
   659  	insertCnt=5
   660  	export GO_FAILPOINTS="github.com/pingcap/tiflow/dm/syncer/mockValidatorDelay=return(2)"
   661  	prepare_for_standalone_test
   662  	run_sql_source1 "create table validator_basic.test(a int primary key, b int)"
   663  	run_sql_source1 "insert into validator_basic.test values(0, 0)"
   664  	trigger_checkpoint_flush
   665  	# wait syncer to start so that validator can start
   666  	sleep 4
   667  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   668  		"query-status test" \
   669  		"\"synced\": true" 1 \
   670  		"\"processedRowsStatus\": \"insert\/update\/delete: 1\/0\/0\"" 1
   671  	for ((k = 1; k <= $insertCnt; k++)); do
   672  		run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   673  			"pause-task test" \
   674  			"\"result\": true" 2
   675  		trigger_checkpoint_flush
   676  		# catchup the last insert when the syncer is stopped
   677  		run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   678  			"query-status test" \
   679  			"\"processedRowsStatus\": \"insert\/update\/delete: $k\/0\/0\"" 1 \
   680  			"new\/ignored\/resolved: 0\/0\/0" 1
   681  		run_sql_source1 "insert into validator_basic.test values($k, $k)"
   682  		trigger_checkpoint_flush
   683  		run_dm_ctl $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   684  			"resume-task test" \
   685  			"\"result\": true" 2
   686  		# syncer synced but the validator delayed
   687  		run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   688  			"query-status test" \
   689  			"\"synced\": true" 1 \
   690  			"\"processedRowsStatus\": \"insert\/update\/delete: $k\/0\/0\"" 1
   691  	done
   692  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   693  		"query-status test" \
   694  		"\"processedRowsStatus\": \"insert\/update\/delete: $(($insertCnt + 1))\/0\/0\"" 1 \
   695  		"new\/ignored\/resolved: 0\/0\/0" 1
   696  }
   697  
   698  function test_dup_autopk() {
   699  	# successfully validate sharding tables
   700  	# though the downstream table deletes the primary key
   701  	# because not null unique key can identify a row accurately.
   702  	echo "--> test duplicate auto-incr pk"
   703  	export GO_FAILPOINTS=""
   704  	prepare_dm_and_source
   705  	dmctl_operate_source create $cur/conf/source2.yaml $SOURCE_ID2
   706  	# auto_incr pk in both tables
   707  	run_sql_source1 "create table validator_basic.shard1(id int primary key auto_increment, ukey int not null unique key)"
   708  	run_sql_file $cur/data/db1.prepare.sql $MYSQL_HOST2 $MYSQL_PORT2 $MYSQL_PASSWORD1
   709  	run_sql_source2 "create table validator_basic.shard1(id int primary key auto_increment, ukey int not null unique key)"
   710  	# delete pk in tidb
   711  	run_sql_tidb "create database if not exists validator_basic"
   712  	run_sql_tidb "create table validator_basic.shard(id int, ukey int not null unique key)"
   713  	dmctl_start_task "$cur/conf/sharding-task.yaml" "--remove-meta"
   714  	run_sql_source1 "insert into validator_basic.shard1(ukey) values(1),(2),(3)"
   715  	run_sql_source2 "insert into validator_basic.shard1(ukey) values(4),(5),(6)"
   716  	sleep 1.5
   717  	run_sql_source2 "alter table $db_name.t1 comment 'a';" # trigger source2 flush
   718  	trigger_checkpoint_flush                               # trigger source1 flush
   719  	# validate pass
   720  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   721  		"query-status test" \
   722  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/0\/0\"" 2 \
   723  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 2 \
   724  		"new\/ignored\/resolved: 0\/0\/0" 2
   725  }
   726  
   727  function test_update_validator() {
   728  	# backup it, will change it in the following case
   729  	cp $cur/conf/dm-task-standalone.yaml $cur/conf/dm-task-standalone.yaml.bak
   730  	cp $cur/conf/source1.yaml $cur/conf/source1.yaml.bak
   731  
   732  	trap restore_on_case_exit EXIT
   733  	# clear fail point
   734  	export GO_FAILPOINTS=""
   735  	cp $cur/conf/source1.yaml.bak $cur/conf/source1.yaml
   736  	sed -i 's/enable-gtid: false/enable-gtid: 'true'/g' $cur/conf/source1.yaml
   737  	sed -i 's/enable-relay: false/enable-relay: 'true'/g' $cur/conf/source1.yaml
   738  	run_sql_source1 "flush binary logs"
   739  	sleep 1
   740  	run_sql_source1 "purge binary logs before now()"
   741  	prepare_dm_and_source
   742  	dmctl_start_task_standalone $cur/conf/dm-task-standalone-long-interval.yaml --remove-meta
   743  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   744  		"config source $SOURCE_ID1" \
   745  		"enable-gtid: true" 1 \
   746  		"enable-relay: true" 1
   747  	run_sql_source1 "insert into $db_name.t1(id, name) values(2,'b'), (3, 'c')"
   748  	run_sql_source1 "delete from $db_name.t1 where id=1"
   749  	# check validator before start, should pass
   750  	# validate pass
   751  	trigger_checkpoint_flush
   752  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   753  		"query-status test" \
   754  		"\"processedRowsStatus\": \"insert\/update\/delete: 2\/0\/1\"" 1 \
   755  		"pendingRowsStatus\": \"insert\/update\/delete: 2\/0\/1" 1 \
   756  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   757  		"\"cutoverBinlogGtid\": \"\"" 1
   758  	gtid_executed=($(get_gtid_executed $MYSQL_HOST1 $MYSQL_PORT1))
   759  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   760  		"validation update test -s $SOURCE_ID1 --cutover-binlog-gtid $gtid_executed" \
   761  		"\"result\": true" 2
   762  	sleep 3
   763  	# after 3 seconds, cutoverBinlogGtid should also not change
   764  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   765  		"query-status test" \
   766  		"\"cutoverBinlogGtid\": \"$gtid_executed\"" 1
   767  	trigger_checkpoint_flush
   768  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   769  		"query-status test" \
   770  		"\"synced\": true" 1
   771  	check_sync_diff $WORK_DIR $cur/conf/diff_config.toml
   772  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   773  		"query-status test" \
   774  		"\"processedRowsStatus\": \"insert\/update\/delete: 2\/0\/1\"" 1 \
   775  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   776  		"new\/ignored\/resolved: 0\/0\/0" 1
   777  	# set gtid_executed again, should be triggered by dml event
   778  	gtid_executed=($(get_gtid_executed $MYSQL_HOST1 $MYSQL_PORT1))
   779  	extracted_number=$(echo "$gtid_executed" | grep -Eo '[0-9]+$')
   780  	incremented_number=$((extracted_number + 1))
   781  	gtid_cutover=$(echo "$gtid_executed" | sed "s/${extracted_number}$/${incremented_number}/")
   782  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   783  		"validation update test -s $SOURCE_ID1 --cutover-binlog-gtid $gtid_cutover" \
   784  		"\"result\": true" 2
   785  	run_sql_source1 "insert into $db_name.t1(id, name) values (4, 'c')"
   786  	# directly sleep without flush, can cutover by itself
   787  	sleep 1.5
   788  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   789  		"query-status test" \
   790  		"\"synced\": true" 1
   791  	check_sync_diff $WORK_DIR $cur/conf/diff_config.toml
   792  	run_dm_ctl_with_retry $WORK_DIR "127.0.0.1:$MASTER_PORT" \
   793  		"query-status test" \
   794  		"\"processedRowsStatus\": \"insert\/update\/delete: 3\/0\/1\"" 1 \
   795  		"pendingRowsStatus\": \"insert\/update\/delete: 0\/0\/0" 1 \
   796  		"new\/ignored\/resolved: 0\/0\/0" 1 \
   797  		"\"cutoverBinlogGtid\": \"\"" 1
   798  }
   799  
   800  run_standalone $*
   801  validate_table_with_different_pk
   802  test_unsupported_table_status
   803  stopped_validator_fail_over
   804  test_data_filter
   805  test_validation_syncer_stopped
   806  test_dup_autopk
   807  test_update_validator
   808  cleanup_process $*
   809  cleanup_data $db_name
   810  cleanup_data_upstream $db_name
   811  
   812  echo "[$(date)] <<<<<< test case $TEST_NAME success! >>>>>>"