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