Moving test_user_dev->user_dev in plugin app configs & adding plugin static serving
[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
c121a7d3 18import sys
1e03504e 19import os
c5678c1a 20import pkg_resources
1e03504e
JK
21import shutil
22
23from functools import wraps
c5678c1a 24
623bee73 25from paste.deploy import loadapp
c5678c1a
CAW
26from webtest import TestApp
27
91b89bde 28from mediagoblin import mg_globals
e9b4e500 29from mediagoblin.db.models import User, MediaEntry, Collection
152a3bfa 30from mediagoblin.tools import testing
421129b6 31from mediagoblin.init.config import read_mediagoblin_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 35from mediagoblin.gmg_commands.dbupdate import run_dbupdate
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')
6588acc1 43
c5678c1a 44
9e1fa239 45USER_DEV_DIRECTORIES_TO_SETUP = ['media/public', 'media/queue']
c5678c1a 46
c5678c1a 47
56dc1c9d 48class TestingMeddleware(BaseMeddleware):
33d11e99 49 """
ce5ae8da 50 Meddleware for the Unit tests
a11aa2d1 51
33d11e99
E
52 It might make sense to perform some tests on all
53 requests/responses. Or prepare them in a special
54 manner. For example all html responses could be tested
55 for being valid html *after* being rendered.
56
57 This module is getting inserted at the front of the
ce5ae8da 58 meddleware list, which means: requests are handed here
33d11e99
E
59 first, responses last. So this wraps up the "normal"
60 app.
61
62 If you need to add a test, either add it directly to
63 the appropiate process_request or process_response, or
64 create a new method and call it from process_*.
65 """
66
33d11e99
E
67 def process_response(self, request, response):
68 # All following tests should be for html only!
74af60bb 69 if getattr(response, 'content_type', None) != "text/html":
33d11e99
E
70 # Get out early
71 return
72
73 # If the template contains a reference to
74 # /mgoblin_static/ instead of using
75 # /request.staticdirect(), error out here.
76 # This could probably be implemented as a grep on
77 # the shipped templates easier...
78 if response.text.find("/mgoblin_static/") >= 0:
79 raise AssertionError(
80 "Response HTML contains reference to /mgoblin_static/ "
81 "instead of staticdirect. Request was for: "
82 + request.full_path)
83
84 return
85
86
5c2ece74
CAW
87def get_app(request, paste_config=None, mgoblin_config=None):
88 """Create a MediaGoblin app for testing.
89
90 Args:
91 - request: Not an http request, but a pytest fixture request. We
92 use this to make temporary directories that pytest
93 automatically cleans up as needed.
94 - paste_config: particular paste config used by this application.
95 - mgoblin_config: particular mediagoblin config used by this
96 application.
97 """
6588acc1
CAW
98 paste_config = paste_config or TEST_SERVER_CONFIG
99 mgoblin_config = mgoblin_config or TEST_APP_CONFIG
100
5c2ece74
CAW
101 # This is the directory we're copying the paste/mgoblin config stuff into
102 run_dir = request.config._tmpdirhandler.mktemp(
103 'mgoblin_app', numbered=True)
491029bc 104 user_dev_dir = run_dir.mkdir('user_dev').strpath
5c2ece74
CAW
105
106 new_paste_config = run_dir.join('paste.ini').strpath
107 new_mgoblin_config = run_dir.join('mediagoblin.ini').strpath
108 shutil.copyfile(paste_config, new_paste_config)
109 shutil.copyfile(mgoblin_config, new_mgoblin_config)
110
9c768866
BS
111 Session.rollback()
112 Session.remove()
113
5c2ece74 114 # install user_dev directories
c5678c1a 115 for directory in USER_DEV_DIRECTORIES_TO_SETUP:
5c2ece74 116 full_dir = os.path.join(user_dev_dir, directory)
c5678c1a
CAW
117 os.makedirs(full_dir)
118
119 # Get app config
5c2ece74 120 global_config, validation_result = read_mediagoblin_config(new_mgoblin_config)
623bee73 121 app_config = global_config['mediagoblin']
c5678c1a 122
d693f6bd 123 # Run database setup/migrations
30520c92 124 run_dbupdate(app_config, global_config)
c5678c1a
CAW
125
126 # setup app and return
0a791a94 127 test_app = loadapp(
5c2ece74 128 'config:' + new_paste_config)
623bee73 129
ce5ae8da 130 # Insert the TestingMeddleware, which can do some
91b89bde 131 # sanity checks on every request/response.
34b0874d
E
132 # Doing it this way is probably not the cleanest way.
133 # We'll fix it, when we have plugins!
ce5ae8da 134 mg_globals.app.meddleware.insert(0, TestingMeddleware(mg_globals.app))
91b89bde 135
623bee73 136 app = TestApp(test_app)
6588acc1 137
623bee73 138 return app
3aa4c668
CAW
139
140
85663692
CAW
141def install_fixtures_simple(db, fixtures):
142 """
143 Very simply install fixtures in the database
144 """
145 for collection_name, collection_fixtures in fixtures.iteritems():
146 collection = db[collection_name]
147 for fixture in collection_fixtures:
148 collection.insert(fixture)
149
150
151def assert_db_meets_expected(db, expected):
152 """
153 Assert a database contains the things we expect it to.
154
5c2b8486
SS
155 Objects are found via 'id', so you should make sure your document
156 has an id.
85663692
CAW
157
158 Args:
159 - db: pymongo or mongokit database connection
160 - expected: the data we expect. Formatted like:
161 {'collection_name': [
5c2b8486 162 {'id': 'foo',
85663692
CAW
163 'some_field': 'some_value'},]}
164 """
165 for collection_name, collection_data in expected.iteritems():
166 collection = db[collection_name]
167 for expected_document in collection_data:
5c2b8486 168 document = collection.find_one({'id': expected_document['id']})
85663692
CAW
169 assert document is not None # make sure it exists
170 assert document == expected_document # make sure it matches
9754802d
E
171
172
a5cf95c5 173def fixture_add_user(username=u'chris', password=u'toast',
bee079f3 174 active_user=True):
4fc0a289
SS
175 # Reuse existing user or create a new one
176 test_user = User.query.filter_by(username=username).first()
177 if test_user is None:
178 test_user = User()
9754802d
E
179 test_user.username = username
180 test_user.email = username + u'@example.com'
181 if password is not None:
182 test_user.pw_hash = bcrypt_gen_password_hash(password)
183 if active_user:
184 test_user.email_verified = True
185 test_user.status = u'active'
186
187 test_user.save()
188
37ef4c66 189 # Reload
a5cf95c5 190 test_user = User.query.filter_by(username=username).first()
37ef4c66
E
191
192 # ... and detach from session:
37ef4c66
E
193 Session.expunge(test_user)
194
9754802d 195 return test_user
cd75b228
E
196
197
e9b4e500
E
198def fixture_media_entry(title=u"Some title", slug=None,
199 uploader=None, save=True, gen_slug=True):
200 entry = MediaEntry()
201 entry.title = title
202 entry.slug = slug
203 entry.uploader = uploader or fixture_add_user().id
204 entry.media_type = u'image'
c121a7d3 205
e9b4e500
E
206 if gen_slug:
207 entry.generate_slug()
208 if save:
209 entry.save()
210
211 return entry
212
213
cd75b228
E
214def fixture_add_collection(name=u"My first Collection", user=None):
215 if user is None:
216 user = fixture_add_user()
217 coll = Collection.query.filter_by(creator=user.id, title=name).first()
218 if coll is not None:
219 return coll
220 coll = Collection()
221 coll.creator = user.id
222 coll.title = name
223 coll.generate_slug()
224 coll.save()
225
226 # Reload
227 Session.refresh(coll)
228
229 # ... and detach from session:
230 Session.expunge(coll)
231
232 return coll
491029bc 233