summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/Bcfg2/Server/Plugins/GroupPatterns.py9
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py47
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py164
3 files changed, 199 insertions, 21 deletions
diff --git a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
index 6f0695bc3..2e8c56b4e 100644
--- a/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
+++ b/src/lib/Bcfg2/Server/Plugins/GroupPatterns.py
@@ -118,7 +118,8 @@ class PatternFile(Bcfg2.Server.Plugin.XMLFileBacked):
self.patterns.append(PatternMap(None, rng, groups))
except: # pylint: disable=W0702
self.logger.error("GroupPatterns: Failed to initialize "
- "pattern %s" % entry.get('pattern'))
+ "pattern %s: %s" % (entry.text,
+ sys.exc_info()[1]))
def process_patterns(self, hostname):
""" return a list of groups that should be added to the given
@@ -126,9 +127,9 @@ class PatternFile(Bcfg2.Server.Plugin.XMLFileBacked):
ret = []
for pattern in self.patterns:
try:
- grpname = pattern.process(hostname)
- if grpname is not None:
- ret.extend(grpname)
+ grps = pattern.process(hostname)
+ if grps is not None:
+ ret.extend(grps)
except: # pylint: disable=W0702
self.logger.error("GroupPatterns: Failed to process pattern "
"%s for %s" % (pattern.pattern, hostname),
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
index d3e97df8d..559742d00 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
@@ -388,6 +388,11 @@ class TestDirectoryBacked(Bcfg2TestCase):
class TestXMLFileBacked(TestFileBacked):
test_obj = XMLFileBacked
+
+ # can be set to True (on child test cases where should_monitor is
+ # always True) or False (on child test cases where should_monitor
+ # is always False)
+ should_monitor = None
path = os.path.join(datastore, "test", "test1.xml")
def get_obj(self, path=None, fam=None, should_monitor=False):
@@ -398,14 +403,19 @@ class TestXMLFileBacked(TestFileBacked):
def test__init(self):
fam = Mock()
xfb = self.get_obj()
- self.assertIsNone(xfb.fam)
+ if self.should_monitor is True:
+ self.assertIsNotNone(xfb.fam)
+ else:
+ self.assertIsNone(xfb.fam)
- xfb = self.get_obj(fam=fam)
- self.assertFalse(fam.AddMonitor.called)
+ if self.should_monitor is not True:
+ xfb = self.get_obj(fam=fam)
+ self.assertFalse(fam.AddMonitor.called)
- fam.reset_mock()
- xfb = self.get_obj(fam=fam, should_monitor=True)
- fam.AddMonitor.assert_called_with(self.path, xfb)
+ if self.should_monitor is not False:
+ fam.reset_mock()
+ xfb = self.get_obj(fam=fam, should_monitor=True)
+ fam.AddMonitor.assert_called_with(self.path, xfb)
@patch("os.path.exists")
@patch("lxml.etree.parse")
@@ -577,17 +587,20 @@ class TestXMLFileBacked(TestFileBacked):
self.assertIn("/test/test2.xml", xfb.extras)
fam = Mock()
- xfb = self.get_obj(fam=fam)
- fam.reset_mock()
- xfb.add_monitor("/test/test3.xml")
- self.assertFalse(fam.AddMonitor.called)
- self.assertIn("/test/test3.xml", xfb.extras)
-
- fam.reset_mock()
- xfb = self.get_obj(fam=fam, should_monitor=True)
- xfb.add_monitor("/test/test4.xml")
- fam.AddMonitor.assert_called_with("/test/test4.xml", xfb)
- self.assertIn("/test/test4.xml", xfb.extras)
+ if self.should_monitor is not True:
+ fam.reset_mock()
+ xfb = self.get_obj(fam=fam)
+ fam.reset_mock()
+ xfb.add_monitor("/test/test3.xml")
+ self.assertFalse(fam.AddMonitor.called)
+ self.assertIn("/test/test3.xml", xfb.extras)
+
+ if self.should_monitor is not False:
+ fam.reset_mock()
+ xfb = self.get_obj(fam=fam, should_monitor=True)
+ xfb.add_monitor("/test/test4.xml")
+ fam.AddMonitor.assert_called_with("/test/test4.xml", xfb)
+ self.assertIn("/test/test4.xml", xfb.extras)
class TestStructFile(TestXMLFileBacked):
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py
new file mode 100644
index 000000000..84d35ccc5
--- /dev/null
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestGroupPatterns.py
@@ -0,0 +1,164 @@
+import os
+import sys
+import lxml.etree
+import Bcfg2.Server.Plugin
+from mock import Mock, MagicMock, patch
+from Bcfg2.Server.Plugins.GroupPatterns import *
+
+# add all parent testsuite directories to sys.path to allow (most)
+# relative imports in python 2.4
+path = os.path.dirname(__file__)
+while path != "/":
+ if os.path.basename(path).lower().startswith("test"):
+ sys.path.append(path)
+ if os.path.basename(path) == "testsuite":
+ break
+ path = os.path.dirname(path)
+from common import *
+from TestPlugin import TestXMLFileBacked, TestPlugin, TestConnector
+
+
+class TestPackedDigitRange(Bcfg2TestCase):
+ def test_includes(self):
+ # tuples of (range description, numbers that are included,
+ # numebrs that are excluded)
+ tests = [("1-3", [1, "2", 3], [4, "0"]),
+ ("1", [1], [0, 2]),
+ ("10-11", [10, 11], [0, 1]),
+ ("9-9", [9], [8, 10]),
+ ("0-100", [0, 10, 99, 100], []),
+ ("1,3,5", [1, 3, 5], [0, 2, 4, 6]),
+ ("1-5,7", [1, 3, 5, 7], [0, 6, 8]),
+ ("852-855,321-497,763", [852, 855, 321, 400, 497, 763], [])]
+ for rng, inc, exc in tests:
+ r = PackedDigitRange(rng)
+ for test in inc:
+ self.assertTrue(r.includes(test))
+ for test in exc:
+ self.assertFalse(r.includes(test))
+
+
+class TestPatternMap(Bcfg2TestCase):
+ def test_ranges(self):
+ """ test processing NameRange patterns """
+ tests = [("foo[[1-5]]",
+ ["foo1", "foo2", "foo5"],
+ ["foo", "foo0", "foo10"]),
+ ("[[10-99]]foo",
+ ["10foo", "99foo", "25foo"],
+ ["foo", "1foo", "999foo", "110foo"]),
+ ("foo[[1,3,5-10]]bar",
+ ["foo1bar", "foo7bar", "foo10bar"],
+ ["foo2bar", "foobar", "foo3", "5bar"]),
+ ("[[9-15]]foo[[16-20]]",
+ ["9foo18", "13foo17"],
+ ["8foo21", "12foo21", "8foo18", "16foo16",
+ "15foo15", "29foo20", "9foo200", "29foo200"])]
+
+ groups = MagicMock()
+ for rng, inc, exc in tests:
+ pmap = PatternMap(None, rng, groups)
+ for test in inc:
+ self.assertEqual(pmap.process(test), groups)
+ for test in exc:
+ self.assertIsNone(pmap.process(test))
+
+ def test_simple_patterns(self):
+ """ test processing NamePatterns without backreferences """
+ tests = [("foo.*",
+ ["foo", "foobar", "barfoo", "barfoobar"],
+ ["bar", "fo0"]),
+ ("^[A-z]fooo?$",
+ ["Afoo", "bfooo"],
+ ["foo", "fooo", "AAfoo", "Afoooo"])]
+
+ groups = ["a", "b", "c"]
+ for rng, inc, exc in tests:
+ pmap = PatternMap(rng, None, groups)
+ for test in inc:
+ self.assertItemsEqual(pmap.process(test), groups)
+ for test in exc:
+ self.assertIsNone(pmap.process(test))
+
+ def test_backref_patterns(self):
+ """ test NamePatterns with backreferences """
+ tests = [("foo(.*)", ['a', 'a$1', '$1a', '$$', '$a', '$1'],
+ {"foo": ['a', 'a', 'a', '$$', '$a', ''],
+ "foooOOo": ['a', 'aoOOo', 'oOOoa', '$$', '$a', 'oOOo'],
+ "barfoo$1": ['a', 'a$1', '$1a', '$$', '$a', '$1']}),
+ ("^([a-z])foo(.+)", ['a', 'a$1', '$1a$2', '$1$$2', '$2'],
+ {"foo": None,
+ "afooa": ['a', 'aa', 'aaa', 'a$a', 'a'],
+ "bfoobar": ['a', 'ab', 'babar', 'b$bar', 'bar']})]
+
+ for rng, groups, cases in tests:
+ pmap = PatternMap(rng, None, groups)
+ for name, ret in cases.items():
+ if ret is None:
+ self.assertIsNone(pmap.process(name))
+ else:
+ self.assertItemsEqual(pmap.process(name), ret)
+
+
+class TestPatternFile(TestXMLFileBacked):
+ test_obj = PatternFile
+ should_monitor = True
+
+ def get_obj(self, path=None, fam=None, core=None, should_monitor=True):
+ if path is None:
+ path = self.path
+ if fam and not core:
+ core = Mock()
+ core.fam = fam
+ elif not core:
+ core = Mock()
+ return self.test_obj(path, core=core)
+
+ @patch("Bcfg2.Server.Plugins.GroupPatterns.PatternMap")
+ def test_Index(self, mock_PatternMap):
+ TestXMLFileBacked.test_Index(self)
+ core = Mock()
+ pf = self.get_obj(core=core)
+
+ pf.data = """
+<GroupPatterns>
+ <GroupPattern>
+ <NamePattern>foo.*</NamePattern>
+ <Group>test1</Group>
+ <Group>test2</Group>
+ </GroupPattern>
+ <GroupPattern>
+ <NameRange>foo[[1-5]]</NameRange>
+ <Group>test3</Group>
+ </GroupPattern>
+</GroupPatterns>"""
+
+ core.metadata_cache_mode = 'aggressive'
+ pf.Index()
+ core.metadata_cache.expire.assert_called_with()
+ self.assertItemsEqual(mock_PatternMap.call_args_list,
+ [call("foo.*", None, ["test1", "test2"]),
+ call(None, "foo[[1-5]]", ["test3"])])
+
+ def test_process_patterns(self):
+ pf = self.get_obj()
+ pf.patterns = [Mock(), Mock(), Mock()]
+ pf.patterns[0].process.return_value = ["a", "b"]
+ pf.patterns[1].process.return_value = None
+ pf.patterns[2].process.return_value = ["b", "c"]
+ self.assertItemsEqual(pf.process_patterns("foo.example.com"),
+ ["a", "b", "b", "c"])
+ for pat in pf.patterns:
+ pat.process.assert_called_with("foo.example.com")
+
+
+class TestGroupPatterns(TestPlugin, TestConnector):
+ test_obj = GroupPatterns
+
+ def test_get_additional_groups(self):
+ gp = self.get_obj()
+ gp.config = Mock()
+ metadata = Mock()
+ self.assertEqual(gp.get_additional_groups(metadata),
+ gp.config.process_patterns.return_value)
+ gp.config.process_patterns.assert_called_with(metadata.hostname)