Fixing ALL THE BROKEN TESTS. I probably broke most of them.
[mediagoblin.git] / mediagoblin / tests / test_auth.py
1
2 # GNU MediaGoblin -- federated, autonomous media hosting
3 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
14 #
15 # You should have received a copy of the GNU Affero General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 import urlparse
18 import pkg_resources
19 import pytest
20
21 from mediagoblin import mg_globals
22 from mediagoblin.db.models import User
23 from mediagoblin.tests.tools import get_app, fixture_add_user
24 from mediagoblin.tools import template, mail
25 from mediagoblin.auth import tools as auth_tools
26
27
28 def test_register_views(test_app):
29 """
30 Massive test function that all our registration-related views all work.
31 """
32 # Test doing a simple GET on the page
33 # -----------------------------------
34
35 test_app.get('/auth/register/')
36 # Make sure it rendered with the appropriate template
37 assert 'mediagoblin/auth/register.html' in template.TEMPLATE_TEST_CONTEXT
38
39 # Try to register without providing anything, should error
40 # --------------------------------------------------------
41
42 template.clear_test_template_context()
43 test_app.post(
44 '/auth/register/', {})
45 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
46 form = context['register_form']
47 assert form.username.errors == [u'This field is required.']
48 assert form.password.errors == [u'This field is required.']
49 assert form.email.errors == [u'This field is required.']
50
51 # Try to register with fields that are known to be invalid
52 # --------------------------------------------------------
53
54 ## too short
55 template.clear_test_template_context()
56 test_app.post(
57 '/auth/register/', {
58 'username': 'l',
59 'password': 'o',
60 'email': 'l'})
61 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
62 form = context['register_form']
63
64 assert form.username.errors == [u'Field must be between 3 and 30 characters long.']
65 assert form.password.errors == [u'Field must be between 5 and 1024 characters long.']
66
67 ## bad form
68 template.clear_test_template_context()
69 test_app.post(
70 '/auth/register/', {
71 'username': '@_@',
72 'email': 'lollerskates'})
73 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
74 form = context['register_form']
75
76 assert form.username.errors == [u'This field does not take email addresses.']
77 assert form.email.errors == [u'This field requires an email address.']
78
79 ## At this point there should be no users in the database ;)
80 assert User.query.count() == 0
81
82 # Successful register
83 # -------------------
84 template.clear_test_template_context()
85 response = test_app.post(
86 '/auth/register/', {
87 'username': u'happygirl',
88 'password': 'iamsohappy',
89 'email': 'happygrrl@example.org'})
90 response.follow()
91
92 ## Did we redirect to the proper page? Use the right template?
93 assert urlparse.urlsplit(response.location)[2] == '/u/happygirl/'
94 assert 'mediagoblin/user_pages/user_nonactive.html' in template.TEMPLATE_TEST_CONTEXT
95
96 ## Make sure user is in place
97 new_user = mg_globals.database.User.query.filter_by(
98 username=u'happygirl').first()
99 assert new_user
100 assert new_user.status == u'needs_email_verification'
101 assert new_user.email_verified == False
102
103 ## Make sure user is logged in
104 request = template.TEMPLATE_TEST_CONTEXT[
105 'mediagoblin/user_pages/user_nonactive.html']['request']
106 assert request.session['user_id'] == unicode(new_user.id)
107
108 ## Make sure we get email confirmation, and try verifying
109 assert len(mail.EMAIL_TEST_INBOX) == 1
110 message = mail.EMAIL_TEST_INBOX.pop()
111 assert message['To'] == 'happygrrl@example.org'
112 email_context = template.TEMPLATE_TEST_CONTEXT[
113 'mediagoblin/auth/verification_email.txt']
114 assert email_context['verification_url'] in message.get_payload(decode=True)
115
116 path = urlparse.urlsplit(email_context['verification_url'])[2]
117 get_params = urlparse.urlsplit(email_context['verification_url'])[3]
118 assert path == u'/auth/verify_email/'
119 parsed_get_params = urlparse.parse_qs(get_params)
120
121 ## Try verifying with bs verification key, shouldn't work
122 template.clear_test_template_context()
123 response = test_app.get(
124 "/auth/verify_email/?token=total_bs")
125 response.follow()
126
127 # Correct redirect?
128 assert urlparse.urlsplit(response.location)[2] == '/'
129
130 # assert context['verification_successful'] == True
131 # TODO: Would be good to test messages here when we can do so...
132 new_user = mg_globals.database.User.query.filter_by(
133 username=u'happygirl').first()
134 assert new_user
135 assert new_user.status == u'needs_email_verification'
136 assert new_user.email_verified == False
137
138 ## Verify the email activation works
139 template.clear_test_template_context()
140 response = test_app.get("%s?%s" % (path, get_params))
141 response.follow()
142 context = template.TEMPLATE_TEST_CONTEXT[
143 'mediagoblin/user_pages/user.html']
144 # assert context['verification_successful'] == True
145 # TODO: Would be good to test messages here when we can do so...
146 new_user = mg_globals.database.User.query.filter_by(
147 username=u'happygirl').first()
148 assert new_user
149 assert new_user.status == u'active'
150 assert new_user.email_verified == True
151
152 # Uniqueness checks
153 # -----------------
154 ## We shouldn't be able to register with that user twice
155 template.clear_test_template_context()
156 response = test_app.post(
157 '/auth/register/', {
158 'username': u'happygirl',
159 'password': 'iamsohappy2',
160 'email': 'happygrrl2@example.org'})
161
162 context = template.TEMPLATE_TEST_CONTEXT[
163 'mediagoblin/auth/register.html']
164 form = context['register_form']
165 assert form.username.errors == [
166 u'Sorry, a user with that name already exists.']
167
168 ## TODO: Also check for double instances of an email address?
169
170 ### Oops, forgot the password
171 # -------------------
172 template.clear_test_template_context()
173 response = test_app.post(
174 '/auth/forgot_password/',
175 {'username': u'happygirl'})
176 response.follow()
177
178 ## Did we redirect to the proper page? Use the right template?
179 assert urlparse.urlsplit(response.location)[2] == '/auth/login/'
180 assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
181
182 ## Make sure link to change password is sent by email
183 assert len(mail.EMAIL_TEST_INBOX) == 1
184 message = mail.EMAIL_TEST_INBOX.pop()
185 assert message['To'] == 'happygrrl@example.org'
186 email_context = template.TEMPLATE_TEST_CONTEXT[
187 'mediagoblin/plugins/basic_auth/fp_verification_email.txt']
188 #TODO - change the name of verification_url to something forgot-password-ish
189 assert email_context['verification_url'] in message.get_payload(decode=True)
190
191 path = urlparse.urlsplit(email_context['verification_url'])[2]
192 get_params = urlparse.urlsplit(email_context['verification_url'])[3]
193 parsed_get_params = urlparse.parse_qs(get_params)
194 assert path == u'/auth/forgot_password/verify/'
195
196 ## Try using a bs password-changing verification key, shouldn't work
197 template.clear_test_template_context()
198 response = test_app.get(
199 "/auth/forgot_password/verify/?token=total_bs")
200 response.follow()
201
202 # Correct redirect?
203 assert urlparse.urlsplit(response.location)[2] == '/'
204
205 ## Verify step 1 of password-change works -- can see form to change password
206 template.clear_test_template_context()
207 response = test_app.get("%s?%s" % (path, get_params))
208 assert 'mediagoblin/plugins/basic_auth/change_fp.html' in \
209 template.TEMPLATE_TEST_CONTEXT
210
211 ## Verify step 2.1 of password-change works -- report success to user
212 template.clear_test_template_context()
213 response = test_app.post(
214 '/auth/forgot_password/verify/', {
215 'password': 'iamveryveryhappy',
216 'token': parsed_get_params['token']})
217 response.follow()
218 assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
219
220 ## Verify step 2.2 of password-change works -- login w/ new password success
221 template.clear_test_template_context()
222 response = test_app.post(
223 '/auth/login/', {
224 'username': u'happygirl',
225 'password': 'iamveryveryhappy'})
226
227 # User should be redirected
228 response.follow()
229 assert urlparse.urlsplit(response.location)[2] == '/'
230 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
231
232
233 def test_authentication_views(test_app):
234 """
235 Test logging in and logging out
236 """
237 # Make a new user
238 test_user = fixture_add_user(active_user=False)
239
240
241 # Get login
242 # ---------
243 test_app.get('/auth/login/')
244 assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
245
246 # Failed login - blank form
247 # -------------------------
248 template.clear_test_template_context()
249 response = test_app.post('/auth/login/')
250 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
251 form = context['login_form']
252 assert form.username.errors == [u'This field is required.']
253
254 # Failed login - blank user
255 # -------------------------
256 template.clear_test_template_context()
257 response = test_app.post(
258 '/auth/login/', {
259 'password': u'toast'})
260 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
261 form = context['login_form']
262 assert form.username.errors == [u'This field is required.']
263
264 # Failed login - blank password
265 # -----------------------------
266 template.clear_test_template_context()
267 response = test_app.post(
268 '/auth/login/', {
269 'username': u'chris'})
270 assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
271
272 # Failed login - bad user
273 # -----------------------
274 template.clear_test_template_context()
275 response = test_app.post(
276 '/auth/login/', {
277 'username': u'steve',
278 'password': 'toast'})
279 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
280 assert context['login_failed']
281
282 # Failed login - bad password
283 # ---------------------------
284 template.clear_test_template_context()
285 response = test_app.post(
286 '/auth/login/', {
287 'username': u'chris',
288 'password': 'jam_and_ham'})
289 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
290 assert context['login_failed']
291
292 # Successful login
293 # ----------------
294 template.clear_test_template_context()
295 response = test_app.post(
296 '/auth/login/', {
297 'username': u'chris',
298 'password': 'toast'})
299
300 # User should be redirected
301 response.follow()
302 assert urlparse.urlsplit(response.location)[2] == '/'
303 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
304
305 # Make sure user is in the session
306 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
307 session = context['request'].session
308 assert session['user_id'] == unicode(test_user.id)
309
310 # Successful logout
311 # -----------------
312 template.clear_test_template_context()
313 response = test_app.get('/auth/logout/')
314
315 # Should be redirected to index page
316 response.follow()
317 assert urlparse.urlsplit(response.location)[2] == '/'
318 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
319
320 # Make sure the user is not in the session
321 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
322 session = context['request'].session
323 assert 'user_id' not in session
324
325 # User is redirected to custom URL if POST['next'] is set
326 # -------------------------------------------------------
327 template.clear_test_template_context()
328 response = test_app.post(
329 '/auth/login/', {
330 'username': u'chris',
331 'password': 'toast',
332 'next' : '/u/chris/'})
333 assert urlparse.urlsplit(response.location)[2] == '/u/chris/'
334
335
336 @pytest.fixture()
337 def authentication_disabled_app(request):
338 return get_app(
339 request,
340 mgoblin_config=pkg_resources.resource_filename(
341 'mediagoblin.tests.auth_configs',
342 'authentication_disabled_appconfig.ini'))
343
344
345 def test_authentication_disabled_app(authentication_disabled_app):
346 # app.auth should = false
347 assert mg_globals.app.auth is False
348
349 # Try to visit register page
350 template.clear_test_template_context()
351 response = authentication_disabled_app.get('/auth/register/')
352 response.follow()
353
354 # Correct redirect?
355 assert urlparse.urlsplit(response.location)[2] == '/'
356 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
357
358 # Try to vist login page
359 template.clear_test_template_context()
360 response = authentication_disabled_app.get('/auth/login/')
361 response.follow()
362
363 # Correct redirect?
364 assert urlparse.urlsplit(response.location)[2] == '/'
365 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
366
367 ## Test check_login_simple should return None
368 assert auth_tools.check_login_simple('test', 'simple') is None
369
370 # Try to visit the forgot password page
371 template.clear_test_template_context()
372 response = authentication_disabled_app.get('/auth/register/')
373 response.follow()
374
375 # Correct redirect?
376 assert urlparse.urlsplit(response.location)[2] == '/'
377 assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT