################################################################################
# InnoDB transparent tablespace data encryption for mysql tablespace.
# For mysql tablespace, this test will test
#    1 - Normal alter encryption
#        - encryption='y' to encryption='n'
#        - encryption='n' to encryption='y'
#    2 - Crash during altering mysql tablespace encryption
#        - encryption='y' to encryption='n'
#        - encryption='n' to encryption='y'
#    3 - Crash
#        - just before encryption processing starts
#        - just after encryption processing finishes
#    4 - Crash during master key rotation
#    5 - Privilege check
################################################################################

--source include/big_test.inc
--source include/have_debug.inc
# Disable in valgrind because of timeout, cf. Bug#22760145
--source include/not_valgrind.inc
# Waiting time when (re)starting the server
--let $explicit_default_wait_counter=10000

--disable_query_log
call mtr.add_suppression("\\[Warning\\] \\[MY-013674\\] \\[InnoDB\\] Decrypting a page in doublewrite file failed: space_id=");
call mtr.add_suppression("\\[Warning\\] \\[MY-013675\\] \\[InnoDB\\] Encryption key missing: space_id=");
--enable_query_log

--echo
--echo #############################################################
--echo # TEST 1 : NORMAL ALTER ENCRYPT mysql TABLESPACE.
--echo #############################################################
--echo
--echo #########################################################################
--echo # RESTART 1 : WITH KEYRING PLUGIN
--echo #########################################################################
let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT;
--source include/restart_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

--echo # Initially, mysql should be unencrypted by default
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

ALTER TABLESPACE mysql ENCRYPTION='Y';
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

ALTER TABLESPACE mysql ENCRYPTION='N';
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo
--echo #############################################################
--echo # TEST 2 : CRASH DURING ALTER ENCRYPT mysql TABLESPACE.
--echo #############################################################
--echo
--echo ############################################################
--echo # ALTER TABLESPACE 1 :    Unencrypted => Encrypted         #
--echo #                         (crash at page 10)               #
--echo ############################################################
--echo # Set Encryption process to crash at page 10
SET SESSION debug= '+d,alter_encrypt_tablespace_page_10';

--echo # Encrypt the tablespace. It will cause crash.
--source include/expect_crash.inc
--error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR
ALTER TABLESPACE mysql ENCRYPTION='Y';
--echo # Restart after crash
--source include/start_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

--echo # Wait for Encryption processing to finish in background thread
let $wait_condition = SELECT ENCRYPTION = 'Y'
        FROM INFORMATION_SCHEMA.INNODB_TABLESPACES
        WHERE NAME='mysql';
--source include/wait_condition.inc

# Make sure ts file is updated with new records in table
set global innodb_buf_flush_list_now = 1;

--echo # After restart/recovery, check that Encryption was roll-forward
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

# Try to do encryption one more time (dummy). Should not do anything.
ALTER TABLESPACE mysql ENCRYPTION='Y';
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo #########################################################################
--echo # RESTART 2 : WITH KEYRING PLUGIN
--echo #########################################################################
let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT;
--source include/restart_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo ############################################################
--echo # ALTER TABLESPACE 2 :    Encrypted => Unencrypted         #
--echo #                         (crash at page 10)               #
--echo ############################################################
--echo # Set Unencryption process to crash at page 10
SET SESSION debug= '+d,alter_encrypt_tablespace_page_10';

--echo # Unencrypt the tablespace. It will cause crash.
--source include/expect_crash.inc
--error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR
ALTER TABLESPACE mysql ENCRYPTION='N';
--echo # Restart after crash
--source include/start_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

--echo # Wait for Unencryption processing to finish in background thread
let $wait_condition = SELECT ENCRYPTION = 'N'
        FROM INFORMATION_SCHEMA.INNODB_TABLESPACES
        WHERE NAME='mysql';
--source include/wait_condition.inc

# Make sure ts file is updated with new records in table
set global innodb_buf_flush_list_now = 1;

--echo # After restart/recovery, check that Unencryption was roll-forward
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

# Try to do unencryption one more time (dummy). Should not do anything.
ALTER TABLESPACE mysql ENCRYPTION='N';
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo #########################################################################
--echo # RESTART 3 : WITHOUT KEYRING PLUGIN
--echo #########################################################################
let $restart_parameters = restart:;
--source include/restart_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo #############################################################
--echo # TEST 3 : CRASH BEFORE/AFTER ENCRYPTION PROCESSING.
--echo #############################################################
--echo
--echo #########################################################################
--echo # RESTART 4 : WITH KEYRING PLUGIN
--echo #########################################################################
let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT;
--source include/restart_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

# Encrypt tablespace
ALTER TABLESPACE mysql ENCRYPTION='Y';
# Read rows from table
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo # Set server to crash just before encryption processing starts
SET SESSION debug="+d,alter_encrypt_tablespace_crash_before_processing";

--echo # Unencrypt the tablespace. It will cause crash.
--source include/expect_crash.inc
--error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR
ALTER TABLESPACE mysql ENCRYPTION='N';
--echo # Restart after crash
--source include/start_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

--echo # Wait for Unencryption processing to finish in background thread
let $wait_condition = select count(*) = 0
        from performance_schema.events_stages_current
        where EVENT_NAME='stage/innodb/alter tablespace (encryption)';
--source include/wait_condition.inc

# Encrytion property of tablespace shouldn't have changed i.e. it should still
# be encrypted.
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';


--echo # Set server to crash just after encryption processing finishes
SET SESSION debug="-d,alter_encrypt_tablespace_crash_before_processing";
SET SESSION debug="+d,alter_encrypt_tablespace_crash_after_processing";

--echo # Unencrypt the tablespace. It will cause crash.
--source include/expect_crash.inc
--error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR
ALTER TABLESPACE mysql ENCRYPTION='N';
--echo # Restart after crash
--source include/start_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

--echo # Wait for Unencryption processing to finish in background thread
let $wait_condition = select count(*) = 0
        from performance_schema.events_stages_current
        where EVENT_NAME='stage/innodb/alter tablespace (encryption)';
--source include/wait_condition.inc

# Encrytion property of tablespace should have changed i.e. it should be
# unencrypted now.
SELECT NAME, ENCRYPTION FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='mysql';
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo #############################################################
--echo # TEST 4 : CRASH DURING KEY ROTATION.
--echo #############################################################
--echo
--echo #########################################################################
--echo # RESTART 5 : WITH KEYRING PLUGIN
--echo #########################################################################
let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT;
--source include/restart_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';

# Encrypt tablespace
ALTER TABLESPACE mysql ENCRYPTION='Y';
# Read rows from table
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo # Set server to crash while rotating encryption
SET SESSION debug="+d,ib_crash_during_rotation_for_encryption";

# Rotate the key. It will cause server to crash.
--source include/expect_crash.inc
--error 0,CR_SERVER_LOST,ER_INTERNAL_ERROR
ALTER INSTANCE ROTATE INNODB MASTER KEY;

--echo # Restart after crash
--source include/start_mysqld_no_echo.inc
SET debug='+d,skip_dd_table_access_check';
# Read rows from table
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

# Rotate the key.
SET SESSION debug="-d,ib_crash_during_rotation_for_encryption";
ALTER INSTANCE ROTATE INNODB MASTER KEY;
# Read rows from table
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo #############################################################
--echo # TEST 5 : PRIVILEGE CHECK.
--echo #############################################################
--echo

CREATE DATABASE priv_test;
CREATE USER myuser@'localhost';
GRANT ALL ON priv_test.* TO myuser@'localhost';

--echo #connection con1
--connect(con1,localhost,myuser,,priv_test)
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
ALTER TABLESPACE mysql ENCRYPTION='Y';

--disconnect con1
--source include/wait_until_disconnected.inc

--echo #connection default
--connection default
--error ER_WRONG_USAGE
GRANT CREATE TABLESPACE ON mysql.* TO myuser@'localhost';
GRANT CREATE TABLESPACE ON *.* TO myuser@'localhost';

--echo #connection con1
--connect(con1,localhost,myuser,,priv_test)
ALTER TABLESPACE mysql ENCRYPTION='N';

--echo #connection default
--connection default
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--echo #connection con1
--connection con1
ALTER TABLESPACE mysql ENCRYPTION='Y';

--echo #connection default
--connection default
SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';

--disconnect con1
DROP DATABASE priv_test;
DROP USER myuser@localhost;

--echo ###########
--echo # Cleanup #
--echo ###########
# Unencrypt tablespace
ALTER TABLESPACE mysql ENCRYPTION='N';

SELECT NAME,OPTIONS FROM mysql.tablespaces WHERE NAME='mysql';
remove_file $MYSQL_TMP_DIR/mysecret_keyring;

--echo #########################################################################
--echo # RESTART 6 : WITHOUT KEYRING PLUGIN
--echo #########################################################################
let $restart_parameters = restart: ;
--source include/restart_mysqld.inc
