 24bb8b0b2c
			
		
	
	24bb8b0b2c
	
	
	
		
			
			The test unnecessarily did an unconditional drop of the user resulting in errors. Also prevented stopping of MaxScale if it wasn't started in the first place.
		
			
				
	
	
		
			269 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			269 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * @file mxs548_short_session_change_user.cpp MXS-548 regression case ("Maxscale crash")
 | |
|  * - configure 2 backend servers (one Master, one Slave)
 | |
|  * - create 'user' with password 'pass2'
 | |
|  * - create load on Master (3 threads are inserting data into 't1' in the loop)
 | |
|  * - in 40 parallel threads open connection, execute change_user to 'user', execute change_user to default user, close connection
 | |
|  * - repeat test first only for RWSplit and second for all maxscales->routers[0]
 | |
|  * - check logs for lack of "Unable to write to backend 'server2' due to authentication failure" errors
 | |
|  * - check for lack of crashes in the log
 | |
|  */
 | |
| 
 | |
| 
 | |
| #include "testconnections.h"
 | |
| #include "sql_t1.h"
 | |
| 
 | |
| typedef struct
 | |
| {
 | |
|     int exit_flag;
 | |
|     int thread_id;
 | |
|     long i;
 | |
|     int rwsplit_only;
 | |
|     TestConnections * Test;
 | |
|     MYSQL * conn1;
 | |
|     MYSQL * conn2;
 | |
|     MYSQL * conn3;
 | |
| } openclose_thread_data;
 | |
| 
 | |
| void *query_thread1(void *ptr);
 | |
| void *query_thread_master(void *ptr);
 | |
| 
 | |
| int main(int argc, char *argv[])
 | |
| {
 | |
|     TestConnections * Test = new TestConnections(argc, argv);
 | |
|     Test->maxscales->ssh_node_f(0, true, "sysctl net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_tw_recycle=1 "
 | |
|                                 "net.core.somaxconn=10000 net.ipv4.tcp_max_syn_backlog=10000");
 | |
|     Test->set_timeout(20);
 | |
| 
 | |
|     int threads_num = 40;
 | |
|     openclose_thread_data data[threads_num];
 | |
| 
 | |
|     int master_load_threads_num = 3;
 | |
|     openclose_thread_data data_master[master_load_threads_num];
 | |
| 
 | |
|     int i;
 | |
| 
 | |
|     int run_time = 300;
 | |
| 
 | |
|     if (Test->smoke)
 | |
|     {
 | |
|         run_time = 10;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < threads_num; i++)
 | |
|     {
 | |
|         data[i].i = 0;
 | |
|         data[i].exit_flag = 0;
 | |
|         data[i].Test = Test;
 | |
|         data[i].rwsplit_only = 1;
 | |
|         data[i].thread_id = i;
 | |
|         data[i].conn1 = NULL;
 | |
|         data[i].conn2 = NULL;
 | |
|         data[i].conn3 = NULL;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     for (i = 0; i < master_load_threads_num; i++)
 | |
|     {
 | |
|         data_master[i].i = 0;
 | |
|         data_master[i].exit_flag = 0;
 | |
|         data_master[i].Test = Test;
 | |
|         data_master[i].rwsplit_only = 1;
 | |
|         data_master[i].thread_id = i;
 | |
|         data_master[i].conn1 = NULL;
 | |
|         data_master[i].conn2 = NULL;
 | |
|         data_master[i].conn3 = NULL;
 | |
|     }
 | |
| 
 | |
|     pthread_t thread1[threads_num];
 | |
| 
 | |
|     pthread_t thread_master[master_load_threads_num];
 | |
| 
 | |
|     Test->repl->connect();
 | |
|     Test->maxscales->connect_maxscale(0);
 | |
|     create_t1(Test->maxscales->conn_rwsplit[0]);
 | |
|     Test->repl->execute_query_all_nodes((char *) "set global max_connections = 2000;");
 | |
|     Test->repl->sync_slaves();
 | |
| 
 | |
|     Test->tprintf("Creating user 'user' \n");
 | |
|     execute_query(Test->maxscales->conn_rwsplit[0], (char *) "DROP USER IF EXISTS user@'%%'");
 | |
|     execute_query(Test->maxscales->conn_rwsplit[0], (char *) "CREATE USER user@'%%' IDENTIFIED BY 'pass2'");
 | |
|     execute_query(Test->maxscales->conn_rwsplit[0], (char *) "GRANT SELECT ON test.* TO user@'%%'");
 | |
|     execute_query(Test->maxscales->conn_rwsplit[0], (char *) "DROP TABLE IF EXISTS test.t1");
 | |
|     execute_query(Test->maxscales->conn_rwsplit[0], (char *) "CREATE TABLE test.t1 (x1 int, fl int)");
 | |
|     Test->repl->sync_slaves();
 | |
| 
 | |
|     /* Create independent threads each of them will create some load on Master */
 | |
|     for (i = 0; i < master_load_threads_num; i++)
 | |
|     {
 | |
|         pthread_create(&thread_master[i], NULL, query_thread_master, &data_master[i]);
 | |
|     }
 | |
| 
 | |
|     /* Create independent threads each of them will execute function */
 | |
|     for (i = 0; i < threads_num; i++)
 | |
|     {
 | |
|         pthread_create(&thread1[i], NULL, query_thread1, &data[i]);
 | |
|     }
 | |
| 
 | |
|     Test->tprintf("Threads are running %d seconds \n", run_time);
 | |
| 
 | |
|     for (i = 0; i < threads_num; i++)
 | |
|     {
 | |
|         data[i].rwsplit_only = 1;
 | |
|     }
 | |
| 
 | |
|     Test->set_timeout(run_time + 60);
 | |
|     sleep(run_time);
 | |
| 
 | |
|     Test->repl->flush_hosts();
 | |
| 
 | |
|     Test->tprintf("all maxscales->routers[0] are involved, threads are running %d seconds more\n", run_time);
 | |
|     Test->set_timeout(run_time + 100);
 | |
| 
 | |
|     for (i = 0; i < threads_num; i++)
 | |
|     {
 | |
|         data[i].rwsplit_only = 0;
 | |
|     }
 | |
| 
 | |
|     sleep(run_time);
 | |
|     Test->set_timeout(120);
 | |
|     Test->tprintf("Waiting for all threads exit\n");
 | |
| 
 | |
|     for (i = 0; i < threads_num; i++)
 | |
|     {
 | |
|         data[i].exit_flag = 1;
 | |
|         pthread_join(thread1[i], NULL);
 | |
|     }
 | |
| 
 | |
|     Test->tprintf("Waiting for all master load threads exit\n");
 | |
| 
 | |
|     for (i = 0; i < master_load_threads_num; i++)
 | |
|     {
 | |
|         data_master[i].exit_flag = 1;
 | |
|         pthread_join(thread_master[i], NULL);
 | |
|     }
 | |
| 
 | |
|     Test->tprintf("Flushing backend hosts\n");
 | |
|     Test->set_timeout(60);
 | |
|     Test->repl->flush_hosts();
 | |
| 
 | |
|     Test->tprintf("Dropping tables and users\n");
 | |
|     Test->set_timeout(60);
 | |
|     execute_query(Test->maxscales->conn_rwsplit[0], (char *) "DROP TABLE test.t1;");
 | |
|     execute_query(Test->maxscales->conn_rwsplit[0], (char *) "DROP USER user@'%%'");
 | |
|     Test->maxscales->close_maxscale_connections(0);
 | |
| 
 | |
|     Test->set_timeout(160);
 | |
|     Test->tprintf("Trying to connect Maxscale\n");
 | |
|     Test->maxscales->connect_maxscale(0);
 | |
|     Test->tprintf("Closing Maxscale connections\n");
 | |
|     Test->maxscales->close_maxscale_connections(0);
 | |
|     Test->tprintf("Checking if Maxscale alive\n");
 | |
|     Test->check_maxscale_alive(0);
 | |
|     Test->tprintf("Checking log for unwanted errors\n");
 | |
|     Test->check_log_err(0, (char *) "due to authentication failure", false);
 | |
|     Test->check_log_err(0, (char *) "fatal signal 11", false);
 | |
|     Test->check_log_err(0, (char *) "due to handshake failure", false);
 | |
| 
 | |
|     // We need to wait for the TCP connections in TIME_WAIT state so that
 | |
|     // later tests don't fail due to a lack of file descriptors
 | |
|     Test->tprintf("Waiting for network connections to die");
 | |
|     sleep(30);
 | |
| 
 | |
|     int rval = Test->global_result;
 | |
|     delete Test;
 | |
|     return rval;
 | |
| }
 | |
| 
 | |
| void *query_thread1(void *ptr)
 | |
| {
 | |
|     openclose_thread_data * data = (openclose_thread_data *) ptr;
 | |
| 
 | |
|     while (data->exit_flag == 0)
 | |
|     {
 | |
|         data->conn1 = data->Test->maxscales->open_rwsplit_connection(0);
 | |
| 
 | |
|         if (data->conn1 != NULL)
 | |
|         {
 | |
|             if (mysql_errno(data->conn1) == 0)
 | |
|             {
 | |
|                 mysql_change_user(data->conn1, (char *) "user", (char *) "pass2", (char *) "test");
 | |
|                 mysql_change_user(data->conn1, data->Test->repl->user_name, data->Test->repl->password, (char *) "test");
 | |
|             }
 | |
|         }
 | |
|         if (data->rwsplit_only == 0)
 | |
|         {
 | |
|             data->conn2 = data->Test->maxscales->open_readconn_master_connection(0);
 | |
| 
 | |
|             if (data->conn2 != NULL)
 | |
|             {
 | |
|                 if (mysql_errno(data->conn2) == 0)
 | |
|                 {
 | |
|                     mysql_change_user(data->conn2, (char *) "user", (char *) "pass2", (char *) "test");
 | |
|                     mysql_change_user(data->conn2, data->Test->repl->user_name, data->Test->repl->password, (char *) "test");
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             data->conn3 = data->Test->maxscales->open_readconn_slave_connection(0);
 | |
| 
 | |
|             if (data->conn3 != NULL)
 | |
|             {
 | |
|                 if (mysql_errno(data->conn3) == 0)
 | |
|                 {
 | |
|                     mysql_change_user(data->conn3, (char *) "user", (char *) "pass2", (char *) "test");
 | |
|                     mysql_change_user(data->conn3, data->Test->repl->user_name, data->Test->repl->password, (char *) "test");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (data->conn1 != NULL)
 | |
|         {
 | |
|             mysql_close(data->conn1);
 | |
|             data->conn1 = NULL;
 | |
|         }
 | |
| 
 | |
|         if (data->rwsplit_only == 0)
 | |
|         {
 | |
|             if (data->conn2 != NULL)
 | |
|             {
 | |
|                 mysql_close(data->conn2);
 | |
|                 data->conn2 = NULL;
 | |
|             }
 | |
| 
 | |
|             if (data->conn3 != NULL)
 | |
|             {
 | |
|                 mysql_close(data->conn3);
 | |
|                 data->conn3 = NULL;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         data->i++;
 | |
|     }
 | |
| 
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| void *query_thread_master(void *ptr)
 | |
| {
 | |
|     openclose_thread_data * data = (openclose_thread_data *) ptr;
 | |
|     char sql[1000000];
 | |
|     data->conn1 = open_conn(data->Test->repl->port[0], data->Test->repl->IP[0],
 | |
|                             data->Test->repl->user_name, data->Test->repl->password, false);
 | |
|     create_insert_string(sql, 5000, 2);
 | |
| 
 | |
|     if (data->conn1 != NULL)
 | |
|     {
 | |
|         while (data->exit_flag == 0)
 | |
|         {
 | |
|             data->Test->try_query(data->conn1, sql);
 | |
|             data->i++;
 | |
|         }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         data->Test->add_result(1, "Error creating MYSQL struct for Master conn\n");
 | |
|     }
 | |
| 
 | |
|     return NULL;
 | |
| }
 |