aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/tests
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin/tests')
-rw-r--r--mediagoblin/tests/__init__.py14
-rw-r--r--mediagoblin/tests/appconfig_context_modified.ini27
-rw-r--r--mediagoblin/tests/appconfig_plugin_specs.ini21
-rw-r--r--mediagoblin/tests/appconfig_static_plugin.ini27
-rw-r--r--mediagoblin/tests/auth_configs/__init__.py0
-rw-r--r--mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini25
-rw-r--r--mediagoblin/tests/auth_configs/openid_appconfig.ini41
-rw-r--r--mediagoblin/tests/conftest.py41
-rw-r--r--mediagoblin/tests/pytest.ini2
-rw-r--r--mediagoblin/tests/resources.py41
-rw-r--r--mediagoblin/tests/test_api.py42
-rw-r--r--mediagoblin/tests/test_auth.py193
-rw-r--r--mediagoblin/tests/test_basic_auth.py59
-rw-r--r--mediagoblin/tests/test_cache.py52
-rw-r--r--mediagoblin/tests/test_celery_setup.py2
-rw-r--r--mediagoblin/tests/test_collections.py11
-rw-r--r--mediagoblin/tests/test_csrf_middleware.py20
-rw-r--r--mediagoblin/tests/test_edit.py147
-rw-r--r--mediagoblin/tests/test_exif.py404
-rw-r--r--mediagoblin/tests/test_globals.py10
-rw-r--r--mediagoblin/tests/test_http_callback.py18
-rw-r--r--mediagoblin/tests/test_messages.py21
-rw-r--r--mediagoblin/tests/test_mgoblin_app.ini27
-rw-r--r--mediagoblin/tests/test_misc.py34
-rw-r--r--mediagoblin/tests/test_modelmethods.py98
-rw-r--r--mediagoblin/tests/test_notifications.py151
-rw-r--r--mediagoblin/tests/test_oauth.py84
-rw-r--r--mediagoblin/tests/test_openid.py373
-rw-r--r--mediagoblin/tests/test_paste.ini23
-rw-r--r--mediagoblin/tests/test_pdf.py39
-rw-r--r--mediagoblin/tests/test_piwigo.py71
-rw-r--r--mediagoblin/tests/test_pluginapi.py313
-rw-r--r--mediagoblin/tests/test_processing.py4
-rw-r--r--mediagoblin/tests/test_session.py30
-rw-r--r--mediagoblin/tests/test_storage.py63
-rw-r--r--mediagoblin/tests/test_submission.py91
-rw-r--r--mediagoblin/tests/test_submission/good.pdfbin0 -> 194007 bytes
-rw-r--r--mediagoblin/tests/test_tags.py4
-rw-r--r--mediagoblin/tests/test_timesince.py57
-rw-r--r--mediagoblin/tests/test_util.py22
-rw-r--r--mediagoblin/tests/test_workbench.py17
-rw-r--r--mediagoblin/tests/testplugins/__init__.py15
-rw-r--r--mediagoblin/tests/testplugins/callables1/__init__.py43
-rw-r--r--mediagoblin/tests/testplugins/callables2/__init__.py41
-rw-r--r--mediagoblin/tests/testplugins/callables3/__init__.py41
-rw-r--r--mediagoblin/tests/testplugins/modify_context/__init__.py55
-rw-r--r--mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html5
-rw-r--r--mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html6
-rw-r--r--mediagoblin/tests/testplugins/modify_context/views.py (renamed from mediagoblin/tests/test_tests.py)29
-rw-r--r--mediagoblin/tests/testplugins/pluginspec/__init__.py22
-rw-r--r--mediagoblin/tests/testplugins/pluginspec/config_spec.ini4
-rw-r--r--mediagoblin/tests/testplugins/staticstuff/__init__.py36
-rw-r--r--mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css4
-rw-r--r--mediagoblin/tests/testplugins/staticstuff/views.py28
-rw-r--r--mediagoblin/tests/tools.py187
55 files changed, 2603 insertions, 632 deletions
diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py
index 5a3235c6..cf200791 100644
--- a/mediagoblin/tests/__init__.py
+++ b/mediagoblin/tests/__init__.py
@@ -14,23 +14,9 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
-import shutil
-
-from mediagoblin import mg_globals
-from mediagoblin.tests.tools import (
- TEST_USER_DEV, suicide_if_bad_celery_environ)
-
def setup_package():
- suicide_if_bad_celery_environ()
import warnings
from sqlalchemy.exc import SAWarning
warnings.simplefilter("error", SAWarning)
-
-
-def teardown_package():
- # Remove and reinstall user_dev directories
- if os.path.exists(TEST_USER_DEV):
- shutil.rmtree(TEST_USER_DEV)
diff --git a/mediagoblin/tests/appconfig_context_modified.ini b/mediagoblin/tests/appconfig_context_modified.ini
new file mode 100644
index 00000000..cc6721f5
--- /dev/null
+++ b/mediagoblin/tests/appconfig_context_modified.ini
@@ -0,0 +1,27 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+#Runs with an in-memory sqlite db for speed.
+sql_engine = "sqlite://"
+run_migrations = true
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
+[[mediagoblin.tests.testplugins.modify_context]]
diff --git a/mediagoblin/tests/appconfig_plugin_specs.ini b/mediagoblin/tests/appconfig_plugin_specs.ini
new file mode 100644
index 00000000..5511cd97
--- /dev/null
+++ b/mediagoblin/tests/appconfig_plugin_specs.ini
@@ -0,0 +1,21 @@
+[mediagoblin]
+direct_remote_path = /mgoblin_static/
+email_sender_address = "notice@mediagoblin.example.org"
+
+## Uncomment and change to your DB's appropiate setting.
+## Default is a local sqlite db "mediagoblin.db".
+# sql_engine = postgresql:///gmg
+
+# set to false to enable sending notices
+email_debug_mode = true
+
+# Set to false to disable registrations
+allow_registration = true
+
+[plugins]
+[[mediagoblin.tests.testplugins.pluginspec]]
+some_string = "not blork"
+some_int = "not an int"
+
+# this one shouldn't have its own config
+[[mediagoblin.tests.testplugins.callables1]]
diff --git a/mediagoblin/tests/appconfig_static_plugin.ini b/mediagoblin/tests/appconfig_static_plugin.ini
new file mode 100644
index 00000000..5ce5c5bd
--- /dev/null
+++ b/mediagoblin/tests/appconfig_static_plugin.ini
@@ -0,0 +1,27 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+#Runs with an in-memory sqlite db for speed.
+sql_engine = "sqlite://"
+run_migrations = true
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
+[[mediagoblin.tests.testplugins.staticstuff]]
diff --git a/mediagoblin/tests/auth_configs/__init__.py b/mediagoblin/tests/auth_configs/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/__init__.py
diff --git a/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini b/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini
new file mode 100644
index 00000000..a64e9e40
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini
@@ -0,0 +1,25 @@
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+# TODO: Switch to using an in-memory database
+sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
diff --git a/mediagoblin/tests/auth_configs/openid_appconfig.ini b/mediagoblin/tests/auth_configs/openid_appconfig.ini
new file mode 100644
index 00000000..c2bd82fd
--- /dev/null
+++ b/mediagoblin/tests/auth_configs/openid_appconfig.ini
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+[mediagoblin]
+direct_remote_path = /test_static/
+email_sender_address = "notice@mediagoblin.example.org"
+email_debug_mode = true
+
+# TODO: Switch to using an in-memory database
+sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db"
+
+# Celery shouldn't be set up by the application as it's setup via
+# mediagoblin.init.celery.from_celery
+celery_setup_elsewhere = true
+
+[storage:publicstore]
+base_dir = %(here)s/user_dev/media/public
+base_url = /mgoblin_media/
+
+[storage:queuestore]
+base_dir = %(here)s/user_dev/media/queue
+
+[celery]
+CELERY_ALWAYS_EAGER = true
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
+
+[plugins]
+[[mediagoblin.plugins.openid]]
diff --git a/mediagoblin/tests/conftest.py b/mediagoblin/tests/conftest.py
new file mode 100644
index 00000000..dbb0aa0a
--- /dev/null
+++ b/mediagoblin/tests/conftest.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+import pytest
+
+from mediagoblin.tests import tools
+from mediagoblin.tools.testing import _activate_testing
+
+
+@pytest.fixture()
+def test_app(request):
+ """
+ py.test fixture to pass sandboxed mediagoblin applications into tests that
+ want them.
+
+ You could make a local version of this method for your own tests
+ to override the paste and config files being used by passing them
+ in differently to get_app.
+ """
+ return tools.get_app(request)
+
+
+@pytest.fixture()
+def pt_fixture_enable_testing():
+ """
+ py.test fixture to enable testing mode in tools.
+ """
+ _activate_testing()
diff --git a/mediagoblin/tests/pytest.ini b/mediagoblin/tests/pytest.ini
new file mode 100644
index 00000000..e561c074
--- /dev/null
+++ b/mediagoblin/tests/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+usefixtures = tmpdir pt_fixture_enable_testing
diff --git a/mediagoblin/tests/resources.py b/mediagoblin/tests/resources.py
new file mode 100644
index 00000000..f7b3037d
--- /dev/null
+++ b/mediagoblin/tests/resources.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+
+from pkg_resources import resource_filename
+
+
+def resource(filename):
+ return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
+
+
+GOOD_JPG = resource('good.jpg')
+GOOD_PNG = resource('good.png')
+EVIL_FILE = resource('evil')
+EVIL_JPG = resource('evil.jpg')
+EVIL_PNG = resource('evil.png')
+BIG_BLUE = resource('bigblue.png')
+GOOD_PDF = resource('good.pdf')
+
+
+def resource_exif(f):
+ return resource_filename('mediagoblin.tests', 'test_exif/' + f)
+
+
+GOOD_JPG = resource_exif('good.jpg')
+EMPTY_JPG = resource_exif('empty.jpg')
+BAD_JPG = resource_exif('bad.jpg')
+GPS_JPG = resource_exif('has-gps.jpg')
diff --git a/mediagoblin/tests/test_api.py b/mediagoblin/tests/test_api.py
index 82b1c1b4..89cf1026 100644
--- a/mediagoblin/tests/test_api.py
+++ b/mediagoblin/tests/test_api.py
@@ -18,40 +18,27 @@
import logging
import base64
-from pkg_resources import resource_filename
+import pytest
from mediagoblin import mg_globals
from mediagoblin.tools import template, pluginapi
-from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
+from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
+ BIG_BLUE
_log = logging.getLogger(__name__)
-def resource(filename):
- '''
- Borrowed from the submission tests
- '''
- return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
-
-
-GOOD_JPG = resource('good.jpg')
-GOOD_PNG = resource('good.png')
-EVIL_FILE = resource('evil')
-EVIL_JPG = resource('evil.jpg')
-EVIL_PNG = resource('evil.png')
-BIG_BLUE = resource('bigblue.png')
-
class TestAPI(object):
- def setUp(self):
- self.app = get_app(dump_old_app=False)
+ def setup(self):
self.db = mg_globals.database
self.user_password = u'4cc355_70k3N'
self.user = fixture_add_user(u'joapi', self.user_password)
- def login(self):
- self.app.post(
+ def login(self, test_app):
+ test_app.post(
'/auth/login/', {
'username': self.user.username,
'password': self.user_password})
@@ -65,14 +52,14 @@ class TestAPI(object):
self.user.username,
self.user_password])))}
- def do_post(self, data, **kwargs):
+ def do_post(self, data, test_app, **kwargs):
url = kwargs.pop('url', '/api/submit')
do_follow = kwargs.pop('do_follow', False)
if not 'headers' in kwargs.keys():
kwargs['headers'] = self.http_auth_headers()
- response = self.app.post(url, data, **kwargs)
+ response = test_app.post(url, data, **kwargs)
if do_follow:
response.follow()
@@ -82,21 +69,22 @@ class TestAPI(object):
def upload_data(self, filename):
return {'upload_files': [('file', filename)]}
- def test_1_test_test_view(self):
- self.login()
+ def test_1_test_test_view(self, test_app):
+ self.login(test_app)
- response = self.app.get(
+ response = test_app.get(
'/api/test',
headers=self.http_auth_headers())
assert response.body == \
'{"username": "joapi", "email": "joapi@example.com"}'
- def test_2_test_submission(self):
- self.login()
+ def test_2_test_submission(self, test_app):
+ self.login(test_app)
response = self.do_post(
{'title': 'Great JPG!'},
+ test_app,
**self.upload_data(GOOD_JPG))
assert response.status_int == 200
diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py
index a59a319c..61503d32 100644
--- a/mediagoblin/tests/test_auth.py
+++ b/mediagoblin/tests/test_auth.py
@@ -13,59 +13,17 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
import urlparse
-import datetime
-
-from nose.tools import assert_equal
+import pkg_resources
+import pytest
from mediagoblin import mg_globals
-from mediagoblin.auth import lib as auth_lib
from mediagoblin.db.models import User
-from mediagoblin.tests.tools import setup_fresh_app, get_app, fixture_add_user
+from mediagoblin.tests.tools import get_app, fixture_add_user
from mediagoblin.tools import template, mail
+from mediagoblin.auth import tools as auth_tools
-########################
-# Test bcrypt auth funcs
-########################
-
-def test_bcrypt_check_password():
- # Check known 'lollerskates' password against check function
- assert auth_lib.bcrypt_check_password(
- 'lollerskates',
- '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
-
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword',
- '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
-
- # Same thing, but with extra fake salt.
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword',
- '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6',
- '3><7R45417')
-
-
-def test_bcrypt_gen_password_hash():
- pw = 'youwillneverguessthis'
-
- # Normal password hash generation, and check on that hash
- hashed_pw = auth_lib.bcrypt_gen_password_hash(pw)
- assert auth_lib.bcrypt_check_password(
- pw, hashed_pw)
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword', hashed_pw)
-
- # Same thing, extra salt.
- hashed_pw = auth_lib.bcrypt_gen_password_hash(pw, '3><7R45417')
- assert auth_lib.bcrypt_check_password(
- pw, hashed_pw, '3><7R45417')
- assert not auth_lib.bcrypt_check_password(
- 'notthepassword', hashed_pw, '3><7R45417')
-
-
-@setup_fresh_app
def test_register_views(test_app):
"""
Massive test function that all our registration-related views all work.
@@ -102,8 +60,8 @@ def test_register_views(test_app):
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
form = context['register_form']
- assert_equal (form.username.errors, [u'Field must be between 3 and 30 characters long.'])
- assert_equal (form.password.errors, [u'Field must be between 5 and 1024 characters long.'])
+ assert form.username.errors == [u'Field must be between 3 and 30 characters long.']
+ assert form.password.errors == [u'Field must be between 5 and 1024 characters long.']
## bad form
template.clear_test_template_context()
@@ -114,11 +72,11 @@ def test_register_views(test_app):
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
form = context['register_form']
- assert_equal (form.username.errors, [u'This field does not take email addresses.'])
- assert_equal (form.email.errors, [u'This field requires an email address.'])
+ assert form.username.errors == [u'This field does not take email addresses.']
+ assert form.email.errors == [u'This field requires an email address.']
## At this point there should be no users in the database ;)
- assert_equal(User.query.count(), 0)
+ assert User.query.count() == 0
# Successful register
# -------------------
@@ -131,14 +89,12 @@ def test_register_views(test_app):
response.follow()
## Did we redirect to the proper page? Use the right template?
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/u/happygirl/')
+ assert urlparse.urlsplit(response.location)[2] == '/u/happygirl/'
assert 'mediagoblin/user_pages/user.html' in template.TEMPLATE_TEST_CONTEXT
## Make sure user is in place
- new_user = mg_globals.database.User.find_one(
- {'username': u'happygirl'})
+ new_user = mg_globals.database.User.query.filter_by(
+ username=u'happygirl').first()
assert new_user
assert new_user.status == u'needs_email_verification'
assert new_user.email_verified == False
@@ -161,24 +117,19 @@ def test_register_views(test_app):
assert path == u'/auth/verify_email/'
parsed_get_params = urlparse.parse_qs(get_params)
- ### user should have these same parameters
- assert parsed_get_params['userid'] == [
- unicode(new_user.id)]
- assert parsed_get_params['token'] == [
- new_user.verification_key]
-
## Try verifying with bs verification key, shouldn't work
template.clear_test_template_context()
response = test_app.get(
- "/auth/verify_email/?userid=%s&token=total_bs" % unicode(
- new_user.id))
+ "/auth/verify_email/?token=total_bs")
response.follow()
- context = template.TEMPLATE_TEST_CONTEXT[
- 'mediagoblin/user_pages/user.html']
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+
# assert context['verification_successful'] == True
# TODO: Would be good to test messages here when we can do so...
- new_user = mg_globals.database.User.find_one(
- {'username': u'happygirl'})
+ new_user = mg_globals.database.User.query.filter_by(
+ username=u'happygirl').first()
assert new_user
assert new_user.status == u'needs_email_verification'
assert new_user.email_verified == False
@@ -191,8 +142,8 @@ def test_register_views(test_app):
'mediagoblin/user_pages/user.html']
# assert context['verification_successful'] == True
# TODO: Would be good to test messages here when we can do so...
- new_user = mg_globals.database.User.find_one(
- {'username': u'happygirl'})
+ new_user = mg_globals.database.User.query.filter_by(
+ username=u'happygirl').first()
assert new_user
assert new_user.status == u'active'
assert new_user.email_verified == True
@@ -224,9 +175,7 @@ def test_register_views(test_app):
response.follow()
## Did we redirect to the proper page? Use the right template?
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/auth/login/')
+ assert urlparse.urlsplit(response.location)[2] == '/auth/login/'
assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
## Make sure link to change password is sent by email
@@ -240,35 +189,17 @@ def test_register_views(test_app):
path = urlparse.urlsplit(email_context['verification_url'])[2]
get_params = urlparse.urlsplit(email_context['verification_url'])[3]
- assert path == u'/auth/forgot_password/verify/'
parsed_get_params = urlparse.parse_qs(get_params)
-
- # user should have matching parameters
- new_user = mg_globals.database.User.find_one({'username': u'happygirl'})
- assert parsed_get_params['userid'] == [unicode(new_user.id)]
- assert parsed_get_params['token'] == [new_user.fp_verification_key]
-
- ### The forgotten password token should be set to expire in ~ 10 days
- # A few ticks have expired so there are only 9 full days left...
- assert (new_user.fp_token_expire - datetime.datetime.now()).days == 9
+ assert path == u'/auth/forgot_password/verify/'
## Try using a bs password-changing verification key, shouldn't work
template.clear_test_template_context()
response = test_app.get(
- "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode(
- new_user.id), status=404)
- assert_equal(response.status.split()[0], u'404') # status="404 NOT FOUND"
+ "/auth/forgot_password/verify/?token=total_bs")
+ response.follow()
- ## Try using an expired token to change password, shouldn't work
- template.clear_test_template_context()
- new_user = mg_globals.database.User.find_one({'username': u'happygirl'})
- real_token_expiration = new_user.fp_token_expire
- new_user.fp_token_expire = datetime.datetime.now()
- new_user.save()
- response = test_app.get("%s?%s" % (path, get_params), status=404)
- assert_equal(response.status.split()[0], u'404') # status="404 NOT FOUND"
- new_user.fp_token_expire = real_token_expiration
- new_user.save()
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
## Verify step 1 of password-change works -- can see form to change password
template.clear_test_template_context()
@@ -279,7 +210,6 @@ def test_register_views(test_app):
template.clear_test_template_context()
response = test_app.post(
'/auth/forgot_password/verify/', {
- 'userid': parsed_get_params['userid'],
'password': 'iamveryveryhappy',
'token': parsed_get_params['token']})
response.follow()
@@ -294,20 +224,18 @@ def test_register_views(test_app):
# User should be redirected
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
+ assert urlparse.urlsplit(response.location)[2] == '/'
assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
-def test_authentication_views():
+def test_authentication_views(test_app):
"""
Test logging in and logging out
"""
- test_app = get_app(dump_old_app=False)
# Make a new user
test_user = fixture_add_user(active_user=False)
+
# Get login
# ---------
test_app.get('/auth/login/')
@@ -320,7 +248,6 @@ def test_authentication_views():
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
form = context['login_form']
assert form.username.errors == [u'This field is required.']
- assert form.password.errors == [u'This field is required.']
# Failed login - blank user
# -------------------------
@@ -338,9 +265,7 @@ def test_authentication_views():
response = test_app.post(
'/auth/login/', {
'username': u'chris'})
- context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
- form = context['login_form']
- assert form.password.errors == [u'This field is required.']
+ assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
# Failed login - bad user
# -----------------------
@@ -372,9 +297,7 @@ def test_authentication_views():
# User should be redirected
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
+ assert urlparse.urlsplit(response.location)[2] == '/'
assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
# Make sure user is in the session
@@ -389,9 +312,7 @@ def test_authentication_views():
# Should be redirected to index page
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
+ assert urlparse.urlsplit(response.location)[2] == '/'
assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
# Make sure the user is not in the session
@@ -407,6 +328,48 @@ def test_authentication_views():
'username': u'chris',
'password': 'toast',
'next' : '/u/chris/'})
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/u/chris/')
+ assert urlparse.urlsplit(response.location)[2] == '/u/chris/'
+
+
+@pytest.fixture()
+def authentication_disabled_app(request):
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests.auth_configs',
+ 'authentication_disabled_appconfig.ini'))
+
+
+def test_authentication_disabled_app(authentication_disabled_app):
+ # app.auth should = false
+ assert mg_globals.app.auth is False
+
+ # Try to visit register page
+ template.clear_test_template_context()
+ response = authentication_disabled_app.get('/auth/register/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Try to vist login page
+ template.clear_test_template_context()
+ response = authentication_disabled_app.get('/auth/login/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ ## Test check_login_simple should return None
+ assert auth_tools.check_login_simple('test', 'simple') is None
+
+ # Try to visit the forgot password page
+ template.clear_test_template_context()
+ response = authentication_disabled_app.get('/auth/register/')
+ response.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
diff --git a/mediagoblin/tests/test_basic_auth.py b/mediagoblin/tests/test_basic_auth.py
new file mode 100644
index 00000000..cdd80fca
--- /dev/null
+++ b/mediagoblin/tests/test_basic_auth.py
@@ -0,0 +1,59 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+from mediagoblin.plugins.basic_auth import tools as auth_tools
+from mediagoblin.tools.testing import _activate_testing
+
+_activate_testing()
+
+
+########################
+# Test bcrypt auth funcs
+########################
+
+
+def test_bcrypt_check_password():
+ # Check known 'lollerskates' password against check function
+ assert auth_tools.bcrypt_check_password(
+ 'lollerskates',
+ '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
+
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword',
+ '$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
+
+ # Same thing, but with extra fake salt.
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword',
+ '$2a$12$ELVlnw3z1FMu6CEGs/L8XO8vl0BuWSlUHgh0rUrry9DUXGMUNWwl6',
+ '3><7R45417')
+
+
+def test_bcrypt_gen_password_hash():
+ pw = 'youwillneverguessthis'
+
+ # Normal password hash generation, and check on that hash
+ hashed_pw = auth_tools.bcrypt_gen_password_hash(pw)
+ assert auth_tools.bcrypt_check_password(
+ pw, hashed_pw)
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword', hashed_pw)
+
+ # Same thing, extra salt.
+ hashed_pw = auth_tools.bcrypt_gen_password_hash(pw, '3><7R45417')
+ assert auth_tools.bcrypt_check_password(
+ pw, hashed_pw, '3><7R45417')
+ assert not auth_tools.bcrypt_check_password(
+ 'notthepassword', hashed_pw, '3><7R45417')
diff --git a/mediagoblin/tests/test_cache.py b/mediagoblin/tests/test_cache.py
deleted file mode 100644
index 48fa1386..00000000
--- a/mediagoblin/tests/test_cache.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# GNU MediaGoblin -- federated, autonomous media hosting
-# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
-#
-# 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 <http://www.gnu.org/licenses/>.
-
-
-from mediagoblin.tests.tools import setup_fresh_app
-from mediagoblin import mg_globals
-
-
-DATA_TO_CACHE = {
- 'herp': 'derp',
- 'lol': 'cats'}
-
-
-def _get_some_data(key):
- """
- Stuid function that makes use of some caching.
- """
- some_data_cache = mg_globals.cache.get_cache('sum_data')
- if some_data_cache.has_key(key):
- return some_data_cache.get(key)
-
- value = DATA_TO_CACHE.get(key)
- some_data_cache.put(key, value)
- return value
-
-
-@setup_fresh_app
-def test_cache_working(test_app):
- some_data_cache = mg_globals.cache.get_cache('sum_data')
- assert not some_data_cache.has_key('herp')
- assert _get_some_data('herp') == 'derp'
- assert some_data_cache.get('herp') == 'derp'
- # should get the same value again
- assert _get_some_data('herp') == 'derp'
-
- # now we force-change it, but the function should use the cached
- # version
- some_data_cache.put('herp', 'pred')
- assert _get_some_data('herp') == 'pred'
diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py
index 5530c6f2..0184436a 100644
--- a/mediagoblin/tests/test_celery_setup.py
+++ b/mediagoblin/tests/test_celery_setup.py
@@ -48,7 +48,7 @@ def test_setup_celery_from_config():
assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float)
assert fake_celery_module.CELERY_RESULT_PERSISTENT is True
assert fake_celery_module.CELERY_IMPORTS == [
- 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.processing.task']
+ 'foo.bar.baz', 'this.is.an.import', 'mediagoblin.processing.task', 'mediagoblin.notifications.task']
assert fake_celery_module.CELERY_RESULT_BACKEND == 'database'
assert fake_celery_module.CELERY_RESULT_DBURI == (
'sqlite:///' +
diff --git a/mediagoblin/tests/test_collections.py b/mediagoblin/tests/test_collections.py
index b19f6362..87782f30 100644
--- a/mediagoblin/tests/test_collections.py
+++ b/mediagoblin/tests/test_collections.py
@@ -14,17 +14,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.tests.tools import fixture_add_collection, fixture_add_user, \
- get_app
+from mediagoblin.tests.tools import fixture_add_collection, fixture_add_user
from mediagoblin.db.models import Collection, User
-from mediagoblin.db.base import Session
-from nose.tools import assert_equal
-def test_user_deletes_collection():
+def test_user_deletes_collection(test_app):
# Setup db.
- get_app(dump_old_app=False)
-
user = fixture_add_user()
coll = fixture_add_collection(user=user)
# Reload into session:
@@ -34,4 +29,4 @@ def test_user_deletes_collection():
user.delete()
cnt2 = Collection.query.count()
- assert_equal(cnt1, cnt2 + 1)
+ assert cnt1 == cnt2 + 1
diff --git a/mediagoblin/tests/test_csrf_middleware.py b/mediagoblin/tests/test_csrf_middleware.py
index e720264c..a272caf6 100644
--- a/mediagoblin/tests/test_csrf_middleware.py
+++ b/mediagoblin/tests/test_csrf_middleware.py
@@ -14,12 +14,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.tests.tools import get_app
from mediagoblin import mg_globals
-def test_csrf_cookie_set():
- test_app = get_app(dump_old_app=False)
+def test_csrf_cookie_set(test_app):
cookie_name = mg_globals.app_config['csrf_cookie_name']
# get login page
@@ -33,11 +31,14 @@ def test_csrf_cookie_set():
assert response.headers.get('Vary', False) == 'Cookie'
-def test_csrf_token_must_match():
- # We need a fresh app for this test on webtest < 1.3.6.
- # We do not understand why, but it fixes the tests.
- # If we require webtest >= 1.3.6, we can switch to a non fresh app here.
- test_app = get_app(dump_old_app=True)
+# We need a fresh app for this test on webtest < 1.3.6.
+# We do not understand why, but it fixes the tests.
+# If we require webtest >= 1.3.6, we can switch to a non fresh app here.
+#
+# ... this comment might be irrelevant post-pytest-fixtures, but I'm not
+# removing it yet in case we move to module-level tests :)
+# -- cwebber
+def test_csrf_token_must_match(test_app):
# construct a request with no cookie or form token
assert test_app.post('/auth/login/',
@@ -67,8 +68,7 @@ def test_csrf_token_must_match():
extra_environ={'gmg.verify_csrf': True}).\
status_int == 200
-def test_csrf_exempt():
- test_app = get_app(dump_old_app=False)
+def test_csrf_exempt(test_app):
# monkey with the views to decorate a known endpoint
import mediagoblin.auth.views
from mediagoblin.meddleware.csrf import csrf_exempt
diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py
index 7db6eaea..d70d0478 100644
--- a/mediagoblin/tests/test_edit.py
+++ b/mediagoblin/tests/test_edit.py
@@ -14,35 +14,36 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from nose.tools import assert_equal
+import urlparse
from mediagoblin import mg_globals
from mediagoblin.db.models import User
-from mediagoblin.tests.tools import get_app, fixture_add_user
-from mediagoblin.tools import template
-from mediagoblin.auth.lib import bcrypt_check_password
+from mediagoblin.tests.tools import fixture_add_user
+from mediagoblin import auth
+from mediagoblin.tools import template, mail
+
class TestUserEdit(object):
- def setUp(self):
- self.app = get_app(dump_old_app=False)
+ def setup(self):
# set up new user
self.user_password = u'toast'
self.user = fixture_add_user(password = self.user_password)
- self.login()
- def login(self):
- self.app.post(
+ def login(self, test_app):
+ test_app.post(
'/auth/login/', {
'username': self.user.username,
'password': self.user_password})
- def test_user_deletion(self):
+ def test_user_deletion(self, test_app):
"""Delete user via web interface"""
+ self.login(test_app)
+
# Make sure user exists
assert User.query.filter_by(username=u'chris').first()
- res = self.app.post('/edit/account/delete/', {'confirmed': 'y'})
+ res = test_app.post('/edit/account/delete/', {'confirmed': 'y'})
# Make sure user has been deleted
assert User.query.filter_by(username=u'chris').first() == None
@@ -52,84 +53,156 @@ class TestUserEdit(object):
#Restore user at end of test
self.user = fixture_add_user(password = self.user_password)
- self.login()
+ self.login(test_app)
- def test_change_password(self):
+ def test_change_password(self, test_app):
"""Test changing password correctly and incorrectly"""
+ self.login(test_app)
+
# test that the password can be changed
- # template.clear_test_template_context()
- res = self.app.post(
- '/edit/account/', {
+ template.clear_test_template_context()
+ res = test_app.post(
+ '/edit/password/', {
'old_password': 'toast',
'new_password': '123456',
- 'wants_comment_notification': 'y'
})
+ res.follow()
+
+ # Did we redirect to the correct page?
+ assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
- # Check for redirect on success
- assert_equal(res.status_int, 302)
# test_user has to be fetched again in order to have the current values
test_user = User.query.filter_by(username=u'chris').first()
- assert bcrypt_check_password('123456', test_user.pw_hash)
+ assert auth.check_password('123456', test_user.pw_hash)
# Update current user passwd
self.user_password = '123456'
# test that the password cannot be changed if the given
- # old_password is wrong template.clear_test_template_context()
- self.app.post(
- '/edit/account/', {
+ # old_password is wrong
+ template.clear_test_template_context()
+ test_app.post(
+ '/edit/password/', {
'old_password': 'toast',
'new_password': '098765',
})
test_user = User.query.filter_by(username=u'chris').first()
- assert not bcrypt_check_password('098765', test_user.pw_hash)
-
+ assert not auth.check_password('098765', test_user.pw_hash)
- def test_change_bio_url(self):
+ def test_change_bio_url(self, test_app):
"""Test changing bio and URL"""
+ self.login(test_app)
+
# Test if legacy profile editing URL redirects correctly
- res = self.app.post(
+ res = test_app.post(
'/edit/profile/', {
'bio': u'I love toast!',
'url': u'http://dustycloud.org/'}, expect_errors=True)
# Should redirect to /u/chris/edit/
- assert_equal (res.status_int, 302)
+ assert res.status_int == 302
assert res.headers['Location'].endswith("/u/chris/edit/")
- res = self.app.post(
+ res = test_app.post(
'/u/chris/edit/', {
'bio': u'I love toast!',
'url': u'http://dustycloud.org/'})
test_user = User.query.filter_by(username=u'chris').first()
- assert_equal(test_user.bio, u'I love toast!')
- assert_equal(test_user.url, u'http://dustycloud.org/')
+ assert test_user.bio == u'I love toast!'
+ assert test_user.url == u'http://dustycloud.org/'
# change a different user than the logged in (should fail with 403)
fixture_add_user(username=u"foo")
- res = self.app.post(
+ res = test_app.post(
'/u/foo/edit/', {
'bio': u'I love toast!',
'url': u'http://dustycloud.org/'}, expect_errors=True)
- assert_equal(res.status_int, 403)
+ assert res.status_int == 403
# test changing the bio and the URL inproperly
too_long_bio = 150 * 'T' + 150 * 'o' + 150 * 'a' + 150 * 's' + 150* 't'
- self.app.post(
+ test_app.post(
'/u/chris/edit/', {
# more than 500 characters
'bio': too_long_bio,
'url': 'this-is-no-url'})
# Check form errors
- context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/edit/edit_profile.html']
+ context = template.TEMPLATE_TEST_CONTEXT[
+ 'mediagoblin/edit/edit_profile.html']
form = context['form']
- assert_equal(form.bio.errors, [u'Field must be between 0 and 500 characters long.'])
- assert_equal(form.url.errors, [u'This address contains errors'])
+ assert form.bio.errors == [
+ u'Field must be between 0 and 500 characters long.']
+ assert form.url.errors == [
+ u'This address contains errors']
+
+ def test_email_change(self, test_app):
+ self.login(test_app)
+
+ # Test email already in db
+ template.clear_test_template_context()
+ test_app.post(
+ '/edit/account/', {
+ 'new_email': 'chris@example.com',
+ 'password': 'toast'})
+ # Check form errors
+ context = template.TEMPLATE_TEST_CONTEXT[
+ 'mediagoblin/edit/edit_account.html']
+ assert context['form'].new_email.errors == [
+ u'Sorry, a user with that email address already exists.']
+
+ # Test successful email change
+ template.clear_test_template_context()
+ res = test_app.post(
+ '/edit/account/', {
+ 'new_email': 'new@example.com',
+ 'password': 'toast'})
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/u/chris/'
+
+ # Make sure we get email verification and try verifying
+ assert len(mail.EMAIL_TEST_INBOX) == 1
+ message = mail.EMAIL_TEST_INBOX.pop()
+ assert message['To'] == 'new@example.com'
+ email_context = template.TEMPLATE_TEST_CONTEXT[
+ 'mediagoblin/edit/verification.txt']
+ assert email_context['verification_url'] in \
+ message.get_payload(decode=True)
+
+ path = urlparse.urlsplit(email_context['verification_url'])[2]
+ assert path == u'/edit/verify_email/'
+
+ ## Try verifying with bs verification key, shouldn't work
+ template.clear_test_template_context()
+ res = test_app.get(
+ "/edit/verify_email/?token=total_bs")
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/'
+
+ # Email shouldn't be saved
+ email_in_db = mg_globals.database.User.query.filter_by(
+ email='new@example.com').first()
+ email = User.query.filter_by(username='chris').first().email
+ assert email_in_db is None
+ assert email == 'chris@example.com'
+
+ # Verify email activation works
+ template.clear_test_template_context()
+ get_params = urlparse.urlsplit(email_context['verification_url'])[3]
+ res = test_app.get('%s?%s' % (path, get_params))
+ res.follow()
+
+ # New email saved?
+ email = User.query.filter_by(username='chris').first().email
+ assert email == 'new@example.com'
# test changing the url inproperly
diff --git a/mediagoblin/tests/test_exif.py b/mediagoblin/tests/test_exif.py
index 100d17f0..c07e24ae 100644
--- a/mediagoblin/tests/test_exif.py
+++ b/mediagoblin/tests/test_exif.py
@@ -15,39 +15,20 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import pkg_resources
-import Image
+try:
+ from PIL import Image
+except ImportError:
+ import Image
from mediagoblin.tools.exif import exif_fix_image_orientation, \
extract_exif, clean_exif, get_gps_data, get_useful
+from .resources import GOOD_JPG, EMPTY_JPG, BAD_JPG, GPS_JPG
def assert_in(a, b):
assert a in b, "%r not in %r" % (a, b)
-GOOD_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'good.jpg'))
-EMPTY_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'empty.jpg'))
-BAD_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'bad.jpg'))
-GPS_JPG = pkg_resources.resource_filename(
- 'mediagoblin.tests',
- os.path.join(
- 'test_exif',
- 'has-gps.jpg'))
-
-
def test_exif_extraction():
'''
Test EXIF extraction from a good image
@@ -67,63 +48,324 @@ def test_exif_extraction():
assert gps == {}
# Do we have the "useful" tags?
- assert useful == {
- 'EXIF Flash': {
- 'field_type': 3,
- 'printable': u'Flash did not fire',
- 'field_offset': 380,
- 'tag': 37385,
- 'values': [0],
- 'field_length': 2},
- 'EXIF ExposureTime': {
- 'field_type': 5,
- 'printable': '1/125',
- 'field_offset': 700,
- 'tag': 33434,
- 'values': [[1, 125]],
- 'field_length': 8},
- 'EXIF FocalLength': {
- 'field_type': 5,
- 'printable': '18',
- 'field_offset': 780,
- 'tag': 37386,
- 'values': [[18, 1]],
- 'field_length': 8},
- 'Image Model': {
- 'field_type': 2,
- 'printable': 'NIKON D80',
- 'field_offset': 152,
- 'tag': 272,
- 'values': 'NIKON D80',
- 'field_length': 10},
- 'Image Make': {
- 'field_type': 2,
- 'printable': 'NIKON CORPORATION',
- 'field_offset': 134,
- 'tag': 271,
- 'values': 'NIKON CORPORATION',
- 'field_length': 18},
- 'EXIF ExposureMode': {
- 'field_type': 3,
- 'printable': 'Manual Exposure',
- 'field_offset': 584,
- 'tag': 41986,
- 'values': [1],
- 'field_length': 2},
- 'EXIF ISOSpeedRatings': {
- 'field_type': 3,
- 'printable': '100',
- 'field_offset': 260,
- 'tag': 34855,
- 'values': [100],
- 'field_length': 2},
- 'EXIF FNumber': {
- 'field_type': 5,
- 'printable': '10',
- 'field_offset': 708,
- 'tag': 33437,
- 'values': [[10, 1]],
- 'field_length': 8}}
+ assert useful == {'EXIF CVAPattern': {'field_length': 8,
+ 'field_offset': 26224,
+ 'field_type': 7,
+ 'printable': u'[0, 2, 0, 2, 1, 2, 0, 1]',
+ 'tag': 41730,
+ 'values': [0, 2, 0, 2, 1, 2, 0, 1]},
+ 'EXIF ColorSpace': {'field_length': 2,
+ 'field_offset': 476,
+ 'field_type': 3,
+ 'printable': u'sRGB',
+ 'tag': 40961,
+ 'values': [1]},
+ 'EXIF ComponentsConfiguration': {'field_length': 4,
+ 'field_offset': 308,
+ 'field_type': 7,
+ 'printable': u'YCbCr',
+ 'tag': 37121,
+ 'values': [1, 2, 3, 0]},
+ 'EXIF CompressedBitsPerPixel': {'field_length': 8,
+ 'field_offset': 756,
+ 'field_type': 5,
+ 'printable': u'4',
+ 'tag': 37122,
+ 'values': [[4, 1]]},
+ 'EXIF Contrast': {'field_length': 2,
+ 'field_offset': 656,
+ 'field_type': 3,
+ 'printable': u'Soft',
+ 'tag': 41992,
+ 'values': [1]},
+ 'EXIF CustomRendered': {'field_length': 2,
+ 'field_offset': 572,
+ 'field_type': 3,
+ 'printable': u'Normal',
+ 'tag': 41985,
+ 'values': [0]},
+ 'EXIF DateTimeDigitized': {'field_length': 20,
+ 'field_offset': 736,
+ 'field_type': 2,
+ 'printable': u'2011:06:22 12:20:33',
+ 'tag': 36868,
+ 'values': u'2011:06:22 12:20:33'},
+ 'EXIF DateTimeOriginal': {'field_length': 20,
+ 'field_offset': 716,
+ 'field_type': 2,
+ 'printable': u'2011:06:22 12:20:33',
+ 'tag': 36867,
+ 'values': u'2011:06:22 12:20:33'},
+ 'EXIF DigitalZoomRatio': {'field_length': 8,
+ 'field_offset': 26232,
+ 'field_type': 5,
+ 'printable': u'1',
+ 'tag': 41988,
+ 'values': [[1, 1]]},
+ 'EXIF ExifImageLength': {'field_length': 2,
+ 'field_offset': 500,
+ 'field_type': 3,
+ 'printable': u'2592',
+ 'tag': 40963,
+ 'values': [2592]},
+ 'EXIF ExifImageWidth': {'field_length': 2,
+ 'field_offset': 488,
+ 'field_type': 3,
+ 'printable': u'3872',
+ 'tag': 40962,
+ 'values': [3872]},
+ 'EXIF ExifVersion': {'field_length': 4,
+ 'field_offset': 272,
+ 'field_type': 7,
+ 'printable': u'0221',
+ 'tag': 36864,
+ 'values': [48, 50, 50, 49]},
+ 'EXIF ExposureBiasValue': {'field_length': 8,
+ 'field_offset': 764,
+ 'field_type': 10,
+ 'printable': u'0',
+ 'tag': 37380,
+ 'values': [[0, 1]]},
+ 'EXIF ExposureMode': {'field_length': 2,
+ 'field_offset': 584,
+ 'field_type': 3,
+ 'printable': u'Manual Exposure',
+ 'tag': 41986,
+ 'values': [1]},
+ 'EXIF ExposureProgram': {'field_length': 2,
+ 'field_offset': 248,
+ 'field_type': 3,
+ 'printable': u'Manual',
+ 'tag': 34850,
+ 'values': [1]},
+ 'EXIF ExposureTime': {'field_length': 8,
+ 'field_offset': 700,
+ 'field_type': 5,
+ 'printable': u'1/125',
+ 'tag': 33434,
+ 'values': [[1, 125]]},
+ 'EXIF FNumber': {'field_length': 8,
+ 'field_offset': 708,
+ 'field_type': 5,
+ 'printable': u'10',
+ 'tag': 33437,
+ 'values': [[10, 1]]},
+ 'EXIF FileSource': {'field_length': 1,
+ 'field_offset': 536,
+ 'field_type': 7,
+ 'printable': u'Digital Camera',
+ 'tag': 41728,
+ 'values': [3]},
+ 'EXIF Flash': {'field_length': 2,
+ 'field_offset': 380,
+ 'field_type': 3,
+ 'printable': u'Flash did not fire',
+ 'tag': 37385,
+ 'values': [0]},
+ 'EXIF FlashPixVersion': {'field_length': 4,
+ 'field_offset': 464,
+ 'field_type': 7,
+ 'printable': u'0100',
+ 'tag': 40960,
+ 'values': [48, 49, 48, 48]},
+ 'EXIF FocalLength': {'field_length': 8,
+ 'field_offset': 780,
+ 'field_type': 5,
+ 'printable': u'18',
+ 'tag': 37386,
+ 'values': [[18, 1]]},
+ 'EXIF FocalLengthIn35mmFilm': {'field_length': 2,
+ 'field_offset': 620,
+ 'field_type': 3,
+ 'printable': u'27',
+ 'tag': 41989,
+ 'values': [27]},
+ 'EXIF GainControl': {'field_length': 2,
+ 'field_offset': 644,
+ 'field_type': 3,
+ 'printable': u'None',
+ 'tag': 41991,
+ 'values': [0]},
+ 'EXIF ISOSpeedRatings': {'field_length': 2,
+ 'field_offset': 260,
+ 'field_type': 3,
+ 'printable': u'100',
+ 'tag': 34855,
+ 'values': [100]},
+ 'EXIF InteroperabilityOffset': {'field_length': 4,
+ 'field_offset': 512,
+ 'field_type': 4,
+ 'printable': u'26240',
+ 'tag': 40965,
+ 'values': [26240]},
+ 'EXIF LightSource': {'field_length': 2,
+ 'field_offset': 368,
+ 'field_type': 3,
+ 'printable': u'Unknown',
+ 'tag': 37384,
+ 'values': [0]},
+ 'EXIF MaxApertureValue': {'field_length': 8,
+ 'field_offset': 772,
+ 'field_type': 5,
+ 'printable': u'18/5',
+ 'tag': 37381,
+ 'values': [[18, 5]]},
+ 'EXIF MeteringMode': {'field_length': 2,
+ 'field_offset': 356,
+ 'field_type': 3,
+ 'printable': u'Pattern',
+ 'tag': 37383,
+ 'values': [5]},
+ 'EXIF Saturation': {'field_length': 2,
+ 'field_offset': 668,
+ 'field_type': 3,
+ 'printable': u'Normal',
+ 'tag': 41993,
+ 'values': [0]},
+ 'EXIF SceneCaptureType': {'field_length': 2,
+ 'field_offset': 632,
+ 'field_type': 3,
+ 'printable': u'Standard',
+ 'tag': 41990,
+ 'values': [0]},
+ 'EXIF SceneType': {'field_length': 1,
+ 'field_offset': 548,
+ 'field_type': 7,
+ 'printable': u'Directly Photographed',
+ 'tag': 41729,
+ 'values': [1]},
+ 'EXIF SensingMethod': {'field_length': 2,
+ 'field_offset': 524,
+ 'field_type': 3,
+ 'printable': u'One-chip color area',
+ 'tag': 41495,
+ 'values': [2]},
+ 'EXIF Sharpness': {'field_length': 2,
+ 'field_offset': 680,
+ 'field_type': 3,
+ 'printable': u'Normal',
+ 'tag': 41994,
+ 'values': [0]},
+ 'EXIF SubSecTime': {'field_length': 3,
+ 'field_offset': 428,
+ 'field_type': 2,
+ 'printable': u'10',
+ 'tag': 37520,
+ 'values': u'10'},
+ 'EXIF SubSecTimeDigitized': {'field_length': 3,
+ 'field_offset': 452,
+ 'field_type': 2,
+ 'printable': u'10',
+ 'tag': 37522,
+ 'values': u'10'},
+ 'EXIF SubSecTimeOriginal': {'field_length': 3,
+ 'field_offset': 440,
+ 'field_type': 2,
+ 'printable': u'10',
+ 'tag': 37521,
+ 'values': u'10'},
+ 'EXIF SubjectDistanceRange': {'field_length': 2,
+ 'field_offset': 692,
+ 'field_type': 3,
+ 'printable': u'0',
+ 'tag': 41996,
+ 'values': [0]},
+ 'EXIF WhiteBalance': {'field_length': 2,
+ 'field_offset': 596,
+ 'field_type': 3,
+ 'printable': u'Auto',
+ 'tag': 41987,
+ 'values': [0]},
+ 'Image DateTime': {'field_length': 20,
+ 'field_offset': 194,
+ 'field_type': 2,
+ 'printable': u'2011:06:22 12:20:33',
+ 'tag': 306,
+ 'values': u'2011:06:22 12:20:33'},
+ 'Image ExifOffset': {'field_length': 4,
+ 'field_offset': 126,
+ 'field_type': 4,
+ 'printable': u'214',
+ 'tag': 34665,
+ 'values': [214]},
+ 'Image Make': {'field_length': 18,
+ 'field_offset': 134,
+ 'field_type': 2,
+ 'printable': u'NIKON CORPORATION',
+ 'tag': 271,
+ 'values': u'NIKON CORPORATION'},
+ 'Image Model': {'field_length': 10,
+ 'field_offset': 152,
+ 'field_type': 2,
+ 'printable': u'NIKON D80',
+ 'tag': 272,
+ 'values': u'NIKON D80'},
+ 'Image Orientation': {'field_length': 2,
+ 'field_offset': 42,
+ 'field_type': 3,
+ 'printable': u'Rotated 90 CCW',
+ 'tag': 274,
+ 'values': [6]},
+ 'Image ResolutionUnit': {'field_length': 2,
+ 'field_offset': 78,
+ 'field_type': 3,
+ 'printable': u'Pixels/Inch',
+ 'tag': 296,
+ 'values': [2]},
+ 'Image Software': {'field_length': 15,
+ 'field_offset': 178,
+ 'field_type': 2,
+ 'printable': u'Shotwell 0.9.3',
+ 'tag': 305,
+ 'values': u'Shotwell 0.9.3'},
+ 'Image XResolution': {'field_length': 8,
+ 'field_offset': 162,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 282,
+ 'values': [[300, 1]]},
+ 'Image YCbCrPositioning': {'field_length': 2,
+ 'field_offset': 114,
+ 'field_type': 3,
+ 'printable': u'Co-sited',
+ 'tag': 531,
+ 'values': [2]},
+ 'Image YResolution': {'field_length': 8,
+ 'field_offset': 170,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 283,
+ 'values': [[300, 1]]},
+ 'Thumbnail Compression': {'field_length': 2,
+ 'field_offset': 26280,
+ 'field_type': 3,
+ 'printable': u'JPEG (old-style)',
+ 'tag': 259,
+ 'values': [6]},
+ 'Thumbnail ResolutionUnit': {'field_length': 2,
+ 'field_offset': 26316,
+ 'field_type': 3,
+ 'printable': u'Pixels/Inch',
+ 'tag': 296,
+ 'values': [2]},
+ 'Thumbnail XResolution': {'field_length': 8,
+ 'field_offset': 26360,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 282,
+ 'values': [[300, 1]]},
+ 'Thumbnail YCbCrPositioning': {'field_length': 2,
+ 'field_offset': 26352,
+ 'field_type': 3,
+ 'printable': u'Co-sited',
+ 'tag': 531,
+ 'values': [2]},
+ 'Thumbnail YResolution': {'field_length': 8,
+ 'field_offset': 26368,
+ 'field_type': 5,
+ 'printable': u'300',
+ 'tag': 283,
+ 'values': [[300, 1]]}}
def test_exif_image_orientation():
diff --git a/mediagoblin/tests/test_globals.py b/mediagoblin/tests/test_globals.py
index 303f89e2..fe3088f8 100644
--- a/mediagoblin/tests/test_globals.py
+++ b/mediagoblin/tests/test_globals.py
@@ -14,16 +14,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from nose.tools import assert_raises
+import pytest
from mediagoblin import mg_globals
class TestGlobals(object):
- def setUp(self):
+ def setup(self):
self.old_database = mg_globals.database
- def tearDown(self):
+ def teardown(self):
mg_globals.database = self.old_database
def test_setup_globals(self):
@@ -36,7 +36,7 @@ class TestGlobals(object):
assert mg_globals.public_store == 'my favorite public_store!'
assert mg_globals.queue_store == 'my favorite queue_store!'
- assert_raises(
+ pytest.raises(
AssertionError,
mg_globals.setup_globals,
- no_such_global_foo = "Dummy")
+ no_such_global_foo="Dummy")
diff --git a/mediagoblin/tests/test_http_callback.py b/mediagoblin/tests/test_http_callback.py
index 8bee7045..a0511af7 100644
--- a/mediagoblin/tests/test_http_callback.py
+++ b/mediagoblin/tests/test_http_callback.py
@@ -16,18 +16,21 @@
import json
+import pytest
from urlparse import urlparse, parse_qs
from mediagoblin import mg_globals
from mediagoblin.tools import processing
-from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
from mediagoblin.tests.test_submission import GOOD_PNG
from mediagoblin.tests import test_oauth as oauth
class TestHTTPCallback(object):
- def setUp(self):
- self.app = get_app(dump_old_app=False)
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
self.db = mg_globals.database
self.user_password = u'secret'
@@ -36,12 +39,12 @@ class TestHTTPCallback(object):
self.login()
def login(self):
- self.app.post('/auth/login/', {
+ self.test_app.post('/auth/login/', {
'username': self.user.username,
'password': self.user_password})
def get_access_token(self, client_id, client_secret, code):
- response = self.app.get('/oauth/access_token', {
+ response = self.test_app.get('/oauth/access_token', {
'code': code,
'client_id': client_id,
'client_secret': client_secret})
@@ -52,9 +55,8 @@ class TestHTTPCallback(object):
def test_callback(self):
''' Test processing HTTP callback '''
-
self.oauth = oauth.TestOAuth()
- self.oauth.setUp()
+ self.oauth.setup(self.test_app)
redirect, client_id = self.oauth.test_4_authorize_confidential_client()
@@ -69,7 +71,7 @@ class TestHTTPCallback(object):
callback_url = 'https://foo.example?secrettestmediagoblinparam'
- res = self.app.post('/api/submit?client_id={0}&access_token={1}\
+ self.test_app.post('/api/submit?client_id={0}&access_token={1}\
&client_secret={2}'.format(
client_id,
access_token,
diff --git a/mediagoblin/tests/test_messages.py b/mediagoblin/tests/test_messages.py
index 4c0f3e2e..22f9e800 100644
--- a/mediagoblin/tests/test_messages.py
+++ b/mediagoblin/tests/test_messages.py
@@ -14,19 +14,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.messages import fetch_messages, add_message
-from mediagoblin.tests.tools import get_app
+from mediagoblin import messages
from mediagoblin.tools import template
-
-def test_messages():
+def test_messages(test_app):
"""
Added messages should show up in the request.session,
fetched messages should be the same as the added ones,
and fetching should clear the message list.
"""
- test_app = get_app(dump_old_app=False)
# Aquire a request object
test_app.get('/')
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
@@ -35,11 +32,19 @@ def test_messages():
# The message queue should be empty
assert request.session.get('messages', []) == []
+ # First of all, we should clear the messages queue
+ messages.clear_add_message()
# Adding a message should modify the session accordingly
- add_message(request, 'herp_derp', 'First!')
+ messages.add_message(request, 'herp_derp', 'First!')
test_msg_queue = [{'text': 'First!', 'level': 'herp_derp'}]
- assert request.session['messages'] == test_msg_queue
+
+ # Alternative tests to the following, test divided in two steps:
+ # assert request.session['messages'] == test_msg_queue
+ # 1. Tests if add_message worked
+ assert messages.ADD_MESSAGE_TEST[-1] == test_msg_queue
+ # 2. Tests if add_message updated session information
+ assert messages.ADD_MESSAGE_TEST[-1] == request.session['messages']
# fetch_messages should return and empty the queue
- assert fetch_messages(request) == test_msg_queue
+ assert messages.fetch_messages(request) == test_msg_queue
assert request.session.get('messages') == []
diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini
index 42d3785a..535cf1c1 100644
--- a/mediagoblin/tests/test_mgoblin_app.ini
+++ b/mediagoblin/tests/test_mgoblin_app.ini
@@ -3,8 +3,9 @@ direct_remote_path = /test_static/
email_sender_address = "notice@mediagoblin.example.org"
email_debug_mode = true
-# TODO: Switch to using an in-memory database
-sql_engine = "sqlite:///%(here)s/test_user_dev/mediagoblin.db"
+#Runs with an in-memory sqlite db for speed.
+sql_engine = "sqlite://"
+run_migrations = true
# tag parsing
tags_max_length = 50
@@ -12,28 +13,24 @@ tags_max_length = 50
# So we can start to test attachments:
allow_attachments = True
-# Celery shouldn't be set up by the application as it's setup via
-# mediagoblin.init.celery.from_celery
-celery_setup_elsewhere = true
-
[storage:publicstore]
-base_dir = %(here)s/test_user_dev/media/public
+base_dir = %(here)s/user_dev/media/public
base_url = /mgoblin_media/
[storage:queuestore]
-base_dir = %(here)s/test_user_dev/media/queue
-
-[beaker.cache]
-data_dir = %(here)s/test_user_dev/beaker/cache/data
-lock_dir = %(here)s/test_user_dev/beaker/cache/lock
+base_dir = %(here)s/user_dev/media/queue
[celery]
CELERY_ALWAYS_EAGER = true
-CELERY_RESULT_DBURI = "sqlite:///%(here)s/test_user_dev/celery.db"
-BROKER_HOST = "sqlite:///%(here)s/test_user_dev/kombu.db"
+CELERY_RESULT_DBURI = "sqlite:///%(here)s/user_dev/celery.db"
+BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
[plugins]
[[mediagoblin.plugins.api]]
[[mediagoblin.plugins.oauth]]
[[mediagoblin.plugins.httpapiauth]]
-
+[[mediagoblin.plugins.piwigo]]
+[[mediagoblin.plugins.basic_auth]]
+[[mediagoblin.plugins.openid]]
+[[mediagoblin.media_types.image]]
+[[mediagoblin.media_types.pdf]]
diff --git a/mediagoblin/tests/test_misc.py b/mediagoblin/tests/test_misc.py
index 776affc6..43ad0b6d 100644
--- a/mediagoblin/tests/test_misc.py
+++ b/mediagoblin/tests/test_misc.py
@@ -14,26 +14,24 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from nose.tools import assert_equal
-
from mediagoblin.db.base import Session
from mediagoblin.db.models import User, MediaEntry, MediaComment
-from mediagoblin.tests.tools import get_app, \
- fixture_add_user, fixture_media_entry
+from mediagoblin.tests.tools import fixture_add_user, fixture_media_entry
-def test_404_for_non_existent():
- test_app = get_app(dump_old_app=False)
+def test_404_for_non_existent(test_app):
res = test_app.get('/does-not-exist/', expect_errors=True)
- assert_equal(res.status_int, 404)
+ assert res.status_int == 404
-def test_user_deletes_other_comments():
+def test_user_deletes_other_comments(test_app):
user_a = fixture_add_user(u"chris_a")
user_b = fixture_add_user(u"chris_b")
- media_a = fixture_media_entry(uploader=user_a.id, save=False)
- media_b = fixture_media_entry(uploader=user_b.id, save=False)
+ media_a = fixture_media_entry(uploader=user_a.id, save=False,
+ expunge=False, fake_upload=False)
+ media_b = fixture_media_entry(uploader=user_b.id, save=False,
+ expunge=False, fake_upload=False)
Session.add(media_a)
Session.add(media_b)
Session.flush()
@@ -60,11 +58,11 @@ def test_user_deletes_other_comments():
cmt_cnt2 = MediaComment.query.count()
# One user deleted
- assert_equal(usr_cnt2, usr_cnt1 - 1)
+ assert usr_cnt2 == usr_cnt1 - 1
# One media gone
- assert_equal(med_cnt2, med_cnt1 - 1)
+ assert med_cnt2 == med_cnt1 - 1
# Three of four comments gone.
- assert_equal(cmt_cnt2, cmt_cnt1 - 3)
+ assert cmt_cnt2 == cmt_cnt1 - 3
User.query.get(user_b.id).delete()
@@ -73,17 +71,17 @@ def test_user_deletes_other_comments():
cmt_cnt2 = MediaComment.query.count()
# All users gone
- assert_equal(usr_cnt2, usr_cnt1 - 2)
+ assert usr_cnt2 == usr_cnt1 - 2
# All media gone
- assert_equal(med_cnt2, med_cnt1 - 2)
+ assert med_cnt2 == med_cnt1 - 2
# All comments gone
- assert_equal(cmt_cnt2, cmt_cnt1 - 4)
+ assert cmt_cnt2 == cmt_cnt1 - 4
-def test_media_deletes_broken_attachment():
+def test_media_deletes_broken_attachment(test_app):
user_a = fixture_add_user(u"chris_a")
- media = fixture_media_entry(uploader=user_a.id, save=False)
+ media = fixture_media_entry(uploader=user_a.id, save=False, expunge=False)
media.attachment_files.append(dict(
name=u"some name",
filepath=[u"does", u"not", u"exist"],
diff --git a/mediagoblin/tests/test_modelmethods.py b/mediagoblin/tests/test_modelmethods.py
index 7719bd97..427aa47c 100644
--- a/mediagoblin/tests/test_modelmethods.py
+++ b/mediagoblin/tests/test_modelmethods.py
@@ -17,13 +17,10 @@
# Maybe not every model needs a test, but some models have special
# methods, and so it makes sense to test them here.
-from nose.tools import assert_equal
-
from mediagoblin.db.base import Session
from mediagoblin.db.models import MediaEntry
-from mediagoblin.tests.tools import get_app, \
- fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
import mock
@@ -35,8 +32,7 @@ UUID_MOCK = mock.Mock(return_value=FakeUUID())
class TestMediaEntrySlugs(object):
- def setUp(self):
- self.test_app = get_app(dump_old_app=True)
+ def _setup(self):
self.chris_user = fixture_add_user(u'chris')
self.emily_user = fixture_add_user(u'emily')
self.existing_entry = self._insert_media_entry_fixture(
@@ -57,56 +53,78 @@ class TestMediaEntrySlugs(object):
return entry
- def test_unique_slug_from_title(self):
+ def test_unique_slug_from_title(self, test_app):
+ self._setup()
+
entry = self._insert_media_entry_fixture(u"Totally unique slug!", save=False)
entry.generate_slug()
assert entry.slug == u'totally-unique-slug'
- def test_old_good_unique_slug(self):
+ def test_old_good_unique_slug(self, test_app):
+ self._setup()
+
entry = self._insert_media_entry_fixture(
u"A title here", u"a-different-slug-there", save=False)
entry.generate_slug()
assert entry.slug == u"a-different-slug-there"
- def test_old_weird_slug(self):
+ def test_old_weird_slug(self, test_app):
+ self._setup()
+
entry = self._insert_media_entry_fixture(
slug=u"wowee!!!!!", save=False)
entry.generate_slug()
assert entry.slug == u"wowee"
- def test_existing_slug_use_id(self):
- entry = self._insert_media_entry_fixture(
- u"Beware, I exist!!", this_id=9000, save=False)
- entry.generate_slug()
- assert entry.slug == u"beware-i-exist-9000"
-
- @mock.patch('uuid.uuid4', UUID_MOCK)
- def test_existing_slug_cant_use_id(self):
- # This one grabs the nine thousand slug
- self._insert_media_entry_fixture(
- slug=u"beware-i-exist-9000")
+ def test_existing_slug_use_id(self, test_app):
+ self._setup()
entry = self._insert_media_entry_fixture(
u"Beware, I exist!!", this_id=9000, save=False)
entry.generate_slug()
- assert entry.slug == u"beware-i-exist-test"
-
- @mock.patch('uuid.uuid4', UUID_MOCK)
- def test_existing_slug_cant_use_id_extra_junk(self):
- # This one grabs the nine thousand slug
- self._insert_media_entry_fixture(
- slug=u"beware-i-exist-9000")
-
- # This one grabs makes sure the annoyance doesn't stop
- self._insert_media_entry_fixture(
- slug=u"beware-i-exist-test")
-
- entry = self._insert_media_entry_fixture(
- u"Beware, I exist!!", this_id=9000, save=False)
- entry.generate_slug()
- assert entry.slug == u"beware-i-exist-testtest"
+ assert entry.slug == u"beware-i-exist-9000"
- def test_garbage_slug(self):
+ def test_existing_slug_cant_use_id(self, test_app):
+ self._setup()
+
+ # Getting tired of dealing with test_app and this mock.patch
+ # thing conflicting, getting lazy.
+ @mock.patch('uuid.uuid4', UUID_MOCK)
+ def _real_test():
+ # This one grabs the nine thousand slug
+ self._insert_media_entry_fixture(
+ slug=u"beware-i-exist-9000")
+
+ entry = self._insert_media_entry_fixture(
+ u"Beware, I exist!!", this_id=9000, save=False)
+ entry.generate_slug()
+ assert entry.slug == u"beware-i-exist-test"
+
+ _real_test()
+
+ def test_existing_slug_cant_use_id_extra_junk(self, test_app):
+ self._setup()
+
+ # Getting tired of dealing with test_app and this mock.patch
+ # thing conflicting, getting lazy.
+ @mock.patch('uuid.uuid4', UUID_MOCK)
+ def _real_test():
+ # This one grabs the nine thousand slug
+ self._insert_media_entry_fixture(
+ slug=u"beware-i-exist-9000")
+
+ # This one grabs makes sure the annoyance doesn't stop
+ self._insert_media_entry_fixture(
+ slug=u"beware-i-exist-test")
+
+ entry = self._insert_media_entry_fixture(
+ u"Beware, I exist!!", this_id=9000, save=False)
+ entry.generate_slug()
+ assert entry.slug == u"beware-i-exist-testtest"
+
+ _real_test()
+
+ def test_garbage_slug(self, test_app):
"""
Titles that sound totally like Q*Bert shouldn't have slugs at
all. We'll just reference them by id.
@@ -126,13 +144,15 @@ class TestMediaEntrySlugs(object):
| |#| |#| |#| |#|
\|/ \|/ \|/ \|/
"""
+ self._setup()
+
qbert_entry = self._insert_media_entry_fixture(
u"@!#?@!", save=False)
qbert_entry.generate_slug()
assert qbert_entry.slug is None
-def test_media_data_init():
+def test_media_data_init(test_app):
Session.rollback()
Session.remove()
media = MediaEntry()
@@ -144,4 +164,4 @@ def test_media_data_init():
for obj in Session():
obj_in_session += 1
print repr(obj)
- assert_equal(obj_in_session, 0)
+ assert obj_in_session == 0
diff --git a/mediagoblin/tests/test_notifications.py b/mediagoblin/tests/test_notifications.py
new file mode 100644
index 00000000..d52b8d5a
--- /dev/null
+++ b/mediagoblin/tests/test_notifications.py
@@ -0,0 +1,151 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+import pytest
+
+import urlparse
+
+from mediagoblin.tools import template, mail
+
+from mediagoblin.db.models import Notification, CommentNotification, \
+ CommentSubscription
+from mediagoblin.db.base import Session
+
+from mediagoblin.notifications import mark_comment_notification_seen
+
+from mediagoblin.tests.tools import fixture_add_comment, \
+ fixture_media_entry, fixture_add_user, \
+ fixture_comment_subscription
+
+
+class TestNotifications:
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
+ # TODO: Possibly abstract into a decorator like:
+ # @as_authenticated_user('chris')
+ self.test_user = fixture_add_user()
+
+ self.current_user = None
+
+ self.login()
+
+ def login(self, username=u'chris', password=u'toast'):
+ response = self.test_app.post(
+ '/auth/login/', {
+ 'username': username,
+ 'password': password})
+
+ response.follow()
+
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ ctx = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
+
+ assert Session.merge(ctx['request'].user).username == username
+
+ self.current_user = ctx['request'].user
+
+ def logout(self):
+ self.test_app.get('/auth/logout/')
+ self.current_user = None
+
+ @pytest.mark.parametrize('wants_email', [True, False])
+ def test_comment_notification(self, wants_email):
+ '''
+ Test
+ - if a notification is created when posting a comment on
+ another users media entry.
+ - that the comment data is consistent and exists.
+
+ '''
+ user = fixture_add_user('otherperson', password='nosreprehto',
+ wants_comment_notification=wants_email)
+
+ user_id = user.id
+
+ media_entry = fixture_media_entry(uploader=user.id, state=u'processed')
+
+ media_entry_id = media_entry.id
+
+ subscription = fixture_comment_subscription(media_entry)
+
+ subscription_id = subscription.id
+
+ media_uri_id = '/u/{0}/m/{1}/'.format(user.username,
+ media_entry.id)
+ media_uri_slug = '/u/{0}/m/{1}/'.format(user.username,
+ media_entry.slug)
+
+ self.test_app.post(
+ media_uri_id + 'comment/add/',
+ {
+ 'comment_content': u'Test comment #42'
+ }
+ )
+
+ notifications = Notification.query.filter_by(
+ user_id=user.id).all()
+
+ assert len(notifications) == 1
+
+ notification = notifications[0]
+
+ assert type(notification) == CommentNotification
+ assert notification.seen == False
+ assert notification.user_id == user.id
+ assert notification.subject.get_author.id == self.test_user.id
+ assert notification.subject.content == u'Test comment #42'
+
+ if wants_email == True:
+ assert mail.EMAIL_TEST_MBOX_INBOX == [
+ {'from': 'notice@mediagoblin.example.org',
+ 'message': 'Content-Type: text/plain; \
+charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: \
+base64\nSubject: GNU MediaGoblin - chris commented on your \
+post\nFrom: notice@mediagoblin.example.org\nTo: \
+otherperson@example.com\n\nSGkgb3RoZXJwZXJzb24sCmNocmlzIGNvbW1lbnRlZCBvbiB5b3VyIHBvc3QgKGh0dHA6Ly9sb2Nh\nbGhvc3Q6ODAvdS9vdGhlcnBlcnNvbi9tL3NvbWUtdGl0bGUvYy8xLyNjb21tZW50KSBhdCBHTlUg\nTWVkaWFHb2JsaW4KClRlc3QgY29tbWVudCAjNDIKCkdOVSBNZWRpYUdvYmxpbg==\n',
+ 'to': [u'otherperson@example.com']}]
+ else:
+ assert mail.EMAIL_TEST_MBOX_INBOX == []
+
+ # Save the ids temporarily because of DetachedInstanceError
+ notification_id = notification.id
+ comment_id = notification.subject.id
+
+ self.logout()
+ self.login('otherperson', 'nosreprehto')
+
+ self.test_app.get(media_uri_slug + '/c/{0}/'.format(comment_id))
+
+ notification = Notification.query.filter_by(id=notification_id).first()
+
+ assert notification.seen == True
+
+ self.test_app.get(media_uri_slug + '/notifications/silence/')
+
+ subscription = CommentSubscription.query.filter_by(id=subscription_id)\
+ .first()
+
+ assert subscription.notify == False
+
+ notifications = Notification.query.filter_by(
+ user_id=user_id).all()
+
+ # User should not have been notified
+ assert len(notifications) == 1
diff --git a/mediagoblin/tests/test_oauth.py b/mediagoblin/tests/test_oauth.py
index 94ba5dab..ea3bd798 100644
--- a/mediagoblin/tests/test_oauth.py
+++ b/mediagoblin/tests/test_oauth.py
@@ -17,19 +17,22 @@
import json
import logging
+import pytest
from urlparse import parse_qs, urlparse
from mediagoblin import mg_globals
from mediagoblin.tools import template, pluginapi
-from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
_log = logging.getLogger(__name__)
class TestOAuth(object):
- def setUp(self):
- self.app = get_app()
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
self.db = mg_globals.database
self.pman = pluginapi.PluginManager()
@@ -40,14 +43,14 @@ class TestOAuth(object):
self.login()
def login(self):
- self.app.post(
- '/auth/login/', {
- 'username': self.user.username,
- 'password': self.user_password})
+ self.test_app.post(
+ '/auth/login/', {
+ 'username': self.user.username,
+ 'password': self.user_password})
def register_client(self, name, client_type, description=None,
- redirect_uri=''):
- return self.app.post(
+ redirect_uri=''):
+ return self.test_app.post(
'/oauth/client/register', {
'name': name,
'description': description,
@@ -59,8 +62,8 @@ class TestOAuth(object):
def test_1_public_client_registration_without_redirect_uri(self):
''' Test 'public' OAuth client registration without any redirect uri '''
- response = self.register_client(u'OMGOMGOMG', 'public',
- 'OMGOMG Apache License v2')
+ response = self.register_client(
+ u'OMGOMGOMG', 'public', 'OMGOMG Apache License v2')
ctx = self.get_context('oauth/client/register.html')
@@ -70,26 +73,30 @@ class TestOAuth(object):
assert response.status_int == 200
# Should display an error
- assert ctx['form'].redirect_uri.errors
+ assert len(ctx['form'].redirect_uri.errors)
# Should not pass through
assert not client
def test_2_successful_public_client_registration(self):
''' Successfully register a public client '''
- self.login()
- self.register_client(u'OMGOMG', 'public', 'OMG!',
- 'http://foo.example')
+ uri = 'http://foo.example'
+ self.register_client(
+ u'OMGOMG', 'public', 'OMG!', uri)
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.name == u'OMGOMG').first()
+ # redirect_uri should be set
+ assert client.redirect_uri == uri
+
# Client should have been registered
assert client
def test_3_successful_confidential_client_reg(self):
''' Register a confidential OAuth client '''
- response = self.register_client(u'GMOGMO', 'confidential', 'NO GMO!')
+ response = self.register_client(
+ u'GMOGMO', 'confidential', 'NO GMO!')
assert response.status_int == 302
@@ -103,15 +110,14 @@ class TestOAuth(object):
def test_4_authorize_confidential_client(self):
''' Authorize a confidential client as a logged in user '''
-
client = self.test_3_successful_confidential_client_reg()
client_identifier = client.identifier
redirect_uri = 'https://foo.example'
- response = self.app.get('/oauth/authorize', {
+ response = self.test_app.get('/oauth/authorize', {
'client_id': client.identifier,
- 'scope': 'admin',
+ 'scope': 'all',
'redirect_uri': redirect_uri})
# User-agent should NOT be redirected
@@ -122,7 +128,7 @@ class TestOAuth(object):
form = ctx['form']
# Short for client authorization post reponse
- capr = self.app.post(
+ capr = self.test_app.post(
'/oauth/client/authorize', {
'client_id': form.client_id.data,
'allow': 'Allow',
@@ -137,6 +143,7 @@ class TestOAuth(object):
return authorization_response, client_identifier
def get_code_from_redirect_uri(self, uri):
+ ''' Get the value of ?code= from an URI '''
return parse_qs(urlparse(uri).query)['code'][0]
def test_token_endpoint_successful_confidential_request(self):
@@ -148,7 +155,7 @@ class TestOAuth(object):
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.identifier == unicode(client_id)).first()
- token_res = self.app.get('/oauth/access_token?client_id={0}&\
+ token_res = self.test_app.get('/oauth/access_token?client_id={0}&\
code={1}&client_secret={2}'.format(client_id, code, client.secret))
assert token_res.status_int == 200
@@ -162,6 +169,11 @@ code={1}&client_secret={2}'.format(client_id, code, client.secret))
assert type(token_data['expires_in']) == int
assert token_data['expires_in'] > 0
+ # There should be a refresh token provided in the token data
+ assert len(token_data['refresh_token'])
+
+ return client_id, token_data
+
def test_token_endpont_missing_id_confidential_request(self):
''' Unsuccessful request against token endpoint, missing client_id '''
code_redirect, client_id = self.test_4_authorize_confidential_client()
@@ -171,7 +183,7 @@ code={1}&client_secret={2}'.format(client_id, code, client.secret))
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.identifier == unicode(client_id)).first()
- token_res = self.app.get('/oauth/access_token?\
+ token_res = self.test_app.get('/oauth/access_token?\
code={0}&client_secret={1}'.format(code, client.secret))
assert token_res.status_int == 200
@@ -181,4 +193,30 @@ code={0}&client_secret={1}'.format(code, client.secret))
assert 'error' in token_data
assert not 'access_token' in token_data
assert token_data['error'] == 'invalid_request'
- assert token_data['error_description'] == 'Missing client_id in request'
+ assert len(token_data['error_description'])
+
+ def test_refresh_token(self):
+ ''' Try to get a new access token using the refresh token '''
+ # Get an access token and a refresh token
+ client_id, token_data =\
+ self.test_token_endpoint_successful_confidential_request()
+
+ client = self.db.OAuthClient.query.filter(
+ self.db.OAuthClient.identifier == client_id).first()
+
+ token_res = self.test_app.get('/oauth/access_token',
+ {'refresh_token': token_data['refresh_token'],
+ 'client_id': client_id,
+ 'client_secret': client.secret
+ })
+
+ assert token_res.status_int == 200
+
+ new_token_data = json.loads(token_res.body)
+
+ assert not 'error' in new_token_data
+ assert 'access_token' in new_token_data
+ assert 'token_type' in new_token_data
+ assert 'expires_in' in new_token_data
+ assert type(new_token_data['expires_in']) == int
+ assert new_token_data['expires_in'] > 0
diff --git a/mediagoblin/tests/test_openid.py b/mediagoblin/tests/test_openid.py
new file mode 100644
index 00000000..23a2290e
--- /dev/null
+++ b/mediagoblin/tests/test_openid.py
@@ -0,0 +1,373 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+import urlparse
+import pkg_resources
+import pytest
+import mock
+
+openid_consumer = pytest.importorskip(
+ "openid.consumer.consumer")
+
+from mediagoblin import mg_globals
+from mediagoblin.db.base import Session
+from mediagoblin.db.models import User
+from mediagoblin.plugins.openid.models import OpenIDUserURL
+from mediagoblin.tests.tools import get_app, fixture_add_user
+from mediagoblin.tools import template
+
+# App with plugin enabled
+@pytest.fixture()
+def openid_plugin_app(request):
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests.auth_configs',
+ 'openid_appconfig.ini'))
+
+
+class TestOpenIDPlugin(object):
+ def _setup(self, openid_plugin_app, value=True, edit=False, delete=False):
+ if value:
+ response = openid_consumer.SuccessResponse(mock.Mock(), mock.Mock())
+ if edit or delete:
+ response.identity_url = u'http://add.myopenid.com'
+ else:
+ response.identity_url = u'http://real.myopenid.com'
+ self._finish_verification = mock.Mock(return_value=response)
+ else:
+ self._finish_verification = mock.Mock(return_value=False)
+
+ @mock.patch('mediagoblin.plugins.openid.views._response_email', mock.Mock(return_value=None))
+ @mock.patch('mediagoblin.plugins.openid.views._response_nickname', mock.Mock(return_value=None))
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ def _setup_start(self, openid_plugin_app, edit, delete):
+ if edit:
+ self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
+ '/edit/openid/finish/'))
+ elif delete:
+ self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
+ '/edit/openid/delete/finish/'))
+ else:
+ self._start_verification = mock.Mock(return_value=openid_plugin_app.post(
+ '/auth/openid/login/finish/'))
+ _setup_start(self, openid_plugin_app, edit, delete)
+
+ def test_bad_login(self, openid_plugin_app):
+ """ Test that attempts to login with invalid paramaters"""
+
+ # Test GET request for auth/register page
+ res = openid_plugin_app.get('/auth/register/').follow()
+
+ # Make sure it redirected to the correct place
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/login page
+ res = openid_plugin_app.get('/auth/login/')
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/openid/register page
+ res = openid_plugin_app.get('/auth/openid/register/')
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/openid/login/finish page
+ res = openid_plugin_app.get('/auth/openid/login/finish/')
+ res.follow()
+
+ # Correct redirect?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+
+ # Test GET request for auth/openid/login page
+ res = openid_plugin_app.get('/auth/openid/login/')
+
+ # Correct place?
+ assert 'mediagoblin/plugins/openid/login.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Try to login with an empty form
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/login/', {})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
+ form = context['login_form']
+ assert form.openid.errors == [u'This field is required.']
+
+ # Try to login with wrong form values
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': 'not_a_url.com'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
+ form = context['login_form']
+ assert form.openid.errors == [u'Please enter a valid url.']
+
+ # Should be no users in the db
+ assert User.query.count() == 0
+
+ # Phony OpenID URl
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': 'http://phoney.myopenid.com/'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/login.html']
+ form = context['login_form']
+ assert form.openid.errors == [u'Sorry, the OpenID server could not be found']
+
+ def test_login(self, openid_plugin_app):
+ """Tests that test login and registion with openid"""
+ # Test finish_login redirects correctly when response = False
+ self._setup(openid_plugin_app, False)
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_non_response():
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': 'http://phoney.myopenid.com/'})
+ res.follow()
+
+ # Correct Place?
+ assert urlparse.urlsplit(res.location)[2] == '/auth/openid/login/'
+ assert 'mediagoblin/plugins/openid/login.html' in template.TEMPLATE_TEST_CONTEXT
+ _test_non_response()
+
+ # Test login with new openid
+ # Need to clear_test_template_context before calling _setup
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app)
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_new_user():
+ openid_plugin_app.post(
+ '/auth/openid/login/', {
+ 'openid': u'http://real.myopenid.com'})
+
+ # Right place?
+ assert 'mediagoblin/auth/register.html' in template.TEMPLATE_TEST_CONTEXT
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
+ register_form = context['register_form']
+
+ # Register User
+ res = openid_plugin_app.post(
+ '/auth/openid/register/', {
+ 'openid': register_form.openid.data,
+ 'username': u'chris',
+ 'email': u'chris@example.com'})
+ res.follow()
+
+ # Correct place?
+ assert urlparse.urlsplit(res.location)[2] == '/u/chris/'
+ assert 'mediagoblin/user_pages/user.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # No need to test if user is in logged in and verification email
+ # awaits, since openid uses the register_user function which is
+ # tested in test_auth
+
+ # Logout User
+ openid_plugin_app.get('/auth/logout')
+
+ # Get user and detach from session
+ test_user = mg_globals.database.User.query.filter_by(
+ username=u'chris').first()
+ Session.expunge(test_user)
+
+ # Log back in
+ # Could not get it to work by 'POST'ing to /auth/openid/login/
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/auth/openid/login/finish/', {
+ 'openid': u'http://real.myopenid.com'})
+ res.follow()
+
+ assert urlparse.urlsplit(res.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Make sure user is in the session
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
+ session = context['request'].session
+ assert session['user_id'] == unicode(test_user.id)
+
+ _test_new_user()
+
+ # Test register with empty form
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/register/', {})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
+ register_form = context['register_form']
+
+ assert register_form.openid.errors == [u'This field is required.']
+ assert register_form.email.errors == [u'This field is required.']
+ assert register_form.username.errors == [u'This field is required.']
+
+ # Try to register with existing username and email
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/auth/openid/register/', {
+ 'openid': 'http://real.myopenid.com',
+ 'email': 'chris@example.com',
+ 'username': 'chris'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
+ register_form = context['register_form']
+
+ assert register_form.username.errors == [u'Sorry, a user with that name already exists.']
+ assert register_form.email.errors == [u'Sorry, a user with that email address already exists.']
+ assert register_form.openid.errors == [u'Sorry, an account is already registered to that OpenID.']
+
+ def test_add_delete(self, openid_plugin_app):
+ """Test adding and deleting openids"""
+ # Add user
+ test_user = fixture_add_user(password='')
+ openid = OpenIDUserURL()
+ openid.openid_url = 'http://real.myopenid.com'
+ openid.user_id = test_user.id
+ openid.save()
+
+ # Log user in
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app)
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _login_user():
+ openid_plugin_app.post(
+ '/auth/openid/login/finish/', {
+ 'openid': u'http://real.myopenid.com'})
+
+ _login_user()
+
+ # Try and delete only OpenID url
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/delete/', {
+ 'openid': 'http://real.myopenid.com'})
+ assert 'mediagoblin/plugins/openid/delete.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # Add OpenID to user
+ # Empty form
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/', {})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
+ form = context['form']
+ assert form.openid.errors == [u'This field is required.']
+
+ # Try with a bad url
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/edit/openid/', {
+ 'openid': u'not_a_url.com'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
+ form = context['form']
+ assert form.openid.errors == [u'Please enter a valid url.']
+
+ # Try with a url that's already registered
+ template.clear_test_template_context()
+ openid_plugin_app.post(
+ '/edit/openid/', {
+ 'openid': 'http://real.myopenid.com'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/add.html']
+ form = context['form']
+ assert form.openid.errors == [u'Sorry, an account is already registered to that OpenID.']
+
+ # Test adding openid to account
+ # Need to clear_test_template_context before calling _setup
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app, edit=True)
+
+ # Need to remove openid_url from db because it was added at setup
+ openid = OpenIDUserURL.query.filter_by(
+ openid_url=u'http://add.myopenid.com')
+ openid.delete()
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_add():
+ # Successful add
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/', {
+ 'openid': u'http://add.myopenid.com'})
+ res.follow()
+
+ # Correct place?
+ assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
+ assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # OpenID Added?
+ new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
+ openid_url=u'http://add.myopenid.com').first()
+ assert new_openid
+
+ _test_add()
+
+ # Test deleting openid from account
+ # Need to clear_test_template_context before calling _setup
+ template.clear_test_template_context()
+ self._setup(openid_plugin_app, delete=True)
+
+ # Need to add OpenID back to user because it was deleted during
+ # patch
+ openid = OpenIDUserURL()
+ openid.openid_url = 'http://add.myopenid.com'
+ openid.user_id = test_user.id
+ openid.save()
+
+ @mock.patch('mediagoblin.plugins.openid.views._finish_verification', self._finish_verification)
+ @mock.patch('mediagoblin.plugins.openid.views._start_verification', self._start_verification)
+ def _test_delete(self, test_user):
+ # Delete openid from user
+ # Create another user to test deleting OpenID that doesn't belong to them
+ new_user = fixture_add_user(username='newman')
+ openid = OpenIDUserURL()
+ openid.openid_url = 'http://realfake.myopenid.com/'
+ openid.user_id = new_user.id
+ openid.save()
+
+ # Try and delete OpenID url that isn't the users
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/delete/', {
+ 'openid': 'http://realfake.myopenid.com/'})
+ context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/plugins/openid/delete.html']
+ form = context['form']
+ assert form.openid.errors == [u'That OpenID is not registered to this account.']
+
+ # Delete OpenID
+ # Kind of weird to POST to delete/finish
+ template.clear_test_template_context()
+ res = openid_plugin_app.post(
+ '/edit/openid/delete/finish/', {
+ 'openid': u'http://add.myopenid.com'})
+ res.follow()
+
+ # Correct place?
+ assert urlparse.urlsplit(res.location)[2] == '/edit/account/'
+ assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
+
+ # OpenID deleted?
+ new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
+ openid_url=u'http://add.myopenid.com').first()
+ assert not new_openid
+
+ _test_delete(self, test_user)
diff --git a/mediagoblin/tests/test_paste.ini b/mediagoblin/tests/test_paste.ini
index d7c18642..a9595432 100644
--- a/mediagoblin/tests/test_paste.ini
+++ b/mediagoblin/tests/test_paste.ini
@@ -6,27 +6,30 @@ use = egg:Paste#urlmap
/ = mediagoblin
/mgoblin_media/ = publicstore_serve
/test_static/ = mediagoblin_static
+/theme_static/ = theme_static
+/plugin_static/ = plugin_static
[app:mediagoblin]
use = egg:mediagoblin#app
-filter-with = beaker
-config = %(here)s/test_mgoblin_app.ini
+config = %(here)s/mediagoblin.ini
[app:publicstore_serve]
use = egg:Paste#static
-document_root = %(here)s/test_user_dev/media/public
+document_root = %(here)s/user_dev/media/public
[app:mediagoblin_static]
use = egg:Paste#static
document_root = %(here)s/mediagoblin/static/
-[filter:beaker]
-use = egg:Beaker#beaker_session
-cache_dir = %(here)s/test_user_dev/beaker
-beaker.session.key = mediagoblin
-# beaker.session.secret = somesupersecret
-beaker.session.data_dir = %(here)s/test_user_dev/beaker/sessions/data
-beaker.session.lock_dir = %(here)s/test_user_dev/beaker/sessions/lock
+[app:theme_static]
+use = egg:Paste#static
+document_root = %(here)s/user_dev/theme_static/
+cache_max_age = 86400
+
+[app:plugin_static]
+use = egg:Paste#static
+document_root = %(here)s/user_dev/plugin_static/
+cache_max_age = 86400
[celery]
CELERY_ALWAYS_EAGER = true
diff --git a/mediagoblin/tests/test_pdf.py b/mediagoblin/tests/test_pdf.py
new file mode 100644
index 00000000..b4d1940a
--- /dev/null
+++ b/mediagoblin/tests/test_pdf.py
@@ -0,0 +1,39 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+import tempfile
+import shutil
+import os
+import pytest
+
+from mediagoblin.media_types.pdf.processing import (
+ pdf_info, check_prerequisites, create_pdf_thumb)
+from .resources import GOOD_PDF as GOOD
+
+
+@pytest.mark.skipif("not check_prerequisites()")
+def test_pdf():
+ good_dict = {'pdf_version_major': 1, 'pdf_title': '',
+ 'pdf_page_size_width': 612, 'pdf_author': '',
+ 'pdf_keywords': '', 'pdf_pages': 10,
+ 'pdf_producer': 'dvips + GNU Ghostscript 7.05',
+ 'pdf_version_minor': 3,
+ 'pdf_creator': 'LaTeX with hyperref package',
+ 'pdf_page_size_height': 792}
+ assert pdf_info(GOOD) == good_dict
+ temp_dir = tempfile.mkdtemp()
+ create_pdf_thumb(GOOD, os.path.join(temp_dir, 'good_256_256.png'), 256, 256)
+ shutil.rmtree(temp_dir)
diff --git a/mediagoblin/tests/test_piwigo.py b/mediagoblin/tests/test_piwigo.py
new file mode 100644
index 00000000..16ad0111
--- /dev/null
+++ b/mediagoblin/tests/test_piwigo.py
@@ -0,0 +1,71 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+import pytest
+from .tools import fixture_add_user
+
+
+XML_PREFIX = "<?xml version='1.0' encoding='utf-8'?>\n"
+
+
+class Test_PWG(object):
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
+
+ fixture_add_user()
+
+ self.username = u"chris"
+ self.password = "toast"
+
+ def do_post(self, method, params):
+ params["method"] = method
+ return self.test_app.post("/api/piwigo/ws.php", params)
+
+ def do_get(self, method, params=None):
+ if params is None:
+ params = {}
+ params["method"] = method
+ return self.test_app.get("/api/piwigo/ws.php", params)
+
+ def test_session(self):
+ resp = self.do_post("pwg.session.login",
+ {"username": u"nouser", "password": "wrong"})
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="fail"><err code="999" msg="Invalid username/password"/></rsp>'
+
+ resp = self.do_post("pwg.session.login",
+ {"username": self.username, "password": "wrong"})
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="fail"><err code="999" msg="Invalid username/password"/></rsp>'
+
+ resp = self.do_get("pwg.session.getStatus")
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="ok"><username>guest</username></rsp>'
+
+ resp = self.do_post("pwg.session.login",
+ {"username": self.username, "password": self.password})
+ assert resp.body == XML_PREFIX + '<rsp stat="ok">1</rsp>'
+
+ resp = self.do_get("pwg.session.getStatus")
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="ok"><username>chris</username></rsp>'
+
+ self.do_get("pwg.session.logout")
+
+ resp = self.do_get("pwg.session.getStatus")
+ assert resp.body == XML_PREFIX \
+ + '<rsp stat="ok"><username>guest</username></rsp>'
diff --git a/mediagoblin/tests/test_pluginapi.py b/mediagoblin/tests/test_pluginapi.py
index 315a95da..eae0ce15 100644
--- a/mediagoblin/tests/test_pluginapi.py
+++ b/mediagoblin/tests/test_pluginapi.py
@@ -14,12 +14,22 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
+import json
import sys
+
from configobj import ConfigObj
+import pytest
+import pkg_resources
+from validate import VdtTypeError
+
from mediagoblin import mg_globals
from mediagoblin.init.plugins import setup_plugins
+from mediagoblin.init.config import read_mediagoblin_config
+from mediagoblin.gmg_commands.assetlink import link_plugin_assets
from mediagoblin.tools import pluginapi
-from nose.tools import eq_
+from mediagoblin.tests.tools import get_app
+from mediagoblin.tools.common import CollectingPrinter
def with_cleanup(*modules_to_delete):
@@ -97,7 +107,7 @@ def test_no_plugins():
setup_plugins()
# Make sure we didn't load anything.
- eq_(len(pman.plugins), 0)
+ assert len(pman.plugins) == 0
@with_cleanup('mediagoblin.plugins.sampleplugin')
@@ -117,14 +127,14 @@ def test_one_plugin():
setup_plugins()
# Make sure we only found one plugin
- eq_(len(pman.plugins), 1)
+ assert len(pman.plugins) == 1
# Make sure the plugin is the one we think it is.
- eq_(pman.plugins[0], 'mediagoblin.plugins.sampleplugin')
+ assert pman.plugins[0] == 'mediagoblin.plugins.sampleplugin'
# Make sure there was one hook registered
- eq_(len(pman.hooks), 1)
+ assert len(pman.hooks) == 1
# Make sure _setup_plugin_called was called once
import mediagoblin.plugins.sampleplugin
- eq_(mediagoblin.plugins.sampleplugin._setup_plugin_called, 1)
+ assert mediagoblin.plugins.sampleplugin._setup_plugin_called == 1
@with_cleanup('mediagoblin.plugins.sampleplugin')
@@ -145,14 +155,14 @@ def test_same_plugin_twice():
setup_plugins()
# Make sure we only found one plugin
- eq_(len(pman.plugins), 1)
+ assert len(pman.plugins) == 1
# Make sure the plugin is the one we think it is.
- eq_(pman.plugins[0], 'mediagoblin.plugins.sampleplugin')
+ assert pman.plugins[0] == 'mediagoblin.plugins.sampleplugin'
# Make sure there was one hook registered
- eq_(len(pman.hooks), 1)
+ assert len(pman.hooks) == 1
# Make sure _setup_plugin_called was called once
import mediagoblin.plugins.sampleplugin
- eq_(mediagoblin.plugins.sampleplugin._setup_plugin_called, 1)
+ assert mediagoblin.plugins.sampleplugin._setup_plugin_called == 1
@with_cleanup()
@@ -172,4 +182,285 @@ def test_disabled_plugin():
setup_plugins()
# Make sure we didn't load the plugin
- eq_(len(pman.plugins), 0)
+ assert len(pman.plugins) == 0
+
+
+CONFIG_ALL_CALLABLES = [
+ ('mediagoblin', {}, []),
+ ('plugins', {}, [
+ ('mediagoblin.tests.testplugins.callables1', {}, []),
+ ('mediagoblin.tests.testplugins.callables2', {}, []),
+ ('mediagoblin.tests.testplugins.callables3', {}, []),
+ ])
+ ]
+
+
+@with_cleanup()
+def test_hook_handle():
+ """
+ Test the hook_handle method
+ """
+ cfg = build_config(CONFIG_ALL_CALLABLES)
+
+ mg_globals.app_config = cfg['mediagoblin']
+ mg_globals.global_config = cfg
+
+ setup_plugins()
+
+ # Just one hook provided
+ call_log = []
+ assert pluginapi.hook_handle(
+ "just_one", call_log) == "Called just once"
+ assert call_log == ["expect this one call"]
+
+ # Nothing provided and unhandled not okay
+ call_log = []
+ pluginapi.hook_handle(
+ "nothing_handling", call_log) == None
+ assert call_log == []
+
+ # Nothing provided and unhandled okay
+ call_log = []
+ assert pluginapi.hook_handle(
+ "nothing_handling", call_log, unhandled_okay=True) is None
+ assert call_log == []
+
+ # Multiple provided, go with the first!
+ call_log = []
+ assert pluginapi.hook_handle(
+ "multi_handle", call_log) == "the first returns"
+ assert call_log == ["Hi, I'm the first"]
+
+ # Multiple provided, one has CantHandleIt
+ call_log = []
+ assert pluginapi.hook_handle(
+ "multi_handle_with_canthandle",
+ call_log) == "the second returns"
+ assert call_log == ["Hi, I'm the second"]
+
+
+@with_cleanup()
+def test_hook_runall():
+ """
+ Test the hook_runall method
+ """
+ cfg = build_config(CONFIG_ALL_CALLABLES)
+
+ mg_globals.app_config = cfg['mediagoblin']
+ mg_globals.global_config = cfg
+
+ setup_plugins()
+
+ # Just one hook, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "just_one", call_log) == ["Called just once"]
+ assert call_log == ["expect this one call"]
+
+ # None provided, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "nothing_handling", call_log) == []
+ assert call_log == []
+
+ # Multiple provided, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "multi_handle", call_log) == [
+ "the first returns",
+ "the second returns",
+ "the third returns",
+ ]
+ assert call_log == [
+ "Hi, I'm the first",
+ "Hi, I'm the second",
+ "Hi, I'm the third"]
+
+ # Multiple provided, one has CantHandleIt, check results
+ call_log = []
+ assert pluginapi.hook_runall(
+ "multi_handle_with_canthandle", call_log) == [
+ "the second returns",
+ "the third returns",
+ ]
+ assert call_log == [
+ "Hi, I'm the second",
+ "Hi, I'm the third"]
+
+
+@with_cleanup()
+def test_hook_transform():
+ """
+ Test the hook_transform method
+ """
+ cfg = build_config(CONFIG_ALL_CALLABLES)
+
+ mg_globals.app_config = cfg['mediagoblin']
+ mg_globals.global_config = cfg
+
+ setup_plugins()
+
+ assert pluginapi.hook_transform(
+ "expand_tuple", (-1, 0)) == (-1, 0, 1, 2, 3)
+
+
+def test_plugin_config():
+ """
+ Make sure plugins can set up their own config
+ """
+ config, validation_result = read_mediagoblin_config(
+ pkg_resources.resource_filename(
+ 'mediagoblin.tests', 'appconfig_plugin_specs.ini'))
+
+ pluginspec_section = config['plugins'][
+ 'mediagoblin.tests.testplugins.pluginspec']
+ assert pluginspec_section['some_string'] == 'not blork'
+ assert pluginspec_section['dont_change_me'] == 'still the default'
+
+ # Make sure validation works... this should be an error
+ assert isinstance(
+ validation_result[
+ 'plugins'][
+ 'mediagoblin.tests.testplugins.pluginspec'][
+ 'some_int'],
+ VdtTypeError)
+
+ # the callables thing shouldn't really have anything though.
+ assert len(config['plugins'][
+ 'mediagoblin.tests.testplugins.callables1']) == 0
+
+
+@pytest.fixture()
+def context_modified_app(request):
+ """
+ Get a MediaGoblin app fixture using appconfig_context_modified.ini
+ """
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests', 'appconfig_context_modified.ini'))
+
+
+def test_modify_context(context_modified_app):
+ """
+ Test that we can modify both the view/template specific and
+ global contexts for templates.
+ """
+ # Specific thing passed into a page
+ result = context_modified_app.get("/modify_context/specific/")
+ assert result.body.strip() == """Specific page!
+
+specific thing: in yer specificpage
+global thing: globally appended!
+something: orother
+doubleme: happyhappy"""
+
+ # General test, should have global context variable only
+ result = context_modified_app.get("/modify_context/")
+ assert result.body.strip() == """General page!
+
+global thing: globally appended!
+lol: cats
+doubleme: joyjoy"""
+
+
+@pytest.fixture()
+def static_plugin_app(request):
+ """
+ Get a MediaGoblin app fixture using appconfig_static_plugin.ini
+ """
+ return get_app(
+ request,
+ mgoblin_config=pkg_resources.resource_filename(
+ 'mediagoblin.tests', 'appconfig_static_plugin.ini'))
+
+
+def test_plugin_assetlink(static_plugin_app):
+ """
+ Test that the assetlink command works correctly
+ """
+ linked_assets_dir = mg_globals.app_config['plugin_linked_assets_dir']
+ plugin_link_dir = os.path.join(
+ linked_assets_dir.rstrip(os.path.sep),
+ 'staticstuff')
+
+ plugin_statics = pluginapi.hook_runall("static_setup")
+ assert len(plugin_statics) == 1
+ plugin_static = plugin_statics[0]
+
+ def run_assetlink():
+ printer = CollectingPrinter()
+
+ link_plugin_assets(
+ plugin_static, linked_assets_dir, printer)
+
+ return printer
+
+ # it shouldn't exist yet
+ assert not os.path.lexists(plugin_link_dir)
+
+ # link dir doesn't exist, link it
+ result = run_assetlink().collection[0]
+ assert result == \
+ 'Linked asset directory for plugin "staticstuff":\n %s\nto:\n %s\n' % (
+ plugin_static.file_path.rstrip(os.path.sep),
+ plugin_link_dir)
+ assert os.path.lexists(plugin_link_dir)
+ assert os.path.islink(plugin_link_dir)
+ assert os.path.realpath(plugin_link_dir) == plugin_static.file_path
+
+ # link dir exists, leave it alone
+ # (and it should exist still since we just ran it..)
+ result = run_assetlink().collection[0]
+ assert result == 'Skipping "staticstuff"; already set up.\n'
+ assert os.path.lexists(plugin_link_dir)
+ assert os.path.islink(plugin_link_dir)
+ assert os.path.realpath(plugin_link_dir) == plugin_static.file_path
+
+ # link dir exists, is a symlink to somewhere else (re-link)
+ junk_file_path = os.path.join(
+ linked_assets_dir.rstrip(os.path.sep),
+ 'junk.txt')
+ with file(junk_file_path, 'w') as junk_file:
+ junk_file.write('barf')
+
+ os.unlink(plugin_link_dir)
+ os.symlink(junk_file_path, plugin_link_dir)
+
+ result = run_assetlink().combined_string
+ assert result == """Old link found for "staticstuff"; removing.
+Linked asset directory for plugin "staticstuff":
+ %s
+to:
+ %s
+""" % (plugin_static.file_path.rstrip(os.path.sep), plugin_link_dir)
+ assert os.path.lexists(plugin_link_dir)
+ assert os.path.islink(plugin_link_dir)
+ assert os.path.realpath(plugin_link_dir) == plugin_static.file_path
+
+ # link dir exists, but is a non-symlink
+ os.unlink(plugin_link_dir)
+ with file(plugin_link_dir, 'w') as clobber_file:
+ clobber_file.write('clobbered!')
+
+ result = run_assetlink().collection[0]
+ assert result == 'Could not link "staticstuff": %s exists and is not a symlink\n' % (
+ plugin_link_dir)
+
+ with file(plugin_link_dir, 'r') as clobber_file:
+ assert clobber_file.read() == 'clobbered!'
+
+
+def test_plugin_staticdirect(static_plugin_app):
+ """
+ Test that the staticdirect utilities pull up the right things
+ """
+ result = json.loads(
+ static_plugin_app.get('/staticstuff/').body)
+
+ assert len(result) == 2
+
+ assert result['mgoblin_bunny_pic'] == '/test_static/images/bunny_pic.png'
+ assert result['plugin_bunny_css'] == \
+ '/plugin_static/staticstuff/css/bunnify.css'
+
diff --git a/mediagoblin/tests/test_processing.py b/mediagoblin/tests/test_processing.py
index fe8489aa..591add96 100644
--- a/mediagoblin/tests/test_processing.py
+++ b/mediagoblin/tests/test_processing.py
@@ -1,7 +1,5 @@
#!/usr/bin/env python
-from nose.tools import assert_equal
-
from mediagoblin import processing
class TestProcessing(object):
@@ -10,7 +8,7 @@ class TestProcessing(object):
result = builder.fill(format)
if output is None:
return result
- assert_equal(output, result)
+ assert output == result
def test_easy_filename_fill(self):
self.run_fill('/home/user/foo.TXT', '{basename}bar{ext}', 'foobar.txt')
diff --git a/mediagoblin/tests/test_session.py b/mediagoblin/tests/test_session.py
new file mode 100644
index 00000000..78d790eb
--- /dev/null
+++ b/mediagoblin/tests/test_session.py
@@ -0,0 +1,30 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools import session
+
+def test_session():
+ sess = session.Session()
+ assert not sess
+ assert not sess.is_updated()
+ sess['user_id'] = 27
+ assert sess
+ assert not sess.is_updated()
+ sess.save()
+ assert sess.is_updated()
+ sess.delete()
+ assert not sess
+ assert sess.is_updated()
diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py
index 61326ae9..f6f1d18f 100644
--- a/mediagoblin/tests/test_storage.py
+++ b/mediagoblin/tests/test_storage.py
@@ -18,7 +18,7 @@
import os
import tempfile
-from nose.tools import assert_raises, assert_equal, assert_true
+import pytest
from werkzeug.utils import secure_filename
from mediagoblin import storage
@@ -41,10 +41,8 @@ def test_clean_listy_filepath():
assert storage.clean_listy_filepath(
['../../../etc/', 'passwd']) == expected
- assert_raises(
- storage.InvalidFilepath,
- storage.clean_listy_filepath,
- ['../../', 'linooks.jpg'])
+ with pytest.raises(storage.InvalidFilepath):
+ storage.clean_listy_filepath(['../../', 'linooks.jpg'])
class FakeStorageSystem():
@@ -78,10 +76,10 @@ def test_storage_system_from_config():
'garbage_arg': 'garbage_arg',
'storage_class':
'mediagoblin.tests.test_storage:FakeStorageSystem'})
- assert_equal(this_storage.foobie, 'eiboof')
- assert_equal(this_storage.blech, 'hcelb')
- assert_equal(unicode(this_storage.__class__),
- u'mediagoblin.tests.test_storage.FakeStorageSystem')
+ assert this_storage.foobie == 'eiboof'
+ assert this_storage.blech == 'hcelb'
+ assert unicode(this_storage.__class__) == \
+ u'mediagoblin.tests.test_storage.FakeStorageSystem'
##########################
@@ -89,7 +87,7 @@ def test_storage_system_from_config():
##########################
def get_tmp_filestorage(mount_url=None, fake_remote=False):
- tmpdir = tempfile.mkdtemp()
+ tmpdir = tempfile.mkdtemp(prefix="test_gmg_storage")
if fake_remote:
this_storage = FakeRemoteStorage(tmpdir, mount_url)
else:
@@ -97,6 +95,14 @@ def get_tmp_filestorage(mount_url=None, fake_remote=False):
return tmpdir, this_storage
+def cleanup_storage(this_storage, tmpdir, *paths):
+ for p in paths:
+ while p:
+ assert this_storage.delete_dir(p) == True
+ p.pop(-1)
+ os.rmdir(tmpdir)
+
+
def test_basic_storage__resolve_filepath():
tmpdir, this_storage = get_tmp_filestorage()
@@ -108,11 +114,13 @@ def test_basic_storage__resolve_filepath():
assert result == os.path.join(
tmpdir, 'etc/passwd')
- assert_raises(
+ pytest.raises(
storage.InvalidFilepath,
this_storage._resolve_filepath,
['../../', 'etc', 'passwd'])
+ cleanup_storage(this_storage, tmpdir)
+
def test_basic_storage_file_exists():
tmpdir, this_storage = get_tmp_filestorage()
@@ -126,6 +134,9 @@ def test_basic_storage_file_exists():
assert not this_storage.file_exists(['dir1', 'dir2', 'thisfile.lol'])
assert not this_storage.file_exists(['dnedir1', 'dnedir2', 'somefile.lol'])
+ this_storage.delete_file(['dir1', 'dir2', 'filename.txt'])
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def test_basic_storage_get_unique_filepath():
tmpdir, this_storage = get_tmp_filestorage()
@@ -146,6 +157,9 @@ def test_basic_storage_get_unique_filepath():
assert len(new_filename) > len('filename.txt')
assert new_filename == secure_filename(new_filename)
+ os.remove(filename)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def test_basic_storage_get_file():
tmpdir, this_storage = get_tmp_filestorage()
@@ -182,6 +196,11 @@ def test_basic_storage_get_file():
with this_storage.get_file(['testydir', 'testyfile.txt']) as testyfile:
assert testyfile.read() == 'testy file! so testy.'
+ this_storage.delete_file(filepath)
+ this_storage.delete_file(new_filepath)
+ this_storage.delete_file(['testydir', 'testyfile.txt'])
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'], ['testydir'])
+
def test_basic_storage_delete_file():
tmpdir, this_storage = get_tmp_filestorage()
@@ -196,19 +215,24 @@ def test_basic_storage_delete_file():
assert os.path.exists(
os.path.join(tmpdir, 'dir1/dir2/ourfile.txt'))
+ assert this_storage.delete_dir(['dir1', 'dir2']) == False
this_storage.delete_file(filepath)
+ assert this_storage.delete_dir(['dir1', 'dir2']) == True
assert not os.path.exists(
os.path.join(tmpdir, 'dir1/dir2/ourfile.txt'))
+ cleanup_storage(this_storage, tmpdir, ['dir1'])
+
def test_basic_storage_url_for_file():
# Not supplying a base_url should actually just bork.
tmpdir, this_storage = get_tmp_filestorage()
- assert_raises(
+ pytest.raises(
storage.NoWebServing,
this_storage.file_url,
['dir1', 'dir2', 'filename.txt'])
+ cleanup_storage(this_storage, tmpdir)
# base_url without domain
tmpdir, this_storage = get_tmp_filestorage('/media/')
@@ -216,6 +240,7 @@ def test_basic_storage_url_for_file():
['dir1', 'dir2', 'filename.txt'])
expected = '/media/dir1/dir2/filename.txt'
assert result == expected
+ cleanup_storage(this_storage, tmpdir)
# base_url with domain
tmpdir, this_storage = get_tmp_filestorage(
@@ -224,6 +249,7 @@ def test_basic_storage_url_for_file():
['dir1', 'dir2', 'filename.txt'])
expected = 'http://media.example.org/ourmedia/dir1/dir2/filename.txt'
assert result == expected
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_get_local_path():
@@ -237,10 +263,13 @@ def test_basic_storage_get_local_path():
assert result == expected
+ cleanup_storage(this_storage, tmpdir)
+
def test_basic_storage_is_local():
tmpdir, this_storage = get_tmp_filestorage()
assert this_storage.local_storage is True
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_copy_locally():
@@ -255,9 +284,14 @@ def test_basic_storage_copy_locally():
new_file_dest = os.path.join(dest_tmpdir, 'file2.txt')
this_storage.copy_locally(filepath, new_file_dest)
+ this_storage.delete_file(filepath)
assert file(new_file_dest).read() == 'Testing this file'
+ os.remove(new_file_dest)
+ os.rmdir(dest_tmpdir)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def _test_copy_local_to_storage_works(tmpdir, this_storage):
local_filename = tempfile.mktemp()
@@ -267,10 +301,15 @@ def _test_copy_local_to_storage_works(tmpdir, this_storage):
this_storage.copy_local_to_storage(
local_filename, ['dir1', 'dir2', 'copiedto.txt'])
+ os.remove(local_filename)
+
assert file(
os.path.join(tmpdir, 'dir1/dir2/copiedto.txt'),
'r').read() == 'haha'
+ this_storage.delete_file(['dir1', 'dir2', 'copiedto.txt'])
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+
def test_basic_storage_copy_local_to_storage():
tmpdir, this_storage = get_tmp_filestorage()
diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py
index fc3d8c83..ac941063 100644
--- a/mediagoblin/tests/test_submission.py
+++ b/mediagoblin/tests/test_submission.py
@@ -20,28 +20,17 @@ sys.setdefaultencoding('utf-8')
import urlparse
import os
+import pytest
-from nose.tools import assert_equal, assert_true
-from pkg_resources import resource_filename
-
-from mediagoblin.tests.tools import get_app, \
- fixture_add_user
+from mediagoblin.tests.tools import fixture_add_user
from mediagoblin import mg_globals
from mediagoblin.db.models import MediaEntry
from mediagoblin.tools import template
-from mediagoblin.media_types.image import MEDIA_MANAGER as img_MEDIA_MANAGER
-
-def resource(filename):
- return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
-
+from mediagoblin.media_types.image import ImageMediaManager
+from mediagoblin.media_types.pdf.processing import check_prerequisites as pdf_check_prerequisites
-GOOD_JPG = resource('good.jpg')
-GOOD_PNG = resource('good.png')
-EVIL_FILE = resource('evil')
-EVIL_JPG = resource('evil.jpg')
-EVIL_PNG = resource('evil.png')
-BIG_BLUE = resource('bigblue.png')
-from .test_exif import GPS_JPG
+from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
+ BIG_BLUE, GOOD_PDF, GPS_JPG
GOOD_TAG_STRING = u'yin,yang'
BAD_TAG_STRING = unicode('rage,' + 'f' * 26 + 'u' * 26)
@@ -51,8 +40,9 @@ REQUEST_CONTEXT = ['mediagoblin/user_pages/user.html', 'request']
class TestSubmission:
- def setUp(self):
- self.test_app = get_app(dump_old_app=False)
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
+ self.test_app = test_app
# TODO: Possibly abstract into a decorator like:
# @as_authenticated_user('chris')
@@ -87,28 +77,28 @@ class TestSubmission:
return {'upload_files': [('file', filename)]}
def check_comments(self, request, media_id, count):
- comments = request.db.MediaComment.find({'media_entry': media_id})
- assert_equal(count, len(list(comments)))
+ comments = request.db.MediaComment.query.filter_by(media_entry=media_id)
+ assert count == len(list(comments))
def test_missing_fields(self):
# Test blank form
# ---------------
response, form = self.do_post({}, *FORM_CONTEXT)
- assert_equal(form.file.errors, [u'You must provide a file.'])
+ assert form.file.errors == [u'You must provide a file.']
# Test blank file
# ---------------
response, form = self.do_post({'title': u'test title'}, *FORM_CONTEXT)
- assert_equal(form.file.errors, [u'You must provide a file.'])
+ assert form.file.errors == [u'You must provide a file.']
def check_url(self, response, path):
- assert_equal(urlparse.urlsplit(response.location)[2], path)
+ assert urlparse.urlsplit(response.location)[2] == path
def check_normal_upload(self, title, filename):
response, context = self.do_post({'title': title}, do_follow=True,
**self.upload_data(filename))
self.check_url(response, '/u/{0}/'.format(self.test_user.username))
- assert_true('mediagoblin/user_pages/user.html' in context)
+ assert 'mediagoblin/user_pages/user.html' in context
# Make sure the media view is at least reachable, logged in...
url = '/u/{0}/m/{1}/'.format(self.test_user.username,
title.lower().replace(' ', '-'))
@@ -123,10 +113,18 @@ class TestSubmission:
def test_normal_png(self):
self.check_normal_upload(u'Normal upload 2', GOOD_PNG)
+ @pytest.mark.skipif("not pdf_check_prerequisites()")
+ def test_normal_pdf(self):
+ response, context = self.do_post({'title': u'Normal upload 3 (pdf)'},
+ do_follow=True,
+ **self.upload_data(GOOD_PDF))
+ self.check_url(response, '/u/{0}/'.format(self.test_user.username))
+ assert 'mediagoblin/user_pages/user.html' in context
+
def check_media(self, request, find_data, count=None):
- media = MediaEntry.find(find_data)
+ media = MediaEntry.query.filter_by(**find_data)
if count is not None:
- assert_equal(media.count(), count)
+ assert media.count() == count
if count == 0:
return
return media[0]
@@ -151,10 +149,10 @@ class TestSubmission:
'tags': BAD_TAG_STRING},
*FORM_CONTEXT,
**self.upload_data(GOOD_JPG))
- assert_equal(form.tags.errors, [
+ assert form.tags.errors == [
u'Tags must be shorter than 50 characters. ' \
'Tags that are too long: ' \
- 'ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu'])
+ 'ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu']
def test_delete(self):
response, request = self.do_post({'title': u'Balanced Goblin'},
@@ -173,7 +171,7 @@ class TestSubmission:
'slug': u"Balanced=Goblin",
'tags': u''})
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
- assert_equal(media.slug, u"balanced-goblin")
+ assert media.slug == u"balanced-goblin"
# Add a comment, so we can test for its deletion later.
self.check_comments(request, media_id, 0)
@@ -207,7 +205,7 @@ class TestSubmission:
response, form = self.do_post({'title': u'Malicious Upload 1'},
*FORM_CONTEXT,
**self.upload_data(EVIL_FILE))
- assert_equal(len(form.file.errors), 1)
+ assert len(form.file.errors) == 1
assert 'Sorry, I don\'t support that file type :(' == \
str(form.file.errors[0])
@@ -220,8 +218,9 @@ class TestSubmission:
**self.upload_data(GOOD_JPG))
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
- assert_equal(media.media_type, u'mediagoblin.media_types.image')
- assert_equal(media.media_manager, img_MEDIA_MANAGER)
+ assert media.media_type == u'mediagoblin.media_types.image'
+ assert isinstance(media.media_manager, ImageMediaManager)
+ assert media.media_manager.entry == media
def test_sniffing(self):
@@ -241,8 +240,8 @@ class TestSubmission:
request = context['request']
- media = request.db.MediaEntry.find_one({
- u'title': u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE'})
+ media = request.db.MediaEntry.query.filter_by(
+ title=u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE').first()
assert media.media_type == 'mediagoblin.media_types.image'
@@ -253,9 +252,9 @@ class TestSubmission:
response, context = self.do_post({'title': title}, do_follow=True,
**self.upload_data(filename))
self.check_url(response, '/u/{0}/'.format(self.test_user.username))
- entry = mg_globals.database.MediaEntry.find_one({'title': title})
- assert_equal(entry.state, 'failed')
- assert_equal(entry.fail_error, u'mediagoblin.processing:BadMediaFail')
+ entry = mg_globals.database.MediaEntry.query.filter_by(title=title).first()
+ assert entry.state == 'failed'
+ assert entry.fail_error == u'mediagoblin.processing:BadMediaFail'
def test_evil_jpg(self):
# Test non-supported file with .jpg extension
@@ -270,9 +269,12 @@ class TestSubmission:
def test_media_data(self):
self.check_normal_upload(u"With GPS data", GPS_JPG)
media = self.check_media(None, {"title": u"With GPS data"}, 1)
- assert_equal(media.media_data.gps_latitude, 59.336666666666666)
+ assert media.media_data.gps_latitude == 59.336666666666666
def test_processing(self):
+ public_store_dir = mg_globals.global_config[
+ 'storage:publicstore']['base_dir']
+
data = {'title': u'Big Blue'}
response, request = self.do_post(data, *REQUEST_CONTEXT, do_follow=True,
**self.upload_data(BIG_BLUE))
@@ -282,12 +284,11 @@ class TestSubmission:
('medium', 'bigblue.medium.png'),
('thumb', 'bigblue.thumbnail.png')):
# Does the processed image have a good filename?
- filename = resource_filename(
- 'mediagoblin.tests',
- os.path.join('test_user_dev/media/public',
- *media.media_files.get(key, [])))
- assert_true(filename.endswith('_' + basename))
+ filename = os.path.join(
+ public_store_dir,
+ *media.media_files[key])
+ assert filename.endswith('_' + basename)
# Is it smaller than the last processed image we looked at?
size = os.stat(filename).st_size
- assert_true(last_size > size)
+ assert last_size > size
last_size = size
diff --git a/mediagoblin/tests/test_submission/good.pdf b/mediagoblin/tests/test_submission/good.pdf
new file mode 100644
index 00000000..ab5db006
--- /dev/null
+++ b/mediagoblin/tests/test_submission/good.pdf
Binary files differ
diff --git a/mediagoblin/tests/test_tags.py b/mediagoblin/tests/test_tags.py
index ccb93085..e25cc283 100644
--- a/mediagoblin/tests/test_tags.py
+++ b/mediagoblin/tests/test_tags.py
@@ -14,17 +14,15 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin.tests.tools import get_app
from mediagoblin.tools import text
-def test_list_of_dicts_conversion():
+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.
"""
- test_app = get_app(dump_old_app=False)
# Leading, trailing, and internal whitespace should be removed and slugified
assert text.convert_to_tag_list_of_dicts('sleep , 6 AM, chainsaw! ') == [
{'name': u'sleep', 'slug': u'sleep'},
diff --git a/mediagoblin/tests/test_timesince.py b/mediagoblin/tests/test_timesince.py
new file mode 100644
index 00000000..6579eb09
--- /dev/null
+++ b/mediagoblin/tests/test_timesince.py
@@ -0,0 +1,57 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+from datetime import datetime, timedelta
+
+from mediagoblin.tools.timesince import is_aware, timesince
+
+
+def test_timesince():
+ test_time = datetime.now()
+
+ # it should ignore second and microseconds
+ assert timesince(test_time, test_time + timedelta(microseconds=1)) == "0 minutes"
+ assert timesince(test_time, test_time + timedelta(seconds=1)) == "0 minutes"
+
+ # test minutes, hours, days, weeks, months and years (singular and plural)
+ assert timesince(test_time, test_time + timedelta(minutes=1)) == "1 minute"
+ assert timesince(test_time, test_time + timedelta(minutes=2)) == "2 minutes"
+
+ assert timesince(test_time, test_time + timedelta(hours=1)) == "1 hour"
+ assert timesince(test_time, test_time + timedelta(hours=2)) == "2 hours"
+
+ assert timesince(test_time, test_time + timedelta(days=1)) == "1 day"
+ assert timesince(test_time, test_time + timedelta(days=2)) == "2 days"
+
+ assert timesince(test_time, test_time + timedelta(days=7)) == "1 week"
+ assert timesince(test_time, test_time + timedelta(days=14)) == "2 weeks"
+
+ assert timesince(test_time, test_time + timedelta(days=30)) == "1 month"
+ assert timesince(test_time, test_time + timedelta(days=60)) == "2 months"
+
+ assert timesince(test_time, test_time + timedelta(days=365)) == "1 year"
+ assert timesince(test_time, test_time + timedelta(days=730)) == "2 years"
+
+ # okay now we want to test combinations
+ # e.g. 1 hour, 5 days
+ assert timesince(test_time, test_time + timedelta(days=5, hours=1)) == "5 days, 1 hour"
+
+ assert timesince(test_time, test_time + timedelta(days=15)) == "2 weeks, 1 day"
+
+ assert timesince(test_time, test_time + timedelta(days=97)) == "3 months, 1 week"
+
+ assert timesince(test_time, test_time + timedelta(days=2250)) == "6 years, 2 months"
+
diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py
index e4c04b7a..bc14f528 100644
--- a/mediagoblin/tests/test_util.py
+++ b/mediagoblin/tests/test_util.py
@@ -104,6 +104,28 @@ def test_locale_to_lower_lower():
assert translate.locale_to_lower_lower('en_us') == 'en-us'
+def test_gettext_lazy_proxy():
+ from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+ from mediagoblin.tools.translate import pass_to_ugettext, set_thread_locale
+ proxy = _(u"Password")
+ orig = u"Password"
+
+ set_thread_locale("es")
+ p1 = unicode(proxy)
+ p1_should = pass_to_ugettext(orig)
+ assert p1_should != orig, "Test useless, string not translated"
+ assert p1 == p1_should
+
+ set_thread_locale("sv")
+ p2 = unicode(proxy)
+ p2_should = pass_to_ugettext(orig)
+ assert p2_should != orig, "Test broken, string not translated"
+ assert p2 == p2_should
+
+ assert p1_should != p2_should, "Test broken, same translated string"
+ assert p1 != p2
+
+
def test_html_cleaner():
# Remove images
result = text.clean_html(
diff --git a/mediagoblin/tests/test_workbench.py b/mediagoblin/tests/test_workbench.py
index 636c8689..6695618b 100644
--- a/mediagoblin/tests/test_workbench.py
+++ b/mediagoblin/tests/test_workbench.py
@@ -21,13 +21,18 @@ import tempfile
from mediagoblin.tools import workbench
from mediagoblin.mg_globals import setup_globals
from mediagoblin.decorators import get_workbench
-from mediagoblin.tests.test_storage import get_tmp_filestorage
+from mediagoblin.tests.test_storage import get_tmp_filestorage, cleanup_storage
class TestWorkbench(object):
- def setUp(self):
+ def setup(self):
+ self.workbench_base = tempfile.mkdtemp(prefix='gmg_workbench_testing')
self.workbench_manager = workbench.WorkbenchManager(
- os.path.join(tempfile.gettempdir(), u'mgoblin_workbench_testing'))
+ self.workbench_base)
+
+ def teardown(self):
+ # If the workbench is empty, this should work.
+ os.rmdir(self.workbench_base)
def test_create_workbench(self):
workbench = self.workbench_manager.create()
@@ -70,6 +75,8 @@ class TestWorkbench(object):
filename = this_workbench.localized_file(this_storage, filepath)
assert filename == os.path.join(
tmpdir, 'dir1/dir2/ourfile.txt')
+ this_storage.delete_file(filepath)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
# with a fake remote file storage
tmpdir, this_storage = get_tmp_filestorage(fake_remote=True)
@@ -95,6 +102,10 @@ class TestWorkbench(object):
assert filename == os.path.join(
this_workbench.dir, 'thisfile.text')
+ this_storage.delete_file(filepath)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
+ this_workbench.destroy()
+
def test_workbench_decorator(self):
"""Test @get_workbench decorator and automatic cleanup"""
# The decorator needs mg_globals.workbench_manager
diff --git a/mediagoblin/tests/testplugins/__init__.py b/mediagoblin/tests/testplugins/__init__.py
new file mode 100644
index 00000000..621845ba
--- /dev/null
+++ b/mediagoblin/tests/testplugins/__init__.py
@@ -0,0 +1,15 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
diff --git a/mediagoblin/tests/testplugins/callables1/__init__.py b/mediagoblin/tests/testplugins/callables1/__init__.py
new file mode 100644
index 00000000..fe801a01
--- /dev/null
+++ b/mediagoblin/tests/testplugins/callables1/__init__.py
@@ -0,0 +1,43 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+def setup_plugin():
+ pass
+
+
+def just_one(call_log):
+ call_log.append("expect this one call")
+ return "Called just once"
+
+
+def multi_handle(call_log):
+ call_log.append("Hi, I'm the first")
+ return "the first returns"
+
+def multi_handle_with_canthandle(call_log):
+ return None
+
+
+def expand_tuple(this_tuple):
+ return this_tuple + (1,)
+
+hooks = {
+ 'setup': setup_plugin,
+ 'just_one': just_one,
+ 'multi_handle': multi_handle,
+ 'multi_handle_with_canthandle': multi_handle_with_canthandle,
+ 'expand_tuple': expand_tuple,
+ }
diff --git a/mediagoblin/tests/testplugins/callables2/__init__.py b/mediagoblin/tests/testplugins/callables2/__init__.py
new file mode 100644
index 00000000..9d5cf950
--- /dev/null
+++ b/mediagoblin/tests/testplugins/callables2/__init__.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+def setup_plugin():
+ pass
+
+
+def just_one(call_log):
+ assert "SHOULD NOT HAPPEN"
+
+def multi_handle(call_log):
+ call_log.append("Hi, I'm the second")
+ return "the second returns"
+
+def multi_handle_with_canthandle(call_log):
+ call_log.append("Hi, I'm the second")
+ return "the second returns"
+
+def expand_tuple(this_tuple):
+ return this_tuple + (2,)
+
+hooks = {
+ 'setup': setup_plugin,
+ 'just_one': just_one,
+ 'multi_handle': multi_handle,
+ 'multi_handle_with_canthandle': multi_handle_with_canthandle,
+ 'expand_tuple': expand_tuple,
+ }
diff --git a/mediagoblin/tests/testplugins/callables3/__init__.py b/mediagoblin/tests/testplugins/callables3/__init__.py
new file mode 100644
index 00000000..04efc8fc
--- /dev/null
+++ b/mediagoblin/tests/testplugins/callables3/__init__.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+def setup_plugin():
+ pass
+
+
+def just_one(call_log):
+ assert "SHOULD NOT HAPPEN"
+
+def multi_handle(call_log):
+ call_log.append("Hi, I'm the third")
+ return "the third returns"
+
+def multi_handle_with_canthandle(call_log):
+ call_log.append("Hi, I'm the third")
+ return "the third returns"
+
+def expand_tuple(this_tuple):
+ return this_tuple + (3,)
+
+hooks = {
+ 'setup': setup_plugin,
+ 'just_one': just_one,
+ 'multi_handle': multi_handle,
+ 'multi_handle_with_canthandle': multi_handle_with_canthandle,
+ 'expand_tuple': expand_tuple,
+ }
diff --git a/mediagoblin/tests/testplugins/modify_context/__init__.py b/mediagoblin/tests/testplugins/modify_context/__init__.py
new file mode 100644
index 00000000..164e66c1
--- /dev/null
+++ b/mediagoblin/tests/testplugins/modify_context/__init__.py
@@ -0,0 +1,55 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools import pluginapi
+import pkg_resources
+
+
+def append_to_specific_context(context):
+ context['specific_page_append'] = 'in yer specificpage'
+ return context
+
+def append_to_global_context(context):
+ context['global_append'] = 'globally appended!'
+ return context
+
+def double_doubleme(context):
+ if 'doubleme' in context:
+ context['doubleme'] = context['doubleme'] * 2
+ return context
+
+
+def setup_plugin():
+ routes = [
+ ('modify_context.specific_page',
+ '/modify_context/specific/',
+ 'mediagoblin.tests.testplugins.modify_context.views:specific'),
+ ('modify_context.general_page',
+ '/modify_context/',
+ 'mediagoblin.tests.testplugins.modify_context.views:general')]
+
+ pluginapi.register_routes(routes)
+ pluginapi.register_template_path(
+ pkg_resources.resource_filename(
+ 'mediagoblin.tests.testplugins.modify_context', 'templates'))
+
+
+hooks = {
+ 'setup': setup_plugin,
+ ('modify_context.specific_page',
+ 'contextplugin/specific.html'): append_to_specific_context,
+ 'template_global_context': append_to_global_context,
+ 'template_context_prerender': double_doubleme}
diff --git a/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html
new file mode 100644
index 00000000..9cf96d3e
--- /dev/null
+++ b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/general.html
@@ -0,0 +1,5 @@
+General page!
+
+global thing: {{ global_append }}
+lol: {{ lol }}
+doubleme: {{ doubleme }}
diff --git a/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html
new file mode 100644
index 00000000..5b1b4c4a
--- /dev/null
+++ b/mediagoblin/tests/testplugins/modify_context/templates/contextplugin/specific.html
@@ -0,0 +1,6 @@
+Specific page!
+
+specific thing: {{ specific_page_append }}
+global thing: {{ global_append }}
+something: {{ something }}
+doubleme: {{ doubleme }}
diff --git a/mediagoblin/tests/test_tests.py b/mediagoblin/tests/testplugins/modify_context/views.py
index d539f1e0..701ec6f9 100644
--- a/mediagoblin/tests/test_tests.py
+++ b/mediagoblin/tests/testplugins/modify_context/views.py
@@ -14,23 +14,20 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from mediagoblin import mg_globals
-from mediagoblin.tests.tools import get_app, fixture_add_user
-from mediagoblin.db.models import User
+from mediagoblin.tools.response import render_to_response
-def test_get_app_wipes_db():
- """
- Make sure we get a fresh database on every wipe :)
- """
- get_app(dump_old_app=True)
- assert User.query.count() == 0
+def specific(request):
+ return render_to_response(
+ request,
+ 'contextplugin/specific.html',
+ {"something": "orother",
+ "doubleme": "happy"})
- fixture_add_user()
- assert User.query.count() == 1
- get_app(dump_old_app=False)
- assert User.query.count() == 1
-
- get_app(dump_old_app=True)
- assert User.query.count() == 0
+def general(request):
+ return render_to_response(
+ request,
+ 'contextplugin/general.html',
+ {"lol": "cats",
+ "doubleme": "joy"})
diff --git a/mediagoblin/tests/testplugins/pluginspec/__init__.py b/mediagoblin/tests/testplugins/pluginspec/__init__.py
new file mode 100644
index 00000000..76ca2b1f
--- /dev/null
+++ b/mediagoblin/tests/testplugins/pluginspec/__init__.py
@@ -0,0 +1,22 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+def setup_plugin():
+ pass
+
+hooks = {
+ 'setup': setup_plugin,
+}
diff --git a/mediagoblin/tests/testplugins/pluginspec/config_spec.ini b/mediagoblin/tests/testplugins/pluginspec/config_spec.ini
new file mode 100644
index 00000000..5c9c3bd7
--- /dev/null
+++ b/mediagoblin/tests/testplugins/pluginspec/config_spec.ini
@@ -0,0 +1,4 @@
+[plugin_spec]
+some_string = string(default="blork")
+some_int = integer(default=50)
+dont_change_me = string(default="still the default") \ No newline at end of file
diff --git a/mediagoblin/tests/testplugins/staticstuff/__init__.py b/mediagoblin/tests/testplugins/staticstuff/__init__.py
new file mode 100644
index 00000000..a2591646
--- /dev/null
+++ b/mediagoblin/tests/testplugins/staticstuff/__init__.py
@@ -0,0 +1,36 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+from mediagoblin.tools.staticdirect import PluginStatic
+from mediagoblin.tools import pluginapi
+from pkg_resources import resource_filename
+
+def setup_plugin():
+ routes = [
+ ('staticstuff.static_demo',
+ '/staticstuff/',
+ 'mediagoblin.tests.testplugins.staticstuff.views:static_demo')]
+
+ pluginapi.register_routes(routes)
+
+
+hooks = {
+ 'setup': setup_plugin,
+ 'static_setup': lambda: PluginStatic(
+ 'staticstuff',
+ resource_filename(
+ 'mediagoblin.tests.testplugins.staticstuff',
+ 'static'))}
diff --git a/mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css b/mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css
new file mode 100644
index 00000000..1294ab8a
--- /dev/null
+++ b/mediagoblin/tests/testplugins/staticstuff/static/css/bunnify.css
@@ -0,0 +1,4 @@
+body {
+ background-color: #5edcf1;
+ color: #eb8add;
+} \ No newline at end of file
diff --git a/mediagoblin/tests/testplugins/staticstuff/views.py b/mediagoblin/tests/testplugins/staticstuff/views.py
new file mode 100644
index 00000000..34a5e8cb
--- /dev/null
+++ b/mediagoblin/tests/testplugins/staticstuff/views.py
@@ -0,0 +1,28 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+import json
+
+from werkzeug import Response
+
+
+def static_demo(request):
+ return Response(json.dumps({
+ # this does not exist, but we'll pretend it does ;)
+ 'mgoblin_bunny_pic': request.staticdirect(
+ 'images/bunny_pic.png'),
+ 'plugin_bunny_css': request.staticdirect(
+ 'css/bunnify.css', 'staticstuff')}))
diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py
index cc4a7add..98361adc 100644
--- a/mediagoblin/tests/tools.py
+++ b/mediagoblin/tests/tools.py
@@ -19,21 +19,19 @@ import os
import pkg_resources
import shutil
-from functools import wraps
from paste.deploy import loadapp
from webtest import TestApp
from mediagoblin import mg_globals
-from mediagoblin.db.models import User, MediaEntry, Collection
+from mediagoblin.db.models import User, MediaEntry, Collection, MediaComment, \
+ CommentSubscription, CommentNotification
from mediagoblin.tools import testing
from mediagoblin.init.config import read_mediagoblin_config
-from mediagoblin.db.open import setup_connection_and_db_from_config
from mediagoblin.db.base import Session
from mediagoblin.meddleware import BaseMeddleware
-from mediagoblin.auth.lib import bcrypt_gen_password_hash
+from mediagoblin.auth import gen_password_hash
from mediagoblin.gmg_commands.dbupdate import run_dbupdate
-from mediagoblin.init.celery import setup_celery_app
MEDIAGOBLIN_TEST_DB_NAME = u'__mediagoblin_tests__'
@@ -41,21 +39,9 @@ TEST_SERVER_CONFIG = pkg_resources.resource_filename(
'mediagoblin.tests', 'test_paste.ini')
TEST_APP_CONFIG = pkg_resources.resource_filename(
'mediagoblin.tests', 'test_mgoblin_app.ini')
-TEST_USER_DEV = pkg_resources.resource_filename(
- 'mediagoblin.tests', 'test_user_dev')
-MGOBLIN_APP = None
-USER_DEV_DIRECTORIES_TO_SETUP = [
- 'media/public', 'media/queue',
- 'beaker/sessions/data', 'beaker/sessions/lock']
-BAD_CELERY_MESSAGE = """\
-Sorry, you *absolutely* must run nosetests with the
-mediagoblin.init.celery.from_tests module. Like so:
-$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests"""
-
-
-class BadCeleryEnviron(Exception): pass
+USER_DEV_DIRECTORIES_TO_SETUP = ['media/public', 'media/queue']
class TestingMeddleware(BaseMeddleware):
@@ -97,41 +83,40 @@ class TestingMeddleware(BaseMeddleware):
return
-def suicide_if_bad_celery_environ():
- if not os.environ.get('CELERY_CONFIG_MODULE') == \
- 'mediagoblin.init.celery.from_tests':
- raise BadCeleryEnviron(BAD_CELERY_MESSAGE)
-
+def get_app(request, paste_config=None, mgoblin_config=None):
+ """Create a MediaGoblin app for testing.
-def get_app(dump_old_app=True):
- suicide_if_bad_celery_environ()
-
- # Make sure we've turned on testing
- testing._activate_testing()
-
- # Leave this imported as it sets up celery.
- from mediagoblin.init.celery import from_tests
+ Args:
+ - request: Not an http request, but a pytest fixture request. We
+ use this to make temporary directories that pytest
+ automatically cleans up as needed.
+ - paste_config: particular paste config used by this application.
+ - mgoblin_config: particular mediagoblin config used by this
+ application.
+ """
+ paste_config = paste_config or TEST_SERVER_CONFIG
+ mgoblin_config = mgoblin_config or TEST_APP_CONFIG
- global MGOBLIN_APP
+ # This is the directory we're copying the paste/mgoblin config stuff into
+ run_dir = request.config._tmpdirhandler.mktemp(
+ 'mgoblin_app', numbered=True)
+ user_dev_dir = run_dir.mkdir('user_dev').strpath
- # Just return the old app if that exists and it's okay to set up
- # and return
- if MGOBLIN_APP and not dump_old_app:
- return MGOBLIN_APP
+ new_paste_config = run_dir.join('paste.ini').strpath
+ new_mgoblin_config = run_dir.join('mediagoblin.ini').strpath
+ shutil.copyfile(paste_config, new_paste_config)
+ shutil.copyfile(mgoblin_config, new_mgoblin_config)
Session.rollback()
Session.remove()
- # Remove and reinstall user_dev directories
- if os.path.exists(TEST_USER_DEV):
- shutil.rmtree(TEST_USER_DEV)
-
+ # install user_dev directories
for directory in USER_DEV_DIRECTORIES_TO_SETUP:
- full_dir = os.path.join(TEST_USER_DEV, directory)
+ full_dir = os.path.join(user_dev_dir, directory)
os.makedirs(full_dir)
# Get app config
- global_config, validation_result = read_mediagoblin_config(TEST_APP_CONFIG)
+ global_config, validation_result = read_mediagoblin_config(new_mgoblin_config)
app_config = global_config['mediagoblin']
# Run database setup/migrations
@@ -139,10 +124,7 @@ def get_app(dump_old_app=True):
# setup app and return
test_app = loadapp(
- 'config:' + TEST_SERVER_CONFIG)
-
- # Re-setup celery
- setup_celery_app(app_config, global_config)
+ 'config:' + new_paste_config)
# Insert the TestingMeddleware, which can do some
# sanity checks on every request/response.
@@ -151,26 +133,10 @@ def get_app(dump_old_app=True):
mg_globals.app.meddleware.insert(0, TestingMeddleware(mg_globals.app))
app = TestApp(test_app)
- MGOBLIN_APP = app
return app
-def setup_fresh_app(func):
- """
- Decorator to setup a fresh test application for this function.
-
- Cleans out test buckets and passes in a new, fresh test_app.
- """
- @wraps(func)
- def wrapper(*args, **kwargs):
- test_app = get_app()
- testing.clear_test_buckets()
- return func(test_app, *args, **kwargs)
-
- return wrapper
-
-
def install_fixtures_simple(db, fixtures):
"""
Very simply install fixtures in the database
@@ -198,13 +164,13 @@ def assert_db_meets_expected(db, expected):
for collection_name, collection_data in expected.iteritems():
collection = db[collection_name]
for expected_document in collection_data:
- document = collection.find_one({'id': expected_document['id']})
+ document = collection.query.filter_by(id=expected_document['id']).first()
assert document is not None # make sure it exists
assert document == expected_document # make sure it matches
def fixture_add_user(username=u'chris', password=u'toast',
- active_user=True):
+ active_user=True, wants_comment_notification=True):
# Reuse existing user or create a new one
test_user = User.query.filter_by(username=username).first()
if test_user is None:
@@ -212,11 +178,13 @@ def fixture_add_user(username=u'chris', password=u'toast',
test_user.username = username
test_user.email = username + u'@example.com'
if password is not None:
- test_user.pw_hash = bcrypt_gen_password_hash(password)
+ test_user.pw_hash = gen_password_hash(password)
if active_user:
test_user.email_verified = True
test_user.status = u'active'
+ test_user.wants_comment_notification = wants_comment_notification
+
test_user.save()
# Reload
@@ -228,19 +196,79 @@ def fixture_add_user(username=u'chris', password=u'toast',
return test_user
+def fixture_comment_subscription(entry, notify=True, send_email=None):
+ if send_email is None:
+ uploader = User.query.filter_by(id=entry.uploader).first()
+ send_email = uploader.wants_comment_notification
+
+ cs = CommentSubscription(
+ media_entry_id=entry.id,
+ user_id=entry.uploader,
+ notify=notify,
+ send_email=send_email)
+
+ cs.save()
+
+ cs = CommentSubscription.query.filter_by(id=cs.id).first()
+
+ Session.expunge(cs)
+
+ return cs
+
+
+def fixture_add_comment_notification(entry_id, subject_id, user_id,
+ seen=False):
+ cn = CommentNotification(user_id=user_id,
+ seen=seen,
+ subject_id=subject_id)
+ cn.save()
+
+ cn = CommentNotification.query.filter_by(id=cn.id).first()
+
+ Session.expunge(cn)
+
+ return cn
+
+
def fixture_media_entry(title=u"Some title", slug=None,
- uploader=None, save=True, gen_slug=True):
+ uploader=None, save=True, gen_slug=True,
+ state=u'unprocessed', fake_upload=True,
+ expunge=True):
+ """
+ Add a media entry for testing purposes.
+
+ Caution: if you're adding multiple entries with fake_upload=True,
+ make sure you save between them... otherwise you'll hit an
+ IntegrityError from multiple newly-added-MediaEntries adding
+ FileKeynames at once. :)
+ """
+ if uploader is None:
+ uploader = fixture_add_user().id
+
entry = MediaEntry()
entry.title = title
entry.slug = slug
- entry.uploader = uploader or fixture_add_user().id
+ entry.uploader = uploader
entry.media_type = u'image'
-
+ entry.state = state
+
+ if fake_upload:
+ entry.media_files = {'thumb': ['a', 'b', 'c.jpg'],
+ 'medium': ['d', 'e', 'f.png'],
+ 'original': ['g', 'h', 'i.png']}
+ entry.media_type = u'mediagoblin.media_types.image'
+
if gen_slug:
entry.generate_slug()
+
if save:
entry.save()
+ if expunge:
+ entry = MediaEntry.query.filter_by(id=entry.id).first()
+
+ Session.expunge(entry)
+
return entry
@@ -263,3 +291,26 @@ def fixture_add_collection(name=u"My first Collection", user=None):
Session.expunge(coll)
return coll
+
+def fixture_add_comment(author=None, media_entry=None, comment=None):
+ if author is None:
+ author = fixture_add_user().id
+
+ if media_entry is None:
+ media_entry = fixture_media_entry().id
+
+ if comment is None:
+ comment = \
+ 'Auto-generated test comment by user #{0} on media #{0}'.format(
+ author, media_entry)
+
+ comment = MediaComment(author=author,
+ media_entry=media_entry,
+ content=comment)
+
+ comment.save()
+
+ Session.expunge(comment)
+
+ return comment
+