summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris St. Pierre <chris.a.st.pierre@gmail.com>2013-10-29 16:35:27 -0400
committerChris St. Pierre <chris.a.st.pierre@gmail.com>2013-10-30 06:37:46 -0400
commitc4e1b49ff7d5b8f5860f5cc208476ff42159724e (patch)
tree84da32caf2072e617dd6b7be992ff5971b50095a
parent2161b4be08f2b295f68e2f7c0f9c791919542a39 (diff)
downloadbcfg2-c4e1b49ff7d5b8f5860f5cc208476ff42159724e.tar.gz
bcfg2-c4e1b49ff7d5b8f5860f5cc208476ff42159724e.tar.bz2
bcfg2-c4e1b49ff7d5b8f5860f5cc208476ff42159724e.zip
Plugins: Added TemplateDataProvider plugin interface
This lets you provide variables to the top-level namespace of templates in a more seamless way than through a Connector plugin. It's mostly useful for TemplateHelper for now, but may find other uses in the future.
-rw-r--r--src/lib/Bcfg2/Server/Plugin/helpers.py84
-rw-r--r--src/lib/Bcfg2/Server/Plugin/interfaces.py37
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py24
-rw-r--r--src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py24
-rw-r--r--src/lib/Bcfg2/Server/Plugins/TemplateHelper.py57
-rw-r--r--src/lib/Bcfg2/Server/__init__.py1
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py21
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py32
8 files changed, 225 insertions, 55 deletions
diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py
index 4cd87bd70..1cb5a7b3e 100644
--- a/src/lib/Bcfg2/Server/Plugin/helpers.py
+++ b/src/lib/Bcfg2/Server/Plugin/helpers.py
@@ -16,7 +16,7 @@ import Bcfg2.Server.FileMonitor
from Bcfg2.Logger import Debuggable
from Bcfg2.Compat import CmpMixin, wraps
from Bcfg2.Server.Plugin.base import Plugin
-from Bcfg2.Server.Plugin.interfaces import Generator
+from Bcfg2.Server.Plugin.interfaces import Generator, TemplateDataProvider
from Bcfg2.Server.Plugin.exceptions import SpecificityError, \
PluginExecutionError
@@ -127,6 +127,82 @@ def default_path_metadata():
'paranoid', 'sensitive']])
+class DefaultTemplateDataProvider(TemplateDataProvider):
+ """ A base
+ :class:`Bcfg2.Server.Plugin.interfaces.TemplateDataProvider` that
+ provides default data for text and XML templates.
+
+ Note that, since Cheetah and Genshi text templates treat the
+ ``path`` variable differently, this is overridden, by
+ :class:`Bcfg2.Server.Plugins.Cfg.CfgCheetahGenerator.DefaultCheetahDataProvider`
+ and
+ :class:`Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.DefaultGenshiDataProvider`,
+ respectively. """
+
+ def get_template_data(self, entry, metadata, template):
+ return dict(name=entry.get('realname', entry.get('name')),
+ metadata=metadata,
+ source_path=template,
+ repo=Bcfg2.Options.setup.repository)
+
+ def get_xml_template_data(self, _, metadata):
+ return dict(metadata=metadata,
+ repo=Bcfg2.Options.setup.repository)
+
+_sentinel = object() # pylint: disable=C0103
+
+
+def _get_template_data(func_name, args, default=_sentinel):
+ """ Generic template data getter for both text and XML templates.
+
+ :param func_name: The name of the function to call on
+ :class:`Bcfg2.Server.Plugin.interfaces.TemplateDataProvider`
+ objects to get data for this template type.
+ Should be one of either ``get_template_data``
+ for text templates, or ``get_xml_template_data``
+ for XML templates.
+ :type func_name: string
+ :param args: The arguments to pass to the data retrieval function
+ :type args: list
+ :param default: An object that provides a set of base values. If
+ this is not provided, an instance of
+ :class:`Bcfg2.Server.Plugin.helpers.DefaultTemplateDataProvider`
+ is used. This can be set to None to avoid setting
+ any base values at all.
+ :type default: Bcfg2.Server.Plugin.interfaces.TemplateDataProvider
+ """
+ if default is _sentinel:
+ default = DefaultTemplateDataProvider()
+ providers = Bcfg2.Server.core.plugins_by_type(TemplateDataProvider)
+ if default is not None:
+ providers.insert(0, default)
+
+ rv = dict()
+ source = dict()
+ for prov in providers:
+ pdata = getattr(prov, func_name)(*args)
+ for key, val in pdata.items():
+ if key not in rv:
+ rv[key] = val
+ source[key] = prov
+ else:
+ LOGGER.warning("Duplicate template variable %s provided by "
+ "both %s and %s" % (key, prov, source[key]))
+ return rv
+
+
+def get_template_data(entry, metadata, template, default=_sentinel):
+ """ Get all template variables for a text (i.e., Cfg) template """
+ return _get_template_data("get_template_data", [entry, metadata, template],
+ default=default)
+
+
+def get_xml_template_data(structfile, metadata, default=_sentinel):
+ """ Get all template variables for an XML template """
+ return _get_template_data("get_xml_template_data", [structfile, metadata],
+ default=default)
+
+
class DatabaseBacked(Plugin):
""" Provides capabilities for a plugin to read and write to a
database. The plugin must add an option to flag database use with
@@ -741,10 +817,8 @@ class StructFile(XMLFileBacked):
XML data
"""
stream = self.template.generate(
- metadata=metadata,
- repo=Bcfg2.Options.setup.repository).filter(removecomment)
- return lxml.etree.XML(stream.render('xml',
- strip_whitespace=False),
+ **get_xml_template_data(self, metadata)).filter(removecomment)
+ return lxml.etree.XML(stream.render('xml', strip_whitespace=False),
parser=Bcfg2.Server.XMLParser)
def _match(self, item, metadata, *args):
diff --git a/src/lib/Bcfg2/Server/Plugin/interfaces.py b/src/lib/Bcfg2/Server/Plugin/interfaces.py
index d51c199cd..622b69c79 100644
--- a/src/lib/Bcfg2/Server/Plugin/interfaces.py
+++ b/src/lib/Bcfg2/Server/Plugin/interfaces.py
@@ -12,6 +12,11 @@ from Bcfg2.Server.Plugin.base import Plugin
from Bcfg2.Server.Plugin.exceptions import PluginInitError, \
MetadataRuntimeError, MetadataConsistencyError
+# Since this file basically just contains abstract interface
+# descriptions, just about every function declaration has unused
+# arguments. Disable this pylint warning for the whole file.
+# pylint: disable=W0613
+
class Generator(object):
""" Generator plugins contribute to literal client configurations.
@@ -27,13 +32,12 @@ class Generator(object):
generate the content. The callable will receive two arguments:
the abstract entry (as an lxml.etree._Element object), and the
client metadata object the entry is being generated for.
-
#. If the entry is not listed in ``Entries``, the Bcfg2 core calls
:func:`HandlesEntry`; if that returns True, then it calls
:func:`HandleEntry`.
"""
- def HandlesEntry(self, entry, metadata): # pylint: disable=W0613
+ def HandlesEntry(self, entry, metadata):
""" HandlesEntry is the slow path method for routing
configuration binding requests. It is called if the
``Entries`` dict does not contain a method for binding the
@@ -48,7 +52,7 @@ class Generator(object):
"""
return False
- def HandleEntry(self, entry, metadata): # pylint: disable=W0613
+ def HandleEntry(self, entry, metadata):
""" HandleEntry is the slow path method for binding
configuration binding requests. It is called if the
``Entries`` dict does not contain a method for binding the
@@ -138,7 +142,6 @@ class Metadata(object):
"""
pass
- # pylint: disable=W0613
def resolve_client(self, address, cleanup_cache=False):
""" Resolve the canonical name of this client. If this method
is not implemented, the hostname claimed by the client is
@@ -156,7 +159,6 @@ class Metadata(object):
:class:`Bcfg2.Server.Plugin.exceptions.MetadataConsistencyError`
"""
return address[1]
- # pylint: enable=W0613
def AuthenticateConnection(self, cert, user, password, address):
""" Authenticate the given client.
@@ -219,7 +221,7 @@ class Connector(object):
""" Connector plugins augment client metadata instances with
additional data, additional groups, or both. """
- def get_additional_groups(self, metadata): # pylint: disable=W0613
+ def get_additional_groups(self, metadata):
""" Return a list of additional groups for the given client.
Each group can be either the name of a group (a string), or a
:class:`Bcfg2.Server.Plugins.Metadata.MetadataGroup` object
@@ -250,7 +252,7 @@ class Connector(object):
"""
return list()
- def get_additional_data(self, metadata): # pylint: disable=W0613
+ def get_additional_data(self, metadata):
""" Return arbitrary additional data for the given
ClientMetadata object. By convention this is usually a dict
object, but doesn't need to be.
@@ -473,7 +475,7 @@ class ThreadedStatistics(Statistics, Threaded, threading.Thread):
# Someone who understands these interfaces better needs to write docs
# for PullSource and PullTarget
class PullSource(object):
- def GetExtra(self, client): # pylint: disable=W0613
+ def GetExtra(self, client):
return []
def GetCurrentEntry(self, client, e_type, e_name):
@@ -630,7 +632,7 @@ class ClientACLs(object):
""" ClientACLs are used to grant or deny access to different
XML-RPC calls based on client IP or metadata. """
- def check_acl_ip(self, address, rmi): # pylint: disable=W0613
+ def check_acl_ip(self, address, rmi):
""" Check if the given IP address is authorized to make the
named XML-RPC call.
@@ -643,7 +645,7 @@ class ClientACLs(object):
"""
return True
- def check_acl_metadata(self, metadata, rmi): # pylint: disable=W0613
+ def check_acl_metadata(self, metadata, rmi):
""" Check if the given client is authorized to make the named
XML-RPC call.
@@ -654,3 +656,18 @@ class ClientACLs(object):
:returns: bool
"""
return True
+
+
+class TemplateDataProvider(object):
+ """ TemplateDataProvider plugins provide variables to templates
+ for use in rendering. """
+
+ def get_template_data(self, entry, metadata, template):
+ """ Get a dict of variables that will be supplied to a Cfg
+ template for rendering """
+ return dict()
+
+ def get_xml_template_data(self, structfile, metadata):
+ """ Get a dict of variables that will be supplied to an XML
+ template (e.g., a bundle) for rendering """
+ return dict()
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py
index 476dc1fc6..84309b5dd 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgCheetahGenerator.py
@@ -3,7 +3,8 @@
:ref:`server-plugins-generators-cfg` files. """
import Bcfg2.Options
-from Bcfg2.Server.Plugin import PluginExecutionError
+from Bcfg2.Server.Plugin import PluginExecutionError, \
+ DefaultTemplateDataProvider, get_template_data
from Bcfg2.Server.Plugins.Cfg import CfgGenerator
try:
@@ -13,6 +14,18 @@ except ImportError:
HAS_CHEETAH = False
+class DefaultCheetahDataProvider(DefaultTemplateDataProvider):
+ """ Template data provider for Cheetah templates. Cheetah and
+ Genshi currently differ over the value of the ``path`` variable,
+ which is why this is necessary. """
+
+ def get_template_data(self, entry, metadata, template):
+ rv = DefaultTemplateDataProvider.get_template_data(self, entry,
+ metadata, template)
+ rv['path'] = rv['name']
+ return rv
+
+
class CfgCheetahGenerator(CfgGenerator):
""" The CfgCheetahGenerator allows you to use the `Cheetah
<http://www.cheetahtemplate.org/>`_ templating system to generate
@@ -37,10 +50,9 @@ class CfgCheetahGenerator(CfgGenerator):
def get_data(self, entry, metadata):
template = Template(self.data.decode(Bcfg2.Options.setup.encoding),
compilerSettings=self.settings)
- template.metadata = metadata
- template.name = entry.get('realname', entry.get('name'))
- template.path = entry.get('realname', entry.get('name'))
- template.source_path = self.name
- template.repo = Bcfg2.Options.setup.repository
+ for key, val in get_template_data(
+ entry, metadata, self.name,
+ default=DefaultCheetahDataProvider()).items():
+ setattr(template, key, val)
return template.respond()
get_data.__doc__ = CfgGenerator.get_data.__doc__
diff --git a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py
index 7ba8c4491..ef4e6a656 100644
--- a/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py
+++ b/src/lib/Bcfg2/Server/Plugins/Cfg/CfgGenshiGenerator.py
@@ -6,7 +6,8 @@ import re
import sys
import traceback
import Bcfg2.Options
-from Bcfg2.Server.Plugin import PluginExecutionError, removecomment
+from Bcfg2.Server.Plugin import PluginExecutionError, removecomment, \
+ DefaultTemplateDataProvider, get_template_data
from Bcfg2.Server.Plugins.Cfg import CfgGenerator
from genshi.template import TemplateLoader, NewTextTemplate
from genshi.template.eval import UndefinedError, Suite
@@ -42,6 +43,18 @@ d['a']"""
GENSHI_REMOVES_BLANK_LINES = _genshi_removes_blank_lines()
+class DefaultGenshiDataProvider(DefaultTemplateDataProvider):
+ """ Template data provider for Genshi templates. Cheetah and
+ Genshi currently differ over the value of the ``path`` variable,
+ which is why this is necessary. """
+
+ def get_template_data(self, entry, metadata, template):
+ rv = DefaultTemplateDataProvider.get_template_data(self, entry,
+ metadata, template)
+ rv['path'] = template
+ return rv
+
+
class CfgGenshiGenerator(CfgGenerator):
""" The CfgGenshiGenerator allows you to use the `Genshi
<http://genshi.edgewall.org>`_ templating system to generate
@@ -81,13 +94,10 @@ class CfgGenshiGenerator(CfgGenerator):
raise PluginExecutionError("Failed to load template %s" %
self.name)
- fname = entry.get('realname', entry.get('name'))
stream = self.template.generate(
- name=fname,
- metadata=metadata,
- path=self.name,
- source_path=self.name,
- repo=Bcfg2.Options.setup.repository).filter(removecomment)
+ **get_template_data(
+ entry, metadata, self.name,
+ default=DefaultGenshiDataProvider())).filter(removecomment)
try:
try:
return stream.render('text',
diff --git a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
index 82d8bfae2..05b5086f9 100644
--- a/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
+++ b/src/lib/Bcfg2/Server/Plugins/TemplateHelper.py
@@ -3,11 +3,9 @@
import re
import imp
import sys
-import logging
+from Bcfg2.Logger import Debuggable
import Bcfg2.Server.Plugin
-LOGGER = logging.getLogger(__name__)
-
MODULE_RE = re.compile(r'(?P<filename>(?P<module>[^\/]+)\.py)$')
@@ -19,10 +17,11 @@ def safe_module_name(module):
return '__TemplateHelper_%s' % module
-class HelperModule(object):
+class HelperModule(Debuggable):
""" Representation of a TemplateHelper module """
def __init__(self, name):
+ Debuggable.__init__(self)
self.name = name
#: The name of the module as used by get_additional_data().
@@ -32,6 +31,9 @@ class HelperModule(object):
#: The attributes exported by this module
self._attrs = []
+ #: The attributes added to the template namespace by this module
+ self.defaults = []
+
def HandleEvent(self, event=None):
""" HandleEvent is called whenever the FAM registers an event.
@@ -47,37 +49,50 @@ class HelperModule(object):
self.name)
except: # pylint: disable=W0702
err = sys.exc_info()[1]
- LOGGER.error("TemplateHelper: Failed to import %s: %s" %
- (self.name, err))
+ self.logger.error("TemplateHelper: Failed to import %s: %s" %
+ (self.name, err))
return
if not hasattr(module, "__export__"):
- LOGGER.error("TemplateHelper: %s has no __export__ list" %
- self.name)
+ self.logger.error("TemplateHelper: %s has no __export__ list" %
+ self.name)
return
newattrs = []
for sym in module.__export__:
if sym not in self._attrs and hasattr(self, sym):
- LOGGER.warning("TemplateHelper: %s: %s is a reserved keyword, "
- "skipping export" % (self.name, sym))
+ self.logger.warning(
+ "TemplateHelper: %s: %s is a reserved keyword, "
+ "skipping export" % (self.name, sym))
continue
try:
setattr(self, sym, getattr(module, sym))
newattrs.append(sym)
except AttributeError:
- LOGGER.warning("TemplateHelper: %s exports %s, but has no "
- "such attribute" % (self.name, sym))
+ self.logger.warning(
+ "TemplateHelper: %s exports %s, but has no such attribute"
+ % (self.name, sym))
+
# remove old exports
for sym in set(self._attrs) - set(newattrs):
delattr(self, sym)
self._attrs = newattrs
+ self.defaults = []
+ for sym in getattr(module, "__default__", []):
+ if sym not in self._attrs:
+ self.logger.warning(
+ "TemplateHelper: %s: %s is flagged as a default, "
+ "but is not exported; skipping")
+ continue
+ self.defaults.append(sym)
+
class TemplateHelper(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Connector,
- Bcfg2.Server.Plugin.DirectoryBacked):
+ Bcfg2.Server.Plugin.DirectoryBacked,
+ Bcfg2.Server.Plugin.TemplateDataProvider):
""" A plugin to provide helper classes and functions to templates """
__author__ = 'chris.a.st.pierre@gmail.com'
ignore = re.compile(r'^(\.#.*|.*~|\..*\.(sw[px])|.*\.py[co])$')
@@ -88,7 +103,23 @@ class TemplateHelper(Bcfg2.Server.Plugin.Plugin,
Bcfg2.Server.Plugin.Plugin.__init__(self, core)
Bcfg2.Server.Plugin.Connector.__init__(self)
Bcfg2.Server.Plugin.DirectoryBacked.__init__(self, self.data)
+ Bcfg2.Server.Plugin.TemplateDataProvider.__init__(self)
def get_additional_data(self, _):
return dict([(h._module_name, h) # pylint: disable=W0212
for h in self.entries.values()])
+
+ def get_template_data(self, *_):
+ rv = dict()
+ source = dict()
+ for helper in self.entries.values():
+ for key in helper.defaults:
+ if key not in rv:
+ rv[key] = getattr(helper, key)
+ source[key] = helper
+ else:
+ self.logger.warning(
+ "TemplateHelper: Duplicate default variable %s "
+ "provided by both %s and %s" %
+ (key, helper.name, source[key].name))
+ return rv
diff --git a/src/lib/Bcfg2/Server/__init__.py b/src/lib/Bcfg2/Server/__init__.py
index 4e46ada09..39ed2ec91 100644
--- a/src/lib/Bcfg2/Server/__init__.py
+++ b/src/lib/Bcfg2/Server/__init__.py
@@ -1,7 +1,6 @@
"""This is the set of modules for Bcfg2.Server."""
import lxml.etree
-import Bcfg2.Options
XI = 'http://www.w3.org/2001/XInclude'
XI_NAMESPACE = '{%s}' % XI
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py
index 2285fb458..93331304a 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgCheetahGenerator.py
@@ -26,12 +26,20 @@ class TestCfgCheetahGenerator(TestCfgGenerator):
set_setup_default("repository", datastore)
@patch("Bcfg2.Server.Plugins.Cfg.CfgCheetahGenerator.Template")
- def test_get_data(self, mock_Template):
+ @patch("Bcfg2.Server.Plugins.Cfg.CfgCheetahGenerator.get_template_data")
+ def test_get_data(self, mock_get_template_data, mock_Template):
ccg = self.get_obj()
ccg.data = "data"
entry = lxml.etree.Element("Path", name="/test.txt")
metadata = Mock()
+ template_vars = dict(name=entry.get("name"),
+ metadata=metadata,
+ path=ccg.name,
+ source_path=ccg.name,
+ repo=datastore)
+ mock_get_template_data.return_value = template_vars
+
self.assertEqual(ccg.get_data(entry, metadata),
mock_Template.return_value.respond.return_value)
mock_Template.assert_called_with(
@@ -39,8 +47,9 @@ class TestCfgCheetahGenerator(TestCfgGenerator):
compilerSettings=ccg.settings)
tmpl = mock_Template.return_value
tmpl.respond.assert_called_with()
- self.assertEqual(tmpl.metadata, metadata)
- self.assertEqual(tmpl.name, entry.get("name"))
- self.assertEqual(tmpl.path, entry.get("name"))
- self.assertEqual(tmpl.source_path, ccg.name)
- self.assertEqual(tmpl.repo, datastore)
+ for key, val in template_vars.items():
+ self.assertEqual(getattr(tmpl, key), val)
+ self.assertItemsEqual(mock_get_template_data.call_args[0],
+ [entry, metadata, ccg.name])
+ self.assertIsInstance(mock_get_template_data.call_args[1]['default'],
+ DefaultCheetahDataProvider)
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py
index 9b6e7fe88..b667d417a 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgGenshiGenerator.py
@@ -31,7 +31,8 @@ class TestCfgGenshiGenerator(TestCfgGenerator):
cgg = self.get_obj()
self.assertIsInstance(cgg.loader, cgg.__loader_cls__)
- def test_get_data(self):
+ @patch("Bcfg2.Server.Plugins.Cfg.CfgGenshiGenerator.get_template_data")
+ def test_get_data(self, mock_get_template_data):
cgg = self.get_obj()
cgg._handle_genshi_exception = Mock()
cgg.template = Mock()
@@ -45,17 +46,22 @@ class TestCfgGenshiGenerator(TestCfgGenerator):
def reset():
cgg.template.reset_mock()
cgg._handle_genshi_exception.reset_mock()
+ mock_get_template_data.reset_mock()
- template_vars = dict(
- name=entry.get("name"),
- metadata=metadata,
- path=cgg.name,
- source_path=cgg.name,
- repo=datastore)
+ template_vars = dict(name=entry.get("name"),
+ metadata=metadata,
+ path=cgg.name,
+ source_path=cgg.name,
+ repo=datastore)
+ mock_get_template_data.return_value = template_vars
self.assertEqual(cgg.get_data(entry, metadata),
stream.render.return_value)
cgg.template.generate.assert_called_with(**template_vars)
+ self.assertItemsEqual(mock_get_template_data.call_args[0],
+ [entry, metadata, cgg.name])
+ self.assertIsInstance(mock_get_template_data.call_args[1]['default'],
+ DefaultGenshiDataProvider)
fltr.filter.assert_called_with(removecomment)
stream.render.assert_called_with(
"text",
@@ -70,6 +76,10 @@ class TestCfgGenshiGenerator(TestCfgGenerator):
self.assertEqual(cgg.get_data(entry, metadata),
stream.render.return_value)
cgg.template.generate.assert_called_with(**template_vars)
+ self.assertItemsEqual(mock_get_template_data.call_args[0],
+ [entry, metadata, cgg.name])
+ self.assertIsInstance(mock_get_template_data.call_args[1]['default'],
+ DefaultGenshiDataProvider)
fltr.filter.assert_called_with(removecomment)
self.assertEqual(stream.render.call_args_list,
[call("text",
@@ -83,6 +93,10 @@ class TestCfgGenshiGenerator(TestCfgGenerator):
self.assertRaises(UndefinedError,
cgg.get_data, entry, metadata)
cgg.template.generate.assert_called_with(**template_vars)
+ self.assertItemsEqual(mock_get_template_data.call_args[0],
+ [entry, metadata, cgg.name])
+ self.assertIsInstance(mock_get_template_data.call_args[1]['default'],
+ DefaultGenshiDataProvider)
fltr.filter.assert_called_with(removecomment)
stream.render.assert_called_with("text",
encoding=Bcfg2.Options.setup.encoding,
@@ -94,6 +108,10 @@ class TestCfgGenshiGenerator(TestCfgGenerator):
self.assertRaises(ValueError,
cgg.get_data, entry, metadata)
cgg.template.generate.assert_called_with(**template_vars)
+ self.assertItemsEqual(mock_get_template_data.call_args[0],
+ [entry, metadata, cgg.name])
+ self.assertIsInstance(mock_get_template_data.call_args[1]['default'],
+ DefaultGenshiDataProvider)
fltr.filter.assert_called_with(removecomment)
stream.render.assert_called_with("text",
encoding=Bcfg2.Options.setup.encoding,