# Creating a test case

This document describes basic principles of test case creation and provides list of basic usefull functions and properties.
For detailed function and properties description and thier full list please see documetation generated by Doxygen.

## Test case basics

For every test case following should be created:
- test executable
- record in the 'templates' file
- Maxscale configuration template (if test requires special Maxscale configuration)
- [CMakeLists.txt](CMakeLists.txt) record:
  - add_test_executable(<source.cpp> <binary_name> <cnf_template_name>)
  - 'set_tests_properties' if test should be added to the group or bigger timeout should be defined (> default 1800s)

## 'templates' file

'templates' file contains information about Maxscale configuration template for every test in plain text format:

\<test_executable_name\> \<suffix_of_cnf_template\>

Template itself should be:

cnf/maxscale.cnf.template.\<suffix_of_cnf_template\>

## Maxscale configuration template

All templates are in cnf/ directory:

cnf/maxscale.cnf.template.\<suffix_of_cnf_template\>

Template can contain following varables:

|Variable|Maeaning|
|--------|--------|
|###threads###| Number of Maxscale treads|
|###node_server_IP_N###|IP of Master/Slave node N|
|###node_server_port_N###|port of Master/Slave node N|
|###galera_server_IP_N###|IP of Galera node N|
|###galera_server_port_N###|port of Galera node N|

## Test creation principles

* start from initializing of an object of TestConnections class
* set timeout before every operation which can got stuck, do not forget to disable timeout before long sleep()
* use TestConnections::tprintf function to print test log
* use TestConnections::add_result() to idicate test failure and print explanation message
* execute TestConnections::copy_all_logs at the end of test
* return TestConnections::global_result value
* do not leave any node blocked by firewall

## Class TestConnections

This class contains all information about Maxscale node and about all backend nodes as well as a set of functions
to handle Maxscale and backends, interact with Maxscale routers and Maxadmin.
Here is only list of main functions, for all details see Doxygen comments in [testconnections.h](testconnections.h)

Currently two backend sets are supported (represented by Mariadb_nodes class objects): 'repl' and 'galera'
- contains all info and operations for Master/Slave and Galera setups
(see Doxygen comments in [mariadb_nodes.h](mariadb_nodes.h) )

It is assumed that following routers+listers are configured

|Router|Port|
|------|----|
|RWSplit|4006|
|ReadConn master|4008|
|ReadConn Slave|4009|
|binlog|5306|
|test case -specific|4016|

### Most important fuctions and variables

Please check Doxygen comments for details

#### TestConnections(int argc, char *argv[]);

* reads all information from environmental variables
* checks backends, if broken - does one attempt to restore
* create maxscale.cnf out of template and copy it to Maxscale node
* create needed directories, set access righs for them, cleanup logs, coredumps
* start Maxscale
* initialize internal structures

#### Timeout functions

int set_timeout(int timeout_seconds)
stop_timeout()

If after set_timeout() a new call of set_timeout() or stop_timeout() is not done the test execution terminated,
logs from Maxscale are copied to host.

#### Open connection functions
|Function|Short description|
|----|---|
| int connect_maxscale();<br>  int connect_rwsplit();<br>  int connect_readconn_master();<br>  int connect_maxscale_slave();|store MYSQL handler in TestConnections object (only one cnnection can be created by them, second call leads to MYSQL handler leak)|
|MYSQL * open_rwsplit_connection() <br> MYSQL * open_readconn_master_connection() <br> MYSQL * open_readconn_slave_connection() |returns MYSQL handler (can be used to create a number of connections to each router)|
| int create_connections(int conn_N) |- open and then close N connections to each router|

A number of useful wrappers for mysql_real_connect() are not included into TestConnections class, but
they are availve from [mariadb_func.h](mariadb_func.h)

#### Backend check and setup functions
|Function|Short description|
|----|---|
|start_replication()|Configure nodes from 'repl' object as Master/Slave|
|start_galera()|Configure nodes from 'galera'|
|start_binlog()|Configure nodes from 'repl' in following way: node0 - Master, node1 - slave of node0, all others - slaves of Maxscale binlog router|
|start_mm()|Configure nodes from 'repl' in multimuster setup|

#### Result reporting functions
|Function|Short description|
|----|---|
|add_result()|failure printing, increase global_result|
|tprint()| printing with timestamp|
|copy_logs()|copy Maxscale log, maxscale.cnf file and core dump from Maxscale machine to current directory|

#### Different checks functions
|Function|Short description|
|----|---|
|try_query()|try SQL query and print error message in case of failure, increase global_result|
|check_t1_table()|check if t1 present in give DB|
|test_maxscale_connections|check status of connections to RWSplit, ReadConn master, ReadConn slave routers|
|check_maxscale_alive()|Check if RWSplit, ReadConn master, ReadConn slave routers are alive|
|check_log_err()|Check Maxscale log for presence of absence of specific string|
|find_connected_slave|find first slave that have connections from Maxscale|

#### Maxscale machine control functions
|Function|Short description|
|----|---|
|start_maxscale()||
|stop_maxscale()||
|restart_maxscale()||
|execute_ssh_maxscale()|execute command on Maxscale node via ssh|

#### Properties
|Name|Short description|Corresponding env variable|
|----|-----|----|
|global_result|0 if there is not single failure during the test| - |
|repl|Mariadb_nodes object for Master/Slave nodes| - |
|galera|Mariadb_nodes object for Galera nodes| - |
|smoke|do short tests if TRUE|smoke|
|maxscale_IP|IP address of Maxscale machine|maxscale_IP|
|maxscale_user|DB user name to access via Maxscale|maxscale_user|
|maxscale_password|password for MaxscaleDB user|maxscale_password|
|maxadmin_password|password for MaxAdmin interface (user name is hard coded 'admin')|maxadmin_password|
|conn_rwsplit|MYSQL handler of connections to RWSplit router| - |
|conn_master|MYSQL handler of connections to ReadConn router in master mode| - |
|conn_slave|MYSQL handler of connections to ReadConn router in master mode| - |

### Mariadb_nodes class

#### Master/Slave and Galera setup and check
|Function|Short description|
|----|---|
|start_replication()|Configure nodes from 'repl' object as Master/Slave|
|start_galera()|Configure nodes from 'galera'|
|set_slave()|execute CHANGE MASTER TO agains the node|
|check_replication()|Check if 'repl' nodes are properly configured as Master/Slave|
|check_galera()|Check if 'galera' nodes are are properly configured as Galera cluster|
|change_master|Make another node to be a master|

#### Connections functions
|Function|Short description|
|----|---|
|connect()|open connections to all nodes, store MYSQL handlers in internal variable, second call leads to handlers leak|
|close_connections()|close connections to all nodes|

#### Nodes control functions
|Function|Short description|
|----|---|
|block_node()|block MariaDB server on the node by firawall|
|unblock_node()|unblock MariaDB server on the node by firawall|
|unblock_all_nodes()|unblock MariaDB server on all nodes by firawall|
|stop_node()|stop MariaDB server on the node|
|start node()|start MariaDB server on the node|
|restart_node()|stop and restart MariaDB server on the node|
|check_node()|check if MariaDB server on the node is alive|
|check_and_restart_node()|check if MariaDB server on the node is alive and restart it if it is not alive|
|stop_nodes()|stop MariaDB server on all nodes|
|ssh_node()|Execute command on the node via ssh, return error code|
|ssh_node_output()|Same as ssh_nodE(), but return command output|
|flush_hosts()|Execute 'mysqladmin flush-hosts' on all nodes|
|execute_query_all_nodes()|Execute same query on all nodes|

#### Properties
|Name|Short description|Corresponding env variable|
|----|-----|----|
|N|Number of nodes|node_N <br> galera_N|
|user_name|DB user name|node_user <br> galera_user|
|password|password for DB user|node_password <br> galera_password|
|IP[ ]|IP address of the node|node_XXX <br> galera_XXX|
|IP_private[ ]|private IP of the node (for AWS nodes)|node_private_XXX <br> galera_private_XXX|
|port[ ]|MariaDB port for the node|node_port_XXX <br> galera_port_XXX|
|nodes[ ]|MYSQL handler| - |

### Maxadmin operations functions
[maxadmin_operations.h](maxadmin_operations.h) contains fuctions to communicate to Maxscale via MaxAdmin interface

|Function|Short description|
|----|---|
|execute_maxadmin_command()|send MaxAdmin command to Maxscale|
|execute_maxadmin_command_print()|send MaxAdmin command to Maxscale and print reply|
|get_maxadmin_param()|send MaxAdmin command to Maxscale and try to find the value of given parameter in output|
