diff --git a/setup-mysql-env.sh b/setup-mysql-env.sh index 6262e301..baea808e 100755 --- a/setup-mysql-env.sh +++ b/setup-mysql-env.sh @@ -17,6 +17,14 @@ wait_for_line () { cat "$2" >/dev/null & } +get_random_port () { + PORT=13306 + while netstat -atwn | grep "^.*:${PORT}.*:\*\s*LISTEN\s*$" + do + PORT=$(( ${PORT} + 1 )) + done +} + trap "clean_exit" EXIT # On systems like Fedora here's where mysqld can be found @@ -25,11 +33,17 @@ export PATH=$PATH:/usr/libexec # Start MySQL process for tests MYSQL_DATA=`mktemp -d /tmp/tooz-mysql-XXXXX` mkfifo ${MYSQL_DATA}/out -mysqld --datadir=${MYSQL_DATA} --pid-file=${MYSQL_DATA}/mysql.pid --socket=${MYSQL_DATA}/mysql.socket --skip-networking --skip-grant-tables &> ${MYSQL_DATA}/out & +# Initialize MySQL Data Directory +mysql_install_db --user=${USER} --ldata=${MYSQL_DATA} +# Get random unused port for mysql +get_random_port +# Start mysqld with networking (i.e. - allow connection with TCP/IP) +mysqld --no-defaults --datadir=${MYSQL_DATA} --port=${PORT} --pid-file=${MYSQL_DATA}/mysql.pid --socket=${MYSQL_DATA}/mysql.socket --slow-query-log-file=${MYSQL_DATA}/mysql-slow.log --skip-grant-tables &> ${MYSQL_DATA}/out & # Wait for MySQL to start listening to connections wait_for_line "mysqld: ready for connections." ${MYSQL_DATA}/out -mysql -S ${MYSQL_DATA}/mysql.socket -e 'CREATE DATABASE test;' -export TOOZ_TEST_MYSQL_URL="mysql://root@localhost/test?unix_socket=${MYSQL_DATA}/mysql.socket" +# The default root password is blank +mysql --host=localhost -S ${MYSQL_DATA}/mysql.socket -e 'CREATE DATABASE IF NOT EXISTS test;' +export TOOZ_TEST_MYSQL_URL="mysql://root@localhost:${PORT}/test" # Yield execution to venv command $* diff --git a/tooz/drivers/mysql.py b/tooz/drivers/mysql.py index a4551274..7e8b2947 100644 --- a/tooz/drivers/mysql.py +++ b/tooz/drivers/mysql.py @@ -108,7 +108,7 @@ class MySQLDriver(coordination.CoordinationDriver): @staticmethod def get_connection(parsed_url, options): - host = parsed_url.netloc + host = parsed_url.hostname port = parsed_url.port dbname = parsed_url.path[1:] username = parsed_url.username @@ -128,5 +128,5 @@ class MySQLDriver(coordination.CoordinationDriver): user=username, passwd=password, database=dbname) - except pymysql.err.OperationalError as e: + except (pymysql.err.OperationalError, pymysql.err.InternalError) as e: raise coordination.ToozConnectionError(utils.exception_message(e)) diff --git a/tooz/tests/test_mysql.py b/tooz/tests/test_mysql.py new file mode 100644 index 00000000..96e9e215 --- /dev/null +++ b/tooz/tests/test_mysql.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2015 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os +import uuid + +import testtools +from testtools import testcase + +from tooz import coordination +from tooz import utils + + +@testtools.skipUnless(os.getenv("TOOZ_TEST_MYSQL_URL"), + "TOOZ_TEST_MYSQL_URL env variable is not set") +class TestMYSQLDriver(testcase.TestCase): + + MYSQL_URL = os.getenv("TOOZ_TEST_MYSQL_URL") + + def _create_coordinator(self, url): + + def _safe_stop(coord): + try: + coord.stop() + except coordination.ToozError as e: + message = utils.exception_message(e) + if (message != 'Can not stop a driver which has not' + ' been started'): + raise + + coord = coordination.get_coordinator(url, + str(uuid.uuid4()).encode('ascii')) + self.addCleanup(_safe_stop, coord) + return coord + + def test_connect_failure_invalid_hostname_provided(self): + url = self.MYSQL_URL.replace('localhost', 'invalidhost') + c = self._create_coordinator(url) + self.assertRaises(coordination.ToozConnectionError, c.start) + + def test_connect_failure_invalid_port_provided(self): + url = self.MYSQL_URL.replace('localhost:13', 'localhost:54') + c = self._create_coordinator(url) + self.assertRaises(coordination.ToozConnectionError, c.start) + + def test_connect_failure_invalid_hostname_and_port_provided(self): + url = self.MYSQL_URL.replace('localhost:13', 'invalidhost:54') + c = self._create_coordinator(url) + self.assertRaises(coordination.ToozConnectionError, c.start) + + def test_connect_failure_invalid_db_name_provided(self): + url = self.MYSQL_URL.replace('test', 'invalid') + c = self._create_coordinator(url) + self.assertRaises(coordination.ToozConnectionError, c.start) + + def test_connect_success(self): + c = self._create_coordinator(self.MYSQL_URL) + c.start()