Commit | Line | Data |
---|---|---|
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 | ||
18 | import urlparse | |
9df37e8a | 19 | import pkg_resources |
a246ccca | 20 | import re |
1975b5dd | 21 | |
afe4e513 | 22 | from nose.tools import assert_equal, assert_true, assert_false |
1975b5dd | 23 | |
9754802d E |
24 | from mediagoblin.tests.tools import setup_fresh_app, get_test_app, \ |
25 | fixture_add_user | |
1975b5dd | 26 | from mediagoblin import mg_globals |
ae3bc7fa | 27 | from mediagoblin.tools import template, common |
1975b5dd | 28 | |
9df37e8a CM |
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') | |
75ce65cf | 39 | |
8ff4dec7 CFD |
40 | GOOD_TAG_STRING = 'yin,yang' |
41 | BAD_TAG_STRING = 'rage,' + 'f' * 26 + 'u' * 26 | |
42 | ||
1975b5dd | 43 | |
1975b5dd CM |
44 | class 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') |