aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/tests
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin/tests')
-rw-r--r--mediagoblin/tests/appconfig_plugin_specs.ini21
-rw-r--r--mediagoblin/tests/resources.py41
-rw-r--r--mediagoblin/tests/test_api.py18
-rw-r--r--mediagoblin/tests/test_exif.py29
-rw-r--r--mediagoblin/tests/test_http_callback.py29
-rw-r--r--mediagoblin/tests/test_mgoblin_app.ini2
-rw-r--r--mediagoblin/tests/test_oauth.py115
-rw-r--r--mediagoblin/tests/test_pdf.py39
-rw-r--r--mediagoblin/tests/test_pluginapi.py104
-rw-r--r--mediagoblin/tests/test_storage.py29
-rw-r--r--mediagoblin/tests/test_submission.py79
-rw-r--r--mediagoblin/tests/test_submission/good.pdfbin0 -> 194007 bytes
-rw-r--r--mediagoblin/tests/test_timesince.py57
-rw-r--r--mediagoblin/tests/test_util.py22
-rw-r--r--mediagoblin/tests/test_workbench.py4
-rw-r--r--mediagoblin/tests/testplugins/callables1/__init__.py8
-rw-r--r--mediagoblin/tests/testplugins/callables2/__init__.py3
-rw-r--r--mediagoblin/tests/testplugins/callables3/__init__.py3
-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.py8
21 files changed, 444 insertions, 193 deletions
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/resources.py b/mediagoblin/tests/resources.py
new file mode 100644
index 00000000..f7b3037d
--- /dev/null
+++ b/mediagoblin/tests/resources.py
@@ -0,0 +1,41 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2013 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+from pkg_resources import resource_filename
+
+
+def resource(filename):
+ return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
+
+
+GOOD_JPG = resource('good.jpg')
+GOOD_PNG = resource('good.png')
+EVIL_FILE = resource('evil')
+EVIL_JPG = resource('evil.jpg')
+EVIL_PNG = resource('evil.png')
+BIG_BLUE = resource('bigblue.png')
+GOOD_PDF = resource('good.pdf')
+
+
+def resource_exif(f):
+ return resource_filename('mediagoblin.tests', 'test_exif/' + f)
+
+
+GOOD_JPG = resource_exif('good.jpg')
+EMPTY_JPG = resource_exif('empty.jpg')
+BAD_JPG = resource_exif('bad.jpg')
+GPS_JPG = resource_exif('has-gps.jpg')
diff --git a/mediagoblin/tests/test_api.py b/mediagoblin/tests/test_api.py
index cff25776..89cf1026 100644
--- a/mediagoblin/tests/test_api.py
+++ b/mediagoblin/tests/test_api.py
@@ -18,31 +18,17 @@
import logging
import base64
-from pkg_resources import resource_filename
-
import pytest
from mediagoblin import mg_globals
from mediagoblin.tools import template, pluginapi
from mediagoblin.tests.tools import fixture_add_user
+from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
+ BIG_BLUE
_log = logging.getLogger(__name__)
-def resource(filename):
- '''
- Borrowed from the submission tests
- '''
- return resource_filename('mediagoblin.tests', 'test_submission/' + filename)
-
-
-GOOD_JPG = resource('good.jpg')
-GOOD_PNG = resource('good.png')
-EVIL_FILE = resource('evil')
-EVIL_JPG = resource('evil.jpg')
-EVIL_PNG = resource('evil.png')
-BIG_BLUE = resource('bigblue.png')
-
class TestAPI(object):
def setup(self):
diff --git a/mediagoblin/tests/test_exif.py b/mediagoblin/tests/test_exif.py
index 100d17f0..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
diff --git a/mediagoblin/tests/test_http_callback.py b/mediagoblin/tests/test_http_callback.py
index e2c85d0d..a0511af7 100644
--- a/mediagoblin/tests/test_http_callback.py
+++ b/mediagoblin/tests/test_http_callback.py
@@ -16,6 +16,7 @@
import json
+import pytest
from urlparse import urlparse, parse_qs
from mediagoblin import mg_globals
@@ -26,21 +27,24 @@ from mediagoblin.tests import test_oauth as oauth
class TestHTTPCallback(object):
- def _setup(self, 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'
self.user = fixture_add_user(u'call_back', self.user_password)
- self.login(test_app)
+ self.login()
- def login(self, testapp):
- testapp.post('/auth/login/', {
+ def login(self):
+ self.test_app.post('/auth/login/', {
'username': self.user.username,
'password': self.user_password})
- def get_access_token(self, testapp, client_id, client_secret, code):
- response = testapp.get('/oauth/access_token', {
+ def get_access_token(self, client_id, client_secret, code):
+ response = self.test_app.get('/oauth/access_token', {
'code': code,
'client_id': client_id,
'client_secret': client_secret})
@@ -49,15 +53,12 @@ class TestHTTPCallback(object):
return response_data['access_token']
- def test_callback(self, test_app):
+ def test_callback(self):
''' Test processing HTTP callback '''
- self._setup(test_app)
-
self.oauth = oauth.TestOAuth()
- self.oauth._setup(test_app)
+ self.oauth.setup(self.test_app)
- redirect, client_id = self.oauth.test_4_authorize_confidential_client(
- test_app)
+ redirect, client_id = self.oauth.test_4_authorize_confidential_client()
code = parse_qs(urlparse(redirect.location).query)['code'][0]
@@ -66,11 +67,11 @@ class TestHTTPCallback(object):
client_secret = client.secret
- access_token = self.get_access_token(test_app, client_id, client_secret, code)
+ access_token = self.get_access_token(client_id, client_secret, code)
callback_url = 'https://foo.example?secrettestmediagoblinparam'
- res = test_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_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini
index b78abe64..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/
diff --git a/mediagoblin/tests/test_oauth.py b/mediagoblin/tests/test_oauth.py
index 901556fe..ea3bd798 100644
--- a/mediagoblin/tests/test_oauth.py
+++ b/mediagoblin/tests/test_oauth.py
@@ -17,6 +17,7 @@
import json
import logging
+import pytest
from urlparse import parse_qs, urlparse
from mediagoblin import mg_globals
@@ -28,7 +29,10 @@ _log = logging.getLogger(__name__)
class TestOAuth(object):
- def _setup(self, 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()
@@ -36,17 +40,17 @@ class TestOAuth(object):
self.user_password = u'4cc355_70k3N'
self.user = fixture_add_user(u'joauth', self.user_password)
- self.login(test_app)
+ self.login()
- def login(self, test_app):
- test_app.post(
- '/auth/login/', {
- 'username': self.user.username,
- 'password': self.user_password})
+ def login(self):
+ self.test_app.post(
+ '/auth/login/', {
+ 'username': self.user.username,
+ 'password': self.user_password})
- def register_client(self, test_app, name, client_type, description=None,
- redirect_uri=''):
- return test_app.post(
+ def register_client(self, name, client_type, description=None,
+ redirect_uri=''):
+ return self.test_app.post(
'/oauth/client/register', {
'name': name,
'description': description,
@@ -56,12 +60,10 @@ class TestOAuth(object):
def get_context(self, template_name):
return template.TEMPLATE_TEST_CONTEXT[template_name]
- def test_1_public_client_registration_without_redirect_uri(self, test_app):
+ def test_1_public_client_registration_without_redirect_uri(self):
''' Test 'public' OAuth client registration without any redirect uri '''
- self._setup(test_app)
-
- response = self.register_client(test_app, 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')
@@ -71,29 +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, test_app):
+ def test_2_successful_public_client_registration(self):
''' Successfully register a public client '''
- self._setup(test_app)
- self.register_client(test_app, 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, test_app):
+ def test_3_successful_confidential_client_reg(self):
''' Register a confidential OAuth client '''
- self._setup(test_app)
-
response = self.register_client(
- test_app, u'GMOGMO', 'confidential', 'NO GMO!')
+ u'GMOGMO', 'confidential', 'NO GMO!')
assert response.status_int == 302
@@ -105,18 +108,16 @@ class TestOAuth(object):
return client
- def test_4_authorize_confidential_client(self, test_app):
+ def test_4_authorize_confidential_client(self):
''' Authorize a confidential client as a logged in user '''
- self._setup(test_app)
-
- client = self.test_3_successful_confidential_client_reg(test_app)
+ client = self.test_3_successful_confidential_client_reg()
client_identifier = client.identifier
redirect_uri = 'https://foo.example'
- response = test_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
@@ -127,7 +128,7 @@ class TestOAuth(object):
form = ctx['form']
# Short for client authorization post reponse
- capr = test_app.post(
+ capr = self.test_app.post(
'/oauth/client/authorize', {
'client_id': form.client_id.data,
'allow': 'Allow',
@@ -142,21 +143,19 @@ 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, test_app):
+ def test_token_endpoint_successful_confidential_request(self):
''' Successful request against token endpoint '''
- self._setup(test_app)
-
- code_redirect, client_id = self.test_4_authorize_confidential_client(
- test_app)
+ code_redirect, client_id = self.test_4_authorize_confidential_client()
code = self.get_code_from_redirect_uri(code_redirect.location)
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.identifier == unicode(client_id)).first()
- token_res = test_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
@@ -170,19 +169,21 @@ code={1}&client_secret={2}'.format(client_id, code, client.secret))
assert type(token_data['expires_in']) == int
assert token_data['expires_in'] > 0
- def test_token_endpont_missing_id_confidential_request(self, test_app):
- ''' Unsuccessful request against token endpoint, missing client_id '''
- self._setup(test_app)
+ # There should be a refresh token provided in the token data
+ assert len(token_data['refresh_token'])
+
+ return client_id, token_data
- code_redirect, client_id = self.test_4_authorize_confidential_client(
- test_app)
+ 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()
code = self.get_code_from_redirect_uri(code_redirect.location)
client = self.db.OAuthClient.query.filter(
self.db.OAuthClient.identifier == unicode(client_id)).first()
- token_res = test_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
@@ -192,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_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 d40a5081..809b5ce9 100644
--- a/mediagoblin/tests/test_pluginapi.py
+++ b/mediagoblin/tests/test_pluginapi.py
@@ -18,9 +18,12 @@ 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
@@ -177,19 +180,22 @@ def test_disabled_plugin():
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_callable_runone():
+def test_hook_handle():
"""
- Test the callable_runone method
+ Test the hook_handle method
"""
- cfg = build_config([
- ('mediagoblin', {}, []),
- ('plugins', {}, [
- ('mediagoblin.tests.testplugins.callables1', {}, []),
- ('mediagoblin.tests.testplugins.callables2', {}, []),
- ('mediagoblin.tests.testplugins.callables3', {}, []),
- ])
- ])
+ cfg = build_config(CONFIG_ALL_CALLABLES)
mg_globals.app_config = cfg['mediagoblin']
mg_globals.global_config = cfg
@@ -198,50 +204,42 @@ def test_callable_runone():
# Just one hook provided
call_log = []
- assert pluginapi.callable_runone(
+ 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 = []
- with pytest.raises(pluginapi.UnhandledCallable):
- pluginapi.callable_runone(
- "nothing_handling", call_log)
+ pluginapi.hook_handle(
+ "nothing_handling", call_log) == None
assert call_log == []
# Nothing provided and unhandled okay
call_log = []
- assert pluginapi.callable_runone(
+ 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.callable_runone(
+ 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.callable_runone(
+ 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_callable_runall():
+def test_hook_runall():
"""
- Test the callable_runall method
+ Test the hook_runall method
"""
- cfg = build_config([
- ('mediagoblin', {}, []),
- ('plugins', {}, [
- ('mediagoblin.tests.testplugins.callables1', {}, []),
- ('mediagoblin.tests.testplugins.callables2', {}, []),
- ('mediagoblin.tests.testplugins.callables3', {}, []),
- ])
- ])
+ cfg = build_config(CONFIG_ALL_CALLABLES)
mg_globals.app_config = cfg['mediagoblin']
mg_globals.global_config = cfg
@@ -250,19 +248,19 @@ def test_callable_runall():
# Just one hook, check results
call_log = []
- assert pluginapi.callable_runall(
- "just_one", call_log) == ["Called just once", None, None]
+ 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.callable_runall(
+ assert pluginapi.hook_runall(
"nothing_handling", call_log) == []
assert call_log == []
# Multiple provided, check results
call_log = []
- assert pluginapi.callable_runall(
+ assert pluginapi.hook_runall(
"multi_handle", call_log) == [
"the first returns",
"the second returns",
@@ -275,7 +273,7 @@ def test_callable_runall():
# Multiple provided, one has CantHandleIt, check results
call_log = []
- assert pluginapi.callable_runall(
+ assert pluginapi.hook_runall(
"multi_handle_with_canthandle", call_log) == [
"the second returns",
"the third returns",
@@ -283,3 +281,45 @@ def test_callable_runall():
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_storage.py b/mediagoblin/tests/test_storage.py
index 749f7b07..f6f1d18f 100644
--- a/mediagoblin/tests/test_storage.py
+++ b/mediagoblin/tests/test_storage.py
@@ -95,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()
@@ -111,7 +119,7 @@ def test_basic_storage__resolve_filepath():
this_storage._resolve_filepath,
['../../', 'etc', 'passwd'])
- os.rmdir(tmpdir)
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_file_exists():
@@ -127,6 +135,7 @@ def test_basic_storage_file_exists():
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():
@@ -149,6 +158,7 @@ def test_basic_storage_get_unique_filepath():
assert new_filename == secure_filename(new_filename)
os.remove(filename)
+ cleanup_storage(this_storage, tmpdir, ['dir1', 'dir2'])
def test_basic_storage_get_file():
@@ -189,6 +199,7 @@ def test_basic_storage_get_file():
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():
@@ -204,11 +215,15 @@ 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.
@@ -217,7 +232,7 @@ def test_basic_storage_url_for_file():
storage.NoWebServing,
this_storage.file_url,
['dir1', 'dir2', 'filename.txt'])
- os.rmdir(tmpdir)
+ cleanup_storage(this_storage, tmpdir)
# base_url without domain
tmpdir, this_storage = get_tmp_filestorage('/media/')
@@ -225,7 +240,7 @@ def test_basic_storage_url_for_file():
['dir1', 'dir2', 'filename.txt'])
expected = '/media/dir1/dir2/filename.txt'
assert result == expected
- os.rmdir(tmpdir)
+ cleanup_storage(this_storage, tmpdir)
# base_url with domain
tmpdir, this_storage = get_tmp_filestorage(
@@ -234,7 +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
- os.rmdir(tmpdir)
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_get_local_path():
@@ -248,13 +263,13 @@ def test_basic_storage_get_local_path():
assert result == expected
- os.rmdir(tmpdir)
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_is_local():
tmpdir, this_storage = get_tmp_filestorage()
assert this_storage.local_storage is True
- os.rmdir(tmpdir)
+ cleanup_storage(this_storage, tmpdir)
def test_basic_storage_copy_locally():
@@ -275,6 +290,7 @@ def test_basic_storage_copy_locally():
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):
@@ -292,6 +308,7 @@ def _test_copy_local_to_storage_works(tmpdir, this_storage):
'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():
diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py
index ac714252..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
-
-from pkg_resources import resource_filename
+import pytest
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 .test_exif import GPS_JPG
+from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
+ BIG_BLUE, GOOD_PDF, GPS_JPG
GOOD_TAG_STRING = u'yin,yang'
BAD_TAG_STRING = unicode('rage,' + 'f' * 26 + 'u' * 26)
@@ -49,7 +40,8 @@ REQUEST_CONTEXT = ['mediagoblin/user_pages/user.html', 'request']
class TestSubmission:
- def _setup(self, test_app):
+ @pytest.fixture(autouse=True)
+ def setup(self, test_app):
self.test_app = test_app
# TODO: Possibly abstract into a decorator like:
@@ -88,9 +80,7 @@ class TestSubmission:
comments = request.db.MediaComment.find({'media_entry': media_id})
assert count == len(list(comments))
- def test_missing_fields(self, test_app):
- self._setup(test_app)
-
+ def test_missing_fields(self):
# Test blank form
# ---------------
response, form = self.do_post({}, *FORM_CONTEXT)
@@ -117,14 +107,20 @@ class TestSubmission:
self.logout()
self.test_app.get(url)
- def test_normal_jpg(self, test_app):
- self._setup(test_app)
+ def test_normal_jpg(self):
self.check_normal_upload(u'Normal upload 1', GOOD_JPG)
- def test_normal_png(self, test_app):
- self._setup(test_app)
+ def test_normal_png(self):
self.check_normal_upload(u'Normal upload 2', GOOD_PNG)
+ @pytest.mark.skipif("not pdf_check_prerequisites()")
+ def test_normal_pdf(self):
+ response, context = self.do_post({'title': u'Normal upload 3 (pdf)'},
+ do_follow=True,
+ **self.upload_data(GOOD_PDF))
+ self.check_url(response, '/u/{0}/'.format(self.test_user.username))
+ assert 'mediagoblin/user_pages/user.html' in context
+
def check_media(self, request, find_data, count=None):
media = MediaEntry.find(find_data)
if count is not None:
@@ -133,9 +129,7 @@ class TestSubmission:
return
return media[0]
- def test_tags(self, test_app):
- self._setup(test_app)
-
+ def test_tags(self):
# Good tag string
# --------
response, request = self.do_post({'title': u'Balanced Goblin 2',
@@ -160,9 +154,7 @@ class TestSubmission:
'Tags that are too long: ' \
'ffffffffffffffffffffffffffuuuuuuuuuuuuuuuuuuuuuuuuuu']
- def test_delete(self, test_app):
- self._setup(test_app)
-
+ def test_delete(self):
response, request = self.do_post({'title': u'Balanced Goblin'},
*REQUEST_CONTEXT, do_follow=True,
**self.upload_data(GOOD_JPG))
@@ -207,9 +199,7 @@ class TestSubmission:
self.check_media(request, {'id': media_id}, 0)
self.check_comments(request, media_id, 0)
- def test_evil_file(self, test_app):
- self._setup(test_app)
-
+ def test_evil_file(self):
# Test non-suppoerted file with non-supported extension
# -----------------------------------------------------
response, form = self.do_post({'title': u'Malicious Upload 1'},
@@ -220,26 +210,23 @@ class TestSubmission:
str(form.file.errors[0])
- def test_get_media_manager(self, test_app):
+ def test_get_media_manager(self):
"""Test if the get_media_manger function returns sensible things
"""
- self._setup(test_app)
-
response, request = self.do_post({'title': u'Balanced Goblin'},
*REQUEST_CONTEXT, do_follow=True,
**self.upload_data(GOOD_JPG))
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
assert media.media_type == u'mediagoblin.media_types.image'
- assert media.media_manager == img_MEDIA_MANAGER
+ assert isinstance(media.media_manager, img_MEDIA_MANAGER)
+ assert media.media_manager.entry == media
- def test_sniffing(self, test_app):
+ def test_sniffing(self):
'''
Test sniffing mechanism to assert that regular uploads work as intended
'''
- self._setup(test_app)
-
template.clear_test_template_context()
response = self.test_app.post(
'/submit/', {
@@ -269,30 +256,22 @@ class TestSubmission:
assert entry.state == 'failed'
assert entry.fail_error == u'mediagoblin.processing:BadMediaFail'
- def test_evil_jpg(self, test_app):
- self._setup(test_app)
-
+ def test_evil_jpg(self):
# Test non-supported file with .jpg extension
# -------------------------------------------
self.check_false_image(u'Malicious Upload 2', EVIL_JPG)
- def test_evil_png(self, test_app):
- self._setup(test_app)
-
+ def test_evil_png(self):
# Test non-supported file with .png extension
# -------------------------------------------
self.check_false_image(u'Malicious Upload 3', EVIL_PNG)
- def test_media_data(self, test_app):
- self._setup(test_app)
-
+ 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, test_app):
- self._setup(test_app)
-
+ def test_processing(self):
public_store_dir = mg_globals.global_config[
'storage:publicstore']['base_dir']
@@ -307,7 +286,7 @@ class TestSubmission:
# Does the processed image have a good filename?
filename = os.path.join(
public_store_dir,
- *media.media_files.get(key, []))
+ *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
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_timesince.py b/mediagoblin/tests/test_timesince.py
new file mode 100644
index 00000000..6579eb09
--- /dev/null
+++ b/mediagoblin/tests/test_timesince.py
@@ -0,0 +1,57 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from datetime import datetime, timedelta
+
+from mediagoblin.tools.timesince import is_aware, timesince
+
+
+def test_timesince():
+ test_time = datetime.now()
+
+ # it should ignore second and microseconds
+ assert timesince(test_time, test_time + timedelta(microseconds=1)) == "0 minutes"
+ assert timesince(test_time, test_time + timedelta(seconds=1)) == "0 minutes"
+
+ # test minutes, hours, days, weeks, months and years (singular and plural)
+ assert timesince(test_time, test_time + timedelta(minutes=1)) == "1 minute"
+ assert timesince(test_time, test_time + timedelta(minutes=2)) == "2 minutes"
+
+ assert timesince(test_time, test_time + timedelta(hours=1)) == "1 hour"
+ assert timesince(test_time, test_time + timedelta(hours=2)) == "2 hours"
+
+ assert timesince(test_time, test_time + timedelta(days=1)) == "1 day"
+ assert timesince(test_time, test_time + timedelta(days=2)) == "2 days"
+
+ assert timesince(test_time, test_time + timedelta(days=7)) == "1 week"
+ assert timesince(test_time, test_time + timedelta(days=14)) == "2 weeks"
+
+ assert timesince(test_time, test_time + timedelta(days=30)) == "1 month"
+ assert timesince(test_time, test_time + timedelta(days=60)) == "2 months"
+
+ assert timesince(test_time, test_time + timedelta(days=365)) == "1 year"
+ assert timesince(test_time, test_time + timedelta(days=730)) == "2 years"
+
+ # okay now we want to test combinations
+ # e.g. 1 hour, 5 days
+ assert timesince(test_time, test_time + timedelta(days=5, hours=1)) == "5 days, 1 hour"
+
+ assert timesince(test_time, test_time + timedelta(days=15)) == "2 weeks, 1 day"
+
+ assert timesince(test_time, test_time + timedelta(days=97)) == "3 months, 1 week"
+
+ assert timesince(test_time, test_time + timedelta(days=2250)) == "6 years, 2 months"
+
diff --git a/mediagoblin/tests/test_util.py b/mediagoblin/tests/test_util.py
index e4c04b7a..bc14f528 100644
--- a/mediagoblin/tests/test_util.py
+++ b/mediagoblin/tests/test_util.py
@@ -104,6 +104,28 @@ def test_locale_to_lower_lower():
assert translate.locale_to_lower_lower('en_us') == 'en-us'
+def test_gettext_lazy_proxy():
+ from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
+ from mediagoblin.tools.translate import pass_to_ugettext, set_thread_locale
+ proxy = _(u"Password")
+ orig = u"Password"
+
+ set_thread_locale("es")
+ p1 = unicode(proxy)
+ p1_should = pass_to_ugettext(orig)
+ assert p1_should != orig, "Test useless, string not translated"
+ assert p1 == p1_should
+
+ set_thread_locale("sv")
+ p2 = unicode(proxy)
+ p2_should = pass_to_ugettext(orig)
+ assert p2_should != orig, "Test broken, string not translated"
+ assert p2 == p2_should
+
+ assert p1_should != p2_should, "Test broken, same translated string"
+ assert p1 != p2
+
+
def test_html_cleaner():
# Remove images
result = text.clean_html(
diff --git a/mediagoblin/tests/test_workbench.py b/mediagoblin/tests/test_workbench.py
index 9cd49671..6695618b 100644
--- a/mediagoblin/tests/test_workbench.py
+++ b/mediagoblin/tests/test_workbench.py
@@ -21,7 +21,7 @@ import tempfile
from mediagoblin.tools import workbench
from mediagoblin.mg_globals import setup_globals
from mediagoblin.decorators import get_workbench
-from mediagoblin.tests.test_storage import get_tmp_filestorage
+from mediagoblin.tests.test_storage import get_tmp_filestorage, cleanup_storage
class TestWorkbench(object):
@@ -76,6 +76,7 @@ class TestWorkbench(object):
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)
@@ -102,6 +103,7 @@ class TestWorkbench(object):
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):
diff --git a/mediagoblin/tests/testplugins/callables1/__init__.py b/mediagoblin/tests/testplugins/callables1/__init__.py
index 9c278b49..fe801a01 100644
--- a/mediagoblin/tests/testplugins/callables1/__init__.py
+++ b/mediagoblin/tests/testplugins/callables1/__init__.py
@@ -14,8 +14,6 @@
# 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.pluginapi import CantHandleIt
-
def setup_plugin():
pass
@@ -30,12 +28,16 @@ def multi_handle(call_log):
return "the first returns"
def multi_handle_with_canthandle(call_log):
- raise CantHandleIt("I just can't accept this stupid method")
+ return None
+
+def expand_tuple(this_tuple):
+ return this_tuple + (1,)
hooks = {
'setup': setup_plugin,
'just_one': just_one,
'multi_handle': multi_handle,
'multi_handle_with_canthandle': multi_handle_with_canthandle,
+ 'expand_tuple': expand_tuple,
}
diff --git a/mediagoblin/tests/testplugins/callables2/__init__.py b/mediagoblin/tests/testplugins/callables2/__init__.py
index aaab5b21..9d5cf950 100644
--- a/mediagoblin/tests/testplugins/callables2/__init__.py
+++ b/mediagoblin/tests/testplugins/callables2/__init__.py
@@ -29,10 +29,13 @@ 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
index 8d0c9c25..04efc8fc 100644
--- a/mediagoblin/tests/testplugins/callables3/__init__.py
+++ b/mediagoblin/tests/testplugins/callables3/__init__.py
@@ -29,10 +29,13 @@ 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 a0498a6e..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
@@ -28,7 +29,6 @@ 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.base import Session
from mediagoblin.meddleware import BaseMeddleware
from mediagoblin.auth.lib import bcrypt_gen_password_hash
@@ -50,7 +50,9 @@ USER_DEV_DIRECTORIES_TO_SETUP = ['media/public', 'media/queue']
BAD_CELERY_MESSAGE = """\
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/py.test"""
+
+$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests {0}
+""".format(sys.argv[0])
class BadCeleryEnviron(Exception): pass
@@ -230,7 +232,7 @@ def fixture_media_entry(title=u"Some title", slug=None,
entry.slug = slug
entry.uploader = uploader or fixture_add_user().id
entry.media_type = u'image'
-
+
if gen_slug:
entry.generate_slug()
if save: