printer = CollectingPrinter -> printer = CollectingPrinter()
[mediagoblin.git] / mediagoblin / tests / test_submission.py
1
2 # GNU MediaGoblin -- federated, autonomous media hosting
3 # Copyright (C) 2011 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
18 import urlparse
19 import pkg_resources
20 import re
21
22 from nose.tools import assert_equal, assert_true, assert_false
23
24 from mediagoblin.tests.tools import setup_fresh_app, get_test_app, \
25 fixture_add_user
26 from mediagoblin import mg_globals
27 from mediagoblin.tools import template, common
28
29 GOOD_JPG = pkg_resources.resource_filename(
30 'mediagoblin.tests', 'test_submission/good.jpg')
31 GOOD_PNG = pkg_resources.resource_filename(
32 'mediagoblin.tests', 'test_submission/good.png')
33 EVIL_FILE = pkg_resources.resource_filename(
34 'mediagoblin.tests', 'test_submission/evil')
35 EVIL_JPG = pkg_resources.resource_filename(
36 'mediagoblin.tests', 'test_submission/evil.jpg')
37 EVIL_PNG = pkg_resources.resource_filename(
38 'mediagoblin.tests', 'test_submission/evil.png')
39
40 GOOD_TAG_STRING = 'yin,yang'
41 BAD_TAG_STRING = 'rage,' + 'f' * 26 + 'u' * 26
42
43
44 class TestSubmission:
45 def setUp(self):
46 self.test_app = get_test_app()
47
48 # TODO: Possibly abstract into a decorator like:
49 # @as_authenticated_user('chris')
50 test_user = fixture_add_user()
51
52 self.test_user = test_user
53
54 self.login()
55
56 def login(self):
57 self.test_app.post(
58 '/auth/login/', {
59 'username': u'chris',
60 'password': 'toast'})
61
62 def logout(self):
63 self.test_app.get('/auth/logout/')
64
65 def test_missing_fields(self):
66 # Test blank form
67 # ---------------
68 template.clear_test_template_context()
69 response = self.test_app.post(
70 '/submit/', {})
71 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
72 form = context['submit_form']
73 assert form.file.errors == [u'You must provide a file.']
74
75 # Test blank file
76 # ---------------
77 template.clear_test_template_context()
78 response = self.test_app.post(
79 '/submit/', {
80 'title': 'test title'})
81 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
82 form = context['submit_form']
83 assert form.file.errors == [u'You must provide a file.']
84
85
86 def test_normal_uploads(self):
87 # Test JPG
88 # --------
89 template.clear_test_template_context()
90 response = self.test_app.post(
91 '/submit/', {
92 'title': 'Normal upload 1'
93 }, upload_files=[(
94 'file', GOOD_JPG)])
95
96 # User should be redirected
97 response.follow()
98 assert_equal(
99 urlparse.urlsplit(response.location)[2],
100 '/u/chris/')
101 assert template.TEMPLATE_TEST_CONTEXT.has_key(
102 'mediagoblin/user_pages/user.html')
103
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
112 # Test PNG
113 # --------
114 template.clear_test_template_context()
115 response = self.test_app.post(
116 '/submit/', {
117 'title': 'Normal upload 2'
118 }, upload_files=[(
119 'file', GOOD_PNG)])
120
121 response.follow()
122 assert_equal(
123 urlparse.urlsplit(response.location)[2],
124 '/u/chris/')
125 assert template.TEMPLATE_TEST_CONTEXT.has_key(
126 'mediagoblin/user_pages/user.html')
127
128 def test_tags(self):
129 # Good tag string
130 # --------
131 template.clear_test_template_context()
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()
141 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html']
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 # ---------------
150 template.clear_test_template_context()
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
159 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
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']
164
165 def test_delete(self):
166 template.clear_test_template_context()
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
176 request = template.TEMPLATE_TEST_CONTEXT[
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(
187 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
188 # No work: user=media.uploader().username,
189 user=self.test_user.username,
190 media=media._id),
191 # no value means no confirm
192 {})
193
194 response.follow()
195
196 request = template.TEMPLATE_TEST_CONTEXT[
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(
207 request.urlgen('mediagoblin.user_pages.media_confirm_delete',
208 # No work: user=media.uploader().username,
209 user=self.test_user.username,
210 media=media._id),
211 {'confirm': 'y'})
212
213 response.follow()
214
215 request = template.TEMPLATE_TEST_CONTEXT[
216 'mediagoblin/user_pages/user.html']['request']
217
218 # Does media entry still exist?
219 assert_false(
220 request.db.MediaEntry.find(
221 {'_id': media._id}).count())
222
223 def test_malicious_uploads(self):
224 # Test non-suppoerted file with non-supported extension
225 # -----------------------------------------------------
226 template.clear_test_template_context()
227 response = self.test_app.post(
228 '/submit/', {
229 'title': 'Malicious Upload 1'
230 }, upload_files=[(
231 'file', EVIL_FILE)])
232
233 context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
234 form = context['submit_form']
235 assert re.match(r'^Could not extract any file extension from ".*?"$', 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')