When media is deleted, delete associated comments too.
[mediagoblin.git] / mediagoblin / tests / test_submission.py
CommitLineData
1975b5dd 1# GNU MediaGoblin -- federated, autonomous media hosting
cf29e8a8 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
1975b5dd
CM
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
17import urlparse
9df37e8a 18import pkg_resources
a246ccca 19import re
1975b5dd 20
afe4e513 21from nose.tools import assert_equal, assert_true, assert_false
1975b5dd 22
9754802d
E
23from mediagoblin.tests.tools import setup_fresh_app, get_test_app, \
24 fixture_add_user
1975b5dd 25from mediagoblin import mg_globals
ae3bc7fa 26from mediagoblin.tools import template, common
1975b5dd 27
9df37e8a
CM
28GOOD_JPG = pkg_resources.resource_filename(
29 'mediagoblin.tests', 'test_submission/good.jpg')
30GOOD_PNG = pkg_resources.resource_filename(
31 'mediagoblin.tests', 'test_submission/good.png')
32EVIL_FILE = pkg_resources.resource_filename(
33 'mediagoblin.tests', 'test_submission/evil')
34EVIL_JPG = pkg_resources.resource_filename(
35 'mediagoblin.tests', 'test_submission/evil.jpg')
36EVIL_PNG = pkg_resources.resource_filename(
37 'mediagoblin.tests', 'test_submission/evil.png')
75ce65cf 38
8ff4dec7
CFD
39GOOD_TAG_STRING = 'yin,yang'
40BAD_TAG_STRING = 'rage,' + 'f' * 26 + 'u' * 26
41
1975b5dd 42
1975b5dd
CM
43class TestSubmission:
44 def setUp(self):
0a78be3e
CM
45 self.test_app = get_test_app()
46
75ce65cf
CM
47 # TODO: Possibly abstract into a decorator like:
48 # @as_authenticated_user('chris')
9754802d 49 test_user = fixture_add_user()
1975b5dd 50
afe4e513
JW
51 self.test_user = test_user
52
c2d6792d
E
53 self.login()
54
55 def login(self):
75ce65cf
CM
56 self.test_app.post(
57 '/auth/login/', {
58 'username': u'chris',
59 'password': 'toast'})
60
c2d6792d
E
61 def logout(self):
62 self.test_app.get('/auth/logout/')
63
75ce65cf 64 def test_missing_fields(self):
ad35dd49
CM
65 # Test blank form
66 # ---------------
ae3bc7fa 67 template.clear_test_template_context()
ad35dd49
CM
68 response = self.test_app.post(
69 '/submit/', {})
ae3bc7fa 70 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
ad35dd49
CM
71 form = context['submit_form']
72 assert form.file.errors == [u'You must provide a file.']
73
74 # Test blank file
75 # ---------------
ae3bc7fa 76 template.clear_test_template_context()
ad35dd49
CM
77 response = self.test_app.post(
78 '/submit/', {
79 'title': 'test title'})
ae3bc7fa 80 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
ad35dd49
CM
81 form = context['submit_form']
82 assert form.file.errors == [u'You must provide a file.']
83
75ce65cf
CM
84
85 def test_normal_uploads(self):
75ce65cf 86 # Test JPG
ad35dd49 87 # --------
ae3bc7fa 88 template.clear_test_template_context()
ad35dd49
CM
89 response = self.test_app.post(
90 '/submit/', {
91 'title': 'Normal upload 1'
92 }, upload_files=[(
9df37e8a 93 'file', GOOD_JPG)])
ad35dd49
CM
94
95 # User should be redirected
96 response.follow()
97 assert_equal(
98 urlparse.urlsplit(response.location)[2],
9df37e8a 99 '/u/chris/')
ae3bc7fa 100 assert template.TEMPLATE_TEST_CONTEXT.has_key(
9df37e8a 101 'mediagoblin/user_pages/user.html')
ad35dd49 102
c2d6792d
E
103 # Make sure the media view is at least reachable, logged in...
104 self.test_app.get('/u/chris/m/normal-upload-1/')
105 # ... and logged out too.
106 self.logout()
107 self.test_app.get('/u/chris/m/normal-upload-1/')
108 # Log back in for the remaining tests.
109 self.login()
110
75ce65cf 111 # Test PNG
ad35dd49 112 # --------
ae3bc7fa 113 template.clear_test_template_context()
ad35dd49
CM
114 response = self.test_app.post(
115 '/submit/', {
116 'title': 'Normal upload 2'
117 }, upload_files=[(
9df37e8a 118 'file', GOOD_PNG)])
ad35dd49
CM
119
120 response.follow()
121 assert_equal(
122 urlparse.urlsplit(response.location)[2],
9df37e8a 123 '/u/chris/')
ae3bc7fa 124 assert template.TEMPLATE_TEST_CONTEXT.has_key(
9df37e8a 125 'mediagoblin/user_pages/user.html')
75ce65cf 126
8ff4dec7
CFD
127 def test_tags(self):
128 # Good tag string
129 # --------
ae3bc7fa 130 template.clear_test_template_context()
8ff4dec7
CFD
131 response = self.test_app.post(
132 '/submit/', {
133 'title': 'Balanced Goblin',
134 'tags': GOOD_TAG_STRING
135 }, upload_files=[(
136 'file', GOOD_JPG)])
137
138 # New media entry with correct tags should be created
139 response.follow()
ae3bc7fa 140 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html']
8ff4dec7
CFD
141 request = context['request']
142 media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0]
8efcd405 143 assert_equal(media.tags,
8ff4dec7
CFD
144 [{'name': u'yin', 'slug': u'yin'},
145 {'name': u'yang', 'slug': u'yang'}])
146
147 # Test tags that are too long
148 # ---------------
ae3bc7fa 149 template.clear_test_template_context()
8ff4dec7
CFD
150 response = self.test_app.post(
151 '/submit/', {
152 'title': 'Balanced Goblin',
153 'tags': BAD_TAG_STRING
154 }, upload_files=[(
155 'file', GOOD_JPG)])
156
157 # Too long error should be raised
ae3bc7fa 158 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
8ff4dec7
CFD
159 form = context['submit_form']
160 assert form.tags.errors == [
161 u'Tags must be shorter than 50 characters. Tags that are too long'\
162 ': ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu']
75ce65cf 163
afe4e513 164 def test_delete(self):
ae3bc7fa 165 template.clear_test_template_context()
afe4e513
JW
166 response = self.test_app.post(
167 '/submit/', {
168 'title': 'Balanced Goblin',
169 }, upload_files=[(
170 'file', GOOD_JPG)])
171
172 # Post image
173 response.follow()
174
ae3bc7fa 175 request = template.TEMPLATE_TEST_CONTEXT[
afe4e513
JW
176 'mediagoblin/user_pages/user.html']['request']
177
178 media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0]
179
180 # Does media entry exist?
181 assert_true(media)
182
a0a7f87f
BS
183 # Add a comment, so we can test for its deletion later.
184 get_comments = lambda: list(
185 request.db.MediaComment.find({'media_entry': media._id}))
186 assert_false(get_comments())
187 response = self.test_app.post(
188 request.urlgen('mediagoblin.user_pages.media_post_comment',
189 user=self.test_user.username,
190 media=media._id),
191 {'comment_content': 'i love this test'})
192 response.follow()
193 assert_true(get_comments())
194
afe4e513
JW
195 # Do not confirm deletion
196 # ---------------------------------------------------
197 response = self.test_app.post(
502073f2 198 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
afe4e513 199 # No work: user=media.uploader().username,
5a4e3ff1 200 user=self.test_user.username,
bcc9ee32 201 media=media._id),
9a64272e
CAW
202 # no value means no confirm
203 {})
afe4e513
JW
204
205 response.follow()
206
ae3bc7fa 207 request = template.TEMPLATE_TEST_CONTEXT[
afe4e513
JW
208 'mediagoblin/user_pages/user.html']['request']
209
210 media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0]
211
212 # Does media entry still exist?
213 assert_true(media)
214
215 # Confirm deletion
216 # ---------------------------------------------------
217 response = self.test_app.post(
502073f2 218 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
afe4e513 219 # No work: user=media.uploader().username,
5a4e3ff1 220 user=self.test_user.username,
bcc9ee32 221 media=media._id),
9a64272e 222 {'confirm': 'y'})
afe4e513
JW
223
224 response.follow()
225
ae3bc7fa 226 request = template.TEMPLATE_TEST_CONTEXT[
afe4e513
JW
227 'mediagoblin/user_pages/user.html']['request']
228
229 # Does media entry still exist?
230 assert_false(
231 request.db.MediaEntry.find(
eabe6b67 232 {'_id': media._id}).count())
afe4e513 233
a0a7f87f
BS
234 # How about the comment?
235 assert_false(get_comments())
236
75ce65cf 237 def test_malicious_uploads(self):
ad35dd49
CM
238 # Test non-suppoerted file with non-supported extension
239 # -----------------------------------------------------
ae3bc7fa 240 template.clear_test_template_context()
ad35dd49
CM
241 response = self.test_app.post(
242 '/submit/', {
68f3ffbe 243 'title': 'Malicious Upload 1'
ad35dd49 244 }, upload_files=[(
9df37e8a 245 'file', EVIL_FILE)])
ad35dd49 246
ae3bc7fa 247 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
ad35dd49 248 form = context['submit_form']
a246ccca
JW
249 assert re.match(r'^Could not extract any file extension from ".*?"$', str(form.file.errors[0]))
250 assert len(form.file.errors) == 1
ad35dd49 251
68f3ffbe
CAW
252 # NOTE: The following 2 tests will ultimately fail, but they
253 # *will* pass the initial form submission step. Instead,
254 # they'll be caught as failures during the processing step.
9df37e8a 255
75ce65cf 256 # Test non-supported file with .jpg extension
ad35dd49 257 # -------------------------------------------
ae3bc7fa 258 template.clear_test_template_context()
68f3ffbe
CAW
259 response = self.test_app.post(
260 '/submit/', {
261 'title': 'Malicious Upload 2'
262 }, upload_files=[(
263 'file', EVIL_JPG)])
264 response.follow()
265 assert_equal(
266 urlparse.urlsplit(response.location)[2],
267 '/u/chris/')
ad35dd49 268
68f3ffbe
CAW
269 entry = mg_globals.database.MediaEntry.find_one(
270 {'title': 'Malicious Upload 2'})
049284b1 271 assert_equal(entry.state, 'failed')
68f3ffbe 272 assert_equal(
8efcd405 273 entry.fail_error,
0bce749b 274 u'mediagoblin.processing:BadMediaFail')
ad35dd49 275
75ce65cf 276 # Test non-supported file with .png extension
ad35dd49 277 # -------------------------------------------
ae3bc7fa 278 template.clear_test_template_context()
68f3ffbe
CAW
279 response = self.test_app.post(
280 '/submit/', {
281 'title': 'Malicious Upload 3'
282 }, upload_files=[(
283 'file', EVIL_PNG)])
284 response.follow()
285 assert_equal(
286 urlparse.urlsplit(response.location)[2],
287 '/u/chris/')
0a78be3e 288
68f3ffbe
CAW
289 entry = mg_globals.database.MediaEntry.find_one(
290 {'title': 'Malicious Upload 3'})
049284b1 291 assert_equal(entry.state, 'failed')
68f3ffbe 292 assert_equal(
8efcd405 293 entry.fail_error,
0bce749b 294 u'mediagoblin.processing:BadMediaFail')