- adding in requirements

- get test_naturalpks to be more generalized
This commit is contained in:
Mike Bayer
2013-02-06 19:06:09 -05:00
parent 47858b85ec
commit a0ef9edc19
8 changed files with 178 additions and 62 deletions
+3 -1
View File
@@ -84,7 +84,9 @@ def succeeds_if(predicate, reason=None):
class Predicate(object):
@classmethod
def as_predicate(cls, predicate):
if isinstance(predicate, Predicate):
if isinstance(predicate, skip_if):
return predicate.predicate
elif isinstance(predicate, Predicate):
return predicate
elif isinstance(predicate, list):
return OrPredicate([cls.as_predicate(pred) for pred in predicate])
+42
View File
@@ -39,6 +39,27 @@ class SuiteRequirements(Requirements):
return exclusions.open()
@property
def on_update_cascade(self):
""""target database must support ON UPDATE..CASCADE behavior in
foreign keys."""
return exclusions.open()
@property
def deferrable_fks(self):
return exclusions.closed()
@property
def on_update_or_deferrable_fks(self):
# TODO: exclusions should be composable,
# somehow only_if([x, y]) isn't working here, negation/conjunctions
# getting confused.
return exclusions.only_if(
lambda: self.on_update_cascade.enabled or self.deferrable_fks.enabled
)
@property
def self_referential_foreign_keys(self):
"""Target database must support self-referential foreign keys."""
@@ -253,6 +274,11 @@ class SuiteRequirements(Requirements):
"""
return exclusions.open()
@property
def unicode_ddl(self):
"""Target driver must support some degree of non-ascii symbol names."""
return exclusions.closed()
@property
def datetime(self):
"""target dialect supports representation of Python
@@ -349,3 +375,19 @@ class SuiteRequirements(Requirements):
"""target database must use a plain percent '%' as the 'modulus'
operator."""
return exclusions.closed()
@property
def unicode_connections(self):
"""Target driver must support non-ASCII characters being passed at all."""
return exclusions.open()
@property
def skip_mysql_on_windows(self):
"""Catchall for a large variety of MySQL on Windows failures"""
return exclusions.open()
def _has_mysql_on_windows(self):
return False
def _has_mysql_fully_case_sensitive(self):
return False
@@ -218,6 +218,9 @@ class ComponentReflectionTest(fixtures.TablesTest):
])) > 0, '%s(%s), %s(%s)' % (col.name,
col.type, cols[i]['name'], ctype))
if not col.primary_key:
assert cols[i]['default'] is None
@testing.requires.table_reflection
def test_get_columns(self):
self._test_get_columns()
@@ -386,5 +389,32 @@ class ComponentReflectionTest(fixtures.TablesTest):
def test_get_table_oid_with_schema(self):
self._test_get_table_oid('users', schema='test_schema')
@testing.provide_metadata
def test_autoincrement_col(self):
"""test that 'autoincrement' is reflected according to sqla's policy.
Don't mark this test as unsupported for any backend !
(technically it fails with MySQL InnoDB since "id" comes before "id2")
A backend is better off not returning "autoincrement" at all,
instead of potentially returning "False" for an auto-incrementing
primary key column.
"""
meta = self.metadata
insp = inspect(meta.bind)
for tname, cname in [
('users', 'user_id'),
('email_addresses', 'address_id'),
('dingalings', 'dingaling_id'),
]:
cols = insp.get_columns(tname)
id_ = dict((c['name'], c) for c in cols)[cname]
assert id_.get('autoincrement', True)
__all__ = ('ComponentReflectionTest', 'HasTableTest')
+35 -2
View File
@@ -4,7 +4,7 @@ from .. import fixtures, config
from ..assertions import eq_
from ..config import requirements
from sqlalchemy import Integer, Unicode, UnicodeText, select
from sqlalchemy import Date, DateTime, Time, MetaData, String
from sqlalchemy import Date, DateTime, Time, MetaData, String, Text
from ..schema import Table, Column
import datetime
@@ -103,6 +103,39 @@ class UnicodeTextTest(_UnicodeFixture, fixtures.TablesTest):
def test_empty_strings_text(self):
self._test_empty_strings()
class TextTest(fixtures.TablesTest):
@classmethod
def define_tables(cls, metadata):
Table('text_table', metadata,
Column('id', Integer, primary_key=True,
test_needs_autoincrement=True),
Column('text_data', Text),
)
def test_text_roundtrip(self):
text_table = self.tables.text_table
config.db.execute(
text_table.insert(),
{"text_data": 'some text'}
)
row = config.db.execute(
select([text_table.c.text_data])
).first()
eq_(row, ('some text',))
def test_text_empty_strings(self):
text_table = self.tables.text_table
config.db.execute(
text_table.insert(),
{"text_data": ''}
)
row = config.db.execute(
select([text_table.c.text_data])
).first()
eq_(row, ('',))
class StringTest(fixtures.TestBase):
@requirements.unbounded_varchar
@@ -212,7 +245,7 @@ class DateHistoricTest(_DateFixture, fixtures.TablesTest):
__all__ = ('UnicodeVarcharTest', 'UnicodeTextTest',
'DateTest', 'DateTimeTest',
'DateTest', 'DateTimeTest', 'TextTest',
'DateTimeHistoricTest', 'DateTimeCoercedToDateTimeTest',
'TimeMicrosecondsTest', 'TimeTest', 'DateTimeMicrosecondsTest',
'DateHistoricTest', 'StringTest')
+3 -3
View File
@@ -645,8 +645,8 @@ class ReflectionTest(fixtures.TestBase, ComparesTables):
id INTEGER NOT NULL,
isbn VARCHAR(50) NOT NULL,
title VARCHAR(100) NOT NULL,
series INTEGER,
series_id INTEGER,
series INTEGER NOT NULL,
series_id INTEGER NOT NULL,
UNIQUE(series, series_id),
PRIMARY KEY(id, isbn)
)""")
@@ -1060,7 +1060,7 @@ class UnicodeReflectionTest(fixtures.TestBase):
# are really limited unless you're on PG or SQLite
# forget about it on these backends
if testing.against('sybase', 'maxdb', 'oracle'):
if not testing.requires.unicode_ddl.enabled:
names = no_multibyte_period
# mysql can't handle casing usually
elif testing.against("mysql") and \
+31 -47
View File
@@ -15,17 +15,23 @@ from sqlalchemy.testing import eq_
from sqlalchemy.testing import fixtures
from test.orm import _fixtures
def _backend_specific_fk_args():
if testing.requires.deferrable_fks.enabled:
fk_args = dict(deferrable=True, initially='deferred')
elif not testing.requires.on_update_cascade.enabled:
fk_args = dict()
else:
fk_args = dict(onupdate='cascade')
return fk_args
class NaturalPKTest(fixtures.MappedTest):
# MySQL 5.5 on Windows crashes (the entire server, not the client)
# if you screw around with ON UPDATE CASCADE type of stuff.
__requires__ = 'skip_mysql_on_windows',
__requires__ = 'skip_mysql_on_windows', 'on_update_or_deferrable_fks'
@classmethod
def define_tables(cls, metadata):
if testing.against('oracle'):
fk_args = dict(deferrable=True, initially='deferred')
else:
fk_args = dict(onupdate='cascade')
fk_args = _backend_specific_fk_args()
users = Table('users', metadata,
Column('username', String(50), primary_key=True),
@@ -128,8 +134,7 @@ class NaturalPKTest(fixtures.MappedTest):
assert sess.query(User).get('ed').fullname == 'jack'
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_onetomany_passive(self):
self._test_onetomany(True)
@@ -190,8 +195,7 @@ class NaturalPKTest(fixtures.MappedTest):
u1 = sess.query(User).get('fred')
eq_(User(username='fred', fullname='jack'), u1)
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_manytoone_passive(self):
self._test_manytoone(True)
@@ -276,8 +280,7 @@ class NaturalPKTest(fixtures.MappedTest):
sess.query(Address).all())
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_onetoone_passive(self):
self._test_onetoone(True)
@@ -323,8 +326,7 @@ class NaturalPKTest(fixtures.MappedTest):
sess.expunge_all()
eq_([Address(username='ed')], sess.query(Address).all())
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_bidirectional_passive(self):
self._test_bidirectional(True)
@@ -339,7 +341,7 @@ class NaturalPKTest(fixtures.MappedTest):
mapper(User, users)
mapper(Address, addresses, properties={
'user':relationship(User, passive_updates=passive_updates,
'user': relationship(User, passive_updates=passive_updates,
backref='addresses')})
sess = create_session()
@@ -382,8 +384,7 @@ class NaturalPKTest(fixtures.MappedTest):
sess.query(Address).all())
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_manytomany_passive(self):
self._test_manytomany(True)
@@ -549,14 +550,13 @@ class ReversePKsTest(fixtures.MappedTest):
class SelfReferentialTest(fixtures.MappedTest):
# mssql, mysql don't allow
# ON UPDATE on self-referential keys
__unsupported_on__ = ('mssql','mysql')
__unsupported_on__ = ('mssql', 'mysql')
__requires__ = 'on_update_or_deferrable_fks',
@classmethod
def define_tables(cls, metadata):
if testing.against('oracle'):
fk_args = dict(deferrable=True, initially='deferred')
else:
fk_args = dict(onupdate='cascade')
fk_args = _backend_specific_fk_args()
Table('nodes', metadata,
Column('name', String(50), primary_key=True),
@@ -622,8 +622,7 @@ class SelfReferentialTest(fixtures.MappedTest):
for n in sess.query(Node).filter(
Node.name.in_(['n11', 'n12', 'n13']))])
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_many_to_one_passive(self):
self._test_many_to_one(True)
@@ -657,14 +656,11 @@ class SelfReferentialTest(fixtures.MappedTest):
class NonPKCascadeTest(fixtures.MappedTest):
__requires__ = 'skip_mysql_on_windows',
__requires__ = 'skip_mysql_on_windows', 'on_update_or_deferrable_fks'
@classmethod
def define_tables(cls, metadata):
if testing.against('oracle'):
fk_args = dict(deferrable=True, initially='deferred')
else:
fk_args = dict(onupdate='cascade')
fk_args = _backend_specific_fk_args()
Table('users', metadata,
Column('id', Integer, primary_key=True,
@@ -689,8 +685,7 @@ class NonPKCascadeTest(fixtures.MappedTest):
class Address(cls.Comparable):
pass
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_onetomany_passive(self):
self._test_onetomany(True)
@@ -770,10 +765,7 @@ class CascadeToFKPKTest(fixtures.MappedTest, testing.AssertsCompiledSQL):
@classmethod
def define_tables(cls, metadata):
if testing.against('oracle'):
fk_args = dict(deferrable=True, initially='deferred')
else:
fk_args = dict(onupdate='cascade')
fk_args = _backend_specific_fk_args()
Table('users', metadata,
Column('username', String(50), primary_key=True),
@@ -796,8 +788,7 @@ class CascadeToFKPKTest(fixtures.MappedTest, testing.AssertsCompiledSQL):
class Address(cls.Comparable):
pass
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_onetomany_passive(self):
self._test_onetomany(True)
@@ -875,9 +866,7 @@ class CascadeToFKPKTest(fixtures.MappedTest, testing.AssertsCompiledSQL):
u2.addresses.append(a1)
sess.flush()
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE '
'but requires referential integrity')
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_change_m2o_passive(self):
self._test_change_m2o(True)
@@ -1030,10 +1019,7 @@ class JoinedInheritanceTest(fixtures.MappedTest):
@classmethod
def define_tables(cls, metadata):
if testing.against('oracle'):
fk_args = dict(deferrable=True, initially='deferred')
else:
fk_args = dict(onupdate='cascade')
fk_args = _backend_specific_fk_args()
Table('person', metadata,
Column('name', String(50), primary_key=True),
@@ -1066,8 +1052,7 @@ class JoinedInheritanceTest(fixtures.MappedTest):
class Manager(Person):
pass
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_pk_passive(self):
self._test_pk(True)
@@ -1076,8 +1061,7 @@ class JoinedInheritanceTest(fixtures.MappedTest):
def test_pk_nonpassive(self):
self._test_pk(False)
@testing.fails_on('sqlite', 'sqlite doesnt support ON UPDATE CASCADE')
@testing.fails_on('oracle', 'oracle doesnt support ON UPDATE CASCADE')
@testing.requires.on_update_cascade
def test_fk_passive(self):
self._test_fk(True)
+15 -8
View File
@@ -1099,20 +1099,27 @@ class FilterTest(QueryTest, AssertsCompiledSQL):
def test_basic(self):
User = self.classes.User
assert [User(id=7), User(id=8), User(id=9),User(id=10)] == create_session().query(User).all()
users = create_session().query(User).all()
eq_(
[User(id=7), User(id=8), User(id=9),User(id=10)],
users
)
@testing.fails_on('maxdb', 'FIXME: unknown')
def test_limit(self):
@testing.requires.offset
def test_limit_offset(self):
User = self.classes.User
assert [User(id=8), User(id=9)] == create_session().query(User).order_by(User.id).limit(2).offset(1).all()
sess = create_session()
assert [User(id=8), User(id=9)] == list(create_session().query(User).order_by(User.id)[1:3])
assert [User(id=8), User(id=9)] == sess.query(User).order_by(User.id).limit(2).offset(1).all()
assert User(id=8) == create_session().query(User).order_by(User.id)[1]
assert [User(id=8), User(id=9)] == list(sess.query(User).order_by(User.id)[1:3])
assert User(id=8) == sess.query(User).order_by(User.id)[1]
assert [] == sess.query(User).order_by(User.id)[3:3]
assert [] == sess.query(User).order_by(User.id)[0:0]
assert [] == create_session().query(User).order_by(User.id)[3:3]
assert [] == create_session().query(User).order_by(User.id)[0:0]
@testing.requires.boolean_col_expressions
def test_exists(self):
+19 -1
View File
@@ -51,6 +51,23 @@ class DefaultRequirements(SuiteRequirements):
no_support('sqlite', 'not supported by database')
)
@property
def on_update_cascade(self):
"""target database must support ON UPDATE..CASCADE behavior in
foreign keys."""
return skip_if(
['sqlite', 'oracle'],
'target backend does not support ON UPDATE CASCADE'
)
@property
def deferrable_fks(self):
"""target database must support deferrable fks"""
return only_on(['oracle'])
@property
def unbounded_varchar(self):
"""Target database must support VARCHAR with no length"""
@@ -316,6 +333,7 @@ class DefaultRequirements(SuiteRequirements):
@property
def unicode_data(self):
"""target drive must support unicode data stored in columns."""
return skip_if([
no_support("sybase", "no unicode driver support")
])
@@ -330,7 +348,7 @@ class DefaultRequirements(SuiteRequirements):
@property
def unicode_ddl(self):
"""Target driver must support some encoding of Unicode across the wire."""
"""Target driver must support some degree of non-ascii symbol names."""
# TODO: expand to exclude MySQLdb versions w/ broken unicode
return skip_if([
no_support('maxdb', 'database support flakey'),