mirror of https://github.com/NaN-tic/nereid.git
302 lines
9.5 KiB
Python
302 lines
9.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
nereid.testing
|
|
~~~~~~~~~~~~~
|
|
|
|
Implements test support helpers. This module is lazily imported
|
|
and usually not used in production environments.
|
|
|
|
:copyright: (c) 2010-2011 by Openlabs Technologies & Consulting (P) Ltd.
|
|
:copyright: (c) 2010 by Armin Ronacher.
|
|
:license: BSD, see LICENSE for more details.
|
|
"""
|
|
import new
|
|
|
|
import unittest2
|
|
from werkzeug import Client, EnvironBuilder
|
|
from nereid import _request_ctx_stack
|
|
from nereid.session import Session
|
|
from werkzeug.contrib.sessions import FilesystemSessionStore
|
|
|
|
|
|
class NereidClient(Client):
|
|
"""Works like a regular Werkzeug test client but has some
|
|
knowledge about how Nereid works to defer the cleanup of the
|
|
request context stack to the end of a with body when used
|
|
in a with statement.
|
|
"""
|
|
|
|
preserve_context = context_preserved = False
|
|
|
|
def open(self, *args, **kwargs):
|
|
if self.context_preserved:
|
|
_request_ctx_stack.pop()
|
|
self.context_preserved = False
|
|
kwargs.setdefault('environ_overrides', {}) \
|
|
['nereid._preserve_context'] = self.preserve_context
|
|
|
|
as_tuple = kwargs.pop('as_tuple', False)
|
|
buffered = kwargs.pop('buffered', False)
|
|
follow_redirects = kwargs.pop('follow_redirects', False)
|
|
|
|
builder = EnvironBuilder(*args, **kwargs)
|
|
|
|
if not isinstance(
|
|
self.application.session_interface.session_store,
|
|
FilesystemSessionStore):
|
|
self.application.session_interface.session_store = \
|
|
FilesystemSessionStore(session_class=Session)
|
|
|
|
if self.application.config.get('SERVER_NAME'):
|
|
server_name = self.application.config.get('SERVER_NAME')
|
|
if ':' not in server_name:
|
|
http_host, http_port = server_name, None
|
|
else:
|
|
http_host, http_port = server_name.split(':', 1)
|
|
if builder.base_url == 'http://localhost/':
|
|
# Default Generated Base URL
|
|
if http_port != None:
|
|
builder.host = http_host + ':' + http_port
|
|
else:
|
|
builder.host = http_host
|
|
old = _request_ctx_stack.top
|
|
try:
|
|
return Client.open(self, builder,
|
|
as_tuple=as_tuple,
|
|
buffered=buffered,
|
|
follow_redirects=follow_redirects)
|
|
finally:
|
|
self.context_preserved = _request_ctx_stack.top is not old
|
|
|
|
def __enter__(self):
|
|
self.preserve_context = True
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, tb):
|
|
self.preserve_context = False
|
|
if self.context_preserved:
|
|
_request_ctx_stack.pop()
|
|
|
|
|
|
|
|
class FailFastTextTestRunner(unittest2.TextTestRunner):
|
|
"""A subclass of TextTestRunner which fails fast by default
|
|
"""
|
|
def _makeResult(self):
|
|
"""This method returns an instance of the TestResult which infact
|
|
handles the failfast behaviour in the core
|
|
"""
|
|
rv = super(FailFastTextTestRunner, self)._makeResult()
|
|
rv.failfast = True
|
|
return rv
|
|
|
|
|
|
class TestingProxy(object):
|
|
"""A collection of helper methods to make testing easier by creating
|
|
a convenience class which could be passed around for testing methods
|
|
like the one documented below.
|
|
"""
|
|
|
|
def __init__(self):
|
|
"""Required for initialisation and easy access to other members
|
|
"""
|
|
self.initialised = False
|
|
|
|
def init(self):
|
|
from trytond.config import CONFIG
|
|
CONFIG['database_type'] = 'sqlite'
|
|
self.db_name = ':memory:'
|
|
|
|
from trytond.backend import Database
|
|
database = Database()
|
|
cursor = database.cursor()
|
|
databases = database.list(cursor)
|
|
cursor.close()
|
|
|
|
if self.db_name not in databases:
|
|
from trytond.protocols.dispatcher import create
|
|
create(self.db_name, 'admin', 'en_US', 'admin')
|
|
|
|
from trytond.pool import Pool
|
|
self.pool = Pool(self.db_name)
|
|
self.pool.init()
|
|
|
|
self.user = 1
|
|
self.context = None
|
|
self.initialised = True
|
|
|
|
def drop_database(self):
|
|
"""
|
|
Drop the database that was used for testing
|
|
"""
|
|
if not self.initialised:
|
|
raise Exception("Cannot drop database when not initialised")
|
|
from trytond.protocols.dispatcher import drop
|
|
drop(self.db_name, 'admin')
|
|
|
|
def install_module(self, module):
|
|
if not self.initialised:
|
|
self.init()
|
|
from trytond.transaction import Transaction
|
|
with Transaction().start(self.db_name, self.user, self.context) as txn:
|
|
module_obj = self.pool.get('ir.module.module')
|
|
module = module_obj.search([('name', '=', module)])
|
|
module_obj.button_install(module)
|
|
|
|
install_wizard = self.pool.get('ir.module.module.install_upgrade',
|
|
type="wizard")
|
|
wiz_id = install_wizard.create()
|
|
install_wizard.execute(wiz_id, {}, 'start')
|
|
txn.cursor.commit()
|
|
|
|
def register(self, name=None):
|
|
"""A decorator that is used to register functions for being attached
|
|
as helper method for testing
|
|
|
|
Eg:
|
|
|
|
@testing_proxy.regsiter()
|
|
def create_something(obj, arg):
|
|
pass
|
|
|
|
"""
|
|
def decorator(f):
|
|
method_name = f.func_name if not name else name
|
|
setattr(self, method_name, new.instancemethod(
|
|
f, self, TestingProxy))
|
|
return f
|
|
return decorator
|
|
|
|
def make_app(self, **options):
|
|
"""Creates an app with the given options
|
|
"""
|
|
from nereid import Nereid
|
|
options['DATABASE_NAME'] = self.db_name
|
|
options['DEBUG'] = True
|
|
return Nereid(**options)
|
|
|
|
|
|
# An instance of testing module which can be used inside test cases
|
|
testing_proxy = TestingProxy()
|
|
|
|
|
|
class TestCase(unittest2.TestCase):
|
|
"""
|
|
A TestCase template that could be subclassed by test implementations
|
|
|
|
Subclassing this gives automatic database creation on setupClass and drop
|
|
of database at the end of execution of the TestCase.
|
|
"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
testing_proxy.init()
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
testing_proxy.drop_database()
|
|
|
|
|
|
@testing_proxy.register()
|
|
def create_company(obj, name, currency='USD'):
|
|
"""Creates a new company and returns the ID
|
|
"""
|
|
company_obj = obj.pool.get('company.company')
|
|
currency_obj = obj.pool.get('currency.currency')
|
|
|
|
currency_id, = currency_obj.search([('code', '=', currency)], limit=1)
|
|
return company_obj.create({'name': name, 'currency': currency_id})
|
|
|
|
|
|
@testing_proxy.register()
|
|
def create_user_party(obj, name, email, password, company):
|
|
"""Creates a user with given data
|
|
|
|
:param obj: The instance of :class:TestingProxy. This value need not be
|
|
passed as the decorator automatically assigns this value
|
|
:param name: The name for the user
|
|
:param email: The email for the user (login)
|
|
:param password: The password of the user
|
|
:param company: The company to which the user must belong
|
|
:return: ID of the created user
|
|
"""
|
|
user_obj = obj.pool.get('nereid.user')
|
|
|
|
return user_obj.create({
|
|
'name': name,
|
|
'email': email,
|
|
'password': password,
|
|
'company': company,
|
|
})
|
|
|
|
|
|
@testing_proxy.register()
|
|
def create_guest_user(obj, name='Guest', email='guest@example.com',
|
|
company=None):
|
|
"""Create guest user
|
|
|
|
.. note::
|
|
This is a wrapper around :function:`create_user_party`
|
|
|
|
:param obj: The instance of :class:TestingProxy. This value need not be
|
|
passed as the decorator automatically assigns this value
|
|
:param name: Name of the user, defaults to `Guest`
|
|
:param email: Email of the user, defaults to `guest@example.com`
|
|
:param company: The company to which the user must belong
|
|
:return: ID of the created user
|
|
"""
|
|
return obj.create_user_party(name, email, 'password', company)
|
|
|
|
|
|
@testing_proxy.register()
|
|
def create_template(obj, name, source, site=False, lang_code='en_US'):
|
|
"""Creates and returns template ID
|
|
"""
|
|
lang_obj = obj.pool.get('ir.lang')
|
|
template_obj = obj.pool.get('nereid.template')
|
|
|
|
return template_obj.create({
|
|
'name': name,
|
|
'source': source,
|
|
'language': lang_obj.search([('code', '=', lang_code)], limit=1)[0],
|
|
'website': site,
|
|
})
|
|
|
|
|
|
@testing_proxy.register()
|
|
def create_site(obj, name, url_map=None, company=None, **options):
|
|
"""Create a site."""
|
|
company_obj = obj.pool.get('company.company')
|
|
site_obj = obj.pool.get('nereid.website')
|
|
url_map_obj = obj.pool.get('nereid.url_map')
|
|
lang_obj = obj.pool.get('ir.lang')
|
|
|
|
options['name'] = name
|
|
|
|
if url_map is None:
|
|
url_map, = url_map_obj.search([], limit=1)
|
|
options['url_map'] = url_map
|
|
|
|
if company is None:
|
|
company, = company_obj.search([], limit=1)
|
|
options['company'] = company
|
|
|
|
if 'default_language' not in options:
|
|
options['default_language'], = lang_obj.search(
|
|
[('code', '=', 'en_US')])
|
|
|
|
if 'application_user' not in options:
|
|
options['application_user'] = 1
|
|
|
|
return site_obj.create(options)
|
|
|
|
|
|
@testing_proxy.register()
|
|
def set_company_for_user(self, user, company):
|
|
"""Set company for current user"""
|
|
user_obj = self.pool.get('res.user')
|
|
return user_obj.write(user, {
|
|
'main_company': company,
|
|
'company': company
|
|
})
|