11
from nose.plugins import Plugin
12
from nose import SkipTest
13
from test.bootstrap import config
15
from test.bootstrap.config import (
16
_create_testing_engine, _engine_pool, _engine_strategy, _engine_uri, _list_dbs, _log,
17
_prep_testing_database, _require, _reverse_topological, _server_side_cursors,
18
_monkeypatch_cdecimal, _zero_timeout,
19
_set_table_options, base_config, db, db_label, db_url, file_config, post_configure,
26
log = logging.getLogger('nose.plugins.sqlalchemy')
28
class NoseSQLAlchemy(Plugin):
30
Handles the setup and extra properties required for testing SQLAlchemy
34
# nose 1.0 will allow us to replace the old "sqlalchemy" plugin,
35
# if installed, using the same name, but nose 1.0 isn't released yet...
39
def options(self, parser, env=os.environ):
40
Plugin.options(self, parser, env)
41
opt = parser.add_option
42
opt("--log-info", action="callback", type="string", callback=_log,
43
help="turn on info logging for <LOG> (multiple OK)")
44
opt("--log-debug", action="callback", type="string", callback=_log,
45
help="turn on debug logging for <LOG> (multiple OK)")
46
opt("--require", action="append", dest="require", default=[],
47
help="require a particular driver or module version (multiple OK)")
48
opt("--db", action="store", dest="db", default="sqlite",
49
help="Use prefab database uri")
50
opt('--dbs', action='callback', callback=_list_dbs,
51
help="List available prefab dbs")
52
opt("--dburi", action="store", dest="dburi",
53
help="Database uri (overrides --db)")
54
opt("--dropfirst", action="store_true", dest="dropfirst",
55
help="Drop all tables in the target database first (use with caution on Oracle, "
57
opt("--mockpool", action="store_true", dest="mockpool",
58
help="Use mock pool (asserts only one connection used)")
59
opt("--zero-timeout", action="callback", callback=_zero_timeout,
60
help="Set pool_timeout to zero, applies to QueuePool only")
61
opt("--low-connections", action="store_true", dest="low_connections",
62
help="Use a low number of distinct connections - i.e. for Oracle TNS"
64
opt("--enginestrategy", action="callback", type="string",
65
callback=_engine_strategy,
66
help="Engine strategy (plain or threadlocal, defaults to plain)")
67
opt("--reversetop", action="store_true", dest="reversetop", default=False,
68
help="Use a random-ordering set implementation in the ORM (helps "
69
"reveal dependency issues)")
70
opt("--with-cdecimal", action="store_true", dest="cdecimal", default=False,
71
help="Monkeypatch the cdecimal library into Python 'decimal' for all tests")
72
opt("--unhashable", action="store_true", dest="unhashable", default=False,
73
help="Disallow SQLAlchemy from performing a hash() on mapped test objects.")
74
opt("--noncomparable", action="store_true", dest="noncomparable", default=False,
75
help="Disallow SQLAlchemy from performing == on mapped test objects.")
76
opt("--truthless", action="store_true", dest="truthless", default=False,
77
help="Disallow SQLAlchemy from truth-evaluating mapped test objects.")
78
opt("--serverside", action="callback", callback=_server_side_cursors,
79
help="Turn on server side cursors for PG")
80
opt("--mysql-engine", action="store", dest="mysql_engine", default=None,
81
help="Use the specified MySQL storage engine for all tables, default is "
82
"a db-default/InnoDB combo.")
83
opt("--table-option", action="append", dest="tableopts", default=[],
84
help="Add a dialect-specific table option, key=value")
85
opt("--write-profiles", action="store_true", dest="write_profiles", default=False,
86
help="Write/update profiling data.")
88
file_config = ConfigParser.ConfigParser()
89
file_config.readfp(StringIO.StringIO(base_config))
90
file_config.read(['test.cfg', os.path.expanduser('~/.satest.cfg')])
91
config.file_config = file_config
93
def configure(self, options, conf):
94
Plugin.configure(self, options, conf)
95
self.options = options
96
for fn in pre_configure:
97
fn(self.options, file_config)
100
global testing, requires, util, fixtures, engines
101
from test.lib import testing, requires, fixtures, engines
102
from sqlalchemy import util
105
testing.requires = requires
107
# Lazy setup of other options (post coverage)
108
for fn in post_configure:
109
fn(self.options, file_config)
111
def describeTest(self, test):
114
def wantFunction(self, fn):
115
if fn.__module__.startswith('test.lib') or \
116
fn.__module__.startswith('test.bootstrap'):
119
def wantClass(self, cls):
120
"""Return true if you want the main test selector to collect
121
tests from this class, false if you don't, and None if you don't
126
The class being examined by the selector
130
if not issubclass(cls, fixtures.TestBase):
132
elif cls.__name__.startswith('_'):
135
if hasattr(cls, 'setup_class'):
136
existing_setup = cls.setup_class.im_func
138
existing_setup = None
140
def setup_class(cls):
144
cls.setup_class = setup_class
148
def _do_skips(self, cls):
149
if hasattr(cls, '__requires__'):
150
def test_suite(): return 'ok'
151
test_suite.__name__ = cls.__name__
152
for requirement in cls.__requires__:
153
check = getattr(requires, requirement)
156
if cls.__unsupported_on__:
157
spec = testing.db_spec(*cls.__unsupported_on__)
160
"'%s' unsupported on DB implementation '%s'" % (
161
cls.__name__, testing.db.name)
164
if getattr(cls, '__only_on__', None):
165
spec = testing.db_spec(*util.to_list(cls.__only_on__))
166
if not spec(testing.db):
168
"'%s' unsupported on DB implementation '%s'" % (
169
cls.__name__, testing.db.name)
172
if getattr(cls, '__skip_if__', False):
173
for c in getattr(cls, '__skip_if__'):
175
raise SkipTest("'%s' skipped by %s" % (
176
cls.__name__, c.__name__)
179
for db, op, spec in getattr(cls, '__excluded_on__', ()):
180
testing.exclude(db, op, spec, "'%s' unsupported on DB %s version %s" % (
181
cls.__name__, testing.db.name,
182
testing._server_version()))
184
def beforeTest(self, test):
185
testing.resetwarnings()
186
testing.current_test = test.id()
188
def afterTest(self, test):
189
engines.testing_reaper._after_test_ctx()
190
testing.resetwarnings()
192
def stopContext(self, ctx):
193
engines.testing_reaper._stop_test_ctx()
194
if not config.options.low_connections:
195
testing.global_cleanup_assertions()