Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Hello, BTS 861511 was reported yesterday against mysql-connector-python stating the new upstream version (2.1.6) fixes CVE-2017-3590. The upstream versions diff (attached) is quite important, so i would understand if you decide not to accept a potential upload of this new version aiming for an unblock to strech, but i would still like you to have a look and decide on it. Thanks, Sandro -- System Information: Debian Release: stretch/sid APT prefers unstable APT policy: (500, 'unstable'), (1, 'experimental') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 4.2.0-1-amd64 (SMP w/8 CPU cores) Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system)
diff --git a/CHANGES.txt b/CHANGES.txt index 18112d1..6e2c797 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,11 +3,23 @@ MySQL Connector/Python 2.1 - Release Notes & Changes ==================================================== MySQL Connector/Python -Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. Full release notes: http://dev.mysql.com/doc/relnotes/connector-python/en/ +v2.1.6 +====== + +- BUG#25726671: Fix compatibility issues with the latest Django versions +- BUG#25558885: Set default connection timeout to pure connector/python +- BUG#25397650: Verify server certificate only if ssl_verify_cert is True +- BUG#25589496: Don't convert to unicode if non-ascii data is present +- BUG#25383644: Add connection back to pool on exception +- BUG#22476689: Importing world.sql fails with cext enabled +- BUG#20736339: Expect multiple include directories from mysql_config +- BUG#19685386: C extension tests are failing using MySQL 5.7.4 + v2.1.5 ====== diff --git a/PKG-INFO b/PKG-INFO index 4af4d6f..9ab448d 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: mysql-connector-python -Version: 2.1.5 +Version: 2.1.6 Summary: MySQL driver written in Python Home-page: http://dev.mysql.com/doc/connector-python/en/index.html Author: Oracle and/or its affiliates @@ -27,6 +27,8 @@ Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 Classifier: Topic :: Database Classifier: Topic :: Software Development Classifier: Topic :: Software Development :: Libraries :: Application Frameworks diff --git a/README.txt b/README.txt index 773af0b..46cce18 100644 --- a/README.txt +++ b/README.txt @@ -3,7 +3,7 @@ MySQL Connector/Python 2.1 ========================== MySQL Connector/Python -Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. License information can be found in the LICENSE.txt file. @@ -28,7 +28,7 @@ doubt, this particular copy of the software is released under the version 2 of the GNU General Public License. MySQL Connector/Python is brought to you by Oracle. -Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. License information can be found in the LICENSE.txt file. diff --git a/lib/cpy_distutils.py b/lib/cpy_distutils.py index e944ce6..04741ea 100644 --- a/lib/cpy_distutils.py +++ b/lib/cpy_distutils.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -136,21 +136,7 @@ def unix_lib_is64bit(lib_file): return False -def get_mysql_config_info(mysql_config): - """Get MySQL information using mysql_config tool - - Returns a dict. - """ - options = ['cflags', 'include', 'libs', 'libs_r', 'plugindir', 'version'] - - cmd = [mysql_config] + [ "--{0}".format(opt) for opt in options ] - - try: - proc = Popen(cmd, stdout=PIPE, universal_newlines=True) - stdout, _ = proc.communicate() - except OSError as exc: - raise DistutilsExecError("Failed executing mysql_config: {0}".format( - str(exc))) +def parse_mysql_config_info(options, stdout): log.debug("# stdout: {0}".format(stdout)) info = {} for option, line in zip(options, stdout.split('\n')): @@ -173,7 +159,28 @@ def get_mysql_config_info(mysql_config): info['lib_r_dir'] = libs[0].replace('-L', '') info['libs_r'] = [ lib.replace('-l', '') for lib in libs[1:] ] - info['include'] = info['include'].replace('-I', '') + info['include'] = [x.strip() for x in info['include'].split('-I')[1:]] + + return info + + +def get_mysql_config_info(mysql_config): + """Get MySQL information using mysql_config tool + + Returns a dict. + """ + options = ['cflags', 'include', 'libs', 'libs_r', 'plugindir', 'version'] + + cmd = [mysql_config] + [ "--{0}".format(opt) for opt in options ] + + try: + proc = Popen(cmd, stdout=PIPE, universal_newlines=True) + stdout, _ = proc.communicate() + except OSError as exc: + raise DistutilsExecError("Failed executing mysql_config: {0}".format( + str(exc))) + + info = parse_mysql_config_info(options, stdout) # Try to figure out the architecture info['arch'] = None @@ -316,7 +323,7 @@ class BuildExtDynamic(build_ext): else: raise OSError("Unsupported platform: %s" % os.name) - include_dir = os.path.join(connc_loc, 'include') + include_dirs = [os.path.join(connc_loc, 'include')] if os.name == 'nt': libraries = ['libmysql'] else: @@ -341,19 +348,20 @@ class BuildExtDynamic(build_ext): log.error(err_version) sys.exit(1) - include_dir = myc_info['include'] + include_dirs = myc_info['include'] libraries = myc_info['libs'] library_dirs = myc_info['lib_dir'] self._mysql_config_info = myc_info self.arch = self._mysql_config_info['arch'] connc_64bit = self.arch == 'x86_64' - if not os.path.exists(include_dir): - log.error(err_invalid_loc, connc_loc) - sys.exit(1) + for include_dir in include_dirs: + if not os.path.exists(include_dir): + log.error(err_invalid_loc, connc_loc) + sys.exit(1) # Set up the build_ext class - self.include_dirs.append(include_dir) + self.include_dirs.extend(include_dirs) self.libraries.extend(libraries) self.library_dirs.append(library_dirs) diff --git a/lib/mysql/connector/abstracts.py b/lib/mysql/connector/abstracts.py index c83a527..928bd8c 100644 --- a/lib/mysql/connector/abstracts.py +++ b/lib/mysql/connector/abstracts.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -62,7 +62,7 @@ class MySQLConnectionAbstract(object): self._use_unicode = True self._get_warnings = False self._raise_on_warnings = False - self._connection_timeout = None + self._connection_timeout = DEFAULT_CONFIGURATION["connect_timeout"] self._buffered = False self._unread_result = False self._have_next_result = False @@ -231,6 +231,13 @@ class MySQLConnectionAbstract(object): except KeyError: self._consume_results = False + # Configure auth_plugin + try: + self._auth_plugin = config['auth_plugin'] + del config['auth_plugin'] + except KeyError: + self._auth_plugin = '' + # Configure character set and collation if 'charset' in config or 'collation' in config: try: diff --git a/lib/mysql/connector/connection.py b/lib/mysql/connector/connection.py index 453c73e..ebf0c38 100644 --- a/lib/mysql/connector/connection.py +++ b/lib/mysql/connector/connection.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -78,7 +78,6 @@ class MySQLConnection(MySQLConnectionAbstract): self._use_unicode = True self._get_warnings = False self._raise_on_warnings = False - self._connection_timeout = None self._buffered = False self._unread_result = False self._have_next_result = False @@ -184,6 +183,7 @@ class MySQLConnection(MySQLConnectionAbstract): Returns subclass of MySQLBaseSocket. """ + # pylint: disable=R0204 conn = None if self.unix_socket and os.name != 'nt': conn = MySQLUnixSocket(unix_socket=self.unix_socket) @@ -191,6 +191,7 @@ class MySQLConnection(MySQLConnectionAbstract): conn = MySQLTCPSocket(host=self.server_host, port=self.server_port, force_ipv6=self._force_ipv6) + # pylint: enable=R0204 conn.set_connection_timeout(self._connection_timeout) return conn @@ -440,14 +441,17 @@ class MySQLConnection(MySQLConnectionAbstract): rows = self._protocol.read_binary_result( self._socket, columns, count) else: - rows = self._protocol.read_text_result(self._socket, self._server_version, count=count) + rows = self._protocol.read_text_result(self._socket, + self._server_version, + count=count) except errors.Error as err: self.unread_result = False raise err if rows[-1] is not None: - ek = rows[-1] # OK or EOF - self._handle_server_status(ek['status_flag'] if 'status_flag' in ek else ek['server_status']) + row = rows[-1] # OK or EOF + self._handle_server_status(row['status_flag'] if 'status_flag' in + row else row['server_status']) self.unread_result = False return rows diff --git a/lib/mysql/connector/connection_cext.py b/lib/mysql/connector/connection_cext.py index 9c00a9a..cf29c3b 100644 --- a/lib/mysql/connector/connection_cext.py +++ b/lib/mysql/connector/connection_cext.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -54,6 +54,7 @@ else: HAVE_CMYSQL = True # pylint: enable=F0401,C0413 + class CMySQLConnection(MySQLConnectionAbstract): """Class initiating a MySQL Connection using Connector/C""" @@ -64,7 +65,6 @@ class CMySQLConnection(MySQLConnectionAbstract): raise RuntimeError( "MySQL Connector/Python C Extension not available") self._cmysql = None - self._connection_timeout = 2 self._columns = [] self.converter = None super(CMySQLConnection, self).__init__(**kwargs) @@ -139,12 +139,11 @@ class CMySQLConnection(MySQLConnectionAbstract): def _open_connection(self): charset_name = CharacterSet.get_info(self._charset_id)[0] - - self._cmysql = _mysql_connector.MySQL( + self._cmysql = _mysql_connector.MySQL( # pylint: disable=E1101 buffered=self._buffered, raw=self._raw, charset_name=charset_name, - connection_timeout=int(self._connection_timeout or 10), + connection_timeout=(self._connection_timeout or 0), use_unicode=self._use_unicode, auth_plugin=self._auth_plugin) @@ -260,6 +259,7 @@ class CMySQLConnection(MySQLConnectionAbstract): raise AttributeError("count should be 1 or higher, or None") counter = 0 + # pylint: disable=R0204 try: row = self._cmysql.fetch_row() while row: @@ -278,7 +278,7 @@ class CMySQLConnection(MySQLConnectionAbstract): self.free_result() raise errors.get_mysql_exception(msg=exc.msg, errno=exc.errno, sqlstate=exc.sqlstate) - + # pylint: enable=R0204 return rows def get_row(self, binary=False, columns=None): diff --git a/lib/mysql/connector/constants.py b/lib/mysql/connector/constants.py index 8d27cb0..709e675 100644 --- a/lib/mysql/connector/constants.py +++ b/lib/mysql/connector/constants.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -686,7 +686,7 @@ class CharacterSet(_Constants): return tuple(res) -class SQLMode(_Constants): # pylint: disable=R0921 +class SQLMode(_Constants): """MySQL SQL Modes The numeric values of SQL Modes are not interesting, only the names diff --git a/lib/mysql/connector/cursor.py b/lib/mysql/connector/cursor.py index 09b7b54..3002192 100644 --- a/lib/mysql/connector/cursor.py +++ b/lib/mysql/connector/cursor.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -41,7 +41,7 @@ RE_SQL_ON_DUPLICATE = re.compile( re.I | re.M | re.S) RE_SQL_INSERT_STMT = re.compile( r"({0}|\s)*INSERT({0}|\s)*INTO\s+[`'\"]?.+[`'\"]?(?:\.[`'\"]?.+[`'\"]?)" - "{{0,2}}\s+VALUES\s*\(.+(?:\s*,.+)*\)".format(SQL_COMMENT), + r"{{0,2}}\s+VALUES\s*\(.+(?:\s*,.+)*\)".format(SQL_COMMENT), re.I | re.M | re.S) RE_SQL_INSERT_VALUES = re.compile(r'.*VALUES\s*(\(.*\)).*', re.I | re.M | re.S) RE_PY_PARAM = re.compile(b'(%s)') @@ -97,20 +97,27 @@ def _bytestr_format_dict(bytestr, value_dict): b'x=%(y)s y=%(x)s' """ def replace(matchobj): + """Replace pattern.""" value = None groups = matchobj.groupdict() if groups["conversion_type"] == b"%": value = b"%" if groups["conversion_type"] == b"s": - key = groups["mapping_key"].encode("utf-8") \ - if PY2 else groups["mapping_key"] + key = groups["mapping_key"] value = value_dict[key] if value is None: raise ValueError("Unsupported conversion_type: {0}" "".format(groups["conversion_type"])) - return value.decode("utf-8") if PY2 else value - return RE_PY_MAPPING_PARAM.sub(replace, bytestr.decode("utf-8") - if PY2 else bytestr) + return bytes(value) if PY2 else value + + stmt = RE_PY_MAPPING_PARAM.sub(replace, bytestr) + if PY2: + try: + return stmt.decode("utf-8") + except UnicodeDecodeError: + pass + return stmt + class CursorBase(MySQLCursorAbstract): """ @@ -749,10 +756,12 @@ class MySQLCursor(CursorBase): can_consume_results = self._connection._consume_results for result in self._connection.cmd_query_iter(call): self._connection._consume_results = False + # pylint: disable=R0204 if self._raw: tmp = MySQLCursorBufferedRaw(self._connection._get_self()) else: tmp = MySQLCursorBuffered(self._connection._get_self()) + # pylint: enable=R0204 tmp._executed = "(a result of {0})".format(call) tmp._handle_result(result) if tmp._warnings is not None: @@ -760,7 +769,7 @@ class MySQLCursor(CursorBase): if 'columns' in result: results.append(tmp) self._connection._consume_results = can_consume_results - #pylint: enable=W0212 + # pylint: enable=W0212 if argnames: select = "SELECT {0}".format(','.join(argtypes)) diff --git a/lib/mysql/connector/cursor_cext.py b/lib/mysql/connector/cursor_cext.py index 4dd6e9a..df5fed3 100644 --- a/lib/mysql/connector/cursor_cext.py +++ b/lib/mysql/connector/cursor_cext.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -28,6 +28,8 @@ from collections import namedtuple import re import weakref +from _mysql_connector import MySQLInterfaceError # pylint: disable=F0401,E0611 + from .abstracts import MySQLConnectionAbstract, MySQLCursorAbstract from .catch23 import PY2, isunicode from . import errors @@ -39,7 +41,6 @@ from .cursor import ( RE_SQL_SPLIT_STMTS ) -from _mysql_connector import MySQLInterfaceError # pylint: disable=F0401 class _ParamSubstitutor(object): @@ -204,7 +205,10 @@ class CMySQLCursor(MySQLCursorAbstract): if exc.errno != CR_NO_RESULT_SET: raise i += 1 - self._executed = executed_list[i].strip() + try: + self._executed = executed_list[i].strip() + except IndexError: + self._executed = executed_list[0] yield self return @@ -429,14 +433,14 @@ class CMySQLCursor(MySQLCursorAbstract): results = [] while self._cnx.result_set_available: result = self._cnx.fetch_eof_columns() - # pylint: disable=W0212 + # pylint: disable=W0212,R0204 if self._raw: cur = CMySQLCursorBufferedRaw(self._cnx._get_self()) else: cur = CMySQLCursorBuffered(self._cnx._get_self()) cur._executed = "(a result of {0})".format(call) cur._handle_result(result) - # pylint: enable=W0212 + # pylint: enable=W0212,R0204 results.append(cur) self._cnx.next_result() self._stored_results = results @@ -807,4 +811,3 @@ class CMySQLCursorPrepared(CMySQLCursor): super(CMySQLCursorPrepared, self).__init__(connection) raise NotImplementedError( "Alternative: Use connection.MySQLCursorPrepared") - diff --git a/lib/mysql/connector/django/introspection.py b/lib/mysql/connector/django/introspection.py index 77e5503..35b3018 100644 --- a/lib/mysql/connector/django/introspection.py +++ b/lib/mysql/connector/django/introspection.py @@ -279,9 +279,8 @@ class DatabaseIntrospection(BaseDatabaseIntrospection): 'unique': False, 'index': False, 'check': False, - 'foreign_key': ( - (ref_table, ref_column) if ref_column else None, - ) + 'foreign_key': \ + (ref_table, ref_column) if ref_column else None } constraints[constraint]['columns'].add(column) # Now get the constraint types diff --git a/lib/mysql/connector/django/operations.py b/lib/mysql/connector/django/operations.py index 127750d..8b23290 100644 --- a/lib/mysql/connector/django/operations.py +++ b/lib/mysql/connector/django/operations.py @@ -185,6 +185,10 @@ class DatabaseOperations(BaseDatabaseOperations): 'value for AutoField.') return value + if django.VERSION > (1, 8): + def adapt_datetimefield_value(self, value): + return self.value_to_db_datetime(value) + def value_to_db_datetime(self, value): if value is None: return None @@ -202,6 +206,10 @@ class DatabaseOperations(BaseDatabaseOperations): return datetime_to_mysql(value) return self.connection.converter.to_mysql(value) + if django.VERSION > (1, 8): + def adapt_timefield_value(self, value): + return self.value_to_db_time(value) + def value_to_db_time(self, value): if value is None: return None @@ -218,9 +226,15 @@ class DatabaseOperations(BaseDatabaseOperations): def max_name_length(self): return 64 - def bulk_insert_sql(self, fields, num_values): - items_sql = "({0})".format(", ".join(["%s"] * len(fields))) - return "VALUES " + ", ".join([items_sql] * num_values) + if django.VERSION < (1, 9): + def bulk_insert_sql(self, fields, num_values): + items_sql = "({0})".format(", ".join(["%s"] * len(fields))) + return "VALUES " + ", ".join([items_sql] * num_values) + else: + def bulk_insert_sql(self, fields, placeholder_rows): + placeholder_rows_sql = (", ".join(row) for row in placeholder_rows) + values_sql = ", ".join("({0})".format(sql) for sql in placeholder_rows_sql) + return "VALUES " + values_sql if django.VERSION < (1, 8): def year_lookup_bounds(self, value): diff --git a/lib/mysql/connector/errors.py b/lib/mysql/connector/errors.py index ea354f2..d2eedfb 100644 --- a/lib/mysql/connector/errors.py +++ b/lib/mysql/connector/errors.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -301,4 +301,5 @@ _ERROR_EXCEPTIONS = { 2049: NotSupportedError, 2055: OperationalError, 2061: InterfaceError, + 2026: InterfaceError, } diff --git a/lib/mysql/connector/fabric/__init__.py b/lib/mysql/connector/fabric/__init__.py index b3d6a06..c88fe03 100644 --- a/lib/mysql/connector/fabric/__init__.py +++ b/lib/mysql/connector/fabric/__init__.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -26,6 +26,15 @@ from collections import namedtuple +from .connection import ( + MODE_READONLY, MODE_READWRITE, + STATUS_PRIMARY, STATUS_SECONDARY, + SCOPE_GLOBAL, SCOPE_LOCAL, + Fabric, FabricConnection, + MySQLFabricConnection, + FabricSet, +) + # Order of field_names must match how Fabric is returning the data FabricMySQLServer = namedtuple( 'FabricMySQLServer', @@ -39,15 +48,6 @@ FabricShard = namedtuple( 'shard', 'shard_type', 'group', 'global_group'] ) -from .connection import ( - MODE_READONLY, MODE_READWRITE, - STATUS_PRIMARY, STATUS_SECONDARY, - SCOPE_GLOBAL, SCOPE_LOCAL, - Fabric, FabricConnection, - MySQLFabricConnection, - FabricSet, -) - def connect(**kwargs): """Create a MySQLFabricConnection object""" diff --git a/lib/mysql/connector/fabric/caching.py b/lib/mysql/connector/fabric/caching.py index a24d6b1..9073498 100644 --- a/lib/mysql/connector/fabric/caching.py +++ b/lib/mysql/connector/fabric/caching.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -116,32 +116,33 @@ class CacheShardTable(CacheEntry): def add_partition(self, key, group): """Add sharding information for a group""" if self.shard_type == 'RANGE': - key = int(key) + _key = int(key) elif self.shard_type == 'RANGE_DATETIME': try: if ':' in key: - key = datetime.strptime(key, "%Y-%m-%d %H:%M:%S") + # pylint: disable=R0204 + _key = datetime.strptime(key, "%Y-%m-%d %H:%M:%S") else: - key = datetime.strptime(key, "%Y-%m-%d").date() + _key = datetime.strptime(key, "%Y-%m-%d").date() except: raise ValueError( "RANGE_DATETIME key could not be parsed, was: {0}".format( key )) elif self.shard_type == 'RANGE_STRING': - pass + _key = key elif self.shard_type == "HASH": - pass + _key = key else: raise ValueError("Unsupported sharding type {0}".format( self.shard_type )) - self.partitioning[key] = { + self.partitioning[_key] = { 'group': group, } self.reset_ttl() - bisect.insort_right(self.keys, key) - insort_right_rev(self.keys_reversed, key) + bisect.insort_right(self.keys, _key) + insort_right_rev(self.keys_reversed, _key) @classmethod def hash_index(cls, part1, part2=None): @@ -175,6 +176,7 @@ class CacheGroup(CacheEntry): group=self.group_name, ) + class FabricCache(object): """Singleton class for caching Fabric data diff --git a/lib/mysql/connector/fabric/connection.py b/lib/mysql/connector/fabric/connection.py index 44da175..7e2f657 100644 --- a/lib/mysql/connector/fabric/connection.py +++ b/lib/mysql/connector/fabric/connection.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -27,13 +27,34 @@ import sys import datetime import time import uuid -from base64 import b16decode -from bisect import bisect -from hashlib import md5 import logging import socket import collections +from base64 import b16decode +from bisect import bisect +from hashlib import md5 + +import mysql.connector + +from ..connection import MySQLConnection +from ..conversion import MySQLConverter +from ..pooling import MySQLConnectionPool +from ..errors import ( + Error, InterfaceError, NotSupportedError, MySQLFabricError, InternalError, + DatabaseError +) +from ..cursor import ( + MySQLCursor, MySQLCursorBuffered, + MySQLCursorRaw, MySQLCursorBufferedRaw +) +from .. import errorcode +from . import FabricMySQLServer, FabricShard +from .caching import FabricCache +from .balancing import WeightedRoundRobin +from .. import version +from ..catch23 import PY2, isunicode, UNICODE_TYPES + # pylint: disable=F0401,E0611 try: from xmlrpclib import Fault, ServerProxy, Transport @@ -47,7 +68,7 @@ except ImportError: if sys.version_info[0] == 2: try: - from httplib import HTTPSConnection + from httplib import HTTPSConnection # pylint: disable=C0412 except ImportError: HAVE_SSL = False else: @@ -59,26 +80,7 @@ else: HAVE_SSL = False else: HAVE_SSL = True -# pylint: enable=F0401,E0611 -import mysql.connector -from ..connection import MySQLConnection -from ..conversion import MySQLConverter -from ..pooling import MySQLConnectionPool -from ..errors import ( - Error, InterfaceError, NotSupportedError, MySQLFabricError, InternalError, - DatabaseError -) -from ..cursor import ( - MySQLCursor, MySQLCursorBuffered, - MySQLCursorRaw, MySQLCursorBufferedRaw -) -from .. import errorcode -from . import FabricMySQLServer, FabricShard -from .caching import FabricCache -from .balancing import WeightedRoundRobin -from .. import version -from ..catch23 import PY2, isunicode, UNICODE_TYPES RESET_CACHE_ON_ERROR = ( errorcode.CR_SERVER_LOST, @@ -213,8 +215,7 @@ class MySQLRPCProtocol(object): kwargs = self._process_params_dict(kwargs) params.extend(kwargs) - params = ', '.join(params) - return params + return ', '.join(params) def execute(self, group, command, *args, **kwargs): """Executes the given command with MySQL protocol @@ -460,7 +461,7 @@ if HAVE_SSL: if PY2: urllib2.HTTPSHandler.__init__(self) else: - super().__init__() # pylint: disable=W0104 + super().__init__() # pylint: disable=W0104,E1004 self._ssl_config = ssl_config def https_open(self, req): @@ -488,7 +489,7 @@ class FabricTransport(Transport): if PY2: Transport.__init__(self, use_datetime=False) else: - super().__init__(use_datetime=False) + super().__init__(use_datetime=False) # pylint: disable=E1004 self._username = username self._password = password self._use_datetime = use_datetime diff --git a/lib/mysql/connector/locales/__init__.py b/lib/mysql/connector/locales/__init__.py index ad784e6..cd5e54f 100644 --- a/lib/mysql/connector/locales/__init__.py +++ b/lib/mysql/connector/locales/__init__.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -68,4 +68,3 @@ def get_client_error(error, language='eng'): return None raise ValueError("error argument needs to be either an integer or string") - diff --git a/lib/mysql/connector/network.py b/lib/mysql/connector/network.py index 1ef55a3..7c097b7 100644 --- a/lib/mysql/connector/network.py +++ b/lib/mysql/connector/network.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -168,9 +168,9 @@ class BaseMySQLSocket(object): tmpbuf = bytearray() for pkt in pkts: tmpbuf += pkt - tmpbuf = buffer(tmpbuf) # pylint: disable=E0602 + tmpbuf = buffer(tmpbuf) # pylint: disable=E0602,R0204 else: - tmpbuf = b''.join(pkts) + tmpbuf = b''.join(pkts) # pylint: disable=R0204 del pkts zbuf = zlib.compress(tmpbuf[:16384]) header = (struct.pack('<I', len(zbuf))[0:3] @@ -181,7 +181,7 @@ class BaseMySQLSocket(object): zpkts.append(header + zbuf) tmpbuf = tmpbuf[16384:] pllen = len(tmpbuf) - self.next_compressed_packet_number + self.next_compressed_packet_number # pylint: disable=W0104 while pllen > maxpktlen: zbuf = zlib.compress(tmpbuf[:maxpktlen]) header = (struct.pack('<I', len(zbuf))[0:3] @@ -192,7 +192,7 @@ class BaseMySQLSocket(object): zpkts.append(header + zbuf) tmpbuf = tmpbuf[maxpktlen:] pllen = len(tmpbuf) - self.next_compressed_packet_number + self.next_compressed_packet_number # pylint: disable=W0104 if tmpbuf: zbuf = zlib.compress(tmpbuf) header = (struct.pack('<I', len(zbuf))[0:3] diff --git a/lib/mysql/connector/pooling.py b/lib/mysql/connector/pooling.py index 17d2f59..b671120 100644 --- a/lib/mysql/connector/pooling.py +++ b/lib/mysql/connector/pooling.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -112,12 +112,13 @@ class PooledMySQLConnection(object): When the pool is configured to reset the session, the session state will be cleared by re-authenticating the user. """ - cnx = self._cnx - if self._cnx_pool.reset_session: - cnx.reset_session() - - self._cnx_pool.add_connection(cnx) - self._cnx = None + try: + cnx = self._cnx + if self._cnx_pool.reset_session: + cnx.reset_session() + finally: + self._cnx_pool.add_connection(cnx) + self._cnx = None def config(self, **kwargs): """Configuration is done through the pool""" diff --git a/lib/mysql/connector/protocol.py b/lib/mysql/connector/protocol.py index 6c75a0a..9014897 100644 --- a/lib/mysql/connector/protocol.py +++ b/lib/mysql/connector/protocol.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -29,7 +29,7 @@ import datetime from decimal import Decimal from .constants import ( - FieldFlag, ServerCmd, FieldType, ClientFlag, MAX_MYSQL_TABLE_COLUMNS) + FieldFlag, ServerCmd, FieldType, ClientFlag) from . import errors, utils from .authentication import get_auth_plugin from .catch23 import PY2, struct_unpack @@ -61,7 +61,7 @@ class MySQLProtocol(object): ssl_enabled=ssl_enabled) plugin_auth_response = auth.auth_response() except (TypeError, errors.InterfaceError) as exc: - raise errors.ProgrammingError( + raise errors.InterfaceError( "Failed authentication: {0}".format(str(exc))) if client_flags & ClientFlag.SECURE_CONNECTION: @@ -90,7 +90,7 @@ class MySQLProtocol(object): username_bytes = username.encode('utf8') # pylint: disable=E1103 except AttributeError: # Username is already bytes - username_bytes = username + username_bytes = username # pylint: disable=R0204 packet = struct.pack('<IIB{filler}{usrlen}sx'.format( filler='x' * 23, usrlen=len(username_bytes)), client_flags, max_allowed_packet, charset, @@ -141,7 +141,7 @@ class MySQLProtocol(object): username_bytes = username.encode('utf8') # pylint: disable=E1103 except AttributeError: # Username is already bytes - username_bytes = username + username_bytes = username # pylint: disable=R0204 packet = struct.pack('<B{usrlen}sx'.format(usrlen=len(username_bytes)), ServerCmd.CHANGE_USER, username_bytes) @@ -328,7 +328,7 @@ class MySQLProtocol(object): packet = sock.recv() datas.append(packet[4:]) rowdata = utils.read_lc_string_list(bytearray(b'').join(datas)) - elif (packet[4] == 254 and packet[0] < 7): + elif packet[4] == 254 and packet[0] < 7: eof = self.parse_eof(packet) rowdata = None else: @@ -385,7 +385,7 @@ class MySQLProtocol(object): mcs = 0 if length == 11: mcs = struct_unpack('I', packet[8:length + 1])[0] - value = datetime.datetime( + value = datetime.datetime( # pylint: disable=R0204 year=struct_unpack('H', packet[1:3])[0], month=packet[3], day=packet[4], diff --git a/lib/mysql/connector/version.py b/lib/mysql/connector/version.py index a3c311c..f6b49d5 100644 --- a/lib/mysql/connector/version.py +++ b/lib/mysql/connector/version.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -26,7 +26,7 @@ The file version.py gets installed and is available after installation as mysql.connector.version. """ -VERSION = (2, 1, 5, '', 0) +VERSION = (2, 1, 6, '', 0) if VERSION[3] and VERSION[4]: VERSION_TEXT = '{0}.{1}.{2}{3}{4}'.format(*VERSION) diff --git a/setupinfo.py b/setupinfo.py index 6784a38..18998ae 100644 --- a/setupinfo.py +++ b/setupinfo.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -88,8 +88,8 @@ libraries and implements the DB API v2.0 specification (PEP-249). """ author = 'Oracle and/or its affiliates' author_email = '' -maintainer = 'Geert Vanderkelen' -maintainer_email = 'geert.vanderke...@oracle.com' +maintainer = 'Nuno Mariz' +maintainer_email = 'nuno.ma...@oracle.com' cpy_gpl_license = "GNU GPLv2 (with FOSS License Exception)" keywords = "mysql db", url = 'http://dev.mysql.com/doc/connector-python/en/index.html' @@ -109,6 +109,8 @@ classifiers = [ 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', 'Topic :: Database', 'Topic :: Software Development', 'Topic :: Software Development :: Libraries :: Application Frameworks', diff --git a/src/mysql_capi.c b/src/mysql_capi.c index e1f995b..370cceb 100644 --- a/src/mysql_capi.c +++ b/src/mysql_capi.c @@ -1,6 +1,6 @@ /* # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -363,7 +363,7 @@ MySQL_init(MySQL *self, PyObject *args, PyObject *kwds) // Initialization expect -1 when parsing arguments failed if (!PyArg_ParseTupleAndKeywords(args, kwds, - "|O!O!O!O!O!O", kwlist, + "|O!O!O!O!O!O!", kwlist, &PyBool_Type, &self->buffered_at_connect, &PyBool_Type, &self->raw_at_connect, &PyStringType, &self->charset_name, @@ -393,6 +393,10 @@ MySQL_init(MySQL *self, PyObject *args, PyObject *kwds) if (auth_plugin) { + if (strcmp(PyStringAsString(auth_plugin), "") == 0) + { + auth_plugin= Py_None; + } if (auth_plugin != Py_None) { tmp= self->auth_plugin; @@ -1036,6 +1040,7 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds) unsigned int ssl_mode; #endif my_bool abool; + my_bool ssl_enabled= 0; MYSQL *res; static char *kwlist[]= @@ -1112,8 +1117,8 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds) mysql_options(&self->session, MYSQL_OPT_WRITE_TIMEOUT, (char*)&tmp_uint); if (ssl_ca || ssl_cert || ssl_key) { + ssl_enabled= 1; #if MYSQL_VERSION_ID > 50703 && MYSQL_VERSION_ID < 50711 - printf(">>>> %d\n", MYSQL_VERSION_ID); { abool= 1; mysql_options(&self->session, MYSQL_OPT_SSL_ENFORCE, (char*)&abool); @@ -1140,8 +1145,10 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds) MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (char*)&abool); } #endif + mysql_ssl_set(&self->session, ssl_key, ssl_cert, ssl_ca, NULL, NULL); + } else { + mysql_ssl_set(&self->session, ssl_key, ssl_cert, NULL, NULL, NULL); } - mysql_ssl_set(&self->session, ssl_key, ssl_cert, ssl_ca, NULL, NULL); } else { // Make sure to not enforce SSL #if MYSQL_VERSION_ID > 50703 && MYSQL_VERSION_ID < 50711 @@ -1158,9 +1165,27 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds) #endif } + Py_END_ALLOW_THREADS if (PyString_Check(self->auth_plugin)) { auth_plugin= PyStringAsString(self->auth_plugin); mysql_options(&self->session, MYSQL_DEFAULT_AUTH, auth_plugin); + if (strcmp(auth_plugin, "sha256_password") == 0 && !ssl_enabled) + { + PyObject *exc_type= MySQLInterfaceError; + PyObject *err_no= PyInt_FromLong(2002); + PyObject *err_msg= PyStringFromString("sha256_password requires SSL"); + PyObject *err_obj= NULL; + err_obj= PyObject_CallFunctionObjArgs(exc_type, err_msg, NULL); + PyObject_SetAttr(err_obj, PyStringFromString("sqlstate"), Py_None); + PyObject_SetAttr(err_obj, PyStringFromString("errno"), err_no); + PyObject_SetAttr(err_obj, PyStringFromString("msg"), err_msg); + PyErr_SetObject(exc_type, err_obj); + Py_XDECREF(exc_type); + Py_XDECREF(err_no); + Py_XDECREF(err_msg); + return NULL; + } + if (strcmp(auth_plugin, "mysql_clear_password") == 0) { abool= 1; @@ -1168,6 +1193,7 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds) (char*)&abool); } } + Py_BEGIN_ALLOW_THREADS if (database && strlen(database) == 0) { diff --git a/tests/cext/test_cext_api.py b/tests/cext/test_cext_api.py index fff08ed..3a2cf74 100644 --- a/tests/cext/test_cext_api.py +++ b/tests/cext/test_cext_api.py @@ -529,6 +529,8 @@ class CExtMySQLTests(tests.MySQLConnectorTests): cmy1.set_character_set('big5') self.assertEqual(exp, get_variables(cmy1, variables=variables)) + @unittest.skipIf(tests.MYSQL_VERSION == (5, 7, 4), + "test_get_ssl_cipher not tested with MySQL version 5.7.4") def test_get_ssl_cipher(self): cmy1 = MySQL(buffered=True) self.assertRaises(MySQLInterfaceError, cmy1.get_ssl_cipher) diff --git a/tests/cext/test_cext_cursor.py b/tests/cext/test_cext_cursor.py index 2584c57..ea809ee 100644 --- a/tests/cext/test_cext_cursor.py +++ b/tests/cext/test_cext_cursor.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -29,6 +29,7 @@ import logging import unittest from mysql.connector import errors, errorcode +from .. import PY2 import tests @@ -516,6 +517,28 @@ class CExtMySQLCursorTests(tests.CMySQLCursorTests): cur.close() self.cnx.rollback() + cur = self._get_cursor(self.cnx) + cur.execute("DROP PROCEDURE IF EXISTS multi_results") + procedure = ( + "CREATE PROCEDURE multi_results () " + "BEGIN SELECT 1; SELECT 'ham'; END" + ) + cur.execute(procedure) + stmt = "CALL multi_results()" + if not PY2: + stmt = b"CALL multi_results()" + exp_result = [[(1,)], [(u'ham',)]] + results = [] + for result in cur.execute(stmt, multi=True): + if result.with_rows: + self.assertEqual(stmt, result._executed) + results.append(result.fetchall()) + + self.assertEqual(exp_result, results) + cur.execute("DROP PROCEDURE multi_results") + + cur.close() + class CExtMySQLCursorBufferedTests(tests.CMySQLCursorTests): diff --git a/tests/data/ssl/tests_CA_cert.pem b/tests/data/ssl/tests_CA_cert.pem index b2032c0..6ce8c47 100644 --- a/tests/data/ssl/tests_CA_cert.pem +++ b/tests/data/ssl/tests_CA_cert.pem @@ -1,20 +1,19 @@ -----BEGIN CERTIFICATE----- -MIIDVzCCAj+gAwIBAgIJAIUsZ/vX9kOGMA0GCSqGSIb3DQEBBQUAMEIxJTAjBgNV -BAsMHE15U1FMQ29ubmVjdG9yUHl0aG9uIFJvb3QgQ0ExGTAXBgNVBAMMEE15Q29u -blB5IFJvb3QgQ0EwHhcNMTMwMzI2MTUzNTUyWhcNMjIwNDE0MTUzNTUyWjBCMSUw -IwYDVQQLDBxNeVNRTENvbm5lY3RvclB5dGhvbiBSb290IENBMRkwFwYDVQQDDBBN -eUNvbm5QeSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA -qWcX9kD+b8c3hkPtPlIgwTsfGvhm/bJ64RHjCtQc2pi/fv9hlcryor8tWmdCCcw7 -ajg5n/QAIJ8crD5D0kheGEnWVI7dyVxZVfT3CiKuS+GBxuQP2ejJi4aDGh2McVv4 -aq1dXRqf2YWkM8PUjM0lzUD9MC9S4APtP6ux0TBhz5rv2ZWdg2EAjAl7Q56KM5m6 -odpF+Z1ExnfVpNzWnpvlYHJ+GhbVWb2F0NbqBTmz4OLEAxU/O2fo43dwVlHp+yNd -ib2V+VxeeyZmTt1CIeK6DStAiKdNLN5/N/+2FHZ9/XcA6qqxLFLeuTIySlPmuaX6 -u2C8tmOWp99TCUL+GZ2iBwIDAQABo1AwTjAdBgNVHQ4EFgQU1objOGh5rgtBTmjK -gPkN6SgXl64wHwYDVR0jBBgwFoAU1objOGh5rgtBTmjKgPkN6SgXl64wDAYDVR0T -BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAWgHZzUo8oGP7YxMn9YACdbipTRYU -IzGF+Cf0ueXktcEDbq7AIa6MsxXTp8pFOObvLiiecrMngYlqfHlYPL2HG+zOLDig -nmkO4pGwTqCDZHO4aYBdiVMlaxSpxMX9R/kFYRP1P4AGLOp66FirNO5iLNlTIjpf -PGebF+k0B1zUSUPsrZfa/d29XcJxBaw7aEOhARQYsymItasnTdcKvjZp1ahGnZYz -yCDtJjVbXK/4qEtiSA4qcV1HrNuHmhZEwWahntLqo++x3oLK7DrWfHwTX5gHMyv2 -DGTggnNfB8uzzNe3giT0j6ie9DJEnvv1hB0GpUToUNECusrKsYnWLdJkIA== +MIIDADCCAegCCQDmOCndJJOWFjANBgkqhkiG9w0BAQsFADBCMSUwIwYDVQQLDBxN +eVNRTENvbm5lY3RvclB5dGhvbiBSb290IENBMRkwFwYDVQQDDBBNeUNvbm5QeSBS +b290IENBMB4XDTE3MDMxNzE1NTAzNloXDTI2MDQwNTE1NTAzNlowQjElMCMGA1UE +CwwcTXlTUUxDb25uZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25u +UHkgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANex2fME +DGfFk6KIIjsCpXQ6Rsv7nClZ+H7iT/xBMDHtQbqVYX1HIDYGRApWIi0Mmg3hosri +6TO5wJIMMEwcSurVStyLXPpCT4Dg3iDuKToYfNNGtuH9DFWh1fnkeni0gbEh+/yT +PIe3FLZCHD+F12ST1z88i4LXOG4NuozKI2cmQcHxdVkYYzknMX4IKdP4AniPgMq0 +9YmQJjXH6y7lPzDXeUuG8YrOSuvfl4W2bjht4mGP6YUUQkwZ5qbRQfrkduQB3+pa ++7P6ckd3q91j1+H1kRCn4a1S28xzPOaey6cLQ/DRVKP9EwPVV9H3/Wm8BdTr0ZMs +1s2VQtocmzcp35kCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAGvUp9Du79gpN/pBD +8eG7ZX/YMpK1cbzUwD+TqmP7QnXItRrZalbmadzZ6P161ff0QOEQPxL181+EEXFe +yC8f33EGu9n6ZlSnj/HrdMZ2sjv8QA8M4Vg2vn81qUT/EsJQOjJA6n30ybncZHWB +ovmFgBlq9miX2gDCMRosiRkzm4HAETdWQhiQ/jU4RV+pgP3/sd/mk/u2D5nqMeuT +Ni61ke1CfskuCar5knXTdw7PYfCVXrD1ndgpf7e+qdz534GMkHcFKQkEvWE+ZuWj +CHx9t32JFekCSzJCYs5YuAfuIJc0aC+RmA/lF7UUGyj++wWFAMnkmVEf5MM3WGjM +HRerEg== -----END CERTIFICATE----- diff --git a/tests/data/ssl/tests_CA_key.pem b/tests/data/ssl/tests_CA_key.pem index bfccf21..1941850 100644 --- a/tests/data/ssl/tests_CA_key.pem +++ b/tests/data/ssl/tests_CA_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/tests/data/ssl/tests_client_cert.pem b/tests/data/ssl/tests_client_cert.pem index 82fcf77..05ae516 100644 --- a/tests/data/ssl/tests_client_cert.pem +++ b/tests/data/ssl/tests_client_cert.pem @@ -1,18 +1,67 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 3 (0x3) + Signature Algorithm: md5WithRSAEncryption + Issuer: OU=MySQLConnectorPython Root CA, CN=MyConnPy Root CA + Validity + Not Before: Mar 17 15:50:37 2017 GMT + Not After : Mar 17 15:50:37 2018 GMT + Subject: OU=MySQLConnectorPython Client Cert, CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b0:7b:da:61:20:7c:13:97:fa:1e:20:83:e0:40: + e8:94:4a:ea:1c:62:22:09:4e:d3:cd:30:66:73:28: + f4:ff:2d:79:a4:b6:0b:c7:b7:20:c8:f6:c0:98:66: + 3d:46:ec:f1:8c:04:8b:d7:3c:b4:fa:69:6c:c5:47: + 1b:04:a4:a3:53:5a:0a:f2:a4:f7:94:d5:2c:d7:b6: + 24:81:e0:c2:ea:51:d1:6e:8e:d4:58:dc:5b:fc:b9: + 1b:6b:7c:52:cc:17:36:85:63:ca:f0:1f:75:2f:b8: + 97:96:d1:08:ab:46:31:31:e6:9c:8b:26:a1:1b:df: + 35:66:36:d9:ba:e1:a4:3d:88:25:7a:9d:68:d3:62: + 20:ec:14:b0:59:2c:33:40:11:cf:03:70:17:1c:de: + 65:ca:0c:2e:26:2d:f0:33:13:52:d7:0f:69:d7:c0: + d6:f8:71:03:19:f4:79:3d:66:98:56:d2:44:db:bf: + aa:a7:d6:fc:2d:0b:29:63:0a:d4:3d:5e:7e:a7:2c: + 6c:b8:2f:32:6f:51:ce:4a:2d:6a:35:54:21:33:76: + a2:64:4a:8c:1d:30:73:47:3e:90:19:68:c9:07:8f: + 14:c5:ff:93:c7:ec:b4:08:d7:30:11:f6:67:3f:7a: + 8a:57:2c:87:63:34:ff:ff:79:2b:6b:70:88:21:ca: + 4e:53 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + 2e:d2:37:97:8b:aa:05:47:8d:b4:c6:87:7d:b8:41:d6:55:12: + 84:14:8d:91:de:4f:84:15:89:a2:90:5a:0a:94:a1:c2:41:42: + 18:3c:b7:10:c7:19:b5:01:96:2e:51:83:14:2f:64:0a:96:bb: + ce:f8:28:df:ab:fe:72:05:e8:6a:fd:1d:7b:09:22:eb:26:e7: + 64:a7:a7:fe:fb:e8:e0:2f:91:e4:9e:fa:f6:ab:0b:5b:f3:82: + e0:54:d5:07:d2:05:ae:99:fd:22:d8:23:ba:e5:16:21:d7:b0: + 82:98:4a:f0:87:36:ca:1e:4e:c0:c3:6a:22:a4:37:18:5f:6f: + 6f:7b:92:e9:bb:15:77:55:6b:9a:57:35:95:4c:64:e9:bb:12: + cb:ab:67:4b:23:27:41:d3:71:15:5e:cf:6b:d6:13:05:f0:7a: + df:0f:f9:fd:bc:0d:8b:e4:cb:e7:62:67:9e:10:00:c9:9d:ea: + a7:cb:3f:ec:47:04:06:96:7f:b3:74:be:3c:cc:bd:72:05:d8: + 91:b7:d6:b1:9a:40:79:bd:eb:cb:7a:49:bc:a6:e7:61:4f:1d: + 68:79:21:ad:18:f6:13:6e:87:b6:13:a6:31:1e:f9:73:4c:ec: + 04:b4:f2:83:5a:25:ae:9c:2e:8e:3a:0a:1d:0a:fd:34:dd:d4: + 12:cc:4f:47 -----BEGIN CERTIFICATE----- -MIIC9TCCAd0CAQEwDQYJKoZIhvcNAQEFBQAwQjElMCMGA1UECwwcTXlTUUxDb25u +MIIC9TCCAd0CAQMwDQYJKoZIhvcNAQEEBQAwQjElMCMGA1UECwwcTXlTUUxDb25u ZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25uUHkgUm9vdCBDQTAe -Fw0xMzAzMjYxNTM1NTJaFw0yMjA0MTQxNTM1NTJaMD8xKTAnBgNVBAsMIE15U1FM +Fw0xNzAzMTcxNTUwMzdaFw0xODAzMTcxNTUwMzdaMD8xKTAnBgNVBAsMIE15U1FM Q29ubmVjdG9yUHl0aG9uIENsaWVudCBDZXJ0MRIwEAYDVQQDDAlsb2NhbGhvc3Qw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXbL7sr/k/W4LwwzTKJj5i -1QtcZL0tMyBhAwuI7XQVyJBVvY7dRUM+G30ADOcUw5DscYbkkVu3L2NtsnmuyB8o -0Y5bbHpTv4xTrVfsQuDkMLe+/LwFfL7XrY1Bm13xdEn345b6edfvhre7eatCgIaG -IKfFr5JDv5oN4faGEJpqYahE/WdxM7zv6xb7Wx+yqLlezldU34VcLcghi8zfDkxb -Fb4cZSgko/9RT7lTUGBJSSgITnq3Re0qANah7UbqFkTM2wfltoXGerbWMYuzOfQo -5r0FiScjuvACkDALHAdUbX4UbXasArqpGovyVqHp4OWu3FWRfcCUnxAxfj3G3x79 -AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFi+U6Fyc1L0qCTCiMvUMQuXacnOMH4q -rHm7qDKkHHcMMGsspNXvLcVKEwJrX3dhP3dZ52eKyFsOjuTkO9eU5H8V2alO8iGD -Zb6vHT/pQRInoc39SVDFx1QnJ7RlC2Z99xzncHMQChSlDCC+Lft/K5am7vXFwQ3e -icfLqmR5hz6nc+opnPc7WbQu/cc7PesP5uroyKScYoqAiDJ2cKQJQFPM4Cvt/KZ3 -22H/yCyQNkplIcrlQRF+l+sInNlJZr36INF0o91GcucyuLQzOXUn0L5eAyFzA9RQ -8xkVztqRN++CgbGAhqIt8ERBtxBvCpNxuFpgm4dPKCTLm+r7fJcKwDI= +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwe9phIHwTl/oeIIPgQOiU +SuocYiIJTtPNMGZzKPT/LXmktgvHtyDI9sCYZj1G7PGMBIvXPLT6aWzFRxsEpKNT +WgrypPeU1SzXtiSB4MLqUdFujtRY3Fv8uRtrfFLMFzaFY8rwH3UvuJeW0QirRjEx +5pyLJqEb3zVmNtm64aQ9iCV6nWjTYiDsFLBZLDNAEc8DcBcc3mXKDC4mLfAzE1LX +D2nXwNb4cQMZ9Hk9ZphW0kTbv6qn1vwtCyljCtQ9Xn6nLGy4LzJvUc5KLWo1VCEz +dqJkSowdMHNHPpAZaMkHjxTF/5PH7LQI1zAR9mc/eopXLIdjNP//eStrcIghyk5T +AgMBAAEwDQYJKoZIhvcNAQEEBQADggEBAC7SN5eLqgVHjbTGh324QdZVEoQUjZHe +T4QViaKQWgqUocJBQhg8txDHGbUBli5RgxQvZAqWu874KN+r/nIF6Gr9HXsJIusm +52Snp/776OAvkeSe+varC1vzguBU1QfSBa6Z/SLYI7rlFiHXsIKYSvCHNsoeTsDD +aiKkNxhfb297kum7FXdVa5pXNZVMZOm7EsurZ0sjJ0HTcRVez2vWEwXwet8P+f28 +DYvky+diZ54QAMmd6qfLP+xHBAaWf7N0vjzMvXIF2JG31rGaQHm968t6Sbym52FP +HWh5Ia0Y9hNuh7YTpjEe+XNM7AS08oNaJa6cLo46Ch0K/TTd1BLMT0c= -----END CERTIFICATE----- diff --git a/tests/data/ssl/tests_client_key.pem b/tests/data/ssl/tests_client_key.pem index 3c2b5c9..787bd4b 100644 --- a/tests/data/ssl/tests_client_key.pem +++ b/tests/data/ssl/tests_client_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/tests/data/ssl/tests_expired_server_cert.pem b/tests/data/ssl/tests_expired_server_cert.pem new file mode 100644 index 0000000..cfba302 --- /dev/null +++ b/tests/data/ssl/tests_expired_server_cert.pem @@ -0,0 +1,68 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 2 (0x2) + Signature Algorithm: md5WithRSAEncryption + Issuer: OU=MySQLConnectorPython Root CA, CN=MyConnPy Root CA + Validity + Not Before: Aug 15 08:00:00 2012 GMT + Not After : Aug 15 09:00:00 2012 GMT + Subject: OU=MySQLConnectorPython Expired Server Cert, CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:df:5a:5b:72:42:5f:46:e5:bb:6c:e5:76:2e:6f: + fd:b8:10:2f:04:10:55:43:0c:bf:af:f1:eb:f0:4f: + 6f:6b:d9:61:9f:2a:39:35:2d:cc:0c:05:5c:88:cc: + 98:a3:5c:78:9e:8c:6b:ba:33:3f:f2:46:96:f2:bb: + 78:63:ca:bd:72:2c:70:34:56:8b:12:e5:e9:ff:82: + d5:50:bb:28:c2:99:83:af:3f:f1:67:77:b4:41:66: + 79:ee:f7:3a:93:8c:55:da:c3:d5:3a:44:40:82:e8: + fa:4c:11:a7:13:20:31:78:48:1d:2e:95:8c:0f:4c: + ea:ac:96:9d:9e:2a:37:c5:7a:42:f2:b1:8f:9b:15: + 69:9d:1c:19:26:69:84:a9:c6:9e:08:65:c0:7c:bf: + 72:a7:b0:ae:60:78:ad:7d:ea:0b:ed:ff:45:fc:24: + 56:f5:c6:f4:b5:00:0f:90:76:3e:52:08:ec:06:c4: + 30:51:66:60:f9:c6:0b:b9:f2:96:6a:c2:39:b8:b7: + 48:b8:3f:02:26:b5:95:f8:55:8d:d3:23:f1:dc:d0: + ab:2c:05:3b:b5:99:4d:9a:81:78:27:60:0d:da:2e: + 23:e8:38:26:0b:6d:6c:f6:fd:a7:42:95:4c:d2:a5: + 7c:05:13:21:7b:c7:6d:ca:f1:e3:3d:ad:d4:32:79: + 5a:d3 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + 36:e4:ba:6c:3b:99:29:ba:33:8b:da:ef:07:b8:7e:f6:07:b6: + 79:7b:c7:b2:0c:0c:48:ff:52:25:05:34:f4:d9:f6:0a:0c:77: + 10:a7:e5:40:f4:47:bf:4c:06:7b:8a:22:53:5a:91:dd:75:32: + d3:58:97:4f:d4:01:e8:b5:8d:ca:52:23:7f:72:1b:e2:c5:9a: + 89:a4:be:e4:17:9b:fa:1f:c0:26:93:5f:c2:d2:1b:e0:c2:9e: + 36:d1:3f:95:bd:6f:af:cd:f3:8f:6a:c6:5c:b0:6b:ae:07:60: + 59:be:fa:fd:f8:43:5b:20:38:02:b8:a6:f5:eb:35:be:46:55: + 7b:84:9f:e5:cb:5d:6b:af:2a:28:d1:af:32:1f:e3:71:d8:f8: + 96:4a:f1:88:f3:10:27:ed:c5:a2:65:f4:b5:2b:58:77:93:25: + e7:36:e1:4b:cb:18:10:cd:81:fc:80:e6:24:0f:27:4c:33:22: + af:36:88:ee:f8:0d:ef:ff:47:74:87:50:e8:ea:03:da:71:a1: + 65:fd:00:8c:c8:a8:27:fa:e0:40:43:60:8f:aa:1f:25:4f:05: + d7:a5:fe:9b:a3:82:90:0b:50:bf:bd:62:a3:9e:14:20:80:18: + 8b:8c:5e:f7:97:b8:b7:a5:63:d8:22:1a:98:6c:32:da:38:7b: + fc:e6:2c:f3 +-----BEGIN CERTIFICATE----- +MIIC/TCCAeUCAQIwDQYJKoZIhvcNAQEEBQAwQjElMCMGA1UECwwcTXlTUUxDb25u +ZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25uUHkgUm9vdCBDQTAe +Fw0xMjA4MTUwODAwMDBaFw0xMjA4MTUwOTAwMDBaMEcxMTAvBgNVBAsMKE15U1FM +Q29ubmVjdG9yUHl0aG9uIEV4cGlyZWQgU2VydmVyIENlcnQxEjAQBgNVBAMMCWxv +Y2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN9aW3JCX0bl +u2zldi5v/bgQLwQQVUMMv6/x6/BPb2vZYZ8qOTUtzAwFXIjMmKNceJ6Ma7ozP/JG +lvK7eGPKvXIscDRWixLl6f+C1VC7KMKZg68/8Wd3tEFmee73OpOMVdrD1TpEQILo ++kwRpxMgMXhIHS6VjA9M6qyWnZ4qN8V6QvKxj5sVaZ0cGSZphKnGnghlwHy/cqew +rmB4rX3qC+3/RfwkVvXG9LUAD5B2PlII7AbEMFFmYPnGC7nylmrCObi3SLg/Aia1 +lfhVjdMj8dzQqywFO7WZTZqBeCdgDdouI+g4JgttbPb9p0KVTNKlfAUTIXvHbcrx +4z2t1DJ5WtMCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEANuS6bDuZKbozi9rvB7h+ +9ge2eXvHsgwMSP9SJQU09Nn2Cgx3EKflQPRHv0wGe4oiU1qR3XUy01iXT9QB6LWN +ylIjf3Ib4sWaiaS+5Beb+h/AJpNfwtIb4MKeNtE/lb1vr83zj2rGXLBrrgdgWb76 +/fhDWyA4Arim9es1vkZVe4Sf5ctda68qKNGvMh/jcdj4lkrxiPMQJ+3FomX0tStY +d5Ml5zbhS8sYEM2B/IDmJA8nTDMirzaI7vgN7/9HdIdQ6OoD2nGhZf0AjMioJ/rg +QENgj6ofJU8F16X+m6OCkAtQv71io54UIIAYi4xe95e4t6Vj2CIamGwy2jh7/OYs +8w== +-----END CERTIFICATE----- diff --git a/tests/data/ssl/tests_expired_server_key.pem b/tests/data/ssl/tests_expired_server_key.pem new file mode 100644 index 0000000..6b68fe2 --- /dev/null +++ b/tests/data/ssl/tests_expired_server_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA31pbckJfRuW7bOV2Lm/9uBAvBBBVQwy/r/Hr8E9va9lhnyo5 +NS3MDAVciMyYo1x4noxrujM/8kaW8rt4Y8q9cixwNFaLEuXp/4LVULsowpmDrz/x +Z3e0QWZ57vc6k4xV2sPVOkRAguj6TBGnEyAxeEgdLpWMD0zqrJadnio3xXpC8rGP +mxVpnRwZJmmEqcaeCGXAfL9yp7CuYHitfeoL7f9F/CRW9cb0tQAPkHY+UgjsBsQw +UWZg+cYLufKWasI5uLdIuD8CJrWV+FWN0yPx3NCrLAU7tZlNmoF4J2AN2i4j6Dgm +C21s9v2nQpVM0qV8BRMhe8dtyvHjPa3UMnla0wIDAQABAoIBAC7IP0U0b75q2hIa +EeHyJSOLiD2Cqkkr/2577p5cFQty8caj0m24FPgjm1kv+XymHsGeyeWrXGaDsJRQ +/gtw6LNkaXAc/G5N5/BT2Bhby1LPUsy/SPISGZhlPX73G7bR+x2iTSQyLYz9/Yc3 +X1ZbNOFrwWkDe92sj67ssUDyuNHMwLpw35/OWX2W7YsGzi7j2zbZdmhp2c3E0/bD +NL2217BsPMLD1/f0og6Ix9kvSt+2Z3XW6RlhP7LDNDRI7F8oRRVvYgQGHBHibvlG +I4n07lycLo0dPsc08PcUvJ5UyhI7VYk/MZACLNhrjgPxYz1HdL7deVoQbW6z4q19 +g1JjI2kCgYEA+eOIvGkz9wga74VVKMZIqXPaMmccNkwbzUb7Ay1CM50pdYLk6E6R +LdEIx0/qQC8Zpw47NhSFzZT8sakHqmK7VIJRdMJWSTKu/4QMooigRasFJXPWwJVa +LsTE1gg3LGL+RkuoQNIlPle6nTGcCLGfnB8Js1GA3/SunFQCoJr+stcCgYEA5NCx +BSmZz07Rso3FWzRMjR52m2JDWvMm4+eU/HxXGrPdYfBQEowxzesORRBRIlp8Z5ki +929ayJ5qONLjMFx1l/QguT9BNkbzO3gpbH3/G187wFQ0v8jXmDRjU7ftgyL6PAD+ +eJsj39+TfA+Hua6m6VkLH5XUpy3Vl8nBkM2cFGUCgYEAl1zEiWOsD1lAf48i2zTn +9IRxSZB9XUJSoM/64Zy7eeobn8tufmyAseDpUVlNyhz9i9wp74MU3Ub+nVqGgyWU +1Qau8mt4upPRvoIs6RKbCjgiQOJe1X5iBuw3UnHdgaxg2xGe08y2tIGNTwQqwHVe ++cEvLggTaRSb46NbiA76cjcCgYBGkWZG5VGecfySSM75FeQWEbMasO98+UihOSbl +x6NFhPtd3TOUxNAHZdr8yc97/NQpTz1NenZRMSopZEDVBW7u8ke1WiDOkIsraB++ +ag1nb7OJ2W57R4HWWzHW+/6wVvU91ECnCZHC1b0yoceGKKsphGC92QPAm44oRf0A +n6jnUQKBgD0MqIjngDIRMwGpkXpsJJDt9/dw6izz3sWhBDkBLKCt63nwT3pykDDF +qJ8dq9TSGwO6H1c/obKdFlx53PBDUpZV9txI8ScF2YNlfs3Ts4+oElkU/jCMJPKi +M73I0Jgg+GwToDcjC4d7oREIBlfXjBLBjCcHx1315NMUW42QkrNo +-----END RSA PRIVATE KEY----- diff --git a/tests/data/ssl/tests_server_cert.pem b/tests/data/ssl/tests_server_cert.pem index dc7938c..3276dea 100644 --- a/tests/data/ssl/tests_server_cert.pem +++ b/tests/data/ssl/tests_server_cert.pem @@ -1,18 +1,67 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: OU=MySQLConnectorPython Root CA, CN=MyConnPy Root CA + Validity + Not Before: Mar 17 15:50:37 2017 GMT + Not After : Mar 17 15:50:37 2018 GMT + Subject: OU=MySQLConnectorPython Server Cert, CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:0d:e6:bd:d7:5e:1e:0f:b2:0a:83:43:50:fe: + 7c:bc:32:dc:04:fd:38:97:86:1e:e0:9c:46:08:65: + ac:76:6f:0d:93:33:31:4e:02:8a:a7:e9:9a:b9:4f: + f9:d3:66:56:29:1a:e5:0f:df:7b:61:e5:3c:06:db: + ea:cd:d6:71:9d:63:b2:f9:e1:c1:ed:9a:6e:2f:2f: + be:94:76:aa:ee:24:b3:58:f0:82:25:00:ef:c8:19: + 4f:15:6f:f2:3b:b4:e4:9b:0d:36:c7:17:39:7d:35: + 45:e8:76:62:94:19:ab:64:d8:89:78:75:92:29:e2: + 35:79:dd:e1:bf:3f:52:bf:ef:4c:d1:c1:fc:d0:a6: + ee:b8:01:39:26:28:67:40:73:46:5e:55:65:3b:56: + c9:c0:e1:7a:a4:a1:0c:46:d2:1e:b3:af:c5:cc:5b: + 07:81:79:c5:d0:44:57:ed:ea:ad:d9:c2:45:70:72: + 46:d3:e2:a3:f4:d0:49:33:ac:66:89:9b:83:65:f9: + 92:07:4e:9c:bf:b0:59:90:f8:35:8f:19:d2:82:d7: + 49:46:f5:4b:6a:c0:bd:5c:5d:0f:a0:fb:29:15:a7: + 68:5e:e1:48:20:c8:14:eb:fc:17:29:d6:95:4a:27: + 70:f3:c3:52:3d:1c:a5:d4:cf:3c:87:81:d7:d9:bb: + dc:49 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption + 36:58:2f:f4:95:e6:8b:ef:5b:59:91:2e:31:c2:21:64:b7:ac: + e6:bf:4e:b7:12:06:7d:8b:74:eb:82:88:65:00:4c:12:5e:6b: + dd:8b:d5:5e:cd:74:92:8a:dd:eb:fb:5b:1d:46:b0:e4:7d:55: + 1a:01:9a:82:0c:4d:91:05:e2:92:f5:17:0f:a5:8b:d9:8e:8f: + 17:55:19:83:07:2b:ea:2b:16:15:30:f7:31:7e:84:cc:b7:e0: + b1:b1:53:5d:e9:40:87:19:98:d5:f8:eb:ae:ef:b4:e7:85:12: + 38:e7:12:f4:44:03:08:a6:fc:3b:aa:26:1c:52:95:e0:7b:93: + 92:00:e2:21:b8:09:00:7d:e5:08:b4:c8:53:1d:2c:11:ea:86: + 5c:f9:14:c6:3f:73:0a:bc:e7:96:cb:e9:39:23:d7:50:0f:7d: + 2e:04:be:e9:5b:0b:bf:99:85:8c:ed:32:14:1d:09:c5:d5:d1: + e6:db:f2:54:51:3f:5f:0e:e0:06:58:c8:52:68:4e:39:25:bd: + b5:1b:8b:b2:1d:95:cb:cb:22:18:b5:d7:27:3d:32:c4:79:c4: + fa:e1:6f:00:1c:63:da:4a:ce:9e:de:0c:a4:dd:bd:d3:d6:cb: + 51:d7:e6:32:5f:5f:31:1f:a5:9d:5f:d5:2c:21:72:a7:ed:f1: + d8:31:c8:b4 -----BEGIN CERTIFICATE----- -MIIC9TCCAd0CAQEwDQYJKoZIhvcNAQEFBQAwQjElMCMGA1UECwwcTXlTUUxDb25u +MIIC9TCCAd0CAQEwDQYJKoZIhvcNAQEEBQAwQjElMCMGA1UECwwcTXlTUUxDb25u ZWN0b3JQeXRob24gUm9vdCBDQTEZMBcGA1UEAwwQTXlDb25uUHkgUm9vdCBDQTAe -Fw0xMzAzMjYxNTM1NTJaFw0yMjA0MTQxNTM1NTJaMD8xKTAnBgNVBAsMIE15U1FM +Fw0xNzAzMTcxNTUwMzdaFw0xODAzMTcxNTUwMzdaMD8xKTAnBgNVBAsMIE15U1FM Q29ubmVjdG9yUHl0aG9uIFNlcnZlciBDZXJ0MRIwEAYDVQQDDAlsb2NhbGhvc3Qw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDv6WQ/Ssum4RchjXSlwbcB -au3WNccfodThBOAM27AOnJQWIjG4e5s9H7lLznI+VF5MgUbgbp/yz4D+CrSFvLgU -4xxzd1/SVbnzRJ5iD2EmaZPjoMkBmvDRd4ow6IdFN80Fpwxij6fUBHdRkyXyiYsG -FE94PQCyD1R47LSubd/gfcjXw8Bt5cWqcopiolZ01bYuMzeZIw0et9gf6Iih2Zh1 -bs9RthHfL3BfN4knljF3XmRQhfsc4w3MvdulX4mcfzS+E+keOOgPjfjo9KVCD1Zl -F00wQdbSCWzf9uCP4OpKJGURyMQEmGMFPBOP98kqns1CqaE0PxKOpbcTX86nSEO5 -AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFy4ONx0zFYgVNL046lfRmimyRf1gbmB -pyyug9eW6QuuTfqbzFWOYZY8pG2lzKnHNUMmgzMNMpiRLRJ38Dj5rApg+7OkiTT+ -l4DMIR/YblJryEvx6tNUq2Cu9GXKW2qrGJO3XVniuBpmg1srugdwyxS+LdFofgBc -I4cKIDuXYATUpOFhEsFbMY6tGVeOXQN2jSWtUj6+mKiUWMyr+5NYD8xhjDV7q4GH -JfQqWFzw7prtSYzwB8lc0PM2SLwxeE9cQUYN/UkW8HRxM7Ft5KyyXUk+2Jg61sZ2 -QxMCV6NAGYMX40WRDqIZbs9AbHWoCxEwoXWtcmNb0GInsk39lFMJqw4= +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjDea9114eD7IKg0NQ/ny8 +MtwE/TiXhh7gnEYIZax2bw2TMzFOAoqn6Zq5T/nTZlYpGuUP33th5TwG2+rN1nGd +Y7L54cHtmm4vL76UdqruJLNY8IIlAO/IGU8Vb/I7tOSbDTbHFzl9NUXodmKUGatk +2Il4dZIp4jV53eG/P1K/70zRwfzQpu64ATkmKGdAc0ZeVWU7VsnA4XqkoQxG0h6z +r8XMWweBecXQRFft6q3ZwkVwckbT4qP00EkzrGaJm4Nl+ZIHTpy/sFmQ+DWPGdKC +10lG9UtqwL1cXQ+g+ykVp2he4UggyBTr/Bcp1pVKJ3Dzw1I9HKXUzzyHgdfZu9xJ +AgMBAAEwDQYJKoZIhvcNAQEEBQADggEBADZYL/SV5ovvW1mRLjHCIWS3rOa/TrcS +Bn2LdOuCiGUATBJea92L1V7NdJKK3ev7Wx1GsOR9VRoBmoIMTZEF4pL1Fw+li9mO +jxdVGYMHK+orFhUw9zF+hMy34LGxU13pQIcZmNX4667vtOeFEjjnEvREAwim/Duq +JhxSleB7k5IA4iG4CQB95Qi0yFMdLBHqhlz5FMY/cwq855bL6Tkj11APfS4Evulb +C7+ZhYztMhQdCcXV0ebb8lRRP18O4AZYyFJoTjklvbUbi7IdlcvLIhi11yc9MsR5 +xPrhbwAcY9pKzp7eDKTdvdPWy1HX5jJfXzEfpZ1f1Swhcqft8dgxyLQ= -----END CERTIFICATE----- diff --git a/tests/data/ssl/tests_server_key.pem b/tests/data/ssl/tests_server_key.pem index 13c39fe..466fc97 100644 --- a/tests/data/ssl/tests_server_key.pem +++ b/tests/data/ssl/tests_server_key.pem @@ -1,27 +1,27 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/tests/mysqld.py b/tests/mysqld.py index 6d6463d..e007361 100644 --- a/tests/mysqld.py +++ b/tests/mysqld.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -343,9 +343,10 @@ class MySQLServerBase(object): class MySQLServer(MySQLServerBase): """Class for managing a MySQL server""" - def __init__(self, basedir, topdir, cnf, bind_address, port, - name, datadir=None, tmpdir=None, - unix_socket_folder=None, ssl_folder=None, sharedir=None): + def __init__(self, basedir, topdir, cnf, bind_address, port, name, + datadir=None, tmpdir=None, unix_socket_folder=None, + ssl_folder=None, ssl_ca=None, ssl_cert=None, ssl_key=None, + sharedir=None): self._cnf = cnf self._option_file = os.path.join(topdir, 'my.cnf') self._bind_address = bind_address @@ -353,6 +354,9 @@ class MySQLServer(MySQLServerBase): self._topdir = topdir self._basedir = basedir self._ssldir = ssl_folder or topdir + self._ssl_ca = os.path.join(self._ssldir, ssl_ca) + self._ssl_cert = os.path.join(self._ssldir, ssl_cert) + self._ssl_key = os.path.join(self._ssldir, ssl_key) self._datadir = datadir or os.path.join(topdir, 'data') self._tmpdir = tmpdir or os.path.join(topdir, 'tmp') self._name = name @@ -540,13 +544,7 @@ class MySQLServer(MySQLServerBase): """Return the unix socket of the server""" return self._unix_socket - def start(self): - """Start a MySQL server""" - if self.check_running(): - LOGGER.error("MySQL server '{name}' already running".format( - name=self.name)) - return - + def update_config(self, **kwargs): options = { 'name': self._name, 'basedir': _convert_forward_slash(self._basedir), @@ -555,16 +553,31 @@ class MySQLServer(MySQLServerBase): 'bind_address': self._bind_address, 'port': self._port, 'unix_socket': _convert_forward_slash(self._unix_socket), - 'ssl_dir': _convert_forward_slash(self._ssldir), + 'ssl_ca': _convert_forward_slash(self._ssl_ca), + 'ssl_cert': _convert_forward_slash(self._ssl_cert), + 'ssl_key': _convert_forward_slash(self._ssl_key), 'pid_file': _convert_forward_slash(self._pid_file), 'serverid': self._serverid, 'lc_messages_dir': _convert_forward_slash( self._lc_messages_dir), } + options.update(**kwargs) try: fp = open(self._option_file, 'w') fp.write(self._cnf.format(**options)) fp.close() + except Exception as ex: + LOGGER.error("Failed to write config file {0}".format(ex)) + sys.exit(1) + + def start(self, **kwargs): + if self.check_running(): + LOGGER.error("MySQL server '{name}' already running".format( + name=self.name)) + return + + self.update_config(**kwargs) + try: self._start_server() for i in range(10): if self.check_running(): diff --git a/tests/test_abstracts.py b/tests/test_abstracts.py index ca376e4..662ac22 100644 --- a/tests/test_abstracts.py +++ b/tests/test_abstracts.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -194,7 +194,13 @@ class ConnectionSubclasses(tests.MySQLConnectorTests): exp = {'insert_id': 0, 'affected_rows': 0, 'field_count': 0, 'warning_count': 0, 'status_flag': 0} - self.assertEqual(exp, self.cnx.cmd_refresh(refresh)) + result = self.cnx.cmd_refresh(refresh) + for key in set(result.keys()) ^ set(exp.keys()): + try: + del result[key] + except KeyError: + del exp[key] + self.assertEqual(exp, result) query = "SHOW GLOBAL STATUS LIKE 'Uptime_since_flush_status'" pre_flush = int(self.cnx.info_query(query)[1]) diff --git a/tests/test_bugs.py b/tests/test_bugs.py index 390b1b8..fc26488 100644 --- a/tests/test_bugs.py +++ b/tests/test_bugs.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -44,6 +44,7 @@ from threading import Thread import traceback import time import unittest +import pickle import tests from tests import foreach_cnx, cnx_config @@ -52,6 +53,7 @@ from mysql.connector import (connection, cursor, conversion, protocol, errors, constants, pooling) from mysql.connector.optionfiles import read_option_files import mysql.connector +import cpy_distutils try: from mysql.connector.connection_cext import CMySQLConnection @@ -62,6 +64,8 @@ except ImportError: ERR_NO_CEXT = "C Extension not available" +@unittest.skipIf(tests.MYSQL_VERSION == (5, 7, 4), + "Bug328998 not tested with MySQL version 5.7.4") class Bug328998Tests(tests.MySQLConnectorTests): """Tests where connection timeout has been set""" @@ -2381,6 +2385,7 @@ class BugOra16217765(tests.MySQLConnectorTests): user = self.users['sha256user'] config['user'] = user['username'] config['password'] = user['password'] + config['auth_plugin'] = user['auth_plugin'] self.assertRaises(errors.InterfaceError, connection.MySQLConnection, **config) if CMySQLConnection: @@ -4196,3 +4201,200 @@ class BugOra21530841(tests.MySQLConnectorTests): cur.execute(query) cur.fetchone() cur.close() + + +class BugOra25397650(tests.MySQLConnectorTests): + """BUG#25397650: CERTIFICATE VALIDITY NOT VERIFIED + """ + def setUp(self): + self.config = tests.get_mysql_config() + self.config = tests.get_mysql_config() + self.config.update({ + 'ssl_ca': os.path.abspath( + os.path.join(tests.SSL_DIR, 'tests_CA_cert.pem')), + 'ssl_cert': os.path.abspath( + os.path.join(tests.SSL_DIR, 'tests_client_cert.pem')), + 'ssl_key': os.path.abspath( + os.path.join(tests.SSL_DIR, 'tests_client_key.pem')), + }) + self.mysql_server = tests.MYSQL_SERVERS[0] + self._use_expired_cert() + + def tearDown(self): + self._use_original_cert() + self._ensure_up() + + def _ensure_up(self): + # Start the MySQL server again + if not self.mysql_server.check_running(): + self.mysql_server.start() + + if not self.mysql_server.wait_up(): + self.fail("Failed restarting MySQL server after test") + + def _use_original_cert(self): + self.mysql_server.stop() + self.mysql_server.wait_down() + + self.mysql_server.start() + self.mysql_server.wait_up() + time.sleep(2) + + def _use_expired_cert(self): + self.mysql_server.stop() + self.mysql_server.wait_down() + + cert = os.path.abspath( + os.path.join(tests.SSL_DIR, 'tests_expired_server_cert.pem')) + key = os.path.abspath( + os.path.join(tests.SSL_DIR, 'tests_expired_server_key.pem')) + if os.name == 'nt': + cert = os.path.normpath(cert) + cert = cert.replace('\\', '\\\\') + key = os.path.normpath(key) + key = key.replace('\\', '\\\\') + self.mysql_server.start(ssl_cert=cert, ssl_key=key) + self.mysql_server.wait_up() + time.sleep(2) + + def test_pure_verify_server_certifcate(self): + self.config["use_pure"] = True + self.config['ssl_verify_cert'] = True + self.assertRaises(errors.InterfaceError, + mysql.connector.connect, **self.config) + self.config['ssl_verify_cert'] = False + mysql.connector.connect(**self.config) + + def test_cext_verify_server_certifcate(self): + self.config["use_pure"] = False + self.config['ssl_verify_cert'] = True + self.assertRaises(errors.InterfaceError, + mysql.connector.connect, **self.config) + self.config['ssl_verify_cert'] = False + mysql.connector.connect(**self.config) + + +class BugOra25589496(tests.MySQLConnectorTests): + """BUG#25589496: COMMITS RELATED TO "BUG22529828" BROKE BINARY DATA + HANDLING FOR PYTHON 2.7 + """ + def setUp(self): + config = tests.get_mysql_config() + self.cnx = connection.MySQLConnection(**config) + self.tbl = "Bug25589496" + self.cnx.cmd_query("DROP TABLE IF EXISTS {0}".format(self.tbl)) + + def tearDown(self): + self.cnx.cmd_query("DROP TABLE IF EXISTS {0}".format(self.tbl)) + self.cnx.close() + + def test_insert_binary(self): + table = """ + CREATE TABLE {0} ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, + `section` VARCHAR(50) NOT NULL, + `pickled` LONGBLOB NOT NULL + ) + """.format(self.tbl) + cursor = self.cnx.cursor() + cursor.execute(table) + + pickled = pickle.dumps({'a': 'b'}, pickle.HIGHEST_PROTOCOL) + add_row_q = "INSERT INTO {0} (section, pickled) " \ + "VALUES (%(section)s, %(pickled)s)".format(self.tbl) + + new_row = cursor.execute(add_row_q, {'section': 'foo', + 'pickled': pickled}) + self.cnx.commit() + self.assertEqual(1, cursor.lastrowid) + cursor.close() + + +class BugOra25383644(tests.MySQLConnectorTests): + """BUG#25383644: LOST SERVER CONNECTION LEAKS POOLED CONNECTIONS + """ + def setUp(self): + config = tests.get_mysql_config() + config["pool_size"] = 3 + self.cnxpool = pooling.MySQLConnectionPool(**config) + self.mysql_server = tests.MYSQL_SERVERS[0] + + def test_pool_exhaustion(self): + sql = "SELECT * FROM dummy" + + i = 4 + while i > 0: + cnx = self.cnxpool.get_connection() + cur = cnx.cursor() + try: + self.mysql_server.stop() + self.mysql_server.wait_down() + cur.execute(sql) + except mysql.connector.errors.OperationalError: + try: + cur.close() + cnx.close() + except mysql.connector.errors.OperationalError: + pass + finally: + i -= 1 + if not self.mysql_server.check_running(): + self.mysql_server.start() + self.mysql_server.wait_up() + + +class BugOra25558885(tests.MySQLConnectorTests): + """BUG#25558885: ERROR 2013 (LOST CONNECTION TO MYSQL SERVER) USING C + EXTENSIONS + """ + def setUp(self): + pass + + def _long_query(self, config, cursor_class): + db_conn = mysql.connector.connect(**config) + cur = db_conn.cursor(cursor_class=cursor_class) + cur.execute("select sleep(15)") + cur.close() + db_conn.disconnect() + + def test_cext_cnx(self): + config = tests.get_mysql_config() + config["use_pure"] = False + del config["connection_timeout"] + cursor_class = mysql.connector.cursor_cext.CMySQLCursorBufferedRaw + self._long_query(config, cursor_class) + + def test_pure_cnx(self): + config = tests.get_mysql_config() + config["use_pure"] = True + del config["connection_timeout"] + cursor_class = mysql.connector.cursor.MySQLCursorBufferedRaw + self._long_query(config, cursor_class) + + +class BugOra20736339(tests.MySQLConnectorTests): + """BUG#20736339: C EXTENSION FAILS TO COMPILE IF MYSQL_CONFIG RETURN MORE + THAN ONE INCLUDE DIR + """ + def test_parse_mysql_config(self): + options = ['cflags', 'include', 'libs', 'libs_r', 'plugindir', 'version'] + includes = ["/mysql/include", "/mysql/another_include"] + config = """ + -I/mysql/include -fabi-version=2 -fno-omit-frame-pointer + -I{0} + -L/mysql/lib -lmysqlclient -lpthread -lm -lrt -lssl -lcrypto -ldl + -L/mysql/lib -lmysqlclient -lpthread -lm -lrt -lssl -lcrypto -ldl + /mysql/lib/plugin + 5.7.17 + """ + + info = cpy_distutils.parse_mysql_config_info(options, + config.strip().format(includes[0])) + self.assertEqual(1, len(info["include"])) + self.assertEqual(includes[0], info["include"][0]) + + info = cpy_distutils.parse_mysql_config_info(options, + config.strip().format(" -I".join(includes))) + self.assertEqual(2, len(info["include"])) + self.assertEqual(includes[0], info["include"][0]) + self.assertEqual(includes[1], info["include"][1]) diff --git a/tests/test_django.py b/tests/test_django.py index 45c2b13..6a94f3b 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -60,6 +60,7 @@ if DJANGO_AVAILABLE: 'TEST_COLLATION': 'utf8_general_ci', 'CONN_MAX_AGE': 0, 'AUTOCOMMIT': True, + 'TIME_ZONE': None, }, } settings.SECRET_KEY = "django_tests_secret_key" @@ -92,15 +93,11 @@ FOREIGN KEY (id_t1) REFERENCES django_t1(id) ON DELETE CASCADE # Have to load django.db to make importing db backend work for Django < 1.6 import django.db # pylint: disable=W0611 -if tests.DJANGO_VERSION >= (1, 6): - if tests.DJANGO_VERSION >= (1, 8): - from django.db.backends.base.introspection import FieldInfo - else: - from django.db.backends import FieldInfo from django.db.backends.signals import connection_created from django.utils.safestring import SafeBytes, SafeText import mysql.connector +from mysql.connector.django.introspection import FieldInfo if DJANGO_AVAILABLE: from mysql.connector.django.base import ( @@ -147,14 +144,14 @@ class DjangoIntrospection(tests.MySQLConnectorTests): def test_get_table_list(self): cur = self.cnx.cursor() - exp = list(TABLES.keys()) - for exp in list(TABLES.keys()): + for exp in TABLES.keys(): if sys.version_info < (2, 7): self.assertTrue(exp in self.introspect.get_table_list(cur)) else: - self.assertIn(exp, self.introspect.get_table_list(cur), - "Table {table_name} not in table list".format( - table_name=exp)) + res = any(table.name == exp + for table in self.introspect.get_table_list(cur)) + self.assertTrue(res, "Table {table_name} not in table list" + "".format(table_name=exp)) def test_get_table_description(self): cur = self.cnx.cursor() @@ -165,24 +162,39 @@ class DjangoIntrospection(tests.MySQLConnectorTests): ('c1', 3, None, None, None, None, 1, 16392), ('c2', 253, None, 20, None, None, 1, 16388) ] - else: + elif tests.DJANGO_VERSION < (1, 8): exp = [ - FieldInfo(name='id', type_code=3, display_size=None, + FieldInfo(name=u'id', type_code=3, display_size=None, internal_size=None, precision=None, scale=None, null_ok=0), - FieldInfo(name='c1', type_code=3, display_size=None, + FieldInfo(name=u'c1', type_code=3, display_size=None, internal_size=None, precision=None, scale=None, null_ok=1), - FieldInfo(name='c2', type_code=253, display_size=None, + FieldInfo(name=u'c2', type_code=253, display_size=None, internal_size=20, precision=None, scale=None, null_ok=1) ] + else: + exp = [ + FieldInfo(name=u'id', type_code=3, display_size=None, + internal_size=None, precision=10, scale=None, + null_ok=0, extra=u'auto_increment'), + FieldInfo(name=u'c1', type_code=3, display_size=None, + internal_size=None, precision=10, scale=None, + null_ok=1, extra=u''), + FieldInfo(name=u'c2', type_code=253, display_size=None, + internal_size=20, precision=None, scale=None, + null_ok=1, extra=u'') + ] res = self.introspect.get_table_description(cur, 'django_t1') self.assertEqual(exp, res) def test_get_relations(self): cur = self.cnx.cursor() - exp = {1: (0, 'django_t1')} + if tests.DJANGO_VERSION < (1, 8): + exp = {1: (0, 'django_t1')} + else: + exp = {u'id_t1': (u'id', u'django_t1')} self.assertEqual(exp, self.introspect.get_relations(cur, 'django_t2')) def test_get_key_columns(self): @@ -204,6 +216,30 @@ class DjangoIntrospection(tests.MySQLConnectorTests): res = self.introspect.get_primary_key_column(cur, 'django_t1') self.assertEqual('id', res) + def test_get_constraints(self): + cur = self.cnx.cursor() + exp = { + 'PRIMARY': {'check': False, + 'columns': ['id'], + 'foreign_key': None, + 'index': True, + 'primary_key': True, + 'unique': True}, + 'django_t2_ibfk_1': {'check': False, + 'columns': ['id_t1'], + 'foreign_key': ('django_t1', 'id'), + 'index': False, + 'primary_key': False, + 'unique': False}, + 'id_t1': {'check': False, + 'columns': ['id_t1'], + 'foreign_key': None, + 'index': True, + 'primary_key': False, + 'unique': False} + } + self.assertEqual( + exp, self.introspect.get_constraints(cur, 'django_t2')) @unittest.skipIf(not DJANGO_AVAILABLE, "Django not available") class DjangoDatabaseWrapper(tests.MySQLConnectorTests): @@ -277,26 +313,49 @@ class DjangoDatabaseOperations(tests.MySQLConnectorTests): self.dbo = DatabaseOperations(self.cnx) def test_value_to_db_time(self): - self.assertEqual(None, self.dbo.value_to_db_time(None)) + if tests.DJANGO_VERSION < (1, 9): + value_to_db_time = self.dbo.value_to_db_time + else: + value_to_db_time = self.dbo.adapt_timefield_value + + self.assertEqual(None, value_to_db_time(None)) value = datetime.time(0, 0, 0) exp = self.conn.converter._time_to_mysql(value) - self.assertEqual(exp, self.dbo.value_to_db_time(value)) + self.assertEqual(exp, value_to_db_time(value)) value = datetime.time(2, 5, 7) exp = self.conn.converter._time_to_mysql(value) - self.assertEqual(exp, self.dbo.value_to_db_time(value)) + self.assertEqual(exp, value_to_db_time(value)) def test_value_to_db_datetime(self): - self.assertEqual(None, self.dbo.value_to_db_datetime(None)) + if tests.DJANGO_VERSION < (1, 9): + value_to_db_datetime = self.dbo.value_to_db_datetime + else: + value_to_db_datetime = self.dbo.adapt_datetimefield_value + + self.assertEqual(None, value_to_db_datetime(None)) value = datetime.datetime(1, 1, 1) exp = self.conn.converter._datetime_to_mysql(value) - self.assertEqual(exp, self.dbo.value_to_db_datetime(value)) + self.assertEqual(exp, value_to_db_datetime(value)) value = datetime.datetime(2, 5, 7, 10, 10) exp = self.conn.converter._datetime_to_mysql(value) - self.assertEqual(exp, self.dbo.value_to_db_datetime(value)) + self.assertEqual(exp, value_to_db_datetime(value)) + + def test_bulk_insert_sql(self): + num_values = 5 + fields = ["col1", "col2", "col3"] + placeholder_rows = [["%s"] * len(fields) for _ in range(num_values)] + exp = "VALUES {0}".format(", ".join( + ["({0})".format(", ".join(["%s"] * len(fields)))] * num_values)) + if tests.DJANGO_VERSION < (1, 9): + self.assertEqual( + exp, self.dbo.bulk_insert_sql(fields, num_values)) + else: + self.assertEqual( + exp, self.dbo.bulk_insert_sql(fields, placeholder_rows)) class DjangoMySQLConverterTests(tests.MySQLConnectorTests): diff --git a/tests/test_setup.py b/tests/test_setup.py index 11d0362..74a0313 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -1,5 +1,5 @@ # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -132,7 +132,8 @@ class SetupInfoTests(tests.MySQLConnectorTests): for clsfr in setupinfo.classifiers: if 'Programming Language :: Python' in clsfr: ver = clsfr.replace('Programming Language :: Python :: ', '') - if ver not in ('2.6', '2.7', '3', '3.1', '3.2', '3.3'): + if ver not in ('2.6', '2.7', '3', '3.1', '3.2', '3.3', '3.4', + '3.5'): self.fail('Unsupported version in classifiers') if 'Development Status ::' in clsfr: status = clsfr.replace('Development Status :: ', '') diff --git a/unittests.py b/unittests.py index bb852e0..bfcc19a 100644 --- a/unittests.py +++ b/unittests.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # MySQL Connector/Python - MySQL driver written in Python. -# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. # MySQL Connector/Python is licensed under the terms of the GPLv2 # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most @@ -144,17 +144,17 @@ ssl # Platform specifics if os.name == 'nt': MY_CNF += '\n'.join(( - "ssl-ca = {ssl_dir}\\\\tests_CA_cert.pem", - "ssl-cert = {ssl_dir}\\\\tests_server_cert.pem", - "ssl-key = {ssl_dir}\\\\tests_server_key.pem", + "ssl-ca = {ssl_ca}", + "ssl-cert = {ssl_cert}", + "ssl-key = {ssl_key}", )) MYSQL_DEFAULT_BASE = os.path.join( "C:/", "Program Files", "MySQL", "MySQL Server 5.6") else: MY_CNF += '\n'.join(( - "ssl-ca = {ssl_dir}/tests_CA_cert.pem", - "ssl-cert = {ssl_dir}/tests_server_cert.pem", - "ssl-key = {ssl_dir}/tests_server_key.pem", + "ssl-ca = {ssl_ca}", + "ssl-cert = {ssl_cert}", + "ssl-key = {ssl_key}", "innodb_flush_method = O_DIRECT", )) MYSQL_DEFAULT_BASE = os.path.join('/', 'usr', 'local', 'mysql') @@ -603,6 +603,9 @@ def init_mysql_server(port, options): port=port, unix_socket_folder=options.unix_socket_folder, ssl_folder=os.path.abspath(tests.SSL_DIR), + ssl_ca="tests_CA_cert.pem", + ssl_cert="tests_server_cert.pem", + ssl_key="tests_server_key.pem", name=name, sharedir=options.mysql_sharedir) except tests.mysqld.MySQLBootstrapError as err: