# Testing master to slave heartbeat protocol
# 
# Including:
# - user interface, grammar, checking the range and warnings about 
#   unreasonable values for the heartbeat period;
# - no rotation of relay log if heartbeat is less that slave_net_timeout
# - SHOW STATUS like 'Slave_received_heartbeats' action
# - SHOW STATUS like 'Slave_heartbeat_period' report
# - SHOW STATUS like 'Slave_last_heartbeat' check

--let $rpl_skip_start_slave= 1
--let $rpl_skip_reset_master_and_slave= 1
--let $rpl_skip_change_master= 1
--source include/master-slave.inc

connection slave;
set @restore_slave_net_timeout= @@global.slave_net_timeout;
set @@global.slave_net_timeout= 10;

#
# check for null value of the Slave_last_heartbeat variable when the slave is not enabled
#
--query_vertical SHOW STATUS LIKE "Slave_last_heartbeat"

###
### Checking the range
###

#
# default period slave_net_timeout/2
#
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 2 ####
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root';
--query_vertical show status like 'Slave_heartbeat_period';

#
# the max for the period is ULONG_MAX/1000; an attempt to exceed it is  denied
#
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 2 ####
--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294968;
--query_vertical show status like 'Slave_heartbeat_period';

#
# the min value for the period is 1 millisecond an attempt to assign a
# lesser will be warned with treating the value as zero
#
connection slave;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 2 ####
### 5.1 mtr does not have --warning ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.0009999;
--query_vertical show status like 'Slave_heartbeat_period';

#
# the actual max and min must be accepted
#
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 2 ####
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294967;
--query_vertical show status like 'Slave_heartbeat_period';

--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 2 ####
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.001;
--query_vertical show status like 'Slave_heartbeat_period';

reset slave;

#
# A warning if period greater than slave_net_timeout
#
set @@global.slave_net_timeout= 5;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 2 ####
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 5.001;
--query_vertical show status like 'Slave_heartbeat_period';

reset slave;

#
# A warning if slave_net_timeout is set to less than the current HB period
#
set @@global.slave_net_timeout= 5;
--replace_result $MASTER_MYPORT MASTER_PORT
--replace_column 2 ####
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4;
--query_vertical show status like 'Slave_heartbeat_period';
set @@global.slave_net_timeout= 3 /* must be a warning */;

reset slave;


###
### checking no rotation
###

connection master;
--disable_warnings
drop table if exists t1;
--enable_warnings
#
# Even though master_heartbeat_period= 0.5 is 20 times less than
# @@global.slave_net_timeout= 10 in some circumstances master will
# not be able to send any heartbeat during the slave's net timeout
# and slave's relay log will rotate.
# The probability for such a scenario is pretty small so the following
# part is almost deterministic.
#

connection slave;
set @@global.slave_net_timeout= 10;
--replace_result $MASTER_MYPORT MASTER_PORT
# no error this time but rather a warning
--replace_column 2 ####
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.5;
--query_vertical show status like 'Slave_heartbeat_period';

start slave;

connection master;
create table t1 (f1 int);

#connection slave;
--source include/sync_slave_sql_with_master.inc
let $slave_param= Relay_Log_File;
let $slave_param_value= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1);

# there is an explicit sleep lasting longer than slave_net_timeout
# to ensure that nothing will come to slave from master for that period.
# That would cause reconnecting and relaylog rotation w/o the fix i.e
# without a heartbeat received.

real_sleep 15;

# check (compare with the previous show's results) that no rotation happened
source include/check_slave_param.inc;

###
### SHOW STATUS like 'Slave_heartbeat_period' and 'Slave_received_heartbeats'
###

--query_vertical show status like 'Slave_heartbeat_period';

#
# proof that there has been received at least one heartbeat;
# The exact number of received heartbeat is an indeterministic value
# and therefore it's not recorded into results.
#

let $slave_wait_param_counter= 300;
let $slave_value= query_get_value("SHOW STATUS like 'Slave_received_heartbeats'", Value, 1);
# Checking the fact that at least one heartbeat is received
while (!$slave_value)
{
  dec $slave_wait_param_counter;
  if (!$slave_wait_param_counter)
  {
    --echo ERROR: failed while waiting for slave parameter $slave_param: $slave_param_value
    query_vertical show slave status;
    SHOW STATUS like 'Slave_received_heartbeats';
    exit;
  }
  sleep 0.1;
  let $slave_value= query_get_value("SHOW STATUS like 'Slave_received_heartbeats'", Value, 1);
}
--echo A heartbeat has been received by the slave

#
# check for non-null value of the Slave_last_heartbeat variable when the slave is enabled
#
--let $assert_text= Slave_last_heartbeat should not be empty
--let $assert_cond= \'[SHOW STATUS LIKE "Slave_last_heartbeat", Value, 1]\' != "" 
--source include/assert.inc  

# cleanup

connection master;
drop table t1;

#connection slave;
--source include/sync_slave_sql_with_master.inc
set @@global.slave_net_timeout= @restore_slave_net_timeout;

--source include/rpl_end.inc
