Commit | Line | Data |
---|---|---|
a246ccca | 1 | |
1975b5dd | 2 | # GNU MediaGoblin -- federated, autonomous media hosting |
12a100e4 | 3 | # Copyright (C) 2011 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 | ||
75ce65cf CM |
54 | self.test_app.post( |
55 | '/auth/login/', { | |
56 | 'username': u'chris', | |
57 | 'password': 'toast'}) | |
58 | ||
59 | def test_missing_fields(self): | |
ad35dd49 CM |
60 | # Test blank form |
61 | # --------------- | |
ae3bc7fa | 62 | template.clear_test_template_context() |
ad35dd49 CM |
63 | response = self.test_app.post( |
64 | '/submit/', {}) | |
ae3bc7fa | 65 | context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] |
ad35dd49 CM |
66 | form = context['submit_form'] |
67 | assert form.file.errors == [u'You must provide a file.'] | |
68 | ||
69 | # Test blank file | |
70 | # --------------- | |
ae3bc7fa | 71 | template.clear_test_template_context() |
ad35dd49 CM |
72 | response = self.test_app.post( |
73 | '/submit/', { | |
74 | 'title': 'test title'}) | |
ae3bc7fa | 75 | context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] |
ad35dd49 CM |
76 | form = context['submit_form'] |
77 | assert form.file.errors == [u'You must provide a file.'] | |
78 | ||
75ce65cf CM |
79 | |
80 | def test_normal_uploads(self): | |
75ce65cf | 81 | # Test JPG |
ad35dd49 | 82 | # -------- |
ae3bc7fa | 83 | template.clear_test_template_context() |
ad35dd49 CM |
84 | response = self.test_app.post( |
85 | '/submit/', { | |
86 | 'title': 'Normal upload 1' | |
87 | }, upload_files=[( | |
9df37e8a | 88 | 'file', GOOD_JPG)]) |
ad35dd49 CM |
89 | |
90 | # User should be redirected | |
91 | response.follow() | |
92 | assert_equal( | |
93 | urlparse.urlsplit(response.location)[2], | |
9df37e8a | 94 | '/u/chris/') |
ae3bc7fa | 95 | assert template.TEMPLATE_TEST_CONTEXT.has_key( |
9df37e8a | 96 | 'mediagoblin/user_pages/user.html') |
ad35dd49 | 97 | |
75ce65cf | 98 | # Test PNG |
ad35dd49 | 99 | # -------- |
ae3bc7fa | 100 | template.clear_test_template_context() |
ad35dd49 CM |
101 | response = self.test_app.post( |
102 | '/submit/', { | |
103 | 'title': 'Normal upload 2' | |
104 | }, upload_files=[( | |
9df37e8a | 105 | 'file', GOOD_PNG)]) |
ad35dd49 CM |
106 | |
107 | response.follow() | |
108 | assert_equal( | |
109 | urlparse.urlsplit(response.location)[2], | |
9df37e8a | 110 | '/u/chris/') |
ae3bc7fa | 111 | assert template.TEMPLATE_TEST_CONTEXT.has_key( |
9df37e8a | 112 | 'mediagoblin/user_pages/user.html') |
75ce65cf | 113 | |
8ff4dec7 CFD |
114 | def test_tags(self): |
115 | # Good tag string | |
116 | # -------- | |
ae3bc7fa | 117 | template.clear_test_template_context() |
8ff4dec7 CFD |
118 | response = self.test_app.post( |
119 | '/submit/', { | |
120 | 'title': 'Balanced Goblin', | |
121 | 'tags': GOOD_TAG_STRING | |
122 | }, upload_files=[( | |
123 | 'file', GOOD_JPG)]) | |
124 | ||
125 | # New media entry with correct tags should be created | |
126 | response.follow() | |
ae3bc7fa | 127 | context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html'] |
8ff4dec7 CFD |
128 | request = context['request'] |
129 | media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] | |
130 | assert_equal(media['tags'], | |
131 | [{'name': u'yin', 'slug': u'yin'}, | |
132 | {'name': u'yang', 'slug': u'yang'}]) | |
133 | ||
134 | # Test tags that are too long | |
135 | # --------------- | |
ae3bc7fa | 136 | template.clear_test_template_context() |
8ff4dec7 CFD |
137 | response = self.test_app.post( |
138 | '/submit/', { | |
139 | 'title': 'Balanced Goblin', | |
140 | 'tags': BAD_TAG_STRING | |
141 | }, upload_files=[( | |
142 | 'file', GOOD_JPG)]) | |
143 | ||
144 | # Too long error should be raised | |
ae3bc7fa | 145 | context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] |
8ff4dec7 CFD |
146 | form = context['submit_form'] |
147 | assert form.tags.errors == [ | |
148 | u'Tags must be shorter than 50 characters. Tags that are too long'\ | |
149 | ': ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu'] | |
75ce65cf | 150 | |
afe4e513 | 151 | def test_delete(self): |
ae3bc7fa | 152 | template.clear_test_template_context() |
afe4e513 JW |
153 | response = self.test_app.post( |
154 | '/submit/', { | |
155 | 'title': 'Balanced Goblin', | |
156 | }, upload_files=[( | |
157 | 'file', GOOD_JPG)]) | |
158 | ||
159 | # Post image | |
160 | response.follow() | |
161 | ||
ae3bc7fa | 162 | request = template.TEMPLATE_TEST_CONTEXT[ |
afe4e513 JW |
163 | 'mediagoblin/user_pages/user.html']['request'] |
164 | ||
165 | media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] | |
166 | ||
167 | # Does media entry exist? | |
168 | assert_true(media) | |
169 | ||
170 | # Do not confirm deletion | |
171 | # --------------------------------------------------- | |
172 | response = self.test_app.post( | |
502073f2 | 173 | request.urlgen('mediagoblin.user_pages.media_confirm_delete', |
afe4e513 | 174 | # No work: user=media.uploader().username, |
5a4e3ff1 | 175 | user=self.test_user.username, |
bcc9ee32 | 176 | media=media._id), |
9a64272e CAW |
177 | # no value means no confirm |
178 | {}) | |
afe4e513 JW |
179 | |
180 | response.follow() | |
181 | ||
ae3bc7fa | 182 | request = template.TEMPLATE_TEST_CONTEXT[ |
afe4e513 JW |
183 | 'mediagoblin/user_pages/user.html']['request'] |
184 | ||
185 | media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] | |
186 | ||
187 | # Does media entry still exist? | |
188 | assert_true(media) | |
189 | ||
190 | # Confirm deletion | |
191 | # --------------------------------------------------- | |
192 | response = self.test_app.post( | |
502073f2 | 193 | request.urlgen('mediagoblin.user_pages.media_confirm_delete', |
afe4e513 | 194 | # No work: user=media.uploader().username, |
5a4e3ff1 | 195 | user=self.test_user.username, |
bcc9ee32 | 196 | media=media._id), |
9a64272e | 197 | {'confirm': 'y'}) |
afe4e513 JW |
198 | |
199 | response.follow() | |
200 | ||
ae3bc7fa | 201 | request = template.TEMPLATE_TEST_CONTEXT[ |
afe4e513 JW |
202 | 'mediagoblin/user_pages/user.html']['request'] |
203 | ||
204 | # Does media entry still exist? | |
205 | assert_false( | |
206 | request.db.MediaEntry.find( | |
eabe6b67 | 207 | {'_id': media._id}).count()) |
afe4e513 | 208 | |
75ce65cf | 209 | def test_malicious_uploads(self): |
ad35dd49 CM |
210 | # Test non-suppoerted file with non-supported extension |
211 | # ----------------------------------------------------- | |
ae3bc7fa | 212 | template.clear_test_template_context() |
ad35dd49 CM |
213 | response = self.test_app.post( |
214 | '/submit/', { | |
68f3ffbe | 215 | 'title': 'Malicious Upload 1' |
ad35dd49 | 216 | }, upload_files=[( |
9df37e8a | 217 | 'file', EVIL_FILE)]) |
ad35dd49 | 218 | |
ae3bc7fa | 219 | context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] |
ad35dd49 | 220 | form = context['submit_form'] |
a246ccca JW |
221 | assert re.match(r'^Could not extract any file extension from ".*?"$', str(form.file.errors[0])) |
222 | assert len(form.file.errors) == 1 | |
ad35dd49 | 223 | |
68f3ffbe CAW |
224 | # NOTE: The following 2 tests will ultimately fail, but they |
225 | # *will* pass the initial form submission step. Instead, | |
226 | # they'll be caught as failures during the processing step. | |
9df37e8a | 227 | |
75ce65cf | 228 | # Test non-supported file with .jpg extension |
ad35dd49 | 229 | # ------------------------------------------- |
ae3bc7fa | 230 | template.clear_test_template_context() |
68f3ffbe CAW |
231 | response = self.test_app.post( |
232 | '/submit/', { | |
233 | 'title': 'Malicious Upload 2' | |
234 | }, upload_files=[( | |
235 | 'file', EVIL_JPG)]) | |
236 | response.follow() | |
237 | assert_equal( | |
238 | urlparse.urlsplit(response.location)[2], | |
239 | '/u/chris/') | |
ad35dd49 | 240 | |
68f3ffbe CAW |
241 | entry = mg_globals.database.MediaEntry.find_one( |
242 | {'title': 'Malicious Upload 2'}) | |
243 | assert_equal(entry['state'], 'failed') | |
244 | assert_equal( | |
245 | entry['fail_error'], | |
0bce749b | 246 | u'mediagoblin.processing:BadMediaFail') |
ad35dd49 | 247 | |
75ce65cf | 248 | # Test non-supported file with .png extension |
ad35dd49 | 249 | # ------------------------------------------- |
ae3bc7fa | 250 | template.clear_test_template_context() |
68f3ffbe CAW |
251 | response = self.test_app.post( |
252 | '/submit/', { | |
253 | 'title': 'Malicious Upload 3' | |
254 | }, upload_files=[( | |
255 | 'file', EVIL_PNG)]) | |
256 | response.follow() | |
257 | assert_equal( | |
258 | urlparse.urlsplit(response.location)[2], | |
259 | '/u/chris/') | |
0a78be3e | 260 | |
68f3ffbe CAW |
261 | entry = mg_globals.database.MediaEntry.find_one( |
262 | {'title': 'Malicious Upload 3'}) | |
263 | assert_equal(entry['state'], 'failed') | |
264 | assert_equal( | |
265 | entry['fail_error'], | |
0bce749b | 266 | u'mediagoblin.processing:BadMediaFail') |