blob: 1bfa5a39ff7c464fabe16b195779382a3d1a4382 [file] [log] [blame]
# -*- coding: utf-8 -*-
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Tests for Apache(TM) Bloodhound's product configuration objects"""
from ConfigParser import ConfigParser
from itertools import groupby
import os.path
import shutil
from StringIO import StringIO
import unittest
from trac.config import Option
from trac.tests.config import ConfigurationTestCase
from trac.util.text import to_unicode
from multiproduct.api import MultiProductSystem
from multiproduct.config import Configuration
from multiproduct.model import Product, ProductSetting
from tests.env import MultiproductTestCase
class ProductConfigTestCase(ConfigurationTestCase, MultiproductTestCase):
r"""Test cases for Trac configuration objects rewritten for product
scope.
"""
def setUp(self):
r"""Replace Trac environment with product environment
"""
self.env = self._setup_test_env()
# Dummy config file, a sibling of trac.ini
tmpdir = os.path.realpath(self.env.path)
self.filename = os.path.join(tmpdir, 'conf', 'product.ini')
# Ensure conf sub-folder is created
os.mkdir(os.path.dirname(self.filename))
self._upgrade_mp(self.env)
self._setup_test_log(self.env)
self._load_product_from_data(self.env, self.default_product)
self._orig_registry = Option.registry
Option.registry = {}
def tearDown(self):
Option.registry = self._orig_registry
shutil.rmtree(self.env.path)
self.env = None
def _read(self, parents=None, product=None):
r"""Override superclass method by returning product-aware configuration
object retrieving settings from the database. Such objects will replace
instances of `trac.config.Configuration` used in inherited test cases.
"""
if product is None:
product = self.default_product
return Configuration(self.env, product, parents)
def _write(self, lines, product=None):
r"""Override superclass method by writing configuration values
to the database rather than ini file in the filesystem.
"""
if product is None:
product = self.default_product
product = to_unicode(product)
fp = StringIO(('\n'.join(lines + [''])).encode('utf-8'))
parser = ConfigParser()
parser.readfp(fp, 'bh-product-test')
with self.env.db_transaction as db:
# Delete existing setting for target product , if any
for setting in ProductSetting.select(self.env, db,
{'product' : product}):
setting.delete()
# Insert new options
for section in parser.sections():
option_key = dict(
section=to_unicode(section),
product=to_unicode(product)
)
for option, value in parser.items(section):
option_key.update(dict(option=to_unicode(option)))
setting = ProductSetting(self.env)
setting._data.update(option_key)
setting._data['value'] = to_unicode(value)
setting.insert()
def _test_with_inherit(self, testcb):
"""Almost exact copy of `trac.tests.config.ConfigurationTestCase`.
Differences explained in inline comments.
"""
# Parent configuration file created in environment's conf sub-folder
# PS: This modification would not be necessary if the corresponding
# statement in overriden method would be written the same way
# but the fact that both files have the same parent folder
# is not made obvious in there
sitename = os.path.join(os.path.dirname(self.filename), 'trac-site.ini')
try:
with open(sitename, 'w') as sitefile:
sitefile.write('[a]\noption = x\n')
self._write(['[inherit]', 'file = trac-site.ini'])
testcb()
finally:
os.remove(sitename)
def _dump_settings(self, config):
product = config.product
fields = ('section', 'option', 'value')
rows = [tuple(getattr(s, f, None) for f in fields) for s in
ProductSetting.select(config.env, where={'product' : product})]
dump = []
for section, group in groupby(sorted(rows), lambda row: row[0]):
dump.append('[%s]\n' % (section,))
for row in group:
dump.append('%s = %s\n' % (row[1], row[2]))
return dump
# Test cases rewritten to avoid reading config file.
# It does make sense for product config as it's stored in the database
def test_set_and_save(self):
config = self._read()
config.set('b', u'öption0', 'y')
config.set(u'aä', 'öption0', 'x')
config.set('aä', 'option2', "Voilà l'été") # UTF-8
config.set(u'aä', 'option1', u"Voilà l'été") # unicode
# Note: the following would depend on the locale.getpreferredencoding()
# config.set('a', 'option3', "Voil\xe0 l'\xe9t\xe9") # latin-1
self.assertEquals('x', config.get(u'aä', u'öption0'))
self.assertEquals(u"Voilà l'été", config.get(u'aä', 'option1'))
self.assertEquals(u"Voilà l'été", config.get(u'aä', 'option2'))
config.save()
dump = self._dump_settings(config)
self.assertEquals([
u'[aä]\n',
u"option1 = Voilà l'été\n",
u"option2 = Voilà l'été\n",
u'öption0 = x\n',
# u"option3 = Voilà l'été\n",
u'[b]\n',
u'öption0 = y\n',
],
dump)
config2 = self._read()
self.assertEquals('x', config2.get(u'aä', u'öption0'))
self.assertEquals(u"Voilà l'été", config2.get(u'aä', 'option1'))
self.assertEquals(u"Voilà l'été", config2.get(u'aä', 'option2'))
# self.assertEquals(u"Voilà l'été", config2.get('a', 'option3'))
def test_set_and_save_inherit(self):
def testcb():
config = self._read()
config.set('a', 'option2', "Voilà l'été") # UTF-8
config.set('a', 'option1', u"Voilà l'été") # unicode
self.assertEquals('x', config.get('a', 'option'))
self.assertEquals(u"Voilà l'été", config.get('a', 'option1'))
self.assertEquals(u"Voilà l'été", config.get('a', 'option2'))
config.save()
dump = self._dump_settings(config)
self.assertEquals([
u'[a]\n',
u"option1 = Voilà l'été\n",
u"option2 = Voilà l'été\n",
u'[inherit]\n',
u"file = trac-site.ini\n",
],
dump)
config2 = self._read()
self.assertEquals('x', config2.get('a', 'option'))
self.assertEquals(u"Voilà l'été", config2.get('a', 'option1'))
self.assertEquals(u"Voilà l'été", config2.get('a', 'option2'))
self._test_with_inherit(testcb)
def test_overwrite(self):
config = self._read()
config.set('a', 'option', 'value1')
self.assertEquals('value1', config.get('a', 'option'))
config.set('a', 'option', 'value2')
self.assertEquals('value2', config.get('a', 'option'))
def test_suite():
return unittest.makeSuite(ProductConfigTestCase,'test')
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')