Audio thumbnailing & spectrograms, media plugins use sniffing
[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 # Do not confirm deletion
184 # ---------------------------------------------------
185 response = self.test_app.post(
186 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
187 # No work: user=media.uploader().username,
188 user=self.test_user.username,
189 media=media._id),
190 # no value means no confirm
191 {})
192
193 response.follow()
194
195 request = template.TEMPLATE_TEST_CONTEXT[
196 'mediagoblin/user_pages/user.html']['request']
197
198 media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0]
199
200 # Does media entry still exist?
201 assert_true(media)
202
203 # Confirm deletion
204 # ---------------------------------------------------
205 response = self.test_app.post(
206 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
207 # No work: user=media.uploader().username,
208 user=self.test_user.username,
209 media=media._id),
210 {'confirm': 'y'})
211
212 response.follow()
213
214 request = template.TEMPLATE_TEST_CONTEXT[
215 'mediagoblin/user_pages/user.html']['request']
216
217 # Does media entry still exist?
218 assert_false(
219 request.db.MediaEntry.find(
220 {'_id': media._id}).count())
221
222 def test_malicious_uploads(self):
223 # Test non-suppoerted file with non-supported extension
224 # -----------------------------------------------------
225 template.clear_test_template_context()
226 response = self.test_app.post(
227 '/submit/', {
228 'title': 'Malicious Upload 1'
229 }, upload_files=[(
230 'file', EVIL_FILE)])
231
232 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
233 form = context['submit_form']
234 assert 'Sorry, I don\'t support that file type :(' == \
235 str(form.file.errors[0])
236 assert len(form.file.errors) == 1
237
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.
241
242 # Test non-supported file with .jpg extension
243 # -------------------------------------------
244 template.clear_test_template_context()
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/')
254
255 entry = mg_globals.database.MediaEntry.find_one(
256 {'title': 'Malicious Upload 2'})
257 assert_equal(entry.state, 'failed')
258 assert_equal(
259 entry['fail_error'],
260 u'mediagoblin.processing:BadMediaFail')
261
262 # Test non-supported file with .png extension
263 # -------------------------------------------
264 template.clear_test_template_context()
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/')
274
275 entry = mg_globals.database.MediaEntry.find_one(
276 {'title': 'Malicious Upload 3'})
277 assert_equal(entry.state, 'failed')
278 assert_equal(
279 entry['fail_error'],
280 u'mediagoblin.processing:BadMediaFail')