# ==== Purpose ====
#
# This test script serves as the functionality testing for the table
# performance_schema.replication_applier_status_by_coordinator. Test
# for ddl and dml operations is a part of the perfschema suite.
# The ddl/dml tests are named:
# 1) ddl_replication_connection_configuration.test and
# 2) dml_replication_connection_configuration.test.
#
# This test script does the following:

#  - Verify that SELECT works for every field in the table.
#  - The SELECT per field produces an output similar to the corresponding field
#    in SHOW SLAVE STATUS(SSS), if there is one.
#  - If there is no matching field in SSS, we resort to other method of testing
#    those fields.
#  - We perform all the testing on connection "slave". On master, the table
#    returns an empty set.
#
# The follwing scenarios are tested in this test script:
#
#  - Test each field in STS on a fresh replication setup.
#  - Change configuration parameters using CHANGE MASTER TO and verify that
#    these changes are seen in SELECTs from PS table.
#  - Verify that, the change in values are correctly shown by the table.
#  - Verify that the values are preserved after STOP SLAVE, thread_id
#    changes to NULL and service_state changes to "Off".
#  - A priliminary test for Multi-threaded slave(MTS) mode.
#
#  ==== Reference ====
#
# MDEV:16437: merge 5.7 P_S replication instrumentation and tables
#
--source include/have_innodb.inc
--source include/have_binlog_format_mixed.inc
--source include/have_perfschema.inc
--source include/master-slave.inc

call mtr.add_suppression("Error 'Table 'test.t' doesn't exist' on query.");

let $assert_text= On master, the table should return an empty set.;
let $assert_cond= count(*) = 0 from performance_schema.replication_applier_status_by_coordinator;
source include/assert.inc;

--connection slave

--let $slave_param= Slave_SQL_Running_State
--let $slave_param_value= Slave has read all relay log; waiting for more updates
source include/wait_for_slave_param.inc;

--echo
--echo # Testing on fresh slave.
--echo

# To verify the correctness of thread_id field, we check for the name of
# the thread.
let $thread_name= `select name from performance_schema.threads where thread_id= (select Thread_Id from performance_schema.replication_applier_status_by_coordinator)`;
let $assert_text= thread_name should should indicate sql thread.;
let $assert_cond= "$thread_name" = "thread/sql/slave_sql";
source include/assert.inc;

let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status_by_coordinator, Service_State, 1);
let $assert_text= SSS shows Slave_IO_Running as "Yes". So, Service_State from this PS table should be "ON".;
let $assert_cond= "$sss_value" = "Yes" AND "$ps_value"= "ON";
source include/assert.inc;

let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1);
let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.;
let $assert_cond= "$sss_value" = "$ps_value";
source include/assert.inc;

let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
let $ps_value= query_get_value(select Last_Error_Message from performance_schema.replication_applier_status_by_coordinator, Last_Error_Message, 1);
let $assert_text= Value returned by SSS and PS table for Last_Error_Message should be same.;
let $assert_cond= "$sss_value" = "$ps_value";
source include/assert.inc;

let $ps_value= query_get_value(select Last_Error_Timestamp from performance_schema.replication_applier_status_by_coordinator, Last_Error_Timestamp, 1);
let $assert_text= Value returned by SSS and PS table for Last_Error_Timestamp should be 0000-00-00 00:00:00.;
let $assert_cond= "$ps_value" = "0000-00-00 00:00:00";
source include/assert.inc;

let $ps_value= query_get_value(select Last_Trans_Retry_Count from performance_schema.replication_applier_status_by_coordinator, Last_Trans_Retry_Count, 1);
let $assert_text= Last_trans_retry_count should be 0.;
let $assert_cond= "$ps_value"= 0;
source include/assert.inc;

--echo
--echo # Cause an error in the SQL thread and check for the correctness of
--echo # values in error number, message and timestamp fields.
--echo

# Cause an error in SQL thread.
# 1) Ceate a table 't' at master, replicate at slave.
# 2) Drop table 't' at slave only.
# 3) Insert a value in table 't' on master and replicate on slave.
# Since slave doesnt have table 't' anymore, SQL thread will show an error.

--connection master
use test;
create table t(a int primary key);
--source include/sync_slave_sql_with_master.inc
drop table t;
--connection master
insert into t values(1);
--connection slave
let $slave_sql_errno=1146;
source include/wait_for_slave_sql_error.inc;

--echo
--echo # Extract the error related fields from SSS and PS table and compare
--echo # them for correctness.
--echo

let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1);
let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.;
let $assert_cond= "$sss_value" = "$ps_value";
source include/assert.inc;

# Availability of special characters like single quote and backtick character
# makes it difficult use the assert.inc or mysql functionstrcmp().
# So, the equality of error messages is checked using the below perl code.

let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
let $ps_value= query_get_value(select Last_Error_Message from performance_schema.replication_applier_status_by_coordinator, Last_Error_Message, 1);

let PS_VALUE= $ps_value;
let SSS_VALUE= $sss_value;

perl;
use strict;
my $ps_value= $ENV{'PS_VALUE'};
my $sss_value= $ENV{'SSS_VALUE'};

if ($ps_value eq $sss_value)
{
  print "Value returned by SSS and PS table for Last_Error_Message is same.\n";
}
else
{
  print "Value returned by SSS and PS table for Last_Error_Message is NOT same\n";
}
EOF

--echo
--echo # Verify that the error fields are preserved after STOP SLAVE, thread_id
--echo # changes to NULL and service_state changes to "Off".
--echo

--echo
--echo # 1. Verify that thread_id changes to NULL and service_state to "off" on
--echo #    STOP SLAVE.
--echo

let $ps_value= query_get_value(select thread_id from performance_schema.replication_applier_status_by_coordinator, thread_id, 1);
let $assert_text= After STOP SLAVE, thread_id should be NULL;
let $assert_cond= "$ps_value" = "NULL";
source include/assert.inc;

let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status_by_coordinator, Service_State, 1);
let $assert_text= SSS shows Slave_SQL_Running as "No". So, Service_State from this PS table should be "OFF".;
let $assert_cond= "$sss_value" = "No" AND "$ps_value"= "OFF";
source include/assert.inc;

--echo
--echo # 2. Extract the error related fields from SSS and PS table and compare
--echo #    them. These fields should preserve their values.
--echo

let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1);
let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.;
let $assert_cond= "$sss_value" = "$ps_value";
source include/assert.inc;

# Availability of special characters like single quote and backtick character
# makes it difficult use the assert.inc or mysql functionstrcmp().
# So, the equality of error messages is checked using the below perl code.

let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
let $ps_value= query_get_value(select Last_Error_Message from performance_schema.replication_applier_status_by_coordinator, Last_Error_Message, 1);

let PS_VALUE= $ps_value;
let SSS_VALUE= $sss_value;

perl;
use strict;
my $ps_value= $ENV{'PS_VALUE'};
my $sss_value= $ENV{'SSS_VALUE'};

if ($ps_value eq $sss_value)
{
  print "Value returned by SSS and PS table for Last_Error_Message is same.\n";
}
else
{
  print "Value returned by SSS and PS table for Last_Error_Message is NOT same\n";
}
EOF

# End of perl code for testing the error message.

--connection master
drop table t;
reset master;

--connection slave
--let $rpl_only_running_threads= 1
--source include/stop_slave.inc
reset slave;
reset master;
set @@global.gtid_slave_pos= "";
set @saved_slave_trans_retry_interval= @@GLOBAL.slave_transaction_retry_interval;
set global slave_transaction_retry_interval=1;
--source include/start_slave.inc
# End of perl code for testing error message.


--echo #
--echo # Test Last_Trans_Retry_Count value.
--echo #

--connection master
create table t1 (f int primary key) engine=innodb;
insert into t1 values (10);
--sync_slave_with_master
connect (slave2,127.0.0.1,root,,test,$SLAVE_MYPORT,);
--connection slave2
begin;
update t1 set f=40 where f=10;

--connection master
begin;
update t1 set f=60 where f=10;
commit;

--connection slave
--let $wait_condition= SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE Info = "update t1 set f=60 where f=10"
--source include/wait_condition.inc
sleep 4 ;
--connection slave2
rollback;

let $ps_value= query_get_value(select Last_Trans_Retry_Count from performance_schema.replication_applier_status_by_coordinator, Last_Trans_Retry_Count, 1);
let $assert_text= Value returned by PS table for Last_Trans_Retry_Count should be > 0.;
let $assert_cond= "$ps_value" >  0;
source include/assert.inc;

--connection master
drop table t1;
--sync_slave_with_master
--disconnect slave2
set global slave_transaction_retry_interval=@saved_slave_trans_retry_interval;

source include/stop_slave.inc;

--echo
--echo # Restarting servers and setting up MTS now. Since, SQL thread and
--echo # coordinator are the same and follow same code path, we can skip
--echo # testing for coordinator thread in all scenarios. Testing for one
--echo # scenario is enough.
--echo

--let $rpl_server_number= 1
--source include/rpl_restart_server.inc

--let $rpl_server_number= 2
--source include/rpl_restart_server.inc

--connection slave
replace_result $MASTER_MYPORT MASTER_MYPORT;
replace_column 2 ###;
eval change master to
  master_host='127.0.0.1',
  master_port=$MASTER_MYPORT,
  master_user='root';
SET @save.slave_parallel_workers=@@global.slave_parallel_workers;
SET @@global.slave_parallel_workers=1;
# to avoid warnings
set @save.slave_transaction_retries= @@global.slave_transaction_retries;
source include/start_slave.inc;

--let $slave_param= Slave_SQL_Running_State
--let $slave_param_value= Slave has read all relay log; waiting for more updates
source include/wait_for_slave_param.inc;

# To verify the correctness of thread_id field, we check for the name of
# the thread.
let $thread_name= `select name from performance_schema.threads where thread_id= (select Thread_Id from performance_schema.replication_applier_status_by_coordinator)`;
let $assert_text= thread_name should should indicate sql thread.;
let $assert_cond= "$thread_name" = "thread/sql/slave_sql";
source include/assert.inc;

let $sss_value= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
let $ps_value= query_get_value(select Service_State from performance_schema.replication_applier_status_by_coordinator, Service_State, 1);
let $assert_text= SSS shows Slave_SQL_Running as "Yes". So, Service_State from this PS table should be "ON".;
let $assert_cond= "$sss_value" = "Yes" AND "$ps_value"= "ON";
source include/assert.inc;

let $sss_value= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
let $ps_value= query_get_value(select Last_Error_Number from performance_schema.replication_applier_status_by_coordinator, Last_Error_Number, 1);
let $assert_text= Value returned by SSS and PS table for Last_Error_Number should be same.;
let $assert_cond= "$sss_value" = "$ps_value";
source include/assert.inc;

--echo
--echo # Cleanup.
--echo

source include/stop_slave.inc;
set @@global.slave_parallel_workers= @save.slave_parallel_workers;
set @@global.slave_transaction_retries= @save.slave_transaction_retries;
source include/start_slave.inc;

source include/rpl_end.inc;
