Dot-Notation for MediaEntry.media_files
[mediagoblin.git] / mediagoblin / tests / test_submission.py
CommitLineData
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
18import urlparse
9df37e8a 19import pkg_resources
a246ccca 20import re
1975b5dd 21
afe4e513 22from nose.tools import assert_equal, assert_true, assert_false
1975b5dd 23
9754802d
E
24from mediagoblin.tests.tools import setup_fresh_app, get_test_app, \
25 fixture_add_user
1975b5dd 26from mediagoblin import mg_globals
ae3bc7fa 27from mediagoblin.tools import template, common
1975b5dd 28
9df37e8a
CM
29GOOD_JPG = pkg_resources.resource_filename(
30 'mediagoblin.tests', 'test_submission/good.jpg')
31GOOD_PNG = pkg_resources.resource_filename(
32 'mediagoblin.tests', 'test_submission/good.png')
33EVIL_FILE = pkg_resources.resource_filename(
34 'mediagoblin.tests', 'test_submission/evil')
35EVIL_JPG = pkg_resources.resource_filename(
36 'mediagoblin.tests', 'test_submission/evil.jpg')
37EVIL_PNG = pkg_resources.resource_filename(
38 'mediagoblin.tests', 'test_submission/evil.png')
75ce65cf 39
8ff4dec7
CFD
40GOOD_TAG_STRING = 'yin,yang'
41BAD_TAG_STRING = 'rage,' + 'f' * 26 + 'u' * 26
42
1975b5dd 43
1975b5dd
CM
44class 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')