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 | ||
183 | # Do not confirm deletion | |
184 | # --------------------------------------------------- | |
185 | response = self.test_app.post( | |
502073f2 | 186 | request.urlgen('mediagoblin.user_pages.media_confirm_delete', |
afe4e513 | 187 | # No work: user=media.uploader().username, |
5a4e3ff1 | 188 | user=self.test_user.username, |
bcc9ee32 | 189 | media=media._id), |
9a64272e CAW |
190 | # no value means no confirm |
191 | {}) | |
afe4e513 JW |
192 | |
193 | response.follow() | |
194 | ||
ae3bc7fa | 195 | request = template.TEMPLATE_TEST_CONTEXT[ |
afe4e513 JW |
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( | |
502073f2 | 206 | request.urlgen('mediagoblin.user_pages.media_confirm_delete', |
afe4e513 | 207 | # No work: user=media.uploader().username, |
5a4e3ff1 | 208 | user=self.test_user.username, |
bcc9ee32 | 209 | media=media._id), |
9a64272e | 210 | {'confirm': 'y'}) |
afe4e513 JW |
211 | |
212 | response.follow() | |
213 | ||
ae3bc7fa | 214 | request = template.TEMPLATE_TEST_CONTEXT[ |
afe4e513 JW |
215 | 'mediagoblin/user_pages/user.html']['request'] |
216 | ||
217 | # Does media entry still exist? | |
218 | assert_false( | |
219 | request.db.MediaEntry.find( | |
eabe6b67 | 220 | {'_id': media._id}).count()) |
afe4e513 | 221 | |
75ce65cf | 222 | def test_malicious_uploads(self): |
ad35dd49 CM |
223 | # Test non-suppoerted file with non-supported extension |
224 | # ----------------------------------------------------- | |
ae3bc7fa | 225 | template.clear_test_template_context() |
ad35dd49 CM |
226 | response = self.test_app.post( |
227 | '/submit/', { | |
68f3ffbe | 228 | 'title': 'Malicious Upload 1' |
ad35dd49 | 229 | }, upload_files=[( |
9df37e8a | 230 | 'file', EVIL_FILE)]) |
ad35dd49 | 231 | |
ae3bc7fa | 232 | context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] |
ad35dd49 | 233 | form = context['submit_form'] |
a246ccca JW |
234 | assert re.match(r'^Could not extract any file extension from ".*?"$', str(form.file.errors[0])) |
235 | assert len(form.file.errors) == 1 | |
ad35dd49 | 236 | |
68f3ffbe CAW |
237 | # NOTE: The following 2 tests will ultimately fail, but they |
238 | # *will* pass the initial form submission step. Instead, | |
239 | # they'll be caught as failures during the processing step. | |
9df37e8a | 240 | |
75ce65cf | 241 | # Test non-supported file with .jpg extension |
ad35dd49 | 242 | # ------------------------------------------- |
ae3bc7fa | 243 | template.clear_test_template_context() |
68f3ffbe CAW |
244 | response = self.test_app.post( |
245 | '/submit/', { | |
246 | 'title': 'Malicious Upload 2' | |
247 | }, upload_files=[( | |
248 | 'file', EVIL_JPG)]) | |
249 | response.follow() | |
250 | assert_equal( | |
251 | urlparse.urlsplit(response.location)[2], | |
252 | '/u/chris/') | |
ad35dd49 | 253 | |
68f3ffbe CAW |
254 | entry = mg_globals.database.MediaEntry.find_one( |
255 | {'title': 'Malicious Upload 2'}) | |
049284b1 | 256 | assert_equal(entry.state, 'failed') |
68f3ffbe | 257 | assert_equal( |
8efcd405 | 258 | entry.fail_error, |
0bce749b | 259 | u'mediagoblin.processing:BadMediaFail') |
ad35dd49 | 260 | |
75ce65cf | 261 | # Test non-supported file with .png extension |
ad35dd49 | 262 | # ------------------------------------------- |
ae3bc7fa | 263 | template.clear_test_template_context() |
68f3ffbe CAW |
264 | response = self.test_app.post( |
265 | '/submit/', { | |
266 | 'title': 'Malicious Upload 3' | |
267 | }, upload_files=[( | |
268 | 'file', EVIL_PNG)]) | |
269 | response.follow() | |
270 | assert_equal( | |
271 | urlparse.urlsplit(response.location)[2], | |
272 | '/u/chris/') | |
0a78be3e | 273 | |
68f3ffbe CAW |
274 | entry = mg_globals.database.MediaEntry.find_one( |
275 | {'title': 'Malicious Upload 3'}) | |
049284b1 | 276 | assert_equal(entry.state, 'failed') |
68f3ffbe | 277 | assert_equal( |
8efcd405 | 278 | entry.fail_error, |
0bce749b | 279 | u'mediagoblin.processing:BadMediaFail') |