From: Caleb Forbes Davis V Date: Fri, 29 Jul 2011 18:56:40 +0000 (-0500) Subject: Adds tag unit testing X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=8ff4dec742d0b9f375afd9d1862a560e1be200d1;p=mediagoblin.git Adds tag unit testing - overrides default tag parsing globals in test_mgoblin_app.ini - piggybacks on existing test_submission code to check correct tag parsing and storage in the database - verifies expected behavior given different delimiters, case sensitivities, tags that are too long, and extra whitespace - verifies list-of-dict database storage and tag slugification --- diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index fd0f87a4..5395ca10 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -7,6 +7,11 @@ email_sender_address = "notice@mediagoblin.example.org" email_debug_mode = true db_name = __mediagoblin_tests__ +# tag parsing +tags_delimiter = "," +tags_case_sensitive = False +tags_max_length = 50 + # Celery shouldn't be set up by the application as it's setup via # mediagoblin.init.celery.from_celery celery_setup_elsewhere = true diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py new file mode 100644 index 00000000..7c6b0f75 --- /dev/null +++ b/mediagoblin/tests/test_submission.py @@ -0,0 +1,198 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import urlparse +import pkg_resources + +from nose.tools import assert_equal + +from mediagoblin.auth import lib as auth_lib +from mediagoblin.tests.tools import setup_fresh_app, get_test_app +from mediagoblin import mg_globals +from mediagoblin import util + +GOOD_JPG = pkg_resources.resource_filename( + 'mediagoblin.tests', 'test_submission/good.jpg') +GOOD_PNG = pkg_resources.resource_filename( + 'mediagoblin.tests', 'test_submission/good.png') +EVIL_FILE = pkg_resources.resource_filename( + 'mediagoblin.tests', 'test_submission/evil') +EVIL_JPG = pkg_resources.resource_filename( + 'mediagoblin.tests', 'test_submission/evil.jpg') +EVIL_PNG = pkg_resources.resource_filename( + 'mediagoblin.tests', 'test_submission/evil.png') + +GOOD_TAG_STRING = 'yin,yang' +BAD_TAG_STRING = 'rage,' + 'f' * 26 + 'u' * 26 + + +class TestSubmission: + def setUp(self): + self.test_app = get_test_app() + + # TODO: Possibly abstract into a decorator like: + # @as_authenticated_user('chris') + test_user = mg_globals.database.User() + test_user['username'] = u'chris' + test_user['email'] = u'chris@example.com' + test_user['email_verified'] = True + test_user['status'] = u'active' + test_user['pw_hash'] = auth_lib.bcrypt_gen_password_hash('toast') + test_user.save() + + self.test_app.post( + '/auth/login/', { + 'username': u'chris', + 'password': 'toast'}) + + def test_missing_fields(self): + # Test blank form + # --------------- + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', {}) + context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + form = context['submit_form'] + assert form.file.errors == [u'You must provide a file.'] + + # Test blank file + # --------------- + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'test title'}) + context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + form = context['submit_form'] + assert form.file.errors == [u'You must provide a file.'] + + + def test_normal_uploads(self): + # Test JPG + # -------- + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'Normal upload 1' + }, upload_files=[( + 'file', GOOD_JPG)]) + + # User should be redirected + response.follow() + assert_equal( + urlparse.urlsplit(response.location)[2], + '/u/chris/') + assert util.TEMPLATE_TEST_CONTEXT.has_key( + 'mediagoblin/user_pages/user.html') + + # Test PNG + # -------- + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'Normal upload 2' + }, upload_files=[( + 'file', GOOD_PNG)]) + + response.follow() + assert_equal( + urlparse.urlsplit(response.location)[2], + '/u/chris/') + assert util.TEMPLATE_TEST_CONTEXT.has_key( + 'mediagoblin/user_pages/user.html') + + + def test_tags(self): + # Good tag string + # -------- + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'Balanced Goblin', + 'tags': GOOD_TAG_STRING + }, upload_files=[( + 'file', GOOD_JPG)]) + + # New media entry with correct tags should be created + response.follow() + context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/user_pages/user.html'] + request = context['request'] + media = request.db.MediaEntry.find({'title': 'Balanced Goblin'})[0] + assert_equal(media['tags'], + [{'name': u'yin', 'slug': u'yin'}, + {'name': u'yang', 'slug': u'yang'}]) + + # Test tags that are too long + # --------------- + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'Balanced Goblin', + 'tags': BAD_TAG_STRING + }, upload_files=[( + 'file', GOOD_JPG)]) + + # Too long error should be raised + context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + form = context['submit_form'] + assert form.tags.errors == [ + u'Tags must be shorter than 50 characters. Tags that are too long'\ + ': ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu'] + + + def test_malicious_uploads(self): + # Test non-suppoerted file with non-supported extension + # ----------------------------------------------------- + util.clear_test_template_context() + response = self.test_app.post( + '/submit/', { + 'title': 'Malicious Upload 2' + }, upload_files=[( + 'file', EVIL_FILE)]) + + context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + form = context['submit_form'] + assert form.file.errors == ['The file doesn\'t seem to be an image!'] + + # NOTE: The following 2 tests will fail. These can be uncommented + # after http://bugs.foocorp.net/issues/324 is resolved and + # bad files are handled properly. + + # Test non-supported file with .jpg extension + # ------------------------------------------- + #util.clear_test_template_context() + #response = self.test_app.post( + # '/submit/', { + # 'title': 'Malicious Upload 2' + # }, upload_files=[( + # 'file', EVIL_JPG)]) + + #context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + #form = context['submit_form'] + #assert form.file.errors == ['The file doesn\'t seem to be an image!'] + + # Test non-supported file with .png extension + # ------------------------------------------- + #util.clear_test_template_context() + #response = self.test_app.post( + # '/submit/', { + # 'title': 'Malicious Upload 3' + # }, upload_files=[( + # 'file', EVIL_PNG)]) + + #context = util.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html'] + #form = context['submit_form'] + #assert form.file.errors == ['The file doesn\'t seem to be an image!'] + diff --git a/mediagoblin/tests/test_submission/evil b/mediagoblin/tests/test_submission/evil new file mode 100755 index 00000000..775da664 Binary files /dev/null and b/mediagoblin/tests/test_submission/evil differ diff --git a/mediagoblin/tests/test_submission/evil.jpg b/mediagoblin/tests/test_submission/evil.jpg new file mode 100755 index 00000000..775da664 Binary files /dev/null and b/mediagoblin/tests/test_submission/evil.jpg differ diff --git a/mediagoblin/tests/test_submission/evil.png b/mediagoblin/tests/test_submission/evil.png new file mode 100755 index 00000000..775da664 Binary files /dev/null and b/mediagoblin/tests/test_submission/evil.png differ diff --git a/mediagoblin/tests/test_submission/good.jpg b/mediagoblin/tests/test_submission/good.jpg new file mode 100644 index 00000000..936458e9 Binary files /dev/null and b/mediagoblin/tests/test_submission/good.jpg differ diff --git a/mediagoblin/tests/test_submission/good.png b/mediagoblin/tests/test_submission/good.png new file mode 100644 index 00000000..c1eadf9c Binary files /dev/null and b/mediagoblin/tests/test_submission/good.png differ diff --git a/mediagoblin/tests/test_tags.py b/mediagoblin/tests/test_tags.py new file mode 100644 index 00000000..fa6beca9 --- /dev/null +++ b/mediagoblin/tests/test_tags.py @@ -0,0 +1,57 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 Free Software Foundation, Inc +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from mediagoblin.tests.tools import setup_fresh_app +from mediagoblin import util +from mediagoblin import mg_globals + + +@setup_fresh_app +def test_list_of_dicts_conversion(test_app): + """ + When the user adds tags to a media entry, the string from the form is + converted into a list of tags, where each tag is stored in the database + as a dict. Each tag dict should contain the tag's name and slug. Another + function performs the reverse operation when populating a form to edit tags. + """ + # Leading, trailing, and internal whitespace should be removed and slugified + assert util.convert_to_tag_list_of_dicts('sleep , 6 AM, chainsaw! ') == [ + {'name': u'sleep', 'slug': u'sleep'}, + {'name': u'6 am', 'slug': u'6-am'}, + {'name': u'chainsaw!', 'slug': u'chainsaw'}] + + # Make sure case-sensitivity is retained when desired + mg_globals.app_config['tags_case_sensitive'] = True + assert util.convert_to_tag_list_of_dicts('sleep , 6 AM, chainsaw! ') == [ + {'name': u'sleep', 'slug': u'sleep'}, + {'name': u'6 AM', 'slug': u'6-am'}, + {'name': u'chainsaw!', 'slug': u'chainsaw'}] + + # If the user enters two identical tags, record only one of them + assert util.convert_to_tag_list_of_dicts('echo,echo') == [{'name': u'echo', + 'slug': u'echo'}] + + # Make sure converting the list of dicts to a string works + assert util.media_tags_as_string([{'name': u'yin', 'slug': u'yin'}, + {'name': u'yang', 'slug': u'yang'}]) == \ + u'yin,yang' + + # If the tag delimiter is a space then we expect different results + mg_globals.app_config['tags_delimiter'] = u' ' + assert util.convert_to_tag_list_of_dicts('unicorn ceramic nazi') == [ + {'name': u'unicorn', 'slug': u'unicorn'}, + {'name': u'ceramic', 'slug': u'ceramic'}, + {'name': u'nazi', 'slug': u'nazi'}]