Added API tests
[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
152a3bfa 28from mediagoblin.tools import testing
421129b6 29from mediagoblin.init.config import read_mediagoblin_config
c5678c1a 30from mediagoblin.db.open import setup_connection_and_db_from_config
d693f6bd 31from mediagoblin.db.sql.base import Session
56dc1c9d 32from mediagoblin.meddleware import BaseMeddleware
9754802d 33from mediagoblin.auth.lib import bcrypt_gen_password_hash
d693f6bd
CAW
34from mediagoblin.gmg_commands.dbupdate import run_dbupdate
35from mediagoblin.init.celery import setup_celery_app
c5678c1a
CAW
36
37
cfd2cbf3 38MEDIAGOBLIN_TEST_DB_NAME = u'__mediagoblin_tests__'
623bee73 39TEST_SERVER_CONFIG = pkg_resources.resource_filename(
5c441e75 40 'mediagoblin.tests', 'test_paste.ini')
c5678c1a 41TEST_APP_CONFIG = pkg_resources.resource_filename(
623bee73 42 'mediagoblin.tests', 'test_mgoblin_app.ini')
c5678c1a
CAW
43TEST_USER_DEV = pkg_resources.resource_filename(
44 'mediagoblin.tests', 'test_user_dev')
45MGOBLIN_APP = None
46
47USER_DEV_DIRECTORIES_TO_SETUP = [
48 'media/public', 'media/queue',
49 'beaker/sessions/data', 'beaker/sessions/lock']
50
29f1333e
CAW
51BAD_CELERY_MESSAGE = """\
52Sorry, you *absolutely* must run nosetests with the
073b61fe
E
53mediagoblin.init.celery.from_tests module. Like so:
54$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests"""
29f1333e 55
c5678c1a
CAW
56
57class BadCeleryEnviron(Exception): pass
58
59
56dc1c9d 60class TestingMeddleware(BaseMeddleware):
33d11e99 61 """
ce5ae8da 62 Meddleware for the Unit tests
a11aa2d1 63
33d11e99
E
64 It might make sense to perform some tests on all
65 requests/responses. Or prepare them in a special
66 manner. For example all html responses could be tested
67 for being valid html *after* being rendered.
68
69 This module is getting inserted at the front of the
ce5ae8da 70 meddleware list, which means: requests are handed here
33d11e99
E
71 first, responses last. So this wraps up the "normal"
72 app.
73
74 If you need to add a test, either add it directly to
75 the appropiate process_request or process_response, or
76 create a new method and call it from process_*.
77 """
78
33d11e99
E
79 def process_response(self, request, response):
80 # All following tests should be for html only!
74af60bb 81 if getattr(response, 'content_type', None) != "text/html":
33d11e99
E
82 # Get out early
83 return
84
85 # If the template contains a reference to
86 # /mgoblin_static/ instead of using
87 # /request.staticdirect(), error out here.
88 # This could probably be implemented as a grep on
89 # the shipped templates easier...
90 if response.text.find("/mgoblin_static/") >= 0:
91 raise AssertionError(
92 "Response HTML contains reference to /mgoblin_static/ "
93 "instead of staticdirect. Request was for: "
94 + request.full_path)
95
96 return
97
98
29f1333e 99def suicide_if_bad_celery_environ():
eaca7874 100 if not os.environ.get('CELERY_CONFIG_MODULE') == \
073b61fe 101 'mediagoblin.init.celery.from_tests':
29f1333e 102 raise BadCeleryEnviron(BAD_CELERY_MESSAGE)
a11aa2d1 103
29f1333e
CAW
104
105def get_test_app(dump_old_app=True):
106 suicide_if_bad_celery_environ()
623bee73 107
0419d0da 108 # Make sure we've turned on testing
152a3bfa 109 testing._activate_testing()
0419d0da 110
9ea5c28b 111 # Leave this imported as it sets up celery.
073b61fe 112 from mediagoblin.init.celery import from_tests
9ea5c28b 113
623bee73 114 global MGOBLIN_APP
c5678c1a
CAW
115
116 # Just return the old app if that exists and it's okay to set up
117 # and return
118 if MGOBLIN_APP and not dump_old_app:
119 return MGOBLIN_APP
120
9c768866
BS
121 Session.rollback()
122 Session.remove()
123
c5678c1a
CAW
124 # Remove and reinstall user_dev directories
125 if os.path.exists(TEST_USER_DEV):
126 shutil.rmtree(TEST_USER_DEV)
127
128 for directory in USER_DEV_DIRECTORIES_TO_SETUP:
129 full_dir = os.path.join(TEST_USER_DEV, directory)
130 os.makedirs(full_dir)
131
132 # Get app config
623bee73
CAW
133 global_config, validation_result = read_mediagoblin_config(TEST_APP_CONFIG)
134 app_config = global_config['mediagoblin']
c5678c1a 135
d693f6bd 136 # Run database setup/migrations
30520c92 137 run_dbupdate(app_config, global_config)
c5678c1a
CAW
138
139 # setup app and return
0a791a94 140 test_app = loadapp(
623bee73
CAW
141 'config:' + TEST_SERVER_CONFIG)
142
d693f6bd
CAW
143 # Re-setup celery
144 setup_celery_app(app_config, global_config)
145
ce5ae8da 146 # Insert the TestingMeddleware, which can do some
91b89bde 147 # sanity checks on every request/response.
34b0874d
E
148 # Doing it this way is probably not the cleanest way.
149 # We'll fix it, when we have plugins!
ce5ae8da 150 mg_globals.app.meddleware.insert(0, TestingMeddleware(mg_globals.app))
91b89bde 151
623bee73
CAW
152 app = TestApp(test_app)
153 MGOBLIN_APP = app
154
623bee73 155 return app
3aa4c668
CAW
156
157
158def setup_fresh_app(func):
159 """
160 Decorator to setup a fresh test application for this function.
161
162 Cleans out test buckets and passes in a new, fresh test_app.
163 """
1e03504e 164 @wraps(func)
3aa4c668
CAW
165 def wrapper(*args, **kwargs):
166 test_app = get_test_app()
152a3bfa 167 testing.clear_test_buckets()
3aa4c668
CAW
168 return func(test_app, *args, **kwargs)
169
1e03504e 170 return wrapper
85663692
CAW
171
172
173def install_fixtures_simple(db, fixtures):
174 """
175 Very simply install fixtures in the database
176 """
177 for collection_name, collection_fixtures in fixtures.iteritems():
178 collection = db[collection_name]
179 for fixture in collection_fixtures:
180 collection.insert(fixture)
181
182
183def assert_db_meets_expected(db, expected):
184 """
185 Assert a database contains the things we expect it to.
186
5c2b8486
SS
187 Objects are found via 'id', so you should make sure your document
188 has an id.
85663692
CAW
189
190 Args:
191 - db: pymongo or mongokit database connection
192 - expected: the data we expect. Formatted like:
193 {'collection_name': [
5c2b8486 194 {'id': 'foo',
85663692
CAW
195 'some_field': 'some_value'},]}
196 """
197 for collection_name, collection_data in expected.iteritems():
198 collection = db[collection_name]
199 for expected_document in collection_data:
5c2b8486 200 document = collection.find_one({'id': expected_document['id']})
85663692
CAW
201 assert document is not None # make sure it exists
202 assert document == expected_document # make sure it matches
9754802d
E
203
204
bee079f3
JW
205def fixture_add_user(username=u'chris', password='toast',
206 active_user=True):
9754802d
E
207 test_user = mg_globals.database.User()
208 test_user.username = username
209 test_user.email = username + u'@example.com'
210 if password is not None:
211 test_user.pw_hash = bcrypt_gen_password_hash(password)
212 if active_user:
213 test_user.email_verified = True
214 test_user.status = u'active'
215
216 test_user.save()
217
37ef4c66
E
218 # Reload
219 test_user = mg_globals.database.User.find_one({'username': username})
220
221 # ... and detach from session:
222 from mediagoblin.db.sql.base import Session
223 Session.expunge(test_user)
224
9754802d 225 return test_user