Use inspect_table; default user license==None.
[mediagoblin.git] / mediagoblin / tests / tools.py
CommitLineData
c5678c1a 1# GNU MediaGoblin -- federated, autonomous media hosting
cf29e8a8 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
c5678c1a
CAW
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as published by
6# the Free Software Foundation, either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
1e03504e 18import os
c5678c1a 19import pkg_resources
1e03504e
JK
20import shutil
21
22from functools import wraps
c5678c1a 23
623bee73 24from paste.deploy import loadapp
c5678c1a
CAW
25from webtest import TestApp
26
91b89bde 27from mediagoblin import mg_globals
cd75b228 28from mediagoblin.db.models import User, Collection
152a3bfa 29from mediagoblin.tools import testing
421129b6 30from mediagoblin.init.config import read_mediagoblin_config
c5678c1a 31from mediagoblin.db.open import setup_connection_and_db_from_config
39dc3bf8 32from mediagoblin.db.base import Session
56dc1c9d 33from mediagoblin.meddleware import BaseMeddleware
9754802d 34from mediagoblin.auth.lib import bcrypt_gen_password_hash
d693f6bd
CAW
35from mediagoblin.gmg_commands.dbupdate import run_dbupdate
36from mediagoblin.init.celery import setup_celery_app
c5678c1a
CAW
37
38
cfd2cbf3 39MEDIAGOBLIN_TEST_DB_NAME = u'__mediagoblin_tests__'
623bee73 40TEST_SERVER_CONFIG = pkg_resources.resource_filename(
5c441e75 41 'mediagoblin.tests', 'test_paste.ini')
c5678c1a 42TEST_APP_CONFIG = pkg_resources.resource_filename(
623bee73 43 'mediagoblin.tests', 'test_mgoblin_app.ini')
c5678c1a
CAW
44TEST_USER_DEV = pkg_resources.resource_filename(
45 'mediagoblin.tests', 'test_user_dev')
46MGOBLIN_APP = None
47
48USER_DEV_DIRECTORIES_TO_SETUP = [
49 'media/public', 'media/queue',
50 'beaker/sessions/data', 'beaker/sessions/lock']
51
29f1333e
CAW
52BAD_CELERY_MESSAGE = """\
53Sorry, you *absolutely* must run nosetests with the
073b61fe
E
54mediagoblin.init.celery.from_tests module. Like so:
55$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests"""
29f1333e 56
c5678c1a
CAW
57
58class BadCeleryEnviron(Exception): pass
59
60
56dc1c9d 61class TestingMeddleware(BaseMeddleware):
33d11e99 62 """
ce5ae8da 63 Meddleware for the Unit tests
a11aa2d1 64
33d11e99
E
65 It might make sense to perform some tests on all
66 requests/responses. Or prepare them in a special
67 manner. For example all html responses could be tested
68 for being valid html *after* being rendered.
69
70 This module is getting inserted at the front of the
ce5ae8da 71 meddleware list, which means: requests are handed here
33d11e99
E
72 first, responses last. So this wraps up the "normal"
73 app.
74
75 If you need to add a test, either add it directly to
76 the appropiate process_request or process_response, or
77 create a new method and call it from process_*.
78 """
79
33d11e99
E
80 def process_response(self, request, response):
81 # All following tests should be for html only!
74af60bb 82 if getattr(response, 'content_type', None) != "text/html":
33d11e99
E
83 # Get out early
84 return
85
86 # If the template contains a reference to
87 # /mgoblin_static/ instead of using
88 # /request.staticdirect(), error out here.
89 # This could probably be implemented as a grep on
90 # the shipped templates easier...
91 if response.text.find("/mgoblin_static/") >= 0:
92 raise AssertionError(
93 "Response HTML contains reference to /mgoblin_static/ "
94 "instead of staticdirect. Request was for: "
95 + request.full_path)
96
97 return
98
99
29f1333e 100def suicide_if_bad_celery_environ():
eaca7874 101 if not os.environ.get('CELERY_CONFIG_MODULE') == \
073b61fe 102 'mediagoblin.init.celery.from_tests':
29f1333e 103 raise BadCeleryEnviron(BAD_CELERY_MESSAGE)
a11aa2d1 104
29f1333e 105
1be247b3 106def get_app(dump_old_app=True):
29f1333e 107 suicide_if_bad_celery_environ()
623bee73 108
0419d0da 109 # Make sure we've turned on testing
152a3bfa 110 testing._activate_testing()
0419d0da 111
9ea5c28b 112 # Leave this imported as it sets up celery.
073b61fe 113 from mediagoblin.init.celery import from_tests
9ea5c28b 114
623bee73 115 global MGOBLIN_APP
c5678c1a
CAW
116
117 # Just return the old app if that exists and it's okay to set up
118 # and return
119 if MGOBLIN_APP and not dump_old_app:
120 return MGOBLIN_APP
121
9c768866
BS
122 Session.rollback()
123 Session.remove()
124
c5678c1a
CAW
125 # Remove and reinstall user_dev directories
126 if os.path.exists(TEST_USER_DEV):
127 shutil.rmtree(TEST_USER_DEV)
128
129 for directory in USER_DEV_DIRECTORIES_TO_SETUP:
130 full_dir = os.path.join(TEST_USER_DEV, directory)
131 os.makedirs(full_dir)
132
133 # Get app config
623bee73
CAW
134 global_config, validation_result = read_mediagoblin_config(TEST_APP_CONFIG)
135 app_config = global_config['mediagoblin']
c5678c1a 136
d693f6bd 137 # Run database setup/migrations
30520c92 138 run_dbupdate(app_config, global_config)
c5678c1a
CAW
139
140 # setup app and return
0a791a94 141 test_app = loadapp(
623bee73
CAW
142 'config:' + TEST_SERVER_CONFIG)
143
d693f6bd
CAW
144 # Re-setup celery
145 setup_celery_app(app_config, global_config)
146
ce5ae8da 147 # Insert the TestingMeddleware, which can do some
91b89bde 148 # sanity checks on every request/response.
34b0874d
E
149 # Doing it this way is probably not the cleanest way.
150 # We'll fix it, when we have plugins!
ce5ae8da 151 mg_globals.app.meddleware.insert(0, TestingMeddleware(mg_globals.app))
91b89bde 152
623bee73
CAW
153 app = TestApp(test_app)
154 MGOBLIN_APP = app
155
623bee73 156 return app
3aa4c668
CAW
157
158
159def setup_fresh_app(func):
160 """
161 Decorator to setup a fresh test application for this function.
162
163 Cleans out test buckets and passes in a new, fresh test_app.
164 """
1e03504e 165 @wraps(func)
3aa4c668 166 def wrapper(*args, **kwargs):
1be247b3 167 test_app = get_app()
152a3bfa 168 testing.clear_test_buckets()
3aa4c668
CAW
169 return func(test_app, *args, **kwargs)
170
1e03504e 171 return wrapper
85663692
CAW
172
173
174def install_fixtures_simple(db, fixtures):
175 """
176 Very simply install fixtures in the database
177 """
178 for collection_name, collection_fixtures in fixtures.iteritems():
179 collection = db[collection_name]
180 for fixture in collection_fixtures:
181 collection.insert(fixture)
182
183
184def assert_db_meets_expected(db, expected):
185 """
186 Assert a database contains the things we expect it to.
187
5c2b8486
SS
188 Objects are found via 'id', so you should make sure your document
189 has an id.
85663692
CAW
190
191 Args:
192 - db: pymongo or mongokit database connection
193 - expected: the data we expect. Formatted like:
194 {'collection_name': [
5c2b8486 195 {'id': 'foo',
85663692
CAW
196 'some_field': 'some_value'},]}
197 """
198 for collection_name, collection_data in expected.iteritems():
199 collection = db[collection_name]
200 for expected_document in collection_data:
5c2b8486 201 document = collection.find_one({'id': expected_document['id']})
85663692
CAW
202 assert document is not None # make sure it exists
203 assert document == expected_document # make sure it matches
9754802d
E
204
205
a5cf95c5 206def fixture_add_user(username=u'chris', password=u'toast',
bee079f3 207 active_user=True):
4fc0a289
SS
208 # Reuse existing user or create a new one
209 test_user = User.query.filter_by(username=username).first()
210 if test_user is None:
211 test_user = User()
9754802d
E
212 test_user.username = username
213 test_user.email = username + u'@example.com'
214 if password is not None:
215 test_user.pw_hash = bcrypt_gen_password_hash(password)
216 if active_user:
217 test_user.email_verified = True
218 test_user.status = u'active'
219
220 test_user.save()
221
37ef4c66 222 # Reload
a5cf95c5 223 test_user = User.query.filter_by(username=username).first()
37ef4c66
E
224
225 # ... and detach from session:
37ef4c66
E
226 Session.expunge(test_user)
227
9754802d 228 return test_user
cd75b228
E
229
230
231def fixture_add_collection(name=u"My first Collection", user=None):
232 if user is None:
233 user = fixture_add_user()
234 coll = Collection.query.filter_by(creator=user.id, title=name).first()
235 if coll is not None:
236 return coll
237 coll = Collection()
238 coll.creator = user.id
239 coll.title = name
240 coll.generate_slug()
241 coll.save()
242
243 # Reload
244 Session.refresh(coll)
245
246 # ... and detach from session:
247 Session.expunge(coll)
248
249 return coll