diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2022-06-07 18:46:36 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@ci3.zzzcomputing.com> | 2022-06-07 18:46:36 +0000 |
commit | 1961e1321440a1e0500ecd13624837ed088eaceb (patch) | |
tree | df1587f23f982ea14b1b6bb99b6c2039e2c4105b /test/dialect/oracle/test_dialect.py | |
parent | c0736e0b2a3bf8c0952db84f5b9943df9ebf18f7 (diff) | |
parent | fcbdae075bb3f3a4ecc9b36e5787bba6b80af9c1 (diff) | |
download | sqlalchemy-1961e1321440a1e0500ecd13624837ed088eaceb.tar.gz |
Merge "Add support for the new oracle driver ``oracledb``." into main
Diffstat (limited to 'test/dialect/oracle/test_dialect.py')
-rw-r--r-- | test/dialect/oracle/test_dialect.py | 230 |
1 files changed, 162 insertions, 68 deletions
diff --git a/test/dialect/oracle/test_dialect.py b/test/dialect/oracle/test_dialect.py index eda0fc986..ad716d8c8 100644 --- a/test/dialect/oracle/test_dialect.py +++ b/test/dialect/oracle/test_dialect.py @@ -1,5 +1,6 @@ # coding: utf-8 +from multiprocessing import get_context import re from unittest import mock from unittest.mock import Mock @@ -23,6 +24,7 @@ from sqlalchemy import Unicode from sqlalchemy import UnicodeText from sqlalchemy.dialects.oracle import base as oracle from sqlalchemy.dialects.oracle import cx_oracle +from sqlalchemy.dialects.oracle import oracledb from sqlalchemy.engine import url from sqlalchemy.testing import assert_raises from sqlalchemy.testing import assert_raises_message @@ -32,6 +34,8 @@ from sqlalchemy.testing import config from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures +from sqlalchemy.testing import is_false +from sqlalchemy.testing import is_true from sqlalchemy.testing.assertions import expect_raises_message from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import pep435_enum @@ -39,35 +43,85 @@ from sqlalchemy.testing.schema import Table from sqlalchemy.testing.suite import test_select -class DialectTest(fixtures.TestBase): +class CxOracleDialectTest(fixtures.TestBase): def test_cx_oracle_version_parse(self): dialect = cx_oracle.OracleDialect_cx_oracle() - eq_(dialect._parse_cx_oracle_ver("5.2"), (5, 2)) + def check(version): + dbapi = Mock(version=version) + dialect._load_version(dbapi) + return dialect.cx_oracle_ver - eq_(dialect._parse_cx_oracle_ver("5.0.1"), (5, 0, 1)) - - eq_(dialect._parse_cx_oracle_ver("6.0b1"), (6, 0)) + eq_(check("7.2"), (7, 2)) + eq_(check("7.0.1"), (7, 0, 1)) + eq_(check("9.0b1"), (9, 0)) def test_minimum_version(self): - with mock.patch( - "sqlalchemy.dialects.oracle.cx_oracle.OracleDialect_cx_oracle." - "_parse_cx_oracle_ver", - lambda self, vers: (5, 1, 5), + with expect_raises_message( + exc.InvalidRequestError, + "cx_Oracle version 7 and above are supported", ): - assert_raises_message( - exc.InvalidRequestError, - "cx_Oracle version 7 and above are supported", - cx_oracle.OracleDialect_cx_oracle, - dbapi=mock.Mock(), - ) + cx_oracle.OracleDialect_cx_oracle(dbapi=Mock(version="5.1.5")) + + dialect = cx_oracle.OracleDialect_cx_oracle( + dbapi=Mock(version="7.1.0") + ) + eq_(dialect.cx_oracle_ver, (7, 1, 0)) + + +class OracleDbDialectTest(fixtures.TestBase): + def test_oracledb_version_parse(self): + dialect = oracledb.OracleDialect_oracledb() - with mock.patch( - "sqlalchemy.dialects.oracle.cx_oracle.OracleDialect_cx_oracle." - "_parse_cx_oracle_ver", - lambda self, vers: (7, 1, 0), + def check(version): + dbapi = Mock(version=version) + dialect._load_version(dbapi) + return dialect.oracledb_ver + + eq_(check("7.2"), (7, 2)) + eq_(check("7.0.1"), (7, 0, 1)) + eq_(check("9.0b1"), (9, 0)) + + def test_minimum_version(self): + with expect_raises_message( + exc.InvalidRequestError, + "oracledb version 1 and above are supported", ): - cx_oracle.OracleDialect_cx_oracle(dbapi=mock.Mock()) + oracledb.OracleDialect_oracledb(dbapi=Mock(version="0.1.5")) + + dialect = oracledb.OracleDialect_oracledb(dbapi=Mock(version="7.1.0")) + eq_(dialect.oracledb_ver, (7, 1, 0)) + + +class OracledbMode(fixtures.TestBase): + __backend__ = True + __only_on__ = "oracle+oracledb" + + def _run_in_process(self, fn): + ctx = get_context("spawn") + queue = ctx.Queue() + process = ctx.Process(target=fn, args=(str(config.db_url), queue)) + try: + process.start() + process.join(10) + eq_(process.exitcode, 0) + return queue.get_nowait() + finally: + process.kill() + + def test_thin_mode(self): + from ._oracledb_mode import run_thin_mode + + mode, is_thin = self._run_in_process(run_thin_mode) + is_true(is_thin) + is_true(mode.startswith("python-oracledb thn")) + + def test_thick_mode(self): + from ._oracledb_mode import run_thick_mode + + mode, is_thin = self._run_in_process(run_thick_mode) + is_false(is_thin) + eq_(mode.strip(), "custom-driver-name") class DialectWBackendTest(fixtures.TestBase): @@ -111,7 +165,7 @@ class DialectWBackendTest(fixtures.TestBase): False, ), ) - @testing.only_on("oracle+cx_oracle") + @testing.only_on(["oracle+cx_oracle", "oracle+oracledb"]) def test_is_disconnect(self, message, code, expected): dialect = testing.db.dialect @@ -289,6 +343,9 @@ class EncodingErrorsTest(fixtures.TestBase): argnames="cx_oracle_type", id_="ia", ) + _dialect = testing.combinations( + cx_oracle.dialect, oracledb.dialect, argnames="dialect_cls" + ) def _assert_errorhandler(self, outconverter, has_errorhandler): data = "\uee2c\u9a66" # this is u"\uee2c\u9a66" @@ -305,14 +362,11 @@ class EncodingErrorsTest(fixtures.TestBase): assert_raises(UnicodeDecodeError, outconverter, utf8_w_errors) @_oracle_char_combinations + @_dialect def test_encoding_errors_cx_oracle( - self, - cx_Oracle, - cx_oracle_type, + self, cx_Oracle, cx_oracle_type, dialect_cls ): - ignore_dialect = cx_oracle.dialect( - dbapi=cx_Oracle, encoding_errors="ignore" - ) + ignore_dialect = dialect_cls(dbapi=cx_Oracle, encoding_errors="ignore") ignore_outputhandler = ( ignore_dialect._generate_connection_outputtype_handler() @@ -334,12 +388,11 @@ class EncodingErrorsTest(fixtures.TestBase): ) @_oracle_char_combinations + @_dialect def test_no_encoding_errors_cx_oracle( - self, - cx_Oracle, - cx_oracle_type, + self, cx_Oracle, cx_oracle_type, dialect_cls ): - plain_dialect = cx_oracle.dialect(dbapi=cx_Oracle) + plain_dialect = dialect_cls(dbapi=cx_Oracle) plain_outputhandler = ( plain_dialect._generate_connection_outputtype_handler() @@ -433,7 +486,7 @@ class ComputedReturningTest(fixtures.TablesTest): class OutParamTest(fixtures.TestBase, AssertsExecutionResults): - __only_on__ = "oracle+cx_oracle" + __only_on__ = ("oracle+cx_oracle", "oracle+oracledb") __backend__ = True @classmethod @@ -877,12 +930,21 @@ class UnicodeSchemaTest(fixtures.TestBase): eq_(result, "’é") -class CXOracleConnectArgsTest(fixtures.TestBase): - __only_on__ = "oracle+cx_oracle" - __backend__ = True +class BaseConnectArgsTest: + @property + def name(self): + raise NotImplementedError + + @property + def dbapi(self): + raise NotImplementedError + + @property + def dialect_cls(self): + raise NotImplementedError def test_cx_oracle_service_name(self): - url_string = "oracle+cx_oracle://scott:tiger@host/?service_name=hr" + url_string = f"oracle+{self.name}://scott:tiger@host/?service_name=hr" eng = create_engine(url_string, _initialize=False) cargs, cparams = eng.dialect.create_connect_args(eng.url) @@ -890,7 +952,9 @@ class CXOracleConnectArgsTest(fixtures.TestBase): assert "SID=hr" not in cparams["dsn"] def test_cx_oracle_service_name_bad(self): - url_string = "oracle+cx_oracle://scott:tiger@host/hr1?service_name=hr2" + url_string = ( + f"oracle+{self.name}://scott:tiger@host/hr1?service_name=hr2" + ) assert_raises( exc.InvalidRequestError, create_engine, @@ -899,69 +963,59 @@ class CXOracleConnectArgsTest(fixtures.TestBase): ) def _test_db_opt(self, url_string, key, value): - import cx_Oracle - url_obj = url.make_url(url_string) - dialect = cx_oracle.dialect(dbapi=cx_Oracle) + dialect = self.dialect_cls(dbapi=self.dbapi) arg, kw = dialect.create_connect_args(url_obj) eq_(kw[key], value) def _test_db_opt_unpresent(self, url_string, key): - import cx_Oracle - url_obj = url.make_url(url_string) - dialect = cx_oracle.dialect(dbapi=cx_Oracle) + dialect = self.dialect_cls(dbapi=self.dbapi) arg, kw = dialect.create_connect_args(url_obj) assert key not in kw def _test_dialect_param_from_url(self, url_string, key, value): - import cx_Oracle - url_obj = url.make_url(url_string) - dialect = cx_oracle.dialect(dbapi=cx_Oracle) + dialect = self.dialect_cls(dbapi=self.dbapi) with testing.expect_deprecated( - "cx_oracle dialect option %r should" % key + f"{self.name} dialect option %r should" % key ): arg, kw = dialect.create_connect_args(url_obj) eq_(getattr(dialect, key), value) # test setting it on the dialect normally - dialect = cx_oracle.dialect(dbapi=cx_Oracle, **{key: value}) + dialect = self.dialect_cls(dbapi=self.dbapi, **{key: value}) eq_(getattr(dialect, key), value) def test_mode(self): - import cx_Oracle - self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?mode=sYsDBA", + f"oracle+{self.name}://scott:tiger@host/?mode=sYsDBA", "mode", - cx_Oracle.SYSDBA, + self.dbapi.SYSDBA, ) self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?mode=SYSOPER", + f"oracle+{self.name}://scott:tiger@host/?mode=SYSOPER", "mode", - cx_Oracle.SYSOPER, + self.dbapi.SYSOPER, ) def test_int_mode(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?mode=32767", "mode", 32767 + f"oracle+{self.name}://scott:tiger@host/?mode=32767", "mode", 32767 ) @testing.requires.cxoracle6_or_greater def test_purity(self): - import cx_Oracle - self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?purity=attr_purity_new", + f"oracle+{self.name}://scott:tiger@host/?purity=attr_purity_new", "purity", - cx_Oracle.ATTR_PURITY_NEW, + self.dbapi.ATTR_PURITY_NEW, ) def test_encoding(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/" + f"oracle+{self.name}://scott:tiger@host/" "?encoding=AMERICAN_AMERICA.UTF8", "encoding", "AMERICAN_AMERICA.UTF8", @@ -969,45 +1023,85 @@ class CXOracleConnectArgsTest(fixtures.TestBase): def test_threaded(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?threaded=true", + f"oracle+{self.name}://scott:tiger@host/?threaded=true", "threaded", True, ) self._test_db_opt_unpresent( - "oracle+cx_oracle://scott:tiger@host/", "threaded" + f"oracle+{self.name}://scott:tiger@host/", "threaded" ) def test_events(self): self._test_db_opt( - "oracle+cx_oracle://scott:tiger@host/?events=true", "events", True + f"oracle+{self.name}://scott:tiger@host/?events=true", + "events", + True, ) def test_threaded_deprecated_at_dialect_level(self): with testing.expect_deprecated( - "The 'threaded' parameter to the cx_oracle dialect" + "The 'threaded' parameter to the cx_oracle/oracledb dialect" ): - dialect = cx_oracle.dialect(threaded=False) + dialect = self.dialect_cls(threaded=False) arg, kw = dialect.create_connect_args( - url.make_url("oracle+cx_oracle://scott:tiger@dsn") + url.make_url(f"oracle+{self.name}://scott:tiger@dsn") ) eq_(kw["threaded"], False) def test_deprecated_use_ansi(self): self._test_dialect_param_from_url( - "oracle+cx_oracle://scott:tiger@host/?use_ansi=False", + f"oracle+{self.name}://scott:tiger@host/?use_ansi=False", "use_ansi", False, ) def test_deprecated_auto_convert_lobs(self): self._test_dialect_param_from_url( - "oracle+cx_oracle://scott:tiger@host/?auto_convert_lobs=False", + f"oracle+{self.name}://scott:tiger@host/?auto_convert_lobs=False", "auto_convert_lobs", False, ) +class CXOracleConnectArgsTest(BaseConnectArgsTest, fixtures.TestBase): + __only_on__ = "oracle+cx_oracle" + __backend__ = True + + @property + def name(self): + return "cx_oracle" + + @property + def dbapi(self): + import cx_Oracle + + return cx_Oracle + + @property + def dialect_cls(self): + return cx_oracle.dialect + + +class OracleDbConnectArgsTest(BaseConnectArgsTest, fixtures.TestBase): + __only_on__ = "oracle+oracledb" + __backend__ = True + + @property + def name(self): + return "oracledb" + + @property + def dbapi(self): + import oracledb + + return oracledb + + @property + def dialect_cls(self): + return oracledb.dialect + + class TableValuedTest(fixtures.TestBase): __backend__ = True __only_on__ = "oracle" |