aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/tests
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin/tests')
-rw-r--r--mediagoblin/tests/__init__.py4
-rw-r--r--mediagoblin/tests/appconfig_plugin_specs.ini21
-rw-r--r--mediagoblin/tests/conftest.py15
-rw-r--r--mediagoblin/tests/pytest.ini2
-rw-r--r--mediagoblin/tests/resources.py41
-rw-r--r--mediagoblin/tests/test_api.py92
-rw-r--r--mediagoblin/tests/test_auth.py96
-rw-r--r--mediagoblin/tests/test_cache.py52
-rw-r--r--mediagoblin/tests/test_collections.py32
-rw-r--r--mediagoblin/tests/test_config.py2
-rw-r--r--mediagoblin/tests/test_csrf_middleware.py13
-rw-r--r--mediagoblin/tests/test_edit.py197
-rw-r--r--mediagoblin/tests/test_exif.py48
-rw-r--r--mediagoblin/tests/test_globals.py15
-rw-r--r--mediagoblin/tests/test_http_callback.py18
-rw-r--r--mediagoblin/tests/test_messages.py8
-rw-r--r--mediagoblin/tests/test_mgoblin_app.ini8
-rw-r--r--mediagoblin/tests/test_misc.py79
-rw-r--r--mediagoblin/tests/test_modelmethods.py167
-rw-r--r--mediagoblin/tests/test_oauth.py84
-rw-r--r--mediagoblin/tests/test_paste.ini11
-rw-r--r--mediagoblin/tests/test_pdf.py39
-rw-r--r--mediagoblin/tests/test_pluginapi.py172
-rw-r--r--mediagoblin/tests/test_session.py30
-rw-r--r--mediagoblin/tests/test_sql_migrations.py4
-rw-r--r--mediagoblin/tests/test_storage.py58
-rw-r--r--mediagoblin/tests/test_submission.py106
-rwxr-xr-xmediagoblin/tests/test_submission/evilbin96284 -> 49 bytes
-rwxr-xr-xmediagoblin/tests/test_submission/evil.jpgbin96284 -> 49 bytes
-rwxr-xr-xmediagoblin/tests/test_submission/evil.pngbin96284 -> 49 bytes
-rw-r--r--mediagoblin/tests/test_submission/good.pdfbin0 -> 194007 bytes
-rw-r--r--mediagoblin/tests/test_tags.py2
-rw-r--r--mediagoblin/tests/test_timesince.py57
-rw-r--r--mediagoblin/tests/test_util.py36
-rw-r--r--mediagoblin/tests/test_workbench.py53
-rw-r--r--mediagoblin/tests/testplugins/__init__.py15
-rw-r--r--mediagoblin/tests/testplugins/callables1/__init__.py (renamed from mediagoblin/tests/test_tests.py)37
-rw-r--r--mediagoblin/tests/testplugins/callables2/__init__.py41
-rw-r--r--mediagoblin/tests/testplugins/callables3/__init__.py41
-rw-r--r--mediagoblin/tests/testplugins/pluginspec/__init__.py22
-rw-r--r--mediagoblin/tests/testplugins/pluginspec/config_spec.ini4
-rw-r--r--mediagoblin/tests/tools.py133
42 files changed, 1402 insertions, 453 deletions
diff --git a/mediagoblin/tests/__init__.py b/mediagoblin/tests/__init__.py
index 4e84914a..5a3235c6 100644
--- a/mediagoblin/tests/__init__.py
+++ b/mediagoblin/tests/__init__.py
@@ -25,6 +25,10 @@ from mediagoblin.tests.tools import (
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
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/conftest.py b/mediagoblin/tests/conftest.py
new file mode 100644
index 00000000..25f495d6
--- /dev/null
+++ b/mediagoblin/tests/conftest.py
@@ -0,0 +1,15 @@
+from mediagoblin.tests import tools
+
+import pytest
+
+@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)
diff --git a/mediagoblin/tests/pytest.ini b/mediagoblin/tests/pytest.ini
new file mode 100644
index 00000000..d4aa2d69
--- /dev/null
+++ b/mediagoblin/tests/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+usefixtures = tmpdir \ No newline at end of file
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
new file mode 100644
index 00000000..89cf1026
--- /dev/null
+++ b/mediagoblin/tests/test_api.py
@@ -0,0 +1,92 @@
+# 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 logging
+import base64
+
+import pytest
+
+from mediagoblin import mg_globals
+from mediagoblin.tools import template, pluginapi
+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__)
+
+
+class TestAPI(object):
+ 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, test_app):
+ test_app.post(
+ '/auth/login/', {
+ 'username': self.user.username,
+ 'password': self.user_password})
+
+ def get_context(self, template_name):
+ return template.TEMPLATE_TEST_CONTEXT[template_name]
+
+ def http_auth_headers(self):
+ return {'Authorization': 'Basic {0}'.format(
+ base64.b64encode(':'.join([
+ self.user.username,
+ self.user_password])))}
+
+ 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 = test_app.post(url, data, **kwargs)
+
+ if do_follow:
+ response.follow()
+
+ return response
+
+ def upload_data(self, filename):
+ return {'upload_files': [('file', filename)]}
+
+ def test_1_test_test_view(self, test_app):
+ self.login(test_app)
+
+ 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, 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
+
+ assert self.db.MediaEntry.query.filter_by(title=u'Great JPG!').first()
diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py
index 1b84b435..755727f9 100644
--- a/mediagoblin/tests/test_auth.py
+++ b/mediagoblin/tests/test_auth.py
@@ -17,11 +17,10 @@
import urlparse
import datetime
-from nose.tools import assert_equal
-
-from mediagoblin.auth import lib as auth_lib
-from mediagoblin.tests.tools import setup_fresh_app, fixture_add_user
from mediagoblin import mg_globals
+from mediagoblin.auth import lib as auth_lib
+from mediagoblin.db.models import User
+from mediagoblin.tests.tools import fixture_add_user
from mediagoblin.tools import template, mail
@@ -39,7 +38,6 @@ def test_bcrypt_check_password():
'notthepassword',
'$2a$12$PXU03zfrVCujBhVeICTwtOaHTUs5FFwsscvSSTJkqx/2RQ0Lhy/nO')
-
# Same thing, but with extra fake salt.
assert not auth_lib.bcrypt_check_password(
'notthepassword',
@@ -57,7 +55,6 @@ def test_bcrypt_gen_password_hash():
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(
@@ -66,7 +63,6 @@ def test_bcrypt_gen_password_hash():
'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.
@@ -76,8 +72,7 @@ def test_register_views(test_app):
test_app.get('/auth/register/')
# Make sure it rendered with the appropriate template
- assert template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/auth/register.html')
+ assert 'mediagoblin/auth/register.html' in template.TEMPLATE_TEST_CONTEXT
# Try to register without providing anything, should error
# --------------------------------------------------------
@@ -104,10 +99,8 @@ def test_register_views(test_app):
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
form = context['register_form']
- assert form.username.errors == [
- u'Field must be between 3 and 30 characters long.']
- assert form.password.errors == [
- u'Field must be between 6 and 30 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()
@@ -118,13 +111,11 @@ def test_register_views(test_app):
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/register.html']
form = context['register_form']
- assert form.username.errors == [
- u'Invalid input.']
- assert form.email.errors == [
- u'Invalid 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 not mg_globals.database.User.find().count()
+ assert User.query.count() == 0
# Successful register
# -------------------
@@ -137,11 +128,8 @@ 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 template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/user_pages/user.html')
+ 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(
@@ -153,7 +141,7 @@ def test_register_views(test_app):
## Make sure user is logged in
request = template.TEMPLATE_TEST_CONTEXT[
'mediagoblin/user_pages/user.html']['request']
- assert request.session['user_id'] == unicode(new_user._id)
+ assert request.session['user_id'] == unicode(new_user.id)
## Make sure we get email confirmation, and try verifying
assert len(mail.EMAIL_TEST_INBOX) == 1
@@ -170,7 +158,7 @@ def test_register_views(test_app):
### user should have these same parameters
assert parsed_get_params['userid'] == [
- unicode(new_user._id)]
+ unicode(new_user.id)]
assert parsed_get_params['token'] == [
new_user.verification_key]
@@ -178,7 +166,7 @@ def test_register_views(test_app):
template.clear_test_template_context()
response = test_app.get(
"/auth/verify_email/?userid=%s&token=total_bs" % unicode(
- new_user._id))
+ new_user.id))
response.follow()
context = template.TEMPLATE_TEST_CONTEXT[
'mediagoblin/user_pages/user.html']
@@ -231,11 +219,8 @@ 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 template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/auth/login.html')
+ 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
assert len(mail.EMAIL_TEST_INBOX) == 1
@@ -253,7 +238,7 @@ def test_register_views(test_app):
# 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['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
@@ -264,8 +249,8 @@ def test_register_views(test_app):
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, '404 Not Found')
+ new_user.id), status=404)
+ assert response.status.split()[0] == u'404' # status="404 NOT FOUND"
## Try using an expired token to change password, shouldn't work
template.clear_test_template_context()
@@ -274,14 +259,14 @@ def test_register_views(test_app):
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, '404 Not Found')
+ assert response.status.split()[0] == u'404' # status="404 NOT FOUND"
new_user.fp_token_expire = real_token_expiration
new_user.save()
## Verify step 1 of password-change works -- can see form to change password
template.clear_test_template_context()
response = test_app.get("%s?%s" % (path, get_params))
- assert template.TEMPLATE_TEST_CONTEXT.has_key('mediagoblin/auth/change_fp.html')
+ assert 'mediagoblin/auth/change_fp.html' in template.TEMPLATE_TEST_CONTEXT
## Verify step 2.1 of password-change works -- report success to user
template.clear_test_template_context()
@@ -291,8 +276,7 @@ def test_register_views(test_app):
'password': 'iamveryveryhappy',
'token': parsed_get_params['token']})
response.follow()
- assert template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/auth/login.html')
+ assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
## Verify step 2.2 of password-change works -- login w/ new password success
template.clear_test_template_context()
@@ -303,14 +287,10 @@ def test_register_views(test_app):
# User should be redirected
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
- assert template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/root.html')
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
-@setup_fresh_app
def test_authentication_views(test_app):
"""
Test logging in and logging out
@@ -321,8 +301,7 @@ def test_authentication_views(test_app):
# Get login
# ---------
test_app.get('/auth/login/')
- assert template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/auth/login.html')
+ assert 'mediagoblin/auth/login.html' in template.TEMPLATE_TEST_CONTEXT
# Failed login - blank form
# -------------------------
@@ -369,7 +348,7 @@ def test_authentication_views(test_app):
response = test_app.post(
'/auth/login/', {
'username': u'chris',
- 'password': 'jam'})
+ 'password': 'jam_and_ham'})
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/auth/login.html']
assert context['login_failed']
@@ -383,16 +362,13 @@ def test_authentication_views(test_app):
# User should be redirected
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
- assert template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/root.html')
+ assert urlparse.urlsplit(response.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)
+ assert session['user_id'] == unicode(test_user.id)
# Successful logout
# -----------------
@@ -401,16 +377,13 @@ def test_authentication_views(test_app):
# Should be redirected to index page
response.follow()
- assert_equal(
- urlparse.urlsplit(response.location)[2],
- '/')
- assert template.TEMPLATE_TEST_CONTEXT.has_key(
- 'mediagoblin/root.html')
+ assert urlparse.urlsplit(response.location)[2] == '/'
+ assert 'mediagoblin/root.html' in template.TEMPLATE_TEST_CONTEXT
# Make sure the user is not in the session
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
session = context['request'].session
- assert session.has_key('user_id') == False
+ assert 'user_id' not in session
# User is redirected to custom URL if POST['next'] is set
# -------------------------------------------------------
@@ -420,7 +393,4 @@ def test_authentication_views(test_app):
'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/'
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_collections.py b/mediagoblin/tests/test_collections.py
new file mode 100644
index 00000000..87782f30
--- /dev/null
+++ b/mediagoblin/tests/test_collections.py
@@ -0,0 +1,32 @@
+# 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 mediagoblin.tests.tools import fixture_add_collection, fixture_add_user
+from mediagoblin.db.models import Collection, User
+
+
+def test_user_deletes_collection(test_app):
+ # Setup db.
+ user = fixture_add_user()
+ coll = fixture_add_collection(user=user)
+ # Reload into session:
+ user = User.query.get(user.id)
+
+ cnt1 = Collection.query.count()
+ user.delete()
+ cnt2 = Collection.query.count()
+
+ assert cnt1 == cnt2 + 1
diff --git a/mediagoblin/tests/test_config.py b/mediagoblin/tests/test_config.py
index 7d8c65c1..b13adae6 100644
--- a/mediagoblin/tests/test_config.py
+++ b/mediagoblin/tests/test_config.py
@@ -36,7 +36,7 @@ def test_read_mediagoblin_config():
assert this_conf['carrotapp']['carrotcake'] == False
assert this_conf['carrotapp']['num_carrots'] == 1
- assert not this_conf['carrotapp'].has_key('encouragement_phrase')
+ assert 'encouragement_phrase' not in this_conf['carrotapp']
assert this_conf['celery']['EAT_CELERY_WITH_CARROTS'] == True
# A good file
diff --git a/mediagoblin/tests/test_csrf_middleware.py b/mediagoblin/tests/test_csrf_middleware.py
index d730909f..a272caf6 100644
--- a/mediagoblin/tests/test_csrf_middleware.py
+++ b/mediagoblin/tests/test_csrf_middleware.py
@@ -14,13 +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 setup_fresh_app
from mediagoblin import mg_globals
-@setup_fresh_app
def test_csrf_cookie_set(test_app):
-
cookie_name = mg_globals.app_config['csrf_cookie_name']
# get login page
@@ -34,7 +31,13 @@ def test_csrf_cookie_set(test_app):
assert response.headers.get('Vary', False) == 'Cookie'
-@setup_fresh_app
+# 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
@@ -65,9 +68,7 @@ def test_csrf_token_must_match(test_app):
extra_environ={'gmg.verify_csrf': True}).\
status_int == 200
-@setup_fresh_app
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 353a7eb9..cda2607f 100644
--- a/mediagoblin/tests/test_edit.py
+++ b/mediagoblin/tests/test_edit.py
@@ -14,83 +14,128 @@
# 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 import mg_globals
-from mediagoblin.tests.tools import setup_fresh_app, fixture_add_user
+from mediagoblin.db.models import User
+from mediagoblin.tests.tools import fixture_add_user
from mediagoblin.tools import template
from mediagoblin.auth.lib import bcrypt_check_password
-
-@setup_fresh_app
-def test_change_password(test_app):
- """Test changing password correctly and incorrectly"""
- # set up new user
- test_user = fixture_add_user()
-
- test_app.post(
- '/auth/login/', {
- 'username': u'chris',
- 'password': 'toast'})
-
- # test that the password can be changed
- # template.clear_test_template_context()
- test_app.post(
- '/edit/account/', {
- 'old_password': 'toast',
- 'new_password': '123456',
- 'wants_comment_notification': 'y'
- })
-
- # test_user has to be fetched again in order to have the current values
- test_user = mg_globals.database.User.one({'username': u'chris'})
-
- assert bcrypt_check_password('123456', test_user.pw_hash)
-
- # test that the password cannot be changed if the given old_password
- # is wrong
- # template.clear_test_template_context()
- test_app.post(
- '/edit/account/', {
- 'old_password': 'toast',
- 'new_password': '098765',
- })
-
- test_user = mg_globals.database.User.one({'username': u'chris'})
-
- assert not bcrypt_check_password('098765', test_user.pw_hash)
-
-
-@setup_fresh_app
-def change_bio_url(test_app):
- """Test changing bio and URL"""
- # set up new user
- test_user = fixture_add_user()
-
- # test changing the bio and the URL properly
- test_app.post(
- '/edit/profile/', {
- 'bio': u'I love toast!',
- 'url': u'http://dustycloud.org/'})
-
- test_user = mg_globals.database.User.one({'username': u'chris'})
-
- assert test_user.bio == u'I love toast!'
- assert test_user.url == u'http://dustycloud.org/'
-
- # test changing the bio and the URL inproperly
- too_long_bio = 150 * 'T' + 150 * 'o' + 150 * 'a' + 150 * 's' + 150* 't'
-
- test_app.post(
- '/edit/profile/', {
- # more than 500 characters
- 'bio': too_long_bio,
- 'url': 'this-is-no-url'})
-
- test_user = mg_globals.database.User.one({'username': u'chris'})
-
- context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/edit/edit_profile.html']
- form = context['edit_profile_form']
-
- assert form.bio.errors == [u'Field must be between 0 and 500 characters long.']
- assert form.url.errors == [u'Improperly formed URL']
-
- # test changing the url inproperly
+class TestUserEdit(object):
+ def setup(self):
+ # set up new user
+ self.user_password = u'toast'
+ self.user = fixture_add_user(password = self.user_password)
+
+ def login(self, test_app):
+ test_app.post(
+ '/auth/login/', {
+ 'username': self.user.username,
+ 'password': self.user_password})
+
+
+ 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 = test_app.post('/edit/account/delete/', {'confirmed': 'y'})
+
+ # Make sure user has been deleted
+ assert User.query.filter_by(username=u'chris').first() == None
+
+ #TODO: make sure all corresponding items comments etc have been
+ # deleted too. Perhaps in submission test?
+
+ #Restore user at end of test
+ self.user = fixture_add_user(password = self.user_password)
+ self.login(test_app)
+
+
+ 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 = test_app.post(
+ '/edit/account/', {
+ 'old_password': 'toast',
+ 'new_password': '123456',
+ 'wants_comment_notification': 'y'
+ })
+
+ # Check for redirect on success
+ assert 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)
+ # 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()
+ test_app.post(
+ '/edit/account/', {
+ '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)
+
+
+ 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 = 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 res.status_int == 302
+ assert res.headers['Location'].endswith("/u/chris/edit/")
+
+ 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 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 = test_app.post(
+ '/u/foo/edit/', {
+ 'bio': u'I love toast!',
+ 'url': u'http://dustycloud.org/'}, expect_errors=True)
+ 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'
+
+ 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']
+ form = context['form']
+
+ assert form.bio.errors == [
+ u'Field must be between 0 and 500 characters long.']
+ assert form.url.errors == [
+ u'This address contains errors']
+
+# test changing the url inproperly
diff --git a/mediagoblin/tests/test_exif.py b/mediagoblin/tests/test_exif.py
index ed95045c..824de3c2 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
@@ -58,10 +39,10 @@ def test_exif_extraction():
gps = get_gps_data(result)
# Do we have the result?
- assert len(result) == 108
+ assert len(result) == 56
# Do we have clean data?
- assert len(clean) == 105
+ assert len(clean) == 53
# GPS data?
assert gps == {}
@@ -70,7 +51,7 @@ def test_exif_extraction():
assert useful == {
'EXIF Flash': {
'field_type': 3,
- 'printable': 'No',
+ 'printable': u'Flash did not fire',
'field_offset': 380,
'tag': 37385,
'values': [0],
@@ -123,18 +104,7 @@ def test_exif_extraction():
'field_offset': 708,
'tag': 33437,
'values': [[10, 1]],
- 'field_length': 8},
- 'EXIF UserComment': {
- 'field_type': 7,
- 'printable': 'Joar Wandborg ',
- 'field_offset': 26180,
- 'tag': 37510,
- 'values': [
- 65, 83, 67, 73, 73, 0, 0, 0, 74, 111, 97, 114, 32, 87,
- 97, 110, 100, 98, 111, 114, 103, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32],
- 'field_length': 44}}
+ 'field_length': 8}}
def test_exif_image_orientation():
diff --git a/mediagoblin/tests/test_globals.py b/mediagoblin/tests/test_globals.py
index 98f6a436..fe3088f8 100644
--- a/mediagoblin/tests/test_globals.py
+++ b/mediagoblin/tests/test_globals.py
@@ -14,32 +14,29 @@
# 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):
- self.old_connection = mg_globals.db_connection
+ def setup(self):
self.old_database = mg_globals.database
- def tearDown(self):
- mg_globals.db_connection = self.old_connection
+ def teardown(self):
mg_globals.database = self.old_database
def test_setup_globals(self):
mg_globals.setup_globals(
- db_connection='my favorite db_connection!',
database='my favorite database!',
public_store='my favorite public_store!',
queue_store='my favorite queue_store!')
- assert mg_globals.db_connection == 'my favorite db_connection!'
assert mg_globals.database == 'my favorite database!'
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 8b0a03b9..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_test_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_test_app()
+ @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 d3b84828..3ac917b0 100644
--- a/mediagoblin/tests/test_messages.py
+++ b/mediagoblin/tests/test_messages.py
@@ -15,11 +15,9 @@
# 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 setup_fresh_app
from mediagoblin.tools import template
-@setup_fresh_app
def test_messages(test_app):
"""
Added messages should show up in the request.session,
@@ -30,15 +28,15 @@ def test_messages(test_app):
test_app.get('/')
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
request = context['request']
-
+
# The message queue should be empty
assert request.session.get('messages', []) == []
-
+
# Adding a message should modify the session accordingly
add_message(request, 'herp_derp', 'First!')
test_msg_queue = [{'text': 'First!', 'level': 'herp_derp'}]
assert request.session['messages'] == test_msg_queue
-
+
# fetch_messages should return and empty the queue
assert 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 cde61a70..9f95a398 100644
--- a/mediagoblin/tests/test_mgoblin_app.ini
+++ b/mediagoblin/tests/test_mgoblin_app.ini
@@ -16,6 +16,8 @@ allow_attachments = True
# mediagoblin.init.celery.from_celery
celery_setup_elsewhere = true
+media_types = mediagoblin.media_types.image, mediagoblin.media_types.pdf
+
[storage:publicstore]
base_dir = %(here)s/test_user_dev/media/public
base_url = /mgoblin_media/
@@ -23,10 +25,6 @@ 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
-
[celery]
CELERY_ALWAYS_EAGER = true
CELERY_RESULT_DBURI = "sqlite:///%(here)s/test_user_dev/celery.db"
@@ -35,3 +33,5 @@ BROKER_HOST = "sqlite:///%(here)s/test_user_dev/kombu.db"
[plugins]
[[mediagoblin.plugins.api]]
[[mediagoblin.plugins.oauth]]
+[[mediagoblin.plugins.httpapiauth]]
+
diff --git a/mediagoblin/tests/test_misc.py b/mediagoblin/tests/test_misc.py
index 94ae5a51..755d863f 100644
--- a/mediagoblin/tests/test_misc.py
+++ b/mediagoblin/tests/test_misc.py
@@ -14,13 +14,78 @@
# 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 fixture_add_user, fixture_media_entry
-from mediagoblin.tests.tools import setup_fresh_app
-
-@setup_fresh_app
def test_404_for_non_existent(test_app):
- assert_equal(test_app.get('/does-not-exist/',
- expect_errors=True).status_int,
- 404)
+ res = test_app.get('/does-not-exist/', expect_errors=True)
+ assert res.status_int == 404
+
+
+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)
+ Session.add(media_a)
+ Session.add(media_b)
+ Session.flush()
+
+ # Create all 4 possible comments:
+ for u_id in (user_a.id, user_b.id):
+ for m_id in (media_a.id, media_b.id):
+ cmt = MediaComment()
+ cmt.media_entry = m_id
+ cmt.author = u_id
+ cmt.content = u"Some Comment"
+ Session.add(cmt)
+
+ Session.flush()
+
+ usr_cnt1 = User.query.count()
+ med_cnt1 = MediaEntry.query.count()
+ cmt_cnt1 = MediaComment.query.count()
+
+ User.query.get(user_a.id).delete(commit=False)
+
+ usr_cnt2 = User.query.count()
+ med_cnt2 = MediaEntry.query.count()
+ cmt_cnt2 = MediaComment.query.count()
+
+ # One user deleted
+ assert usr_cnt2 == usr_cnt1 - 1
+ # One media gone
+ assert med_cnt2 == med_cnt1 - 1
+ # Three of four comments gone.
+ assert cmt_cnt2 == cmt_cnt1 - 3
+
+ User.query.get(user_b.id).delete()
+
+ usr_cnt2 = User.query.count()
+ med_cnt2 = MediaEntry.query.count()
+ cmt_cnt2 = MediaComment.query.count()
+
+ # All users gone
+ assert usr_cnt2 == usr_cnt1 - 2
+ # All media gone
+ assert med_cnt2 == med_cnt1 - 2
+ # All comments gone
+ assert cmt_cnt2 == cmt_cnt1 - 4
+
+
+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.attachment_files.append(dict(
+ name=u"some name",
+ filepath=[u"does", u"not", u"exist"],
+ ))
+ Session.add(media)
+ Session.flush()
+
+ MediaEntry.query.get(media.id).delete()
+ User.query.get(user_a.id).delete()
diff --git a/mediagoblin/tests/test_modelmethods.py b/mediagoblin/tests/test_modelmethods.py
new file mode 100644
index 00000000..427aa47c
--- /dev/null
+++ b/mediagoblin/tests/test_modelmethods.py
@@ -0,0 +1,167 @@
+# 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/>.
+
+# Maybe not every model needs a test, but some models have special
+# methods, and so it makes sense to test them here.
+
+from mediagoblin.db.base import Session
+from mediagoblin.db.models import MediaEntry
+
+from mediagoblin.tests.tools import fixture_add_user
+
+import mock
+
+
+class FakeUUID(object):
+ hex = 'testtest-test-test-test-testtesttest'
+
+UUID_MOCK = mock.Mock(return_value=FakeUUID())
+
+
+class TestMediaEntrySlugs(object):
+ 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(
+ title=u"Beware, I exist!",
+ slug=u"beware-i-exist")
+
+ def _insert_media_entry_fixture(self, title=None, slug=None, this_id=None,
+ uploader=None, save=True):
+ entry = MediaEntry()
+ entry.title = title or u"Some title"
+ entry.slug = slug
+ entry.id = this_id
+ entry.uploader = uploader or self.chris_user.id
+ entry.media_type = u'image'
+
+ if save:
+ entry.save()
+
+ return entry
+
+ 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, 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, 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, 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-9000"
+
+ 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.
+
+ ,
+ / \ (@!#?@!)
+ |\,/| ,-, /
+ | |#| ( ")~
+ / \|/ \ L L
+ |\,/|\,/|
+ | |#, |#|
+ / \|/ \|/ \
+ |\,/|\,/|\,/|
+ | |#| |#| |#|
+ / \|/ \|/ \|/ \
+ |\,/|\,/|\,/|\,/|
+ | |#| |#| |#| |#|
+ \|/ \|/ \|/ \|/
+ """
+ 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(test_app):
+ Session.rollback()
+ Session.remove()
+ media = MediaEntry()
+ media.media_type = u"mediagoblin.media_types.image"
+ assert media.media_data is None
+ media.media_data_init()
+ assert media.media_data is not None
+ obj_in_session = 0
+ for obj in Session():
+ obj_in_session += 1
+ print repr(obj)
+ assert obj_in_session == 0
diff --git a/mediagoblin/tests/test_oauth.py b/mediagoblin/tests/test_oauth.py
index a72f766e..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_test_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_test_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_paste.ini b/mediagoblin/tests/test_paste.ini
index d7c18642..91ecbb84 100644
--- a/mediagoblin/tests/test_paste.ini
+++ b/mediagoblin/tests/test_paste.ini
@@ -9,8 +9,7 @@ use = egg:Paste#urlmap
[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
@@ -20,14 +19,6 @@ document_root = %(here)s/test_user_dev/media/public
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
-
[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_pluginapi.py b/mediagoblin/tests/test_pluginapi.py
index 315a95da..809b5ce9 100644
--- a/mediagoblin/tests/test_pluginapi.py
+++ b/mediagoblin/tests/test_pluginapi.py
@@ -15,11 +15,16 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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.tools import pluginapi
-from nose.tools import eq_
def with_cleanup(*modules_to_delete):
@@ -97,7 +102,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 +122,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 +150,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 +177,149 @@ 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
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_sql_migrations.py b/mediagoblin/tests/test_sql_migrations.py
index 6383d096..2fc4c043 100644
--- a/mediagoblin/tests/test_sql_migrations.py
+++ b/mediagoblin/tests/test_sql_migrations.py
@@ -25,8 +25,8 @@ from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import select, insert
from migrate import changeset
-from mediagoblin.db.sql.base import GMGTableBase
-from mediagoblin.db.sql.util import MigrationManager, RegisterMigration
+from mediagoblin.db.base import GMGTableBase
+from mediagoblin.db.migration_tools import MigrationManager, RegisterMigration
from mediagoblin.tools.common import CollectingPrinter
diff --git a/mediagoblin/tests/test_storage.py b/mediagoblin/tests/test_storage.py
index 6fc2e57c..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
+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():
@@ -80,7 +78,8 @@ def test_storage_system_from_config():
'mediagoblin.tests.test_storage:FakeStorageSystem'})
assert this_storage.foobie == 'eiboof'
assert this_storage.blech == 'hcelb'
- assert this_storage.__class__ is FakeStorageSystem
+ assert unicode(this_storage.__class__) == \
+ u'mediagoblin.tests.test_storage.FakeStorageSystem'
##########################
@@ -88,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:
@@ -96,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()
@@ -107,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()
@@ -125,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()
@@ -145,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()
@@ -181,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()
@@ -195,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/')
@@ -215,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(
@@ -223,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():
@@ -236,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():
@@ -254,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()
@@ -266,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 b6fe0015..162b2d19 100644
--- a/mediagoblin/tests/test_submission.py
+++ b/mediagoblin/tests/test_submission.py
@@ -20,26 +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_test_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
+from mediagoblin.media_types.pdf.processing import check_prerequisites as pdf_check_prerequisites
-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')
+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)
@@ -49,8 +40,9 @@ REQUEST_CONTEXT = ['mediagoblin/user_pages/user.html', 'request']
class TestSubmission:
- def setUp(self):
- self.test_app = get_test_app()
+ @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')
@@ -86,27 +78,27 @@ class TestSubmission:
def check_comments(self, request, media_id, count):
comments = request.db.MediaComment.find({'media_entry': media_id})
- assert_equal(count, len(list(comments)))
+ 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(' ', '-'))
@@ -121,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 = request.db.MediaEntry.find(find_data)
+ media = MediaEntry.find(find_data)
if count is not None:
- assert_equal(media.count(), count)
+ assert media.count() == count
if count == 0:
return
return media[0]
@@ -132,11 +132,11 @@ class TestSubmission:
def test_tags(self):
# Good tag string
# --------
- response, request = self.do_post({'title': u'Balanced Goblin',
+ response, request = self.do_post({'title': u'Balanced Goblin 2',
'tags': GOOD_TAG_STRING},
*REQUEST_CONTEXT, do_follow=True,
**self.upload_data(GOOD_JPG))
- media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
+ media = self.check_media(request, {'title': u'Balanced Goblin 2'}, 1)
assert media.tags[0]['name'] == u'yin'
assert media.tags[0]['slug'] == u'yin'
@@ -145,14 +145,14 @@ class TestSubmission:
# Test tags that are too long
# ---------------
- response, form = self.do_post({'title': u'Balanced Goblin',
+ response, form = self.do_post({'title': u'Balanced Goblin 2',
'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'},
@@ -161,11 +161,23 @@ class TestSubmission:
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
media_id = media.id
+ # render and post to the edit page.
+ edit_url = request.urlgen(
+ 'mediagoblin.edit.edit_media',
+ user=self.test_user.username, media_id=media_id)
+ self.test_app.get(edit_url)
+ self.test_app.post(edit_url,
+ {'title': u'Balanced Goblin',
+ 'slug': u"Balanced=Goblin",
+ 'tags': u''})
+ media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
+ assert media.slug == u"balanced-goblin"
+
# Add a comment, so we can test for its deletion later.
self.check_comments(request, media_id, 0)
comment_url = request.urlgen(
'mediagoblin.user_pages.media_post_comment',
- user=self.test_user.username, media=media_id)
+ user=self.test_user.username, media_id=media_id)
response = self.do_post({'comment_content': 'i love this test'},
url=comment_url, do_follow=True)[0]
self.check_comments(request, media_id, 1)
@@ -174,7 +186,7 @@ class TestSubmission:
# ---------------------------------------------------
delete_url = request.urlgen(
'mediagoblin.user_pages.media_confirm_delete',
- user=self.test_user.username, media=media_id)
+ user=self.test_user.username, media_id=media_id)
# Empty data means don't confirm
response = self.do_post({}, do_follow=True, url=delete_url)[0]
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
@@ -184,7 +196,7 @@ class TestSubmission:
# ---------------------------------------------------
response, request = self.do_post({'confirm': 'y'}, *REQUEST_CONTEXT,
do_follow=True, url=delete_url)
- self.check_media(request, {'_id': media_id}, 0)
+ self.check_media(request, {'id': media_id}, 0)
self.check_comments(request, media_id, 0)
def test_evil_file(self):
@@ -193,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])
@@ -206,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, img_MEDIA_MANAGER)
+ assert media.media_manager.entry == media
def test_sniffing(self):
@@ -240,8 +253,8 @@ class TestSubmission:
**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')
+ assert entry.state == 'failed'
+ assert entry.fail_error == u'mediagoblin.processing:BadMediaFail'
def test_evil_jpg(self):
# Test non-supported file with .jpg extension
@@ -253,7 +266,15 @@ class TestSubmission:
# -------------------------------------------
self.check_false_image(u'Malicious Upload 3', EVIL_PNG)
+ 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 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))
@@ -263,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/evil b/mediagoblin/tests/test_submission/evil
index 775da664..2c850e29 100755
--- a/mediagoblin/tests/test_submission/evil
+++ b/mediagoblin/tests/test_submission/evil
Binary files differ
diff --git a/mediagoblin/tests/test_submission/evil.jpg b/mediagoblin/tests/test_submission/evil.jpg
index 775da664..2c850e29 100755
--- a/mediagoblin/tests/test_submission/evil.jpg
+++ b/mediagoblin/tests/test_submission/evil.jpg
Binary files differ
diff --git a/mediagoblin/tests/test_submission/evil.png b/mediagoblin/tests/test_submission/evil.png
index 775da664..2c850e29 100755
--- a/mediagoblin/tests/test_submission/evil.png
+++ b/mediagoblin/tests/test_submission/evil.png
Binary files differ
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 bc657660..e25cc283 100644
--- a/mediagoblin/tests/test_tags.py
+++ b/mediagoblin/tests/test_tags.py
@@ -14,10 +14,8 @@
# 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.tools import text
-@setup_fresh_app
def test_list_of_dicts_conversion(test_app):
"""
When the user adds tags to a media entry, the string from the form is
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 452090e1..bc14f528 100644
--- a/mediagoblin/tests/test_util.py
+++ b/mediagoblin/tests/test_util.py
@@ -70,13 +70,13 @@ I hope you like unit tests JUST AS MUCH AS I DO!"""
I hope you like unit tests JUST AS MUCH AS I DO!"""
def test_slugify():
- assert url.slugify('a walk in the park') == 'a-walk-in-the-park'
- assert url.slugify('A Walk in the Park') == 'a-walk-in-the-park'
- assert url.slugify('a walk in the park') == 'a-walk-in-the-park'
- assert url.slugify('a walk in-the-park') == 'a-walk-in-the-park'
- assert url.slugify('a w@lk in the park?') == 'a-w-lk-in-the-park'
- assert url.slugify(u'a walk in the par\u0107') == 'a-walk-in-the-parc'
- assert url.slugify(u'\u00E0\u0042\u00E7\u010F\u00EB\u0066') == 'abcdef'
+ assert url.slugify(u'a walk in the park') == u'a-walk-in-the-park'
+ assert url.slugify(u'A Walk in the Park') == u'a-walk-in-the-park'
+ assert url.slugify(u'a walk in the park') == u'a-walk-in-the-park'
+ assert url.slugify(u'a walk in-the-park') == u'a-walk-in-the-park'
+ assert url.slugify(u'a w@lk in the park?') == u'a-w-lk-in-the-park'
+ assert url.slugify(u'a walk in the par\u0107') == u'a-walk-in-the-parc'
+ assert url.slugify(u'\u00E0\u0042\u00E7\u010F\u00EB\u0066') == u'abcdef'
def test_locale_to_lower_upper():
"""
@@ -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 04a74653..6695618b 100644
--- a/mediagoblin/tests/test_workbench.py
+++ b/mediagoblin/tests/test_workbench.py
@@ -18,29 +18,37 @@ import os
import tempfile
-from mediagoblin import workbench
-from mediagoblin.tests.test_storage import get_tmp_filestorage
+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, 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_workbench()
+ workbench = self.workbench_manager.create()
assert os.path.isdir(workbench.dir)
assert workbench.dir.startswith(self.workbench_manager.base_workbench_dir)
+ workbench.destroy()
def test_joinpath(self):
- this_workbench = self.workbench_manager.create_workbench()
+ this_workbench = self.workbench_manager.create()
tmpname = this_workbench.joinpath('temp.txt')
assert tmpname == os.path.join(this_workbench.dir, 'temp.txt')
- this_workbench.destroy_self()
+ this_workbench.destroy()
def test_destroy_workbench(self):
# kill a workbench
- this_workbench = self.workbench_manager.create_workbench()
+ this_workbench = self.workbench_manager.create()
tmpfile_name = this_workbench.joinpath('temp.txt')
tmpfile = file(tmpfile_name, 'w')
with tmpfile:
@@ -49,14 +57,14 @@ class TestWorkbench(object):
assert os.path.exists(tmpfile_name)
wb_dir = this_workbench.dir
- this_workbench.destroy_self()
+ this_workbench.destroy()
assert not os.path.exists(tmpfile_name)
assert not os.path.exists(wb_dir)
def test_localized_file(self):
tmpdir, this_storage = get_tmp_filestorage()
- this_workbench = self.workbench_manager.create_workbench()
-
+ this_workbench = self.workbench_manager.create()
+
# Write a brand new file
filepath = ['dir1', 'dir2', 'ourfile.txt']
@@ -67,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)
@@ -78,7 +88,7 @@ class TestWorkbench(object):
filename = this_workbench.localized_file(this_storage, filepath)
assert filename == os.path.join(
this_workbench.dir, 'ourfile.txt')
-
+
# fake remote file storage, filename_if_copying set
filename = this_workbench.localized_file(
this_storage, filepath, 'thisfile')
@@ -91,3 +101,22 @@ class TestWorkbench(object):
this_storage, filepath, 'thisfile.text', False)
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
+ setup_globals(workbench_manager=self.workbench_manager)
+
+ @get_workbench
+ def create_it(workbench=None):
+ # workbench dir exists?
+ assert os.path.isdir(workbench.dir)
+ return workbench.dir
+
+ benchdir = create_it()
+ # workbench dir has been cleaned up automatically?
+ assert not os.path.isdir(benchdir)
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/test_tests.py b/mediagoblin/tests/testplugins/callables1/__init__.py
index 20832ac7..fe801a01 100644
--- a/mediagoblin/tests/test_tests.py
+++ b/mediagoblin/tests/testplugins/callables1/__init__.py
@@ -14,25 +14,30 @@
# 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_test_app
+def setup_plugin():
+ pass
-from mediagoblin import mg_globals
+def just_one(call_log):
+ call_log.append("expect this one call")
+ return "Called just once"
-def test_get_test_app_wipes_db():
- """
- Make sure we get a fresh database on every wipe :)
- """
- get_test_app()
- assert mg_globals.database.User.find().count() == 0
- new_user = mg_globals.database.User()
- new_user.username = u'lolcat'
- new_user.email = u'lol@cats.example.org'
- new_user.pw_hash = u'pretend_this_is_a_hash'
- new_user.save()
- assert mg_globals.database.User.find().count() == 1
+def multi_handle(call_log):
+ call_log.append("Hi, I'm the first")
+ return "the first returns"
- get_test_app()
+def multi_handle_with_canthandle(call_log):
+ return None
- assert mg_globals.database.User.find().count() == 0
+
+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/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/tools.py b/mediagoblin/tests/tools.py
index d3369831..52635e18 100644
--- a/mediagoblin/tests/tools.py
+++ b/mediagoblin/tests/tools.py
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import sys
import os
import pkg_resources
import shutil
@@ -25,10 +26,10 @@ from paste.deploy import loadapp
from webtest import TestApp
from mediagoblin import mg_globals
+from mediagoblin.db.models import User, MediaEntry, Collection
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.sql.base import Session
+from mediagoblin.db.base import Session
from mediagoblin.meddleware import BaseMeddleware
from mediagoblin.auth.lib import bcrypt_gen_password_hash
from mediagoblin.gmg_commands.dbupdate import run_dbupdate
@@ -42,16 +43,16 @@ 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']
+
+USER_DEV_DIRECTORIES_TO_SETUP = ['media/public', 'media/queue']
BAD_CELERY_MESSAGE = """\
-Sorry, you *absolutely* must run nosetests with the
+Sorry, you *absolutely* must run tests with the
mediagoblin.init.celery.from_tests module. Like so:
-$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests"""
+
+$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests {0}
+""".format(sys.argv[0])
class BadCeleryEnviron(Exception): pass
@@ -78,7 +79,7 @@ class TestingMeddleware(BaseMeddleware):
def process_response(self, request, response):
# All following tests should be for html only!
- if response.content_type != "text/html":
+ if getattr(response, 'content_type', None) != "text/html":
# Get out early
return
@@ -102,7 +103,30 @@ def suicide_if_bad_celery_environ():
raise BadCeleryEnviron(BAD_CELERY_MESSAGE)
-def get_test_app(dump_old_app=True):
+def get_app(request, paste_config=None, mgoblin_config=None):
+ """Create a MediaGoblin app for testing.
+
+ 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
+
+ # 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('test_user_dev').strpath
+
+ 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)
+
suicide_if_bad_celery_environ()
# Make sure we've turned on testing
@@ -111,26 +135,16 @@ def get_test_app(dump_old_app=True):
# Leave this imported as it sets up celery.
from mediagoblin.init.celery import from_tests
- global MGOBLIN_APP
-
- # 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
-
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
@@ -138,7 +152,7 @@ def get_test_app(dump_old_app=True):
# setup app and return
test_app = loadapp(
- 'config:' + TEST_SERVER_CONFIG)
+ 'config:' + new_paste_config)
# Re-setup celery
setup_celery_app(app_config, global_config)
@@ -150,26 +164,10 @@ def get_test_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_test_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
@@ -184,27 +182,30 @@ def assert_db_meets_expected(db, expected):
"""
Assert a database contains the things we expect it to.
- Objects are found via '_id', so you should make sure your document
- has an _id.
+ Objects are found via 'id', so you should make sure your document
+ has an id.
Args:
- db: pymongo or mongokit database connection
- expected: the data we expect. Formatted like:
{'collection_name': [
- {'_id': 'foo',
+ {'id': 'foo',
'some_field': 'some_value'},]}
"""
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.find_one({'id': expected_document['id']})
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='toast',
+def fixture_add_user(username=u'chris', password=u'toast',
active_user=True):
- test_user = mg_globals.database.User()
+ # Reuse existing user or create a new one
+ test_user = User.query.filter_by(username=username).first()
+ if test_user is None:
+ test_user = User()
test_user.username = username
test_user.email = username + u'@example.com'
if password is not None:
@@ -216,10 +217,46 @@ def fixture_add_user(username=u'chris', password='toast',
test_user.save()
# Reload
- test_user = mg_globals.database.User.find_one({'username': username})
+ test_user = User.query.filter_by(username=username).first()
# ... and detach from session:
- from mediagoblin.db.sql.base import Session
Session.expunge(test_user)
return test_user
+
+
+def fixture_media_entry(title=u"Some title", slug=None,
+ uploader=None, save=True, gen_slug=True):
+ entry = MediaEntry()
+ entry.title = title
+ entry.slug = slug
+ entry.uploader = uploader or fixture_add_user().id
+ entry.media_type = u'image'
+
+ if gen_slug:
+ entry.generate_slug()
+ if save:
+ entry.save()
+
+ return entry
+
+
+def fixture_add_collection(name=u"My first Collection", user=None):
+ if user is None:
+ user = fixture_add_user()
+ coll = Collection.query.filter_by(creator=user.id, title=name).first()
+ if coll is not None:
+ return coll
+ coll = Collection()
+ coll.creator = user.id
+ coll.title = name
+ coll.generate_slug()
+ coll.save()
+
+ # Reload
+ Session.refresh(coll)
+
+ # ... and detach from session:
+ Session.expunge(coll)
+
+ return coll