Merge remote-tracking branch 'refs/remotes/brett/bug270-lazycelery-script'
[mediagoblin.git] / mediagoblin / tests / test_submission.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
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 import urlparse
18 import pkg_resources
19 import re
20
21 from nose.tools import assert_equal, assert_true, assert_false
22
23 from mediagoblin.tests.tools import setup_fresh_app, get_test_app, \
24 fixture_add_user
25 from mediagoblin import mg_globals
26 from mediagoblin.tools import template, common
27
28 GOOD_JPG = pkg_resources.resource_filename(
29 'mediagoblin.tests', 'test_submission/good.jpg')
30 GOOD_PNG = pkg_resources.resource_filename(
31 'mediagoblin.tests', 'test_submission/good.png')
32 EVIL_FILE = pkg_resources.resource_filename(
33 'mediagoblin.tests', 'test_submission/evil')
34 EVIL_JPG = pkg_resources.resource_filename(
35 'mediagoblin.tests', 'test_submission/evil.jpg')
36 EVIL_PNG = pkg_resources.resource_filename(
37 'mediagoblin.tests', 'test_submission/evil.png')
38
39 GOOD_TAG_STRING = 'yin,yang'
40 BAD_TAG_STRING = 'rage,' + 'f' * 26 + 'u' * 26
41
42
43 class TestSubmission:
44 def setUp(self):
45 self.test_app = get_test_app()
46
47 # TODO: Possibly abstract into a decorator like:
48 # @as_authenticated_user('chris')
49 test_user = fixture_add_user()
50
51 self.test_user = test_user
52
53 self.login()
54
55 def login(self):
56 self.test_app.post(
57 '/auth/login/', {
58 'username': u'chris',
59 'password': 'toast'})
60
61 def logout(self):
62 self.test_app.get('/auth/logout/')
63
64 def test_missing_fields(self):
65 # Test blank form
66 # ---------------
67 template.clear_test_template_context()
68 response = self.test_app.post(
69 '/submit/', {})
70 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
71 form = context['submit_form']
72 assert form.file.errors == [u'You must provide a file.']
73
74 # Test blank file
75 # ---------------
76 template.clear_test_template_context()
77 response = self.test_app.post(
78 '/submit/', {
79 'title': 'test title'})
80 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
81 form = context['submit_form']
82 assert form.file.errors == [u'You must provide a file.']
83
84
85 def test_normal_uploads(self):
86 # Test JPG
87 # --------
88 template.clear_test_template_context()
89 response = self.test_app.post(
90 '/submit/', {
91 'title': 'Normal upload 1'
92 }, upload_files=[(
93 'file', GOOD_JPG)])
94
95 # User should be redirected
96 response.follow()
97 assert_equal(
98 urlparse.urlsplit(response.location)[2],
99 '/u/chris/')
100 assert template.TEMPLATE_TEST_CONTEXT.has_key(
101 'mediagoblin/user_pages/user.html')
102
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
111 # Test PNG
112 # --------
113 template.clear_test_template_context()
114 response = self.test_app.post(
115 '/submit/', {
116 'title': 'Normal upload 2'
117 }, upload_files=[(
118 'file', GOOD_PNG)])
119
120 response.follow()
121 assert_equal(
122 urlparse.urlsplit(response.location)[2],
123 '/u/chris/')
124 assert template.TEMPLATE_TEST_CONTEXT.has_key(
125 'mediagoblin/user_pages/user.html')
126
127 def test_tags(self):
128 # Good tag string
129 # --------
130 template.clear_test_template_context()
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()
140 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html']
141 request = context['request']
142 media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0]
143 assert_equal(media.tags,
144 [{'name': u'yin', 'slug': u'yin'},
145 {'name': u'yang', 'slug': u'yang'}])
146
147 # Test tags that are too long
148 # ---------------
149 template.clear_test_template_context()
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
158 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
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']
163
164 def test_delete(self):
165 template.clear_test_template_context()
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
175 request = template.TEMPLATE_TEST_CONTEXT[
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
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
195 # Do not confirm deletion
196 # ---------------------------------------------------
197 response = self.test_app.post(
198 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
199 # No work: user=media.uploader().username,
200 user=self.test_user.username,
201 media=media._id),
202 # no value means no confirm
203 {})
204
205 response.follow()
206
207 request = template.TEMPLATE_TEST_CONTEXT[
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(
218 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
219 # No work: user=media.uploader().username,
220 user=self.test_user.username,
221 media=media._id),
222 {'confirm': 'y'})
223
224 response.follow()
225
226 request = template.TEMPLATE_TEST_CONTEXT[
227 'mediagoblin/user_pages/user.html']['request']
228
229 # Does media entry still exist?
230 assert_false(
231 request.db.MediaEntry.find(
232 {'_id': media._id}).count())
233
234 # How about the comment?
235 assert_false(get_comments())
236
237 def test_malicious_uploads(self):
238 # Test non-suppoerted file with non-supported extension
239 # -----------------------------------------------------
240 template.clear_test_template_context()
241 response = self.test_app.post(
242 '/submit/', {
243 'title': 'Malicious Upload 1'
244 }, upload_files=[(
245 'file', EVIL_FILE)])
246
247 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
248 form = context['submit_form']
249 assert re.match(r'^Could not extract any file extension from ".*?"$', str(form.file.errors[0]))
250 assert len(form.file.errors) == 1
251
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.
255
256 # Test non-supported file with .jpg extension
257 # -------------------------------------------
258 template.clear_test_template_context()
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/')
268
269 entry = mg_globals.database.MediaEntry.find_one(
270 {'title': 'Malicious Upload 2'})
271 assert_equal(entry.state, 'failed')
272 assert_equal(
273 entry.fail_error,
274 u'mediagoblin.processing:BadMediaFail')
275
276 # Test non-supported file with .png extension
277 # -------------------------------------------
278 template.clear_test_template_context()
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/')
288
289 entry = mg_globals.database.MediaEntry.find_one(
290 {'title': 'Malicious Upload 3'})
291 assert_equal(entry.state, 'failed')
292 assert_equal(
293 entry.fail_error,
294 u'mediagoblin.processing:BadMediaFail')