summaryrefslogtreecommitdiff
path: root/tests/unit/db/sqlalchemy/test_sqlalchemy.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/db/sqlalchemy/test_sqlalchemy.py')
-rw-r--r--tests/unit/db/sqlalchemy/test_sqlalchemy.py198
1 files changed, 132 insertions, 66 deletions
diff --git a/tests/unit/db/sqlalchemy/test_sqlalchemy.py b/tests/unit/db/sqlalchemy/test_sqlalchemy.py
index f7de80c..fbe8c69 100644
--- a/tests/unit/db/sqlalchemy/test_sqlalchemy.py
+++ b/tests/unit/db/sqlalchemy/test_sqlalchemy.py
@@ -17,6 +17,8 @@
"""Unit tests for SQLAlchemy specific code."""
+import logging
+
import _mysql_exceptions
import mock
import sqlalchemy
@@ -32,7 +34,6 @@ from openstack.common.db.sqlalchemy import session
from openstack.common.db.sqlalchemy import test_base
from openstack.common import log
from openstack.common import test
-from openstack.common.gettextutils import _LW, _LI
from tests.unit import test_log
@@ -379,72 +380,137 @@ class EngineFacadeTestCase(test.BaseTestCase):
expire_on_commit=True)
-class SetSQLModeTestCase(test_log.LogTestBase):
- def setUp(self):
- super(SetSQLModeTestCase, self).setUp()
- self.dbapi_mock = mock.Mock()
- self.cursor = mock.Mock()
- self.dbapi_mock.cursor.return_value = self.cursor
- # Add fake logger so we can verify log messages
- self.logger = log.getLogger('openstack.common.db.sqlalchemy.session')
- self._add_handler_with_cleanup(self.logger)
-
- def _assert_calls(self, test_mode, recommended):
- self.cursor.execute.assert_any_call("SET SESSION sql_mode = %s",
- [test_mode])
- self.cursor.execute.assert_called_with(
- "SHOW VARIABLES LIKE 'sql_mode'")
- self.assertIn(_LI('MySQL server mode set to %s') % test_mode,
+class MysqlSetCallbackTest(test_log.LogTestBase):
+
+ class FakeCursor(object):
+ def __init__(self, execs):
+ self._execs = execs
+
+ def execute(self, sql, arg):
+ self._execs.append(sql % arg)
+
+ class FakeDbapiCon(object):
+ def __init__(self, execs):
+ self._execs = execs
+
+ def cursor(self):
+ return MysqlSetCallbackTest.FakeCursor(self._execs)
+
+ class FakeResultSet(object):
+ def __init__(self, realmode):
+ self._realmode = realmode
+
+ def fetchone(self):
+ return ['ignored', self._realmode]
+
+ class FakeEngine(object):
+ def __init__(self, realmode=None):
+ self._cbs = {}
+ self._execs = []
+ self._realmode = realmode
+
+ def set_callback(self, name, cb):
+ self._cbs[name] = cb
+
+ def execute(self, sql):
+ cb = self._cbs.get('checkout', lambda *x, **y: None)
+ dbapi_con = MysqlSetCallbackTest.FakeDbapiCon(self._execs)
+ connection_rec = None # Not used.
+ connection_proxy = None # Not used.
+ cb(dbapi_con, connection_rec, connection_proxy)
+ self._execs.append(sql)
+ return MysqlSetCallbackTest.FakeResultSet(self._realmode)
+
+ def stub_listen(engine, name, cb):
+ engine.set_callback(name, cb)
+
+ @mock.patch.object(sqlalchemy.event, 'listen', side_effect=stub_listen)
+ def _call_set_callback(self, listen_mock, sql_mode=None, realmode=None):
+ engine = self.FakeEngine(realmode=realmode)
+
+ logger = log.getLogger('openstack.common.db.sqlalchemy.session')
+ self._set_log_level_with_cleanup(logger, logging.DEBUG)
+ self._add_handler_with_cleanup(logger)
+
+ session._mysql_set_mode_callback(engine, sql_mode=sql_mode)
+ return engine
+
+ def test_set_mode_traditional(self):
+ # If _mysql_set_mode_callback is called with an sql_mode, then the SQL
+ # mode is set on the connection.
+
+ engine = self._call_set_callback(sql_mode='TRADITIONAL')
+
+ exp_calls = [
+ "SET SESSION sql_mode = ['TRADITIONAL']",
+ "SHOW VARIABLES LIKE 'sql_mode'"
+ ]
+ self.assertEqual(exp_calls, engine._execs)
+
+ def test_set_mode_ansi(self):
+ # If _mysql_set_mode_callback is called with an sql_mode, then the SQL
+ # mode is set on the connection.
+
+ engine = self._call_set_callback(sql_mode='ANSI')
+
+ exp_calls = [
+ "SET SESSION sql_mode = ['ANSI']",
+ "SHOW VARIABLES LIKE 'sql_mode'"
+ ]
+ self.assertEqual(exp_calls, engine._execs)
+
+ def test_set_mode_no_mode(self):
+ # If _mysql_set_mode_callback is called with sql_mode=None, then
+ # the SQL mode is NOT set on the connection.
+
+ engine = self._call_set_callback()
+
+ exp_calls = [
+ "SHOW VARIABLES LIKE 'sql_mode'"
+ ]
+ self.assertEqual(exp_calls, engine._execs)
+
+ def test_fail_detect_mode(self):
+ # If "SHOW VARIABLES LIKE 'sql_mode'" results in no row, then
+ # we get a log indicating can't detect the mode.
+
+ self._call_set_callback()
+
+ self.assertIn('Unable to detect effective SQL mode',
self.stream.getvalue())
- if not recommended:
- self.assertIn(_LW("MySQL SQL mode is '%s', "
- "consider enabling TRADITIONAL or "
- "STRICT_ALL_TABLES")
- % test_mode,
- self.stream.getvalue())
-
- def _set_cursor_retval(self, test_mode):
- retval = mock.MagicMock()
- retval.__getitem__.return_value = test_mode
- self.cursor.fetchone.return_value = retval
-
- def test_set_mode_not_recommended(self):
- test_mode = 'foo'
- self._set_cursor_retval(test_mode)
- session._set_session_sql_mode(self.dbapi_mock, None, None,
- sql_mode=test_mode)
- self._assert_calls(test_mode, recommended=False)
-
- def test_set_mode_none(self):
- test_mode = None
- self._set_cursor_retval('')
- session._set_session_sql_mode(self.dbapi_mock, None, None,
- sql_mode=test_mode)
- self.cursor.execute.assert_called_with(
- "SHOW VARIABLES LIKE 'sql_mode'")
- self.assertIn(_LW("MySQL SQL mode is '', "
- "consider enabling TRADITIONAL or "
- "STRICT_ALL_TABLES"),
+
+ def test_logs_real_mode(self):
+ # If "SHOW VARIABLES LIKE 'sql_mode'" results in a value, then
+ # we get a log with the value.
+
+ self._call_set_callback(realmode='SOMETHING')
+
+ self.assertIn('MySQL server mode set to SOMETHING',
self.stream.getvalue())
- def test_set_mode_traditional(self):
- test_mode = 'traditional'
- self._set_cursor_retval(test_mode)
- session._set_session_sql_mode(self.dbapi_mock, None, None,
- sql_mode=test_mode)
- self._assert_calls(test_mode, True)
-
- def test_set_mode_strict_all_tables(self):
- test_mode = 'STRICT_ALL_TABLES'
- self._set_cursor_retval(test_mode)
- session._set_session_sql_mode(self.dbapi_mock, None, None,
- sql_mode=test_mode)
- self._assert_calls(test_mode, True)
-
- def test_read_mode_fail(self):
- test_mode = None
- self.cursor.fetchone.return_value = None
- session._set_session_sql_mode(self.dbapi_mock, None, None,
- sql_mode=test_mode)
- self.assertIn(_LW('Unable to detect effective SQL mode'),
+ def test_warning_when_not_traditional(self):
+ # If "SHOW VARIABLES LIKE 'sql_mode'" results in a value that doesn't
+ # include 'TRADITIONAL', then a warning is logged.
+
+ self._call_set_callback(realmode='NOT_TRADIT')
+
+ self.assertIn("consider enabling TRADITIONAL or STRICT_ALL_TABLES",
self.stream.getvalue())
+
+ def test_no_warning_when_traditional(self):
+ # If "SHOW VARIABLES LIKE 'sql_mode'" results in a value that includes
+ # 'TRADITIONAL', then no warning is logged.
+
+ self._call_set_callback(realmode='TRADITIONAL')
+
+ self.assertNotIn("consider enabling TRADITIONAL or STRICT_ALL_TABLES",
+ self.stream.getvalue())
+
+ def test_no_warning_when_strict_all_tables(self):
+ # If "SHOW VARIABLES LIKE 'sql_mode'" results in a value that includes
+ # 'STRICT_ALL_TABLES', then no warning is logged.
+
+ self._call_set_callback(realmode='STRICT_ALL_TABLES')
+
+ self.assertNotIn("consider enabling TRADITIONAL or STRICT_ALL_TABLES",
+ self.stream.getvalue())