# -*- coding: utf-8 -*-
"""
Inheritance Diagram
-------------------
.. inheritance-diagram:: kotti.testing
"""
import os
from os.path import join, dirname
from unittest import TestCase
from pytest import mark
from pyramid import testing
from pyramid.events import NewResponse
from pyramid.interfaces import ILocation
from pyramid.security import ALL_PERMISSIONS
from zope.deprecation.deprecation import deprecate
from zope.interface import implementer
import transaction
# re-enable deprecation warnings during test runs
# however, let the `ImportWarning` produced by Babel's
# `localedata.py` vs `localedata/` show up once...
from warnings import catch_warnings
with catch_warnings():
from babel import localedata
import compiler
localedata, compiler # make pyflakes happy... :p
# py.test markers (see http://pytest.org/latest/example/markers.html)
user = mark.user
BASE_URL = 'http://localhost:6543'
[docs]class Dummy(dict):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
[docs]class DummyRequest(testing.DummyRequest):
is_xhr = False
POST = dict()
user = None
referrer = None
def is_response(self, ob):
return (hasattr(ob, 'app_iter') and hasattr(ob, 'headerlist') and
hasattr(ob, 'status'))
def asset(name):
import kotti
return open(join(dirname(kotti.__file__), 'tests', name), 'rb')
def includeme_login(config):
config.add_view(
login_view,
name='login',
renderer='kotti:templates/login.pt')
def includeme_layout(config):
# override edit master layout with view master layout
config.override_asset(
to_override='kotti:templates/edit/master.pt',
override_with='kotti:templates/view/master.pt')
def login_view(request):
return {}
def dummy_search(search_term, request):
return u"Not found. Sorry!"
def testing_db_url():
return os.environ.get('KOTTI_TEST_DB_STRING', 'sqlite://')
def _initTestingDB():
from sqlalchemy import create_engine
from kotti import get_settings
from kotti.resources import initialize_sql
database_url = testing_db_url()
get_settings()['sqlalchemy.url'] = database_url
session = initialize_sql(create_engine(database_url), drop_all=True)
return session
def _populator():
from kotti import DBSession
from kotti.resources import Document
from kotti.populate import populate
populate()
for doc in DBSession.query(Document)[1:]:
DBSession.delete(doc)
transaction.commit()
def _turn_warnings_into_errors(): # pragma: no cover
# turn all warnings into errors, but let the `ImportWarning`
# produced by Babel's `localedata.py` vs `localedata/` show up once...
from babel import localedata
localedata # make pyflakes happy... :p
from warnings import filterwarnings
filterwarnings("error")
def setUp(init_db=True, **kwargs):
# _turn_warnings_into_errors()
from kotti import _resolve_dotted
from kotti import conf_defaults
tearDown()
settings = conf_defaults.copy()
settings['kotti.secret'] = 'secret'
settings['kotti.secret2'] = 'secret2'
settings['kotti.populators'] = 'kotti.testing._populator'
settings.update(kwargs.get('settings', {}))
settings = _resolve_dotted(settings)
kwargs['settings'] = settings
config = testing.setUp(**kwargs)
config.add_default_renderers()
if init_db:
_initTestingDB()
transaction.begin()
return config
def tearDown():
from kotti import events
from kotti import security
from kotti.message import _inject_mailer
# These should arguable use the configurator, so they don't need
# to be torn down separately:
events.clear()
security.reset()
_inject_mailer[:] = []
transaction.abort()
testing.tearDown()
[docs]class UnitTestBase(TestCase):
[docs] def setUp(self, **kwargs):
self.config = setUp(**kwargs)
[docs] def tearDown(self):
tearDown()
[docs]class EventTestBase(TestCase):
[docs] def setUp(self, **kwargs):
super(EventTestBase, self).setUp(**kwargs)
self.config.include('kotti.events')
# Functional ----
def _functional_includeme(config):
from kotti import DBSession
def expire(event):
DBSession.flush()
DBSession.expire_all()
config.add_subscriber(expire, NewResponse)
def _zope_testbrowser_pyquery(self):
from pyquery import PyQuery
return PyQuery(
self.contents.replace('xmlns="http://www.w3.org/1999/xhtml', ''))
def setUpFunctional(global_config=None, **settings):
from kotti import main
import wsgi_intercept.zope_testbrowser
from webtest import TestApp
tearDown()
_settings = {
'sqlalchemy.url': testing_db_url(),
'kotti.secret': 'secret',
'kotti.site_title': 'Website des Kottbusser Tors', # for mailing
'kotti.populators': 'kotti.testing._populator',
'mail.default_sender': 'kotti@localhost',
'pyramid.includes': 'kotti.testing._functional_includeme',
}
_settings.update(settings)
host, port = BASE_URL.split(':')[-2:]
app = main({}, **_settings)
wsgi_intercept.add_wsgi_intercept(host[2:], int(port), lambda: app)
Browser = wsgi_intercept.zope_testbrowser.WSGI_Browser
Browser.pyquery = property(_zope_testbrowser_pyquery)
return dict(
Browser=Browser,
browser=Browser(),
test_app=TestApp(app),
)
[docs]class FunctionalTestBase(TestCase):
BASE_URL = BASE_URL
[docs] def setUp(self, **kwargs):
self.__dict__.update(setUpFunctional(**kwargs))
[docs] def tearDown(self):
tearDown()
def login(self, login=u'admin', password=u'secret'):
return self.test_app.post(
'/@@login',
{'login': login, 'password': password, 'submit': 'submit'},
status=302,
)
@deprecate('login_testbrowser is deprecated as of Kotti 0.7. Please use '
'the `browser` funcarg in conjunction with the `@user` '
'decorator.')
def login_testbrowser(self, login=u'admin', password=u'secret'):
browser = self.Browser()
browser.open(BASE_URL + '/edit')
browser.getControl("Username or email").value = login
browser.getControl("Password").value = password
browser.getControl(name="submit").click()
return browser
[docs]@implementer(ILocation)
class TestingRootFactory(dict):
__name__ = '' # root is required to have an empty name!
__parent__ = None
__acl__ = [('Allow', 'role:admin', ALL_PERMISSIONS)]
def __init__(self, request):
super(TestingRootFactory, self).__init__()
def dummy_view(context, request):
return {}
def include_testing_view(config):
config.add_view(
dummy_view,
context=TestingRootFactory,
renderer='kotti:tests/testing_view.pt',
)
config.add_view(
dummy_view,
name='secured',
permission='view',
context=TestingRootFactory,
renderer='kotti:tests/testing_view.pt',
)
def setUpFunctionalStrippedDownApp(global_config=None, **settings):
# An app that doesn't use Nodes at all
_settings = {
'kotti.base_includes': (
'kotti kotti.views kotti.views.login kotti.views.users '
'kotti.views.view'),
'kotti.use_tables': 'principals',
'kotti.populators': 'kotti.populate.populate_users',
'pyramid.includes': 'kotti.testing.include_testing_view',
'kotti.root_factory': 'kotti.testing.TestingRootFactory',
'kotti.site_title': 'My Stripped Down Kotti',
}
_settings.update(settings)
return setUpFunctional(global_config, **_settings)
def registerDummyMailer():
from pyramid_mailer.mailer import DummyMailer
from kotti.message import _inject_mailer
mailer = DummyMailer()
_inject_mailer.append(mailer)
return mailer
# set up deprecation warnings
from zope.deprecation.deprecation import deprecated # noqa
for item in UnitTestBase, EventTestBase, FunctionalTestBase, _initTestingDB:
name = getattr(item, '__name__', item)
deprecated(name, 'Unittest-style tests are deprecated as of Kotti 0.7. '
'Please use pytest function arguments instead.')