diff --git a/zaza/openstack/charm_tests/mysql/tests.py b/zaza/openstack/charm_tests/mysql/tests.py index 04b511e..50ac8de 100644 --- a/zaza/openstack/charm_tests/mysql/tests.py +++ b/zaza/openstack/charm_tests/mysql/tests.py @@ -14,6 +14,7 @@ """MySQL/Percona Cluster Testing.""" +import json import logging import os import re @@ -27,31 +28,17 @@ import zaza.openstack.utilities.openstack as openstack_utils import zaza.openstack.utilities.generic as generic_utils -class MySQLTest(test_utils.OpenStackBaseTest): +class MySQLBaseTest(test_utils.OpenStackBaseTest): """Base for mysql charm tests.""" @classmethod def setUpClass(cls): """Run class setup for running mysql tests.""" - super(MySQLTest, cls).setUpClass() + super(MySQLBaseTest, cls).setUpClass() cls.application = "mysql" cls.services = ["mysqld"] - - -class PerconaClusterTest(test_utils.OpenStackBaseTest): - """Base for percona-cluster charm tests.""" - - @classmethod - def setUpClass(cls): - """Run class setup for running percona-cluster tests.""" - super(PerconaClusterTest, cls).setUpClass() - cls.application = "percona-cluster" - # This is the service pidof will attempt to find - # rather than what systemctl uses - cls.services = ["mysqld"] - cls.vip = os.environ.get("OS_VIP00") - cls.leader = None - cls.non_leaders = [] + # Config file affected by juju set config change + cls.conf_file = "/etc/mysql/mysql.conf.d/mysqld.cnf" def get_root_password(self): """Get the MySQL root password. @@ -63,6 +50,76 @@ class PerconaClusterTest(test_utils.OpenStackBaseTest): self.application, "leader-get root-password")["Stdout"].strip() + def get_leaders_and_non_leaders(self): + """Get leader node and non-leader nodes of percona. + + Update and set on the object the leader node and list of non-leader + nodes. + + :returns: None + :rtype: None + """ + status = zaza.model.get_status().applications[self.application] + # Reset + self.leader = None + self.non_leaders = [] + for unit in status["units"]: + if status["units"][unit].get("leader"): + self.leader = unit + else: + self.non_leaders.append(unit) + return self.leader, self.non_leaders + + +class MySQLCommonTests(MySQLBaseTest): + """Common mysql charm tests.""" + + def test_910_restart_on_config_change(self): + """Checking restart happens on config change. + + Change disk format and assert then change propagates to the correct + file and that services are restarted as a result + """ + # Expected default and alternate values + set_default = {"max-connections": "600"} + set_alternate = {"max-connections": "1000"} + + # Make config change, check for service restarts + logging.debug("Setting peer timeout ...") + self.restart_on_changed( + self.conf_file, + set_default, + set_alternate, + {}, {}, + self.services) + logging.info("Passed restart on changed test.") + + def test_920_pause_resume(self): + """Run pause and resume tests. + + Pause service and check services are stopped then resume and check + they are started + """ + with self.pause_resume(self.services): + logging.info("Testing pause resume") + logging.info("Passed pause and resume test.") + + +class PerconaClusterBaseTest(MySQLBaseTest): + """Base for percona-cluster charm tests.""" + + @classmethod + def setUpClass(cls): + """Run class setup for running percona-cluster tests.""" + super().setUpClass() + cls.application = "percona-cluster" + # This is the service pidof will attempt to find + # rather than what systemctl uses + cls.services = ["mysqld"] + cls.vip = os.environ.get("TEST_VIP00") + # Config file affected by juju set config change + cls.conf_file = "/etc/mysql/percona-xtradb-cluster.conf.d/mysqld.cnf" + def get_wsrep_value(self, attr): """Get wsrrep value from the DB. @@ -123,39 +180,13 @@ class PerconaClusterTest(test_utils.OpenStackBaseTest): ) return unit.entity_id - def update_leaders_and_non_leaders(self): - """Get leader node and non-leader nodes of percona. - Update and set on the object the leader node and list of non-leader - nodes. - - :returns: None - :rtype: None - """ - status = zaza.model.get_status().applications[self.application] - # Reset - self.leader = None - self.non_leaders = [] - for unit in status["units"]: - if status["units"][unit].get("leader"): - self.leader = unit - else: - self.non_leaders.append(unit) - - -class PerconaClusterCharmTests(PerconaClusterTest): - """Base for percona-cluster charm tests. +class PerconaClusterCharmTests(MySQLCommonTests, PerconaClusterBaseTest): + """Percona-cluster charm tests. .. note:: these have tests have been ported from amulet tests """ - @classmethod - def setUpClass(cls): - """Run class setup for running percona-cluster tests.""" - super(PerconaClusterTest, cls).setUpClass() - cls.application = "percona-cluster" - cls.services = ["mysqld"] - def test_100_bootstrapped_and_clustered(self): """Ensure PXC is bootstrapped and that peer units are clustered.""" self.units = zaza.model.get_application_config( @@ -170,38 +201,6 @@ class PerconaClusterCharmTests(PerconaClusterTest): " (wanted=%s, cluster_size=%s)" % (self.units, cluster_size)) assert cluster_size >= self.units, msg - def test_110_restart_on_config_change(self): - """Checking restart happens on config change. - - Change disk format and assert then change propagates to the correct - file and that services are restarted as a result - """ - # Expected default and alternate values - set_default = {"peer-timeout": "PT3S"} - set_alternate = {"peer-timeout": "PT15S"} - - # Config file affected by juju set config change - conf_file = "/etc/mysql/percona-xtradb-cluster.conf.d/mysqld.cnf" - - # Make config change, check for service restarts - logging.debug("Setting peer timeout ...") - self.restart_on_changed( - conf_file, - set_default, - set_alternate, - {}, {}, - self.services) - logging.info("Passed restart on changed") - - def test_120_pause_resume(self): - """Run pause and resume tests. - - Pause service and check services are stopped then resume and check - they are started - """ - with self.pause_resume(self.services): - logging.info("Testing pause resume") - def test_130_change_root_password(self): """Change root password. @@ -232,7 +231,7 @@ class PerconaClusterCharmTests(PerconaClusterTest): assert code == "0", output -class PerconaClusterColdStartTest(PerconaClusterTest): +class PerconaClusterColdStartTest(PerconaClusterBaseTest): """Percona Cluster cold start tests.""" @classmethod @@ -317,14 +316,14 @@ class PerconaClusterColdStartTest(PerconaClusterTest): zaza.model.wait_for_application_states(states=states) # Update which node is the leader and which are not - self.update_leaders_and_non_leaders() + _leader, _non_leaders = self.get_leaders_and_non_leaders() # We want to test the worst possible scenario which is the # non-leader with the highest sequence number. We will use the leader # for the notify-bootstrapped after. They just need to be different # units. logging.info("Execute bootstrap-pxc action after cold boot ...") zaza.model.run_action( - self.non_leaders[0], + _non_leaders[0], "bootstrap-pxc", action_params={}) logging.debug("Wait for application states ...") @@ -349,17 +348,9 @@ class PerconaClusterColdStartTest(PerconaClusterTest): states=test_config.get("target_deploy_status", {})) -class PerconaClusterScaleTests(PerconaClusterTest): +class PerconaClusterScaleTests(PerconaClusterBaseTest): """Percona Cluster scale tests.""" - @classmethod - def setUpClass(cls): - """Run class setup for running percona scale tests. - - .. note:: these have tests have been ported from amulet tests - """ - super(PerconaClusterScaleTests, cls).setUpClass() - def test_100_kill_crm_master(self): """Ensure VIP failover. @@ -398,3 +389,35 @@ class PerconaClusterScaleTests(PerconaClusterTest): # always true. assert generic_utils.is_port_open("3306", self.vip), \ "Cannot connect to vip" + + +class MySQLInnoDBClusterTests(MySQLCommonTests): + """Mysql-innodb-cluster charm tests. + + Note: The restart on changed and pause/resume tests also validate the + changing of the R/W primary. On each mysqld shutodown a new R/W primary is + elected automatically by MySQL. + """ + + @classmethod + def setUpClass(cls): + """Run class setup for running mysql-innodb-cluster tests.""" + super().setUpClass() + cls.application = "mysql-innodb-cluster" + + def test_100_cluster_status(self): + """Checking cluster status. + + Run the cluster-status action. + """ + # Update which node is the leader and which are not + _leaders, _non_leaders = self.get_leaders_and_non_leaders() + logging.info("Execute cluster-status action") + action = zaza.model.run_action( + _non_leaders[0], + "cluster-status", + action_params={}) + cluster_status = json.loads(action.data["results"]["cluster-status"]) + assert "OK" in cluster_status["defaultReplicaSet"]["status"], ( + "Cluster status action failed.") + logging.info("Passed cluster-status action test.")