summaryrefslogtreecommitdiff
path: root/test/lib/requires.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/lib/requires.py')
-rw-r--r--test/lib/requires.py327
1 files changed, 327 insertions, 0 deletions
diff --git a/test/lib/requires.py b/test/lib/requires.py
new file mode 100644
index 000000000..08fde66c3
--- /dev/null
+++ b/test/lib/requires.py
@@ -0,0 +1,327 @@
+"""Global database feature support policy.
+
+Provides decorators to mark tests requiring specific feature support from the
+target database.
+
+"""
+
+from testing import \
+ _block_unconditionally as no_support, \
+ _chain_decorators_on, \
+ exclude, \
+ emits_warning_on,\
+ skip_if,\
+ fails_on,\
+ fails_on_everything_except
+
+import testing
+import sys
+
+def deferrable_constraints(fn):
+ """Target database must support derferable constraints."""
+ return _chain_decorators_on(
+ fn,
+ no_support('firebird', 'not supported by database'),
+ no_support('mysql', 'not supported by database'),
+ no_support('mssql', 'not supported by database'),
+ )
+
+def foreign_keys(fn):
+ """Target database must support foreign keys."""
+ return _chain_decorators_on(
+ fn,
+ no_support('sqlite', 'not supported by database'),
+ )
+
+
+def unbounded_varchar(fn):
+ """Target database must support VARCHAR with no length"""
+ return _chain_decorators_on(
+ fn,
+ no_support('firebird', 'not supported by database'),
+ no_support('oracle', 'not supported by database'),
+ no_support('mysql', 'not supported by database'),
+ )
+
+def boolean_col_expressions(fn):
+ """Target database must support boolean expressions as columns"""
+ return _chain_decorators_on(
+ fn,
+ no_support('firebird', 'not supported by database'),
+ no_support('oracle', 'not supported by database'),
+ no_support('mssql', 'not supported by database'),
+ no_support('sybase', 'not supported by database'),
+ no_support('maxdb', 'FIXME: verify not supported by database'),
+ no_support('informix', 'not supported by database'),
+ )
+
+def identity(fn):
+ """Target database must support GENERATED AS IDENTITY or a facsimile.
+
+ Includes GENERATED AS IDENTITY, AUTOINCREMENT, AUTO_INCREMENT, or other
+ column DDL feature that fills in a DB-generated identifier at INSERT-time
+ without requiring pre-execution of a SEQUENCE or other artifact.
+
+ """
+ return _chain_decorators_on(
+ fn,
+ no_support('firebird', 'not supported by database'),
+ no_support('oracle', 'not supported by database'),
+ no_support('postgresql', 'not supported by database'),
+ no_support('sybase', 'not supported by database'),
+ )
+
+def independent_cursors(fn):
+ """Target must support simultaneous, independent database cursors on a single connection."""
+
+ return _chain_decorators_on(
+ fn,
+ no_support('mssql+pyodbc', 'no driver support'),
+ no_support('mssql+mxodbc', 'no driver support'),
+ )
+
+def independent_connections(fn):
+ """Target must support simultaneous, independent database connections."""
+
+ # This is also true of some configurations of UnixODBC and probably win32
+ # ODBC as well.
+ return _chain_decorators_on(
+ fn,
+ no_support('sqlite', 'no driver support'),
+ exclude('mssql', '<', (9, 0, 0),
+ 'SQL Server 2005+ is required for independent connections'),
+ )
+
+def row_triggers(fn):
+ """Target must support standard statement-running EACH ROW triggers."""
+ return _chain_decorators_on(
+ fn,
+ # no access to same table
+ no_support('mysql', 'requires SUPER priv'),
+ exclude('mysql', '<', (5, 0, 10), 'not supported by database'),
+
+ # huh? TODO: implement triggers for PG tests, remove this
+ no_support('postgresql', 'PG triggers need to be implemented for tests'),
+ )
+
+def correlated_outer_joins(fn):
+ """Target must support an outer join to a subquery which correlates to the parent."""
+
+ return _chain_decorators_on(
+ fn,
+ no_support('oracle', 'Raises "ORA-01799: a column may not be outer-joined to a subquery"')
+ )
+
+def savepoints(fn):
+ """Target database must support savepoints."""
+ return _chain_decorators_on(
+ fn,
+ emits_warning_on('mssql', 'Savepoint support in mssql is experimental and may lead to data loss.'),
+ no_support('access', 'not supported by database'),
+ no_support('sqlite', 'not supported by database'),
+ no_support('sybase', 'FIXME: guessing, needs confirmation'),
+ exclude('mysql', '<', (5, 0, 3), 'not supported by database'),
+ exclude('informix', '<', (11, 55, 'xC3'), 'not supported by database'),
+ )
+
+def denormalized_names(fn):
+ """Target database must have 'denormalized', i.e. UPPERCASE as case insensitive names."""
+
+ return skip_if(
+ lambda: not testing.db.dialect.requires_name_normalize,
+ "Backend does not require denomralized names."
+ )(fn)
+
+def schemas(fn):
+ """Target database must support external schemas, and have one named 'test_schema'."""
+
+ return _chain_decorators_on(
+ fn,
+ no_support('sqlite', 'no schema support'),
+ no_support('firebird', 'no schema support')
+ )
+
+def sequences(fn):
+ """Target database must support SEQUENCEs."""
+ return _chain_decorators_on(
+ fn,
+ no_support('access', 'no SEQUENCE support'),
+ no_support('mssql', 'no SEQUENCE support'),
+ no_support('mysql', 'no SEQUENCE support'),
+ no_support('sqlite', 'no SEQUENCE support'),
+ no_support('sybase', 'no SEQUENCE support'),
+ no_support('informix', 'no SEQUENCE support'),
+ )
+
+def update_nowait(fn):
+ """Target database must support SELECT...FOR UPDATE NOWAIT"""
+ return _chain_decorators_on(
+ fn,
+ no_support('access', 'no FOR UPDATE NOWAIT support'),
+ no_support('firebird', 'no FOR UPDATE NOWAIT support'),
+ no_support('mssql', 'no FOR UPDATE NOWAIT support'),
+ no_support('mysql', 'no FOR UPDATE NOWAIT support'),
+ no_support('sqlite', 'no FOR UPDATE NOWAIT support'),
+ no_support('sybase', 'no FOR UPDATE NOWAIT support'),
+ )
+
+def subqueries(fn):
+ """Target database must support subqueries."""
+ return _chain_decorators_on(
+ fn,
+ exclude('mysql', '<', (4, 1, 1), 'no subquery support'),
+ )
+
+def intersect(fn):
+ """Target database must support INTERSECT or equivlaent."""
+ return _chain_decorators_on(
+ fn,
+ fails_on('firebird', 'no support for INTERSECT'),
+ fails_on('mysql', 'no support for INTERSECT'),
+ fails_on('sybase', 'no support for INTERSECT'),
+ fails_on('informix', 'no support for INTERSECT'),
+ )
+
+def except_(fn):
+ """Target database must support EXCEPT or equivlaent (i.e. MINUS)."""
+ return _chain_decorators_on(
+ fn,
+ fails_on('firebird', 'no support for EXCEPT'),
+ fails_on('mysql', 'no support for EXCEPT'),
+ fails_on('sybase', 'no support for EXCEPT'),
+ fails_on('informix', 'no support for EXCEPT'),
+ )
+
+def offset(fn):
+ """Target database must support some method of adding OFFSET or equivalent to a result set."""
+ return _chain_decorators_on(
+ fn,
+ fails_on('sybase', 'no support for OFFSET or equivalent'),
+ )
+
+def returning(fn):
+ return _chain_decorators_on(
+ fn,
+ no_support('access', 'not supported by database'),
+ no_support('sqlite', 'not supported by database'),
+ no_support('mysql', 'not supported by database'),
+ no_support('maxdb', 'not supported by database'),
+ no_support('sybase', 'not supported by database'),
+ no_support('informix', 'not supported by database'),
+ )
+
+def two_phase_transactions(fn):
+ """Target database must support two-phase transactions."""
+ return _chain_decorators_on(
+ fn,
+ no_support('access', 'not supported by database'),
+ no_support('firebird', 'no SA implementation'),
+ no_support('maxdb', 'not supported by database'),
+ no_support('mssql', 'FIXME: guessing, needs confirmation'),
+ no_support('oracle', 'no SA implementation'),
+ no_support('sqlite', 'not supported by database'),
+ no_support('sybase', 'FIXME: guessing, needs confirmation'),
+ no_support('postgresql+zxjdbc', 'FIXME: JDBC driver confuses the transaction state, may '
+ 'need separate XA implementation'),
+ exclude('mysql', '<', (5, 0, 3), 'not supported by database'),
+ )
+
+def unicode_connections(fn):
+ """Target driver must support some encoding of Unicode across the wire."""
+ # TODO: expand to exclude MySQLdb versions w/ broken unicode
+ return _chain_decorators_on(
+ fn,
+ exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'),
+ )
+
+def unicode_ddl(fn):
+ """Target driver must support some encoding of Unicode across the wire."""
+ # TODO: expand to exclude MySQLdb versions w/ broken unicode
+ return _chain_decorators_on(
+ fn,
+ no_support('maxdb', 'database support flakey'),
+ no_support('oracle', 'FIXME: no support in database?'),
+ no_support('sybase', 'FIXME: guessing, needs confirmation'),
+ no_support('mssql+pymssql', 'no FreeTDS support'),
+ exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'),
+ )
+
+def sane_rowcount(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(lambda: not testing.db.dialect.supports_sane_rowcount)
+ )
+
+def cextensions(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(lambda: not _has_cextensions(), "C extensions not installed")
+ )
+
+def dbapi_lastrowid(fn):
+ return _chain_decorators_on(
+ fn,
+ fails_on_everything_except('mysql+mysqldb', 'mysql+oursql', 'sqlite+pysqlite')
+ )
+
+def sane_multi_rowcount(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(lambda: not testing.db.dialect.supports_sane_multi_rowcount)
+ )
+
+def reflects_pk_names(fn):
+ """Target driver reflects the name of primary key constraints."""
+ return _chain_decorators_on(
+ fn,
+ fails_on_everything_except('postgresql', 'oracle')
+ )
+
+def python2(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(
+ lambda: sys.version_info >= (3,),
+ "Python version 2.xx is required."
+ )
+ )
+
+def python26(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(
+ lambda: sys.version_info < (2, 6),
+ "Python version 2.6 or greater is required"
+ )
+ )
+
+def python25(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(
+ lambda: sys.version_info < (2, 5),
+ "Python version 2.5 or greater is required"
+ )
+ )
+
+def _has_cextensions():
+ try:
+ from sqlalchemy import cresultproxy, cprocessors
+ return True
+ except ImportError:
+ return False
+
+def _has_sqlite():
+ from sqlalchemy import create_engine
+ try:
+ e = create_engine('sqlite://')
+ return True
+ except ImportError:
+ return False
+
+def sqlite(fn):
+ return _chain_decorators_on(
+ fn,
+ skip_if(lambda: not _has_sqlite())
+ )
+