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