1 | import logging |
---|
2 | import os |
---|
3 | import re |
---|
4 | import sys |
---|
5 | import time |
---|
6 | import warnings |
---|
7 | import ConfigParser |
---|
8 | import StringIO |
---|
9 | from config import db, db_label, db_url, file_config, base_config, \ |
---|
10 | post_configure, \ |
---|
11 | _list_dbs, _server_side_cursors, _engine_strategy, \ |
---|
12 | _engine_uri, _require, _engine_pool, \ |
---|
13 | _create_testing_engine, _prep_testing_database, \ |
---|
14 | _set_table_options, _reverse_topological, _log |
---|
15 | from sqlalchemy.test import testing, config, requires |
---|
16 | from nose.plugins import Plugin |
---|
17 | from nose.util import tolist |
---|
18 | import nose.case |
---|
19 | |
---|
20 | log = logging.getLogger('nose.plugins.sqlalchemy') |
---|
21 | |
---|
22 | class NoseSQLAlchemy(Plugin): |
---|
23 | """ |
---|
24 | Handles the setup and extra properties required for testing SQLAlchemy |
---|
25 | """ |
---|
26 | enabled = True |
---|
27 | name = 'sqlalchemy' |
---|
28 | score = 100 |
---|
29 | |
---|
30 | def options(self, parser, env=os.environ): |
---|
31 | Plugin.options(self, parser, env) |
---|
32 | opt = parser.add_option |
---|
33 | #opt("--verbose", action="store_true", dest="verbose", |
---|
34 | #help="enable stdout echoing/printing") |
---|
35 | #opt("--quiet", action="store_true", dest="quiet", help="suppress output") |
---|
36 | opt("--log-info", action="callback", type="string", callback=_log, |
---|
37 | help="turn on info logging for <LOG> (multiple OK)") |
---|
38 | opt("--log-debug", action="callback", type="string", callback=_log, |
---|
39 | help="turn on debug logging for <LOG> (multiple OK)") |
---|
40 | opt("--require", action="append", dest="require", default=[], |
---|
41 | help="require a particular driver or module version (multiple OK)") |
---|
42 | opt("--db", action="store", dest="db", default="sqlite", |
---|
43 | help="Use prefab database uri") |
---|
44 | opt('--dbs', action='callback', callback=_list_dbs, |
---|
45 | help="List available prefab dbs") |
---|
46 | opt("--dburi", action="store", dest="dburi", |
---|
47 | help="Database uri (overrides --db)") |
---|
48 | opt("--dropfirst", action="store_true", dest="dropfirst", |
---|
49 | help="Drop all tables in the target database first (use with caution on Oracle, MS-SQL)") |
---|
50 | opt("--mockpool", action="store_true", dest="mockpool", |
---|
51 | help="Use mock pool (asserts only one connection used)") |
---|
52 | opt("--enginestrategy", action="callback", type="string", |
---|
53 | callback=_engine_strategy, |
---|
54 | help="Engine strategy (plain or threadlocal, defaults to plain)") |
---|
55 | opt("--reversetop", action="store_true", dest="reversetop", default=False, |
---|
56 | help="Reverse the collection ordering for topological sorts (helps " |
---|
57 | "reveal dependency issues)") |
---|
58 | opt("--unhashable", action="store_true", dest="unhashable", default=False, |
---|
59 | help="Disallow SQLAlchemy from performing a hash() on mapped test objects.") |
---|
60 | opt("--noncomparable", action="store_true", dest="noncomparable", default=False, |
---|
61 | help="Disallow SQLAlchemy from performing == on mapped test objects.") |
---|
62 | opt("--truthless", action="store_true", dest="truthless", default=False, |
---|
63 | help="Disallow SQLAlchemy from truth-evaluating mapped test objects.") |
---|
64 | opt("--serverside", action="callback", callback=_server_side_cursors, |
---|
65 | help="Turn on server side cursors for PG") |
---|
66 | opt("--mysql-engine", action="store", dest="mysql_engine", default=None, |
---|
67 | help="Use the specified MySQL storage engine for all tables, default is " |
---|
68 | "a db-default/InnoDB combo.") |
---|
69 | opt("--table-option", action="append", dest="tableopts", default=[], |
---|
70 | help="Add a dialect-specific table option, key=value") |
---|
71 | |
---|
72 | global file_config |
---|
73 | file_config = ConfigParser.ConfigParser() |
---|
74 | file_config.readfp(StringIO.StringIO(base_config)) |
---|
75 | file_config.read(['test.cfg', os.path.expanduser('~/.satest.cfg')]) |
---|
76 | config.file_config = file_config |
---|
77 | |
---|
78 | def configure(self, options, conf): |
---|
79 | Plugin.configure(self, options, conf) |
---|
80 | |
---|
81 | import testing, requires |
---|
82 | testing.db = db |
---|
83 | testing.requires = requires |
---|
84 | |
---|
85 | # Lazy setup of other options (post coverage) |
---|
86 | for fn in post_configure: |
---|
87 | fn(options, file_config) |
---|
88 | |
---|
89 | def describeTest(self, test): |
---|
90 | return "" |
---|
91 | |
---|
92 | def wantClass(self, cls): |
---|
93 | """Return true if you want the main test selector to collect |
---|
94 | tests from this class, false if you don't, and None if you don't |
---|
95 | care. |
---|
96 | |
---|
97 | :Parameters: |
---|
98 | cls : class |
---|
99 | The class being examined by the selector |
---|
100 | |
---|
101 | """ |
---|
102 | |
---|
103 | if not issubclass(cls, testing.TestBase): |
---|
104 | return False |
---|
105 | else: |
---|
106 | if (hasattr(cls, '__whitelist__') and |
---|
107 | testing.db.name in cls.__whitelist__): |
---|
108 | return True |
---|
109 | else: |
---|
110 | return not self.__should_skip_for(cls) |
---|
111 | |
---|
112 | def __should_skip_for(self, cls): |
---|
113 | if hasattr(cls, '__requires__'): |
---|
114 | def test_suite(): return 'ok' |
---|
115 | for requirement in cls.__requires__: |
---|
116 | check = getattr(requires, requirement) |
---|
117 | if check(test_suite)() != 'ok': |
---|
118 | # The requirement will perform messaging. |
---|
119 | return True |
---|
120 | if (hasattr(cls, '__unsupported_on__') and |
---|
121 | testing.db.name in cls.__unsupported_on__): |
---|
122 | print "'%s' unsupported on DB implementation '%s'" % ( |
---|
123 | cls.__class__.__name__, testing.db.name) |
---|
124 | return True |
---|
125 | if (getattr(cls, '__only_on__', None) not in (None, testing.db.name)): |
---|
126 | print "'%s' unsupported on DB implementation '%s'" % ( |
---|
127 | cls.__class__.__name__, testing.db.name) |
---|
128 | return True |
---|
129 | if (getattr(cls, '__skip_if__', False)): |
---|
130 | for c in getattr(cls, '__skip_if__'): |
---|
131 | if c(): |
---|
132 | print "'%s' skipped by %s" % ( |
---|
133 | cls.__class__.__name__, c.__name__) |
---|
134 | return True |
---|
135 | for rule in getattr(cls, '__excluded_on__', ()): |
---|
136 | if testing._is_excluded(*rule): |
---|
137 | print "'%s' unsupported on DB %s version %s" % ( |
---|
138 | cls.__class__.__name__, testing.db.name, |
---|
139 | _server_version()) |
---|
140 | return True |
---|
141 | return False |
---|
142 | |
---|
143 | #def begin(self): |
---|
144 | #pass |
---|
145 | |
---|
146 | def beforeTest(self, test): |
---|
147 | testing.resetwarnings() |
---|
148 | |
---|
149 | def afterTest(self, test): |
---|
150 | testing.resetwarnings() |
---|
151 | |
---|
152 | #def handleError(self, test, err): |
---|
153 | #pass |
---|
154 | |
---|
155 | #def finalize(self, result=None): |
---|
156 | #pass |
---|