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