def test_cluster_password(self): midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc._get_password = mock.MagicMock() midbc._get_password.side_effect = self._fake_data _pass = "******" self.data = {"cluster-password": _pass} self.assertEqual(midbc.cluster_password, _pass)
def test_configure_instance(self): _pass = "******" _addr = "10.10.30.30" self.data = {"cluster-password": _pass} self.is_flag_set.return_value = False midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc._get_password = mock.MagicMock() midbc._get_password.side_effect = self._fake_data midbc._wait_until_connectable = mock.MagicMock() _script_template = """ dba.configureInstance('{}:{}@{}'); var myshell = shell.connect('{}:{}@{}'); myshell.runSql("RESTART;"); """.format(midbc.cluster_user, midbc.cluster_password, _addr, midbc.cluster_user, midbc.cluster_password, _addr) midbc.configure_instance(_addr) self.is_flag_set.assert_called_once_with( "leadership.set.cluster-instance-configured-{}".format(_addr)) self.subprocess.check_output.assert_called_once_with( [midbc.mysqlsh_bin, "--no-wizard", "-f", self.filename], stderr=self.stdin) self.file.write.assert_called_once_with(_script_template) midbc._wait_until_connectable.assert_called_once_with( address=_addr, username=midbc.cluster_user, password=midbc.cluster_password) self.leader_set.assert_called_once_with( {"cluster-instance-configured-{}".format(_addr): True})
def test__wait_unit_connectable(self): _pass = "******" _user = "******" _addr = "10.20.40.40" _conn_check = mock.MagicMock() midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.check_mysql_connection = _conn_check # Successful connect _conn_check.return_value = True midbc._wait_until_connectable(username=_user, password=_pass, address=_addr) _conn_check.assert_called_once_with(username=_user, password=_pass, address=_addr) # Failed to connect _conn_check.reset_mock() _conn_check.return_value = False with self.assertRaises(mysql_innodb_cluster.CannotConnectToMySQL): midbc._wait_until_connectable() _conn_check.assert_called_once_with(username=None, password=None, address=None)
def test_get_db_helper(self): _helper = mock.MagicMock() self.patch_object(mysql_innodb_cluster.mysql, "MySQL8Helper") midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() self.MySQL8Helper.return_value = _helper self.assertEqual(_helper, midbc.get_db_helper()) self.MySQL8Helper.assert_called_once()
def test_custom_assess_status_check(self): _check = mock.MagicMock() _check.return_value = None, None _conn_check = mock.MagicMock() _conn_check.return_value = True # All is well midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.check_if_paused = _check midbc.check_interfaces = _check midbc.check_mandatory_config = _check midbc.check_mysql_connection = _conn_check self.assertEqual((None, None), midbc.custom_assess_status_check()) self.assertEqual(3, len(_check.mock_calls)) _conn_check.assert_called_once_with() # First checks fail _check.return_value = "blocked", "for some reason" self.assertEqual(("blocked", "for some reason"), midbc.custom_assess_status_check()) # MySQL connect fails _check.return_value = None, None _conn_check.return_value = False self.assertEqual(("blocked", "MySQL is down"), midbc.custom_assess_status_check())
def test_configure_db_router(self): _user = "******" _addr = "10.10.90.90" _pass = "******" _json_addrs = '["10.30.10.10", "10.30.10.20", "10.30.10.30"]' _helper = mock.MagicMock() _helper.configure_router.return_value = _pass midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.get_db_helper = mock.MagicMock() midbc.get_db_helper.return_value = _helper # One host self.assertEqual(_pass, midbc.configure_db_router(_addr, _user)) _helper.configure_router.assert_called_once_with(_addr, _user) # Json multiple hosts _helper.reset_mock() _calls = [ mock.call("10.30.10.10", _user), mock.call("10.30.10.20", _user), mock.call("10.30.10.30", _user) ] self.assertEqual(_pass, midbc.configure_db_router(_json_addrs, _user)) _helper.configure_router.assert_has_calls(_calls)
def test_check_mysql_connection(self): self.patch_object(mysql_innodb_cluster.mysql.MySQLdb, "_exceptions") self._exceptions.OperationalError = Exception _helper = mock.MagicMock() _pass = "******" _root_pass = "******" _user = "******" _addr = "10.20.30.30" self.data = {"mysql.passwd": _root_pass} midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.get_db_helper = mock.MagicMock() midbc.get_db_helper.return_value = _helper midbc._get_password = mock.MagicMock() midbc._get_password.side_effect = self._fake_data self.assertTrue( midbc.check_mysql_connection(username=_user, password=_pass, address=_addr)) _helper.connect.assert_called_once_with(user=_user, password=_pass, host=_addr) _helper.reset_mock() _helper.connect.side_effect = self._exceptions.OperationalError self.assertFalse(midbc.check_mysql_connection()) _helper.connect.assert_called_once_with(user="******", password=_root_pass, host="localhost")
def test_create_cluster(self): _pass = "******" _addr = "10.10.40.40" _name = "jujuCluster" self.get_relation_ip.return_value = _addr self.data = {"cluster-password": _pass} self.is_flag_set.side_effect = [False, True] midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc._get_password = mock.MagicMock() midbc._get_password.side_effect = self._fake_data midbc._wait_until_connectable = mock.MagicMock() midbc.options.cluster_name = _name _script_template = """ shell.connect("{}:{}@{}") var cluster = dba.createCluster("{}"); """.format(midbc.cluster_user, midbc.cluster_password, midbc.cluster_address, midbc.cluster_name) midbc.create_cluster() _is_flag_set_calls = [ mock.call("leadership.set.cluster-created"), mock.call( "leadership.set.cluster-instance-configured-{}".format(_addr)) ] self.is_flag_set.assert_has_calls(_is_flag_set_calls) self.subprocess.check_output.assert_called_once_with( [midbc.mysqlsh_bin, "--no-wizard", "-f", self.filename], stderr=self.stdin) self.file.write.assert_called_once_with(_script_template) _leader_set_calls = [ mock.call({"cluster-instance-clustered-{}".format(_addr): True}), mock.call({"cluster-created": self.uuid_of_cluster}) ] self.leader_set.assert_has_calls(_leader_set_calls)
def test_get_allowed_units(self): _allowed = ["unit/2", "unit/1", "unit/0"] _expected = "unit/0 unit/1 unit/2" _helper = mock.MagicMock() midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.get_db_helper = mock.MagicMock() midbc.get_db_helper.return_value = _helper _helper.get_allowed_units.return_value = _allowed self.assertEqual(_expected, midbc.get_allowed_units("db", "user", "rel:2"))
def test_install(self): self.patch_object( mysql_innodb_cluster.charms_openstack.charm.OpenStackCharm, "install", "super_install") midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.configure_mysql_password = mock.MagicMock() midbc.configure_source = mock.MagicMock() midbc.render_all_configs = mock.MagicMock() midbc.install() self.super_install.assert_called_once() midbc.configure_mysql_password.assert_called_once() midbc.configure_source.assert_called_once() midbc.render_all_configs.assert_called_once()
def test__get_password(self): midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() # Pwgen _pwgenpass = "******" self.pwgen.return_value = _pwgenpass self.assertEqual(midbc._get_password("pwgenpw"), _pwgenpass) # Config _configpass = "******" self.config_data = {"configpw": _configpass} self.assertEqual(midbc._get_password("configpw"), _configpass) # Leader settings _leaderpass = "******" self.leader_data = {"leaderpw": _leaderpass} self.assertEqual(midbc._get_password("leaderpw"), _leaderpass)
def test_configure_mysql_password(self): _pass = "******" self.data = {"mysql.passwd": _pass} _debconf = mock.MagicMock() self.subprocess.Popen.return_value = _debconf midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc._get_password = mock.MagicMock() midbc._get_password.side_effect = self._fake_data midbc.configure_mysql_password() _calls = [] for package in ["mysql-server", "mysql-server-8.0"]: _calls.append( mock.call("{} {}/root_password password {}\n".format( package, package, _pass).encode("UTF-8"))) _calls.append( mock.call("{} {}/root_password_again password {}\n".format( package, package, _pass).encode("UTF-8"))) _debconf.stdin.write.assert_has_calls(_calls, any_order=True)
def test_create_cluster_user(self): _user = "******" _pass = "******" _addr = "10.10.20.20" _helper = mock.MagicMock() midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.get_db_helper = mock.MagicMock() midbc.get_db_helper.return_value = _helper # Non-local midbc.create_cluster_user(_addr, _user, _pass) _calls = [ mock.call("CREATE USER '{}'@'{}' IDENTIFIED BY '{}'".format( _user, _addr, _pass)), mock.call("GRANT ALL PRIVILEGES ON *.* TO '{}'@'{}'".format( _user, _addr)), mock.call("GRANT GRANT OPTION ON *.* TO '{}'@'{}'".format( _user, _addr)), mock.call("flush privileges") ] _helper.execute.assert_has_calls(_calls) # Local _localhost = "localhost" _helper.reset_mock() self.get_relation_ip.return_value = _addr midbc.create_cluster_user(_addr, _user, _pass) _calls = [ mock.call("CREATE USER '{}'@'{}' IDENTIFIED BY '{}'".format( _user, _addr, _pass)), mock.call("GRANT ALL PRIVILEGES ON *.* TO '{}'@'{}'".format( _user, _addr)), mock.call("GRANT GRANT OPTION ON *.* TO '{}'@'{}'".format( _user, _addr)), mock.call('flush privileges'), mock.call("CREATE USER '{}'@'{}' IDENTIFIED BY '{}'".format( _user, _localhost, _pass)), mock.call("GRANT ALL PRIVILEGES ON *.* TO '{}'@'{}'".format( _user, _localhost)), mock.call("GRANT GRANT OPTION ON *.* TO '{}'@'{}'".format( _user, _localhost)), mock.call("flush privileges") ] _helper.execute.assert_has_calls(_calls)
def test_states_to_check(self): self.patch_object( mysql_innodb_cluster.charms_openstack.charm.OpenStackCharm, "states_to_check", "super_states") self.super_states.return_value = {} _required_rels = ["cluster"] _name = "jujuCluster" _addr = "10.20.20.20" self.get_relation_ip.return_value = _addr midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.options.cluster_name = _name _results = midbc.states_to_check(_required_rels) _states_to_check = [x[0] for x in _results["charm"]] self.super_states.assert_called_once_with(_required_rels) self.assertTrue("charm.installed" in _states_to_check) self.assertTrue("leadership.set.cluster-instance-configured-{}".format( _addr) in _states_to_check) self.assertTrue("leadership.set.cluster-created" in _states_to_check) self.assertTrue( "leadership.set.cluster-instances-configured" in _states_to_check) self.assertTrue("leadership.set.cluster-instance-clustered-{}".format( _addr) in _states_to_check) self.assertTrue( "leadership.set.cluster-instances-clustered" in _states_to_check)
def test_add_instance_to_cluster(self): _pass = "******" _local_addr = "10.10.50.50" _remote_addr = "10.10.60.60" _name = "theCluster" self.get_relation_ip.return_value = _local_addr self.data = {"cluster-password": _pass} self.is_flag_set.return_value = False midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc._get_password = mock.MagicMock() midbc._get_password.side_effect = self._fake_data midbc._wait_until_connectable = mock.MagicMock() midbc.options.cluster_name = _name _script_template = """ shell.connect("{}:{}@{}") var cluster = dba.getCluster("{}"); print("Adding instances to the cluster."); cluster.addInstance( {{user: "******", host: "{}", password: "******", port: "3306"}}, {{recoveryMethod: "clone"}}); """.format(midbc.cluster_user, midbc.cluster_password, midbc.cluster_address, midbc.cluster_name, midbc.cluster_user, _remote_addr, midbc.cluster_password) midbc.add_instance_to_cluster(_remote_addr) self.is_flag_set.assert_called_once_with( "leadership.set.cluster-instance-clustered-{}".format( _remote_addr)) self.subprocess.check_output.assert_called_once_with( [midbc.mysqlsh_bin, "--no-wizard", "-f", self.filename], stderr=self.stdin) self.file.write.assert_called_once_with(_script_template) self.leader_set.assert_called_once_with( {"cluster-instance-clustered-{}".format(_remote_addr): True})
def test_create_databases_and_users_db_router(self): # The test setup is a bit convoluted and requires mimicking reactive, # however, this is the heart of the charm and therefore deserves to # be thoroughly tested. It is important to have multiple relations and # multiple units per relation. self.patch_object(mysql_innodb_cluster.mysql, "get_db_data") self.get_db_data.side_effect = self._fake_get_db_data _addr = "10.99.99.99" self.get_relation_ip.return_value = _addr self.interface.relations = { self.kmr_db_router.relation_id: self.kmr_db_router, self.nmr_db_router.relation_id: self.nmr_db_router } self.interface.all_joined_units = [] for rel in self.interface.relations.values(): self.interface.all_joined_units.extend(rel.joined_units) midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() midbc.get_allowed_units = mock.MagicMock() midbc.get_allowed_units.side_effect = self._fake_get_allowed_units midbc.configure_db_for_hosts = mock.MagicMock() midbc.configure_db_for_hosts.side_effect = self._fake_configure midbc.configure_db_router = mock.MagicMock() midbc.configure_db_router.side_effect = self._fake_configure # Execute the function under test midbc.create_databases_and_users(self.interface) # Validate _conigure_db_router_calls = [ mock.call(self.kmr_unit5_ip, "mysqlrouteruser"), mock.call(self.kmr_unit7_ip, "mysqlrouteruser"), mock.call(self.nmr_unit5_ip, "mysqlrouteruser"), mock.call(self.nmr_unit7_ip, "mysqlrouteruser") ] midbc.configure_db_router.assert_has_calls(_conigure_db_router_calls) _configure_db_calls = [ mock.call(self.kmr_unit5_ip, "keystone", "keystone"), mock.call(self.kmr_unit7_ip, "keystone", "keystone"), mock.call(self.nmr_unit5_ip, "nova", "nova"), mock.call(self.nmr_unit5_ip, "nova_api", "nova"), mock.call(self.nmr_unit5_ip, "nova_cell0", "nova"), mock.call(self.nmr_unit7_ip, "nova", "nova"), mock.call(self.nmr_unit7_ip, "nova_api", "nova"), mock.call(self.nmr_unit7_ip, "nova_cell0", "nova") ] midbc.configure_db_for_hosts.assert_has_calls(_configure_db_calls) _set_calls = [ mock.call(self.kmr_db_router.relation_id, _addr, "keystone-pwd", allowed_units=self._fake_get_allowed_units( None, None, self.kmr_db_router.relation_id), prefix=self.mock_unprefixed), mock.call(self.kmr_db_router.relation_id, _addr, "mysqlrouteruser-pwd", allowed_units=" ".join([ x.unit_name for x in self.kmr_db_router.joined_units ]), prefix="mysqlrouter"), mock.call(self.nmr_db_router.relation_id, _addr, "nova-pwd", allowed_units=self._fake_get_allowed_units( None, None, self.nmr_db_router.relation_id), prefix="nova"), mock.call(self.nmr_db_router.relation_id, _addr, "nova-pwd", allowed_units=self._fake_get_allowed_units( None, None, self.nmr_db_router.relation_id), prefix="novaapi"), mock.call(self.nmr_db_router.relation_id, _addr, "nova-pwd", allowed_units=self._fake_get_allowed_units( None, None, self.nmr_db_router.relation_id), prefix="novacell0"), mock.call(self.nmr_db_router.relation_id, _addr, "mysqlrouteruser-pwd", allowed_units=" ".join([ x.unit_name for x in self.nmr_db_router.joined_units ]), prefix="mysqlrouter") ] self.interface.set_db_connection_info.assert_has_calls(_set_calls)
def test_db_router_address(self): midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() _addr = "10.10.10.70" self.get_relation_ip.return_value = _addr self.assertEqual(midbc.db_router_address, _addr)
def test_cluster_name(self): midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() _name = "jujuCluster" midbc.options.cluster_name = _name self.assertEqual(midbc.cluster_name, _name)
def test_mysqlsh_bin(self): midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() self.assertEqual(midbc.mysqlsh_bin, "/snap/mysql-shell/current/usr/bin/mysqlsh")
def test_cluster_user(self): midbc = mysql_innodb_cluster.MySQLInnoDBClusterCharm() self.assertEqual(midbc.cluster_user, "clusteruser")