summaryrefslogtreecommitdiffstats
path: root/testsuite
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite')
-rw-r--r--testsuite/Testschema/test_schema.py2
-rw-r--r--testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py247
-rw-r--r--testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/Testbase.py15
-rw-r--r--testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py15
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testbase.py42
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py47
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestAWSTags.py140
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py8
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py19
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPublicKeyCreator.py105
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py65
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py79
-rw-r--r--testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProbes.py38
-rw-r--r--testsuite/Testsrc/test_code_checks.py10
-rwxr-xr-xtestsuite/before_install.sh5
-rw-r--r--testsuite/common.py60
-rw-r--r--testsuite/ext/exception_messages.py30
-rwxr-xr-xtestsuite/install.sh19
-rw-r--r--testsuite/pylintrc.conf2
-rw-r--r--testsuite/requirements.txt2
20 files changed, 739 insertions, 211 deletions
diff --git a/testsuite/Testschema/test_schema.py b/testsuite/Testschema/test_schema.py
index ddfe4775f..cd9b74cdf 100644
--- a/testsuite/Testschema/test_schema.py
+++ b/testsuite/Testschema/test_schema.py
@@ -41,7 +41,7 @@ class TestSchemas(Bcfg2TestCase):
xmllint = Popen(['xmllint', '--xinclude', '--noout', '--schema',
self.schema_url] + schemas,
stdout=PIPE, stderr=STDOUT)
- print(xmllint.communicate()[0])
+ print(xmllint.communicate()[0].decode())
self.assertEqual(xmllint.wait(), 0)
def test_duplicates(self):
diff --git a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py
new file mode 100644
index 000000000..b8534f5a8
--- /dev/null
+++ b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/TestAugeas.py
@@ -0,0 +1,247 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+import copy
+import lxml.etree
+import tempfile
+from mock import Mock, MagicMock, patch
+try:
+ from Bcfg2.Client.Tools.POSIX.Augeas import *
+ HAS_AUGEAS = True
+except ImportError:
+ POSIXAugeas = None
+ HAS_AUGEAS = False
+
+# 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 TestPOSIX.Testbase import TestPOSIXTool
+from common import *
+
+
+test_data = """<Test>
+ <Empty/>
+ <Text>content with spaces</Text>
+ <Attrs foo="foo" bar="bar"/>
+ <Children identical="false">
+ <Foo/>
+ <Bar attr="attr"/>
+ </Children>
+ <Children identical="true">
+ <Thing>one</Thing>
+ <Thing>two</Thing>
+ </Children>
+ <Children multi="true">
+ <Thing>same</Thing>
+ <Thing>same</Thing>
+ <Thing>same</Thing>
+ <Thing>same</Thing>
+ </Children>
+</Test>
+"""
+
+test_xdata = lxml.etree.XML(test_data)
+
+if can_skip or HAS_AUGEAS:
+ class TestPOSIXAugeas(TestPOSIXTool):
+ test_obj = POSIXAugeas
+
+ applied_commands = dict(
+ insert=lxml.etree.Element(
+ "Insert", label="Thing",
+ path='Test/Children[#attribute/identical = "true"]/Thing'),
+ set=lxml.etree.Element("Set", path="Test/Text/#text",
+ value="content with spaces"),
+ move=lxml.etree.Element(
+ "Move", source="Test/Foo",
+ destination='Test/Children[#attribute/identical = "false"]/Foo'),
+ remove=lxml.etree.Element("Remove", path="Test/Bar"),
+ clear=lxml.etree.Element("Clear", path="Test/Empty/#text"),
+ setm=lxml.etree.Element(
+ "SetMulti", sub="#text", value="same",
+ base='Test/Children[#attribute/multi = "true"]/Thing'))
+
+ @skipUnless(HAS_AUGEAS, "Python Augeas libraries not found")
+ def setUp(self):
+ fd, self.tmpfile = tempfile.mkstemp()
+ os.fdopen(fd, 'w').write(test_data)
+
+ def tearDown(self):
+ tmpfile = getattr(self, "tmpfile", None)
+ if tmpfile and os.path.exists(tmpfile):
+ os.unlink(tmpfile)
+
+ def test_fully_specified(self):
+ ptool = self.get_obj()
+
+ entry = lxml.etree.Element("Path", name="/test", type="augeas")
+ self.assertFalse(ptool.fully_specified(entry))
+
+ lxml.etree.SubElement(entry, "Set", path="/test", value="test")
+ self.assertTrue(ptool.fully_specified(entry))
+
+ def test_install(self):
+ # this is tested adequately by the other tests
+ pass
+
+ def test_verify(self):
+ # this is tested adequately by the other tests
+ pass
+
+ @patch("Bcfg2.Client.Tools.POSIX.Augeas.POSIXTool.verify")
+ def _verify(self, commands, mock_verify):
+ ptool = self.get_obj()
+ mock_verify.return_value = True
+
+ entry = lxml.etree.Element("Path", name=self.tmpfile,
+ type="augeas", lens="Xml")
+ entry.extend(commands)
+
+ modlist = []
+ self.assertTrue(ptool.verify(entry, modlist))
+ mock_verify.assert_called_with(ptool, entry, modlist)
+ self.assertXMLEqual(lxml.etree.parse(self.tmpfile).getroot(),
+ test_xdata)
+
+ def test_verify_insert(self):
+ """ Test successfully verifying an Insert command """
+ self._verify([self.applied_commands['insert']])
+
+ def test_verify_set(self):
+ """ Test successfully verifying a Set command """
+ self._verify([self.applied_commands['set']])
+
+ def test_verify_move(self):
+ """ Test successfully verifying a Move command """
+ self._verify([self.applied_commands['move']])
+
+ def test_verify_remove(self):
+ """ Test successfully verifying a Remove command """
+ self._verify([self.applied_commands['remove']])
+
+ def test_verify_clear(self):
+ """ Test successfully verifying a Clear command """
+ self._verify([self.applied_commands['clear']])
+
+ def test_verify_set_multi(self):
+ """ Test successfully verifying a SetMulti command """
+ self._verify([self.applied_commands['setm']])
+
+ def test_verify_all(self):
+ """ Test successfully verifying multiple commands """
+ self._verify(self.applied_commands.values())
+
+ @patch("Bcfg2.Client.Tools.POSIX.Augeas.POSIXTool.install")
+ def _install(self, commands, expected, mock_install, **attrs):
+ ptool = self.get_obj()
+ mock_install.return_value = True
+
+ entry = lxml.etree.Element("Path", name=self.tmpfile,
+ type="augeas", lens="Xml")
+ for key, val in attrs.items():
+ entry.set(key, val)
+ entry.extend(commands)
+
+ self.assertTrue(ptool.install(entry))
+ mock_install.assert_called_with(ptool, entry)
+ self.assertXMLEqual(lxml.etree.parse(self.tmpfile).getroot(),
+ expected)
+
+ def test_install_set_existing(self):
+ """ Test setting the value of an existing node """
+ expected = copy.deepcopy(test_xdata)
+ expected.find("Text").text = "Changed content"
+ self._install([lxml.etree.Element("Set", path="Test/Text/#text",
+ value="Changed content")],
+ expected)
+
+ def test_install_set_new(self):
+ """ Test setting the value of an new node """
+ expected = copy.deepcopy(test_xdata)
+ newtext = lxml.etree.SubElement(expected, "NewText")
+ newtext.text = "new content"
+ self._install([lxml.etree.Element("Set", path="Test/NewText/#text",
+ value="new content")],
+ expected)
+
+ def test_install_remove(self):
+ """ Test removing a node """
+ expected = copy.deepcopy(test_xdata)
+ expected.remove(expected.find("Attrs"))
+ self._install(
+ [lxml.etree.Element("Remove",
+ path='Test/*[#attribute/foo = "foo"]')],
+ expected)
+
+ def test_install_move(self):
+ """ Test moving a node """
+ expected = copy.deepcopy(test_xdata)
+ foo = expected.xpath("//Foo")[0]
+ expected.append(foo)
+ self._install(
+ [lxml.etree.Element("Move", source='Test/Children/Foo',
+ destination='Test/Foo')],
+ expected)
+
+ def test_install_clear(self):
+ """ Test clearing a node """
+ # TODO: clearing a node doesn't seem to work with the XML lens
+ #
+ # % augtool -b
+ # augtool> set /augeas/load/Xml/incl[3] "/tmp/test.xml"
+ # augtool> load
+ # augtool> clear '/files/tmp/test.xml/Test/Text/#text'
+ # augtool> save
+ # error: Failed to execute command
+ # saving failed (run 'print /augeas//error' for details)
+ # augtool> print /augeas//error
+ #
+ # The error isn't useful.
+ pass
+
+ def test_install_set_multi(self):
+ """ Test setting multiple nodes at once """
+ expected = copy.deepcopy(test_xdata)
+ for thing in expected.xpath("Children[@identical='true']/Thing"):
+ thing.text = "same"
+ self._install(
+ [lxml.etree.Element(
+ "SetMulti", value="same",
+ base='Test/Children[#attribute/identical = "true"]',
+ sub="Thing/#text")],
+ expected)
+
+ def test_install_insert(self):
+ """ Test inserting a node """
+ expected = copy.deepcopy(test_xdata)
+ children = expected.xpath("Children[@identical='true']")[0]
+ thing = lxml.etree.Element("Thing")
+ thing.text = "three"
+ children.append(thing)
+ self._install(
+ [lxml.etree.Element(
+ "Insert",
+ path='Test/Children[#attribute/identical = "true"]/Thing[2]',
+ label="Thing", where="after"),
+ lxml.etree.Element(
+ "Set",
+ path='Test/Children[#attribute/identical = "true"]/Thing[3]/#text',
+ value="three")],
+ expected)
+
+ def test_install_initial(self):
+ """ Test creating initial content and then modifying it """
+ os.unlink(self.tmpfile)
+ expected = copy.deepcopy(test_xdata)
+ expected.find("Text").text = "Changed content"
+ initial = lxml.etree.Element("Initial")
+ initial.text = test_data
+ modify = lxml.etree.Element("Set", path="Test/Text/#text",
+ value="Changed content")
+ self._install([initial, modify], expected, current_exists="false")
diff --git a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/Testbase.py b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/Testbase.py
index 49e9be2ba..d2f383f42 100644
--- a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/Testbase.py
+++ b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIX/Testbase.py
@@ -711,12 +711,13 @@ class TestPOSIXTool(TestTool):
gather_data_rv[idx] = val
ptool._gather_data.return_value = tuple(gather_data_rv)
+ stat_mode = 17407
mtime = 1344430414
+ stat_rv = (stat_mode, Mock(), Mock(), Mock(), Mock(), Mock(), Mock(),
+ Mock(), mtime, Mock())
+ gather_data_rv[0] = stat_rv
entry = reset()
entry.set("mtime", str(mtime))
- stat_rv = MagicMock()
- stat_rv.__getitem__.return_value = mtime
- gather_data_rv[0] = stat_rv
ptool._gather_data.return_value = tuple(gather_data_rv)
self.assertTrue(ptool._verify_metadata(entry))
ptool._gather_data.assert_called_with(entry.get("name"))
@@ -788,7 +789,7 @@ class TestPOSIXTool(TestTool):
ptool._gather_data.assert_called_with(entry.get("name"))
ptool._verify_acls.assert_called_with(entry,
path=entry.get("name"))
- mock_matchpathcon.assert_called_with(entry.get("name"), 0)
+ mock_matchpathcon.assert_called_with(entry.get("name"), stat_mode)
self.assertEqual(entry.get("current_exists", 'true'), 'true')
for attr, idx, val in expected:
self.assertEqual(entry.get(attr), val)
@@ -803,7 +804,7 @@ class TestPOSIXTool(TestTool):
ptool._gather_data.assert_called_with(entry.get("name"))
ptool._verify_acls.assert_called_with(entry,
path=entry.get("name"))
- mock_matchpathcon.assert_called_with(entry.get("name"), 0)
+ mock_matchpathcon.assert_called_with(entry.get("name"), stat_mode)
self.assertEqual(entry.get("current_exists", 'true'), 'true')
for attr, idx, val in expected:
self.assertEqual(entry.get(attr), val)
@@ -897,7 +898,7 @@ class TestPOSIXTool(TestTool):
filedef_rv.__iter__.return_value = iter(file_acls)
defacls = acls
- for akey, perms in acls.items():
+ for akey, perms in list(acls.items()):
defacls[('default', akey[1], akey[2])] = perms
self.assertItemsEqual(ptool._list_file_acls(path), defacls)
mock_isdir.assert_called_with(path)
@@ -1009,7 +1010,7 @@ class TestPOSIXTool(TestTool):
else:
return True
ptool._set_perms.side_effect = set_perms_rv
- self.assertFalse(ptool._makedirs(entry))
+ self.assertTrue(ptool._makedirs(entry))
self.assertItemsEqual(mock_exists.call_args_list,
[call("/test"), call("/test/foo"),
call("/test/foo/bar")])
diff --git a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py
index 9478f7071..c207900f1 100644
--- a/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py
+++ b/testsuite/Testsrc/Testlib/TestClient/TestTools/TestPOSIXUsers.py
@@ -27,7 +27,14 @@ class TestPOSIXUsers(TestTool):
def get_obj(self, logger=None, setup=None, config=None):
if setup is None:
setup = MagicMock()
- setup.__getitem__.return_value = []
+ def getitem(key):
+ if key == 'encoding':
+ return 'UTF-8'
+ else:
+ return []
+
+ setup.__getitem__.side_effect = getitem
+
return TestTool.get_obj(self, logger, setup, config)
@patch("pwd.getpwall")
@@ -381,15 +388,15 @@ class TestPOSIXUsers(TestTool):
(lxml.etree.Element("POSIXUser", name="test", group="test",
home="/home/test", shell="/bin/zsh",
gecos="Test McTest"),
- ["-m", "-g", "test", "-d", "/home/test", "-s", "/bin/zsh",
+ ["-g", "test", "-d", "/home/test", "-s", "/bin/zsh",
"-c", "Test McTest"]),
(lxml.etree.Element("POSIXUser", name="test", group="test",
home="/home/test", shell="/bin/zsh",
gecos="Test McTest", uid="1001"),
- ["-m", "-u", "1001", "-g", "test", "-d", "/home/test",
+ ["-u", "1001", "-g", "test", "-d", "/home/test",
"-s", "/bin/zsh", "-c", "Test McTest"]),
(entry,
- ["-m", "-g", "test", "-G", "wheel,users", "-d", "/home/test",
+ ["-g", "test", "-G", "wheel,users", "-d", "/home/test",
"-s", "/bin/zsh", "-c", "Test McTest"])]
for entry, expected in cases:
for action in ["add", "mod", "del"]:
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testbase.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testbase.py
index 318f5ceaa..870983f60 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testbase.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testbase.py
@@ -29,16 +29,11 @@ class TestDebuggable(Bcfg2TestCase):
def test_set_debug(self):
d = self.get_obj()
- d.debug_log = Mock()
self.assertEqual(True, d.set_debug(True))
self.assertEqual(d.debug_flag, True)
- self.assertTrue(d.debug_log.called)
-
- d.debug_log.reset_mock()
self.assertEqual(False, d.set_debug(False))
self.assertEqual(d.debug_flag, False)
- self.assertTrue(d.debug_log.called)
def test_toggle_debug(self):
d = self.get_obj()
@@ -80,24 +75,25 @@ class TestPlugin(TestDebuggable):
@patch("os.makedirs")
@patch("os.path.exists")
def test__init(self, mock_exists, mock_makedirs):
- core = Mock()
- core.setup = MagicMock()
-
- mock_exists.return_value = True
- p = self.get_obj(core=core)
- self.assertEqual(p.data, os.path.join(datastore, p.name))
- self.assertEqual(p.core, core)
- mock_exists.assert_any_call(p.data)
- self.assertFalse(mock_makedirs.called)
-
- mock_exists.reset_mock()
- mock_makedirs.reset_mock()
- mock_exists.return_value = False
- p = self.get_obj(core=core)
- self.assertEqual(p.data, os.path.join(datastore, p.name))
- self.assertEqual(p.core, core)
- mock_exists.assert_any_call(p.data)
- mock_makedirs.assert_any_call(p.data)
+ if self.test_obj.create:
+ core = Mock()
+ core.setup = MagicMock()
+
+ mock_exists.return_value = True
+ p = self.get_obj(core=core)
+ self.assertEqual(p.data, os.path.join(datastore, p.name))
+ self.assertEqual(p.core, core)
+ mock_exists.assert_any_call(p.data)
+ self.assertFalse(mock_makedirs.called)
+
+ mock_exists.reset_mock()
+ mock_makedirs.reset_mock()
+ mock_exists.return_value = False
+ p = self.get_obj(core=core)
+ self.assertEqual(p.data, os.path.join(datastore, p.name))
+ self.assertEqual(p.core, core)
+ mock_exists.assert_any_call(p.data)
+ mock_makedirs.assert_any_call(p.data)
@patch("os.makedirs")
def test_init_repo(self, mock_makedirs):
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
index 94866cf39..ce17cb076 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugin/Testhelpers.py
@@ -1,5 +1,4 @@
import os
-import re
import sys
import copy
import lxml.etree
@@ -7,6 +6,7 @@ import Bcfg2.Server
from Bcfg2.Compat import reduce
from mock import Mock, MagicMock, patch
from Bcfg2.Server.Plugin.helpers import *
+from Bcfg2.Server.Plugin.exceptions import PluginInitError
# add all parent testsuite directories to sys.path to allow (most)
# relative imports in python 2.4
@@ -28,6 +28,7 @@ def tostring(el):
class FakeElementTree(lxml.etree._ElementTree):
xinclude = Mock()
+ parse = Mock
class TestFunctions(Bcfg2TestCase):
@@ -76,6 +77,14 @@ class TestFunctions(Bcfg2TestCase):
class TestDatabaseBacked(TestPlugin):
test_obj = DatabaseBacked
+ def get_obj(self, core=None):
+ if not HAS_DJANGO:
+ if core is None:
+ core = MagicMock()
+ # disable the database
+ core.setup.cfp.getboolean.return_value = False
+ return TestPlugin.get_obj(self, core=core)
+
@skipUnless(HAS_DJANGO, "Django not found")
def test__use_db(self):
core = Mock()
@@ -90,13 +99,13 @@ class TestDatabaseBacked(TestPlugin):
Bcfg2.Server.Plugin.helpers.HAS_DJANGO = False
core = Mock()
+ core.setup.cfp.getboolean.return_value = False
db = self.get_obj(core)
self.assertFalse(db._use_db)
core = Mock()
core.setup.cfp.getboolean.return_value = True
- db = self.get_obj(core)
- self.assertFalse(db._use_db)
+ self.assertRaises(PluginInitError, self.get_obj, core)
Bcfg2.Server.Plugin.helpers.HAS_DJANGO = True
@@ -623,17 +632,9 @@ class TestXMLFileBacked(TestFileBacked):
self.assertIn("/test/test2.xml", xfb.extra_monitors)
fam = Mock()
- 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.extra_monitors)
-
- if self.should_monitor is not False:
- fam.reset_mock()
- xfb = self.get_obj(fam=fam, should_monitor=True)
+ fam.reset_mock()
+ xfb = self.get_obj(fam=fam)
+ if xfb.fam:
xfb.add_monitor("/test/test4.xml")
fam.AddMonitor.assert_called_with("/test/test4.xml", xfb)
self.assertIn("/test/test4.xml", xfb.extra_monitors)
@@ -1131,14 +1132,14 @@ class TestXMLSrc(TestXMLFileBacked):
# ensure that the node object has the necessary interface
self.assertTrue(hasattr(self.test_obj.__node__, "Match"))
- @patch("%s.open" % builtins)
- def test_HandleEvent(self, mock_open):
+ @patch("lxml.etree.parse")
+ def test_HandleEvent(self, mock_parse):
xdata = lxml.etree.Element("Test")
lxml.etree.SubElement(xdata, "Path", name="path", attr="whatever")
xsrc = self.get_obj("/test/foo.xml")
xsrc.__node__ = Mock()
- mock_open.return_value.read.return_value = tostring(xdata)
+ mock_parse.return_value = xdata.getroottree()
if xsrc.__priority_required__:
# test with no priority at all
@@ -1147,20 +1148,20 @@ class TestXMLSrc(TestXMLFileBacked):
# test with bogus priority
xdata.set("priority", "cow")
- mock_open.return_value.read.return_value = tostring(xdata)
+ mock_parse.return_value = xdata.getroottree()
self.assertRaises(PluginExecutionError,
- xsrc.HandleEvent, Mock())
+ xsrc.HandleEvent, Mock())
# assign a priority to use in future tests
xdata.set("priority", "10")
- mock_open.return_value.read.return_value = tostring(xdata)
+ mock_parse.return_value = xdata.getroottree()
- mock_open.reset_mock()
+ mock_parse.reset_mock()
xsrc = self.get_obj("/test/foo.xml")
xsrc.__node__ = Mock()
xsrc.HandleEvent(Mock())
- mock_open.assert_called_with("/test/foo.xml")
- mock_open.return_value.read.assert_any_call()
+ mock_parse.assert_called_with("/test/foo.xml",
+ parser=Bcfg2.Server.XMLParser)
self.assertXMLEqual(xsrc.__node__.call_args[0][0], xdata)
self.assertEqual(xsrc.__node__.call_args[0][1], dict())
self.assertEqual(xsrc.pnode, xsrc.__node__.return_value)
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestAWSTags.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestAWSTags.py
new file mode 100644
index 000000000..05e0bb9a1
--- /dev/null
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestAWSTags.py
@@ -0,0 +1,140 @@
+import os
+import sys
+import lxml.etree
+import Bcfg2.Server.Plugin
+from mock import Mock, MagicMock, patch
+try:
+ from Bcfg2.Server.Plugins.AWSTags import *
+ HAS_BOTO = True
+except ImportError:
+ HAS_BOTO = False
+
+# 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 TestPlugin, TestConnector, TestClientRunHooks
+
+config = '''
+<AWSTags>
+ <Tag name="name-only">
+ <Group>group1</Group>
+ <Group>group2</Group>
+ </Tag>
+ <Tag name="name-and-value" value="value">
+ <Group>group3</Group>
+ </Tag>
+ <Tag name="regex-(.*)">
+ <Group>group-$1</Group>
+ </Tag>
+ <Tag name="regex-value" value="(.*)">
+ <Group>group-$1</Group>
+ </Tag>
+</AWSTags>
+'''
+
+tags = {
+ "empty.example.com": {},
+ "no-matches.example.com": {"nameonly": "foo",
+ "Name": "no-matches",
+ "foo": "bar"},
+ "foo.example.com": {"name-only": "name-only",
+ "name-and-value": "wrong",
+ "regex-name": "foo"},
+ "bar.example.com": {"name-and-value": "value",
+ "regex-value": "bar"}}
+
+groups = {
+ "empty.example.com": [],
+ "no-matches.example.com": [],
+ "foo.example.com": ["group1", "group2", "group-name"],
+ "bar.example.com": ["group3", "group-value", "group-bar"]}
+
+
+def make_instance(name):
+ rv = Mock()
+ rv.private_dns_name = name
+ rv.tags = tags[name]
+ return rv
+
+
+instances = [make_instance(n) for n in tags.keys()]
+
+
+def get_all_instances(filters=None):
+ insts = [i for i in instances
+ if i.private_dns_name == filters['private-dns-name']]
+ res = Mock()
+ res.instances = insts
+ return [res]
+
+
+if HAS_BOTO:
+ class TestAWSTags(TestPlugin, TestClientRunHooks, TestConnector):
+ test_obj = AWSTags
+
+ def get_obj(self, core=None):
+ @patchIf(not isinstance(Bcfg2.Server.Plugins.AWSTags.connect_ec2,
+ Mock),
+ "Bcfg2.Server.Plugins.AWSTags.connect_ec2", Mock())
+ @patch("lxml.etree.Element", Mock())
+ def inner():
+ obj = TestPlugin.get_obj(self, core=core)
+ obj.config.data = config
+ obj.config.Index()
+ return obj
+ return inner()
+
+ @patch("Bcfg2.Server.Plugins.AWSTags.connect_ec2")
+ def test_connect(self, mock_connect_ec2):
+ """ Test connection to EC2 """
+ key_id = "a09sdbipasdf"
+ access_key = "oiilb234ipwe9"
+
+ def cfp_get(section, option):
+ if option == "access_key_id":
+ return key_id
+ elif option == "secret_access_key":
+ return access_key
+ else:
+ return Mock()
+
+ core = Mock()
+ core.setup.cfp.get = Mock(side_effect=cfp_get)
+ awstags = self.get_obj(core=core)
+ mock_connect_ec2.assert_called_with(
+ aws_access_key_id=key_id,
+ aws_secret_access_key=access_key)
+
+ def test_get_additional_data(self):
+ """ Test AWSTags.get_additional_data() """
+ awstags = self.get_obj()
+ awstags._ec2.get_all_instances = \
+ Mock(side_effect=get_all_instances)
+
+ for hostname, expected in tags.items():
+ metadata = Mock()
+ metadata.hostname = hostname
+ self.assertItemsEqual(awstags.get_additional_data(metadata),
+ expected)
+
+ def test_get_additional_groups_caching(self):
+ """ Test AWSTags.get_additional_groups() with caching enabled """
+ awstags = self.get_obj()
+ awstags._ec2.get_all_instances = \
+ Mock(side_effect=get_all_instances)
+
+ for hostname, expected in groups.items():
+ metadata = Mock()
+ metadata.hostname = hostname
+ actual = awstags.get_additional_groups(metadata)
+ msg = """%s has incorrect groups:
+actual: %s
+expected: %s""" % (hostname, actual, expected)
+ self.assertItemsEqual(actual, expected, msg)
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py
index 71a7410da..2bfec0e2d 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgEncryptedGenerator.py
@@ -1,6 +1,7 @@
import os
import sys
import lxml.etree
+import Bcfg2.Server.Plugins.Cfg
from mock import Mock, MagicMock, patch
from Bcfg2.Server.Plugins.Cfg.CfgEncryptedGenerator import *
from Bcfg2.Server.Plugin import PluginExecutionError
@@ -47,9 +48,10 @@ if can_skip or HAS_CRYPTO:
ceg = self.get_obj()
ceg.handle_event(event)
mock_handle_event.assert_called_with(ceg, event)
- mock_decrypt.assert_called_with("encrypted",
- setup=SETUP,
- algorithm=mock_get_algorithm.return_value)
+ mock_decrypt.assert_called_with(
+ "encrypted",
+ setup=Bcfg2.Server.Plugins.Cfg.SETUP,
+ algorithm=mock_get_algorithm.return_value)
self.assertEqual(ceg.data, "plaintext")
reset()
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py
index dc4b11241..e139a592b 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPrivateKeyCreator.py
@@ -31,6 +31,7 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile):
should_monitor = False
def get_obj(self, name=None, fam=None):
+ Bcfg2.Server.Plugins.Cfg.CfgPublicKeyCreator.CFG = Mock()
return TestCfgCreator.get_obj(self, name=name)
@patch("Bcfg2.Server.Plugins.Cfg.CfgCreator.handle_event")
@@ -259,24 +260,6 @@ class TestCfgPrivateKeyCreator(TestCfgCreator, TestStructFile):
pkc.write_data.assert_called_with("privatekey", group="foo")
mock_rmtree.assert_called_with(datastore)
- reset()
- self.assertEqual(pkc.create_data(entry, metadata, return_pair=True),
- ("ssh-rsa publickey pubkey.filename\n",
- "privatekey"))
- pkc.XMLMatch.assert_called_with(metadata)
- pkc.get_specificity.assert_called_with(metadata,
- pkc.XMLMatch.return_value)
- pkc._gen_keypair.assert_called_with(metadata,
- pkc.XMLMatch.return_value)
- self.assertItemsEqual(mock_open.call_args_list,
- [call(privkey + ".pub"), call(privkey)])
- pkc.pubkey_creator.get_filename.assert_called_with(group="foo")
- pkc.pubkey_creator.write_data.assert_called_with(
- "ssh-rsa publickey pubkey.filename\n",
- group="foo")
- pkc.write_data.assert_called_with("privatekey", group="foo")
- mock_rmtree.assert_called_with(datastore)
-
inner()
if HAS_CRYPTO:
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPublicKeyCreator.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPublicKeyCreator.py
index 04772cf9a..ef4610fae 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPublicKeyCreator.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/TestCfgPublicKeyCreator.py
@@ -26,6 +26,7 @@ class TestCfgPublicKeyCreator(TestCfgCreator, TestStructFile):
should_monitor = False
def get_obj(self, name=None, fam=None):
+ Bcfg2.Server.Plugins.Cfg.CfgPublicKeyCreator.CFG = Mock()
return TestCfgCreator.get_obj(self, name=name)
@patch("Bcfg2.Server.Plugins.Cfg.CfgCreator.handle_event")
@@ -37,41 +38,117 @@ class TestCfgPublicKeyCreator(TestCfgCreator, TestStructFile):
mock_HandleEvent.assert_called_with(pkc, evt)
mock_handle_event.assert_called_with(pkc, evt)
- def test_create_data(self):
+ @patch("os.unlink")
+ @patch("os.path.exists")
+ @patch("tempfile.mkstemp")
+ @patch("os.fdopen", Mock())
+ @patch("%s.open" % builtins)
+ def test_create_data(self, mock_open, mock_mkstemp, mock_exists,
+ mock_unlink):
metadata = Mock()
pkc = self.get_obj()
pkc.cfg = Mock()
+ pkc.core = Mock()
+ pkc.cmd = Mock()
+ pkc.write_data = Mock()
+ pubkey = "public key data"
privkey_entryset = Mock()
privkey_creator = Mock()
- pubkey = Mock()
- privkey = Mock()
- privkey_creator.create_data.return_value = (pubkey, privkey)
- privkey_entryset.best_matching.return_value = privkey_creator
+ privkey_creator.get_specificity = Mock()
+ privkey_creator.get_specificity.return_value = dict()
+ fileloc = pkc.get_filename()
pkc.cfg.entries = {"/home/foo/.ssh/id_rsa": privkey_entryset}
+ def reset():
+ privkey_creator.reset_mock()
+ pkc.cmd.reset_mock()
+ pkc.core.reset_mock()
+ pkc.write_data.reset_mock()
+ mock_exists.reset_mock()
+ mock_unlink.reset_mock()
+ mock_mkstemp.reset_mock()
+ mock_open.reset_mock()
+
# public key doesn't end in .pub
entry = lxml.etree.Element("Path", name="/home/bar/.ssh/bogus")
self.assertRaises(CfgCreationError,
pkc.create_data, entry, metadata)
+ self.assertFalse(pkc.write_data.called)
+
+ # cannot bind private key
+ reset()
+ pkc.core.Bind.side_effect = PluginExecutionError
+ entry = lxml.etree.Element("Path", name="/home/foo/.ssh/id_rsa.pub")
+ self.assertRaises(CfgCreationError,
+ pkc.create_data, entry, metadata)
+ self.assertFalse(pkc.write_data.called)
# private key not in cfg.entries
+ reset()
+ pkc.core.Bind.side_effect = None
+ pkc.core.Bind.return_value = "private key data"
entry = lxml.etree.Element("Path", name="/home/bar/.ssh/id_rsa.pub")
self.assertRaises(CfgCreationError,
pkc.create_data, entry, metadata)
+ self.assertFalse(pkc.write_data.called)
- # successful operation
+ # no privkey.xml defined
+ reset()
+ privkey_entryset.best_matching.side_effect = PluginExecutionError
+ entry = lxml.etree.Element("Path", name="/home/foo/.ssh/id_rsa.pub")
+ self.assertRaises(CfgCreationError,
+ pkc.create_data, entry, metadata)
+ self.assertFalse(pkc.write_data.called)
+
+ # successful operation, create new key
+ reset()
+ pkc.cmd.run.return_value = Mock()
+ pkc.cmd.run.return_value.success = True
+ pkc.cmd.run.return_value.stdout = pubkey
+ mock_mkstemp.return_value = (Mock(), str(Mock()))
+ mock_exists.return_value = False
+ privkey_entryset.best_matching.side_effect = None
+ privkey_entryset.best_matching.return_value = privkey_creator
entry = lxml.etree.Element("Path", name="/home/foo/.ssh/id_rsa.pub")
self.assertEqual(pkc.create_data(entry, metadata), pubkey)
+ self.assertTrue(pkc.core.Bind.called)
+ (privkey_entry, md) = pkc.core.Bind.call_args[0]
+ self.assertXMLEqual(privkey_entry,
+ lxml.etree.Element("Path",
+ name="/home/foo/.ssh/id_rsa"))
+ self.assertEqual(md, metadata)
+
privkey_entryset.get_handlers.assert_called_with(metadata, CfgCreator)
- privkey_entryset.best_matching.assert_called_with(metadata,
- privkey_entryset.get_handlers.return_value)
- self.assertXMLEqual(privkey_creator.create_data.call_args[0][0],
+ privkey_entryset.best_matching.assert_called_with(
+ metadata,
+ privkey_entryset.get_handlers.return_value)
+ mock_exists.assert_called_with(fileloc)
+ pkc.cmd.run.assert_called_with(["ssh-keygen", "-y", "-f",
+ mock_mkstemp.return_value[1]])
+ self.assertEqual(pkc.write_data.call_args[0][0], pubkey)
+ mock_unlink.assert_called_with(mock_mkstemp.return_value[1])
+ self.assertFalse(mock_open.called)
+
+ # successful operation, no need to create new key
+ reset()
+ mock_exists.return_value = True
+ mock_open.return_value = Mock()
+ mock_open.return_value.read.return_value = pubkey
+ pkc.cmd.run.return_value.stdout = None
+ self.assertEqual(pkc.create_data(entry, metadata), pubkey)
+ self.assertTrue(pkc.core.Bind.called)
+ (privkey_entry, md) = pkc.core.Bind.call_args[0]
+ self.assertXMLEqual(privkey_entry,
lxml.etree.Element("Path",
name="/home/foo/.ssh/id_rsa"))
- self.assertEqual(privkey_creator.create_data.call_args[0][1], metadata)
+ self.assertEqual(md, metadata)
- # no privkey.xml
- privkey_entryset.best_matching.side_effect = PluginExecutionError
- self.assertRaises(CfgCreationError,
- pkc.create_data, entry, metadata)
+ privkey_entryset.get_handlers.assert_called_with(metadata, CfgCreator)
+ privkey_entryset.best_matching.assert_called_with(
+ metadata,
+ privkey_entryset.get_handlers.return_value)
+ mock_exists.assert_called_with(fileloc)
+ mock_open.assert_called_with(fileloc)
+ self.assertFalse(mock_mkstemp.called)
+ self.assertFalse(pkc.write_data.called)
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py
index 2e758774e..fdfb3a9f7 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestCfg/Test_init.py
@@ -6,7 +6,7 @@ import Bcfg2.Options
from Bcfg2.Compat import walk_packages
from mock import Mock, MagicMock, patch
from Bcfg2.Server.Plugins.Cfg import *
-from Bcfg2.Server.Plugin import PluginExecutionError
+from Bcfg2.Server.Plugin import PluginExecutionError, Specificity
# add all parent testsuite directories to sys.path to allow (most)
# relative imports in python 2.4
@@ -298,21 +298,20 @@ class TestCfgEntrySet(TestEntrySet):
for submodule in walk_packages(path=Bcfg2.Server.Plugins.Cfg.__path__,
prefix="Bcfg2.Server.Plugins.Cfg."):
expected.append(submodule[1].rsplit('.', 1)[-1])
- eset = self.get_obj()
- self.assertItemsEqual(expected,
- [h.__name__ for h in eset.handlers])
+ self.assertItemsEqual(expected, [h.__name__ for h in handlers()])
- def test_handle_event(self):
+ @patch("Bcfg2.Server.Plugins.Cfg.handlers")
+ def test_handle_event(self, mock_handlers):
eset = self.get_obj()
eset.entry_init = Mock()
- eset._handlers = [Mock(), Mock(), Mock()]
- for hdlr in eset.handlers:
+ mock_handlers.return_value = [Mock(), Mock(), Mock()]
+ for hdlr in mock_handlers.return_value:
hdlr.__name__ = "handler"
eset.entries = dict()
def reset():
eset.entry_init.reset_mock()
- for hdlr in eset.handlers:
+ for hdlr in mock_handlers.return_value:
hdlr.reset_mock()
# test that a bogus deleted event is discarded
@@ -322,7 +321,7 @@ class TestCfgEntrySet(TestEntrySet):
eset.handle_event(evt)
self.assertFalse(eset.entry_init.called)
self.assertItemsEqual(eset.entries, dict())
- for hdlr in eset.handlers:
+ for hdlr in mock_handlers.return_value:
self.assertFalse(hdlr.handles.called)
self.assertFalse(hdlr.ignore.called)
@@ -333,7 +332,7 @@ class TestCfgEntrySet(TestEntrySet):
evt.filename = os.path.join(datastore, "test.txt")
# test with no handler that handles
- for hdlr in eset.handlers:
+ for hdlr in mock_handlers.return_value:
hdlr.handles.return_value = False
hdlr.ignore.return_value = False
@@ -341,16 +340,16 @@ class TestCfgEntrySet(TestEntrySet):
eset.handle_event(evt)
self.assertFalse(eset.entry_init.called)
self.assertItemsEqual(eset.entries, dict())
- for hdlr in eset.handlers:
+ for hdlr in mock_handlers.return_value:
hdlr.handles.assert_called_with(evt, basename=eset.path)
hdlr.ignore.assert_called_with(evt, basename=eset.path)
# test with a handler that handles the entry
reset()
- eset.handlers[-1].handles.return_value = True
+ mock_handlers.return_value[-1].handles.return_value = True
eset.handle_event(evt)
- eset.entry_init.assert_called_with(evt, eset.handlers[-1])
- for hdlr in eset.handlers:
+ eset.entry_init.assert_called_with(evt, mock_handlers.return_value[-1])
+ for hdlr in mock_handlers.return_value:
hdlr.handles.assert_called_with(evt, basename=eset.path)
if not hdlr.return_value:
hdlr.ignore.assert_called_with(evt, basename=eset.path)
@@ -358,14 +357,14 @@ class TestCfgEntrySet(TestEntrySet):
# test with a handler that ignores the entry before one
# that handles it
reset()
- eset.handlers[0].ignore.return_value = True
+ mock_handlers.return_value[0].ignore.return_value = True
eset.handle_event(evt)
self.assertFalse(eset.entry_init.called)
- eset.handlers[0].handles.assert_called_with(evt,
+ mock_handlers.return_value[0].handles.assert_called_with(evt,
basename=eset.path)
- eset.handlers[0].ignore.assert_called_with(evt,
+ mock_handlers.return_value[0].ignore.assert_called_with(evt,
basename=eset.path)
- for hdlr in eset.handlers[1:]:
+ for hdlr in mock_handlers.return_value[1:]:
self.assertFalse(hdlr.handles.called)
self.assertFalse(hdlr.ignore.called)
@@ -377,7 +376,7 @@ class TestCfgEntrySet(TestEntrySet):
eset.entries[evt.filename] = Mock()
eset.handle_event(evt)
self.assertFalse(eset.entry_init.called)
- for hdlr in eset.handlers:
+ for hdlr in mock_handlers.return_value:
self.assertFalse(hdlr.handles.called)
self.assertFalse(hdlr.ignore.called)
eset.entries[evt.filename].handle_event.assert_called_with(evt)
@@ -387,7 +386,7 @@ class TestCfgEntrySet(TestEntrySet):
evt.code2str.return_value = "deleted"
eset.handle_event(evt)
self.assertFalse(eset.entry_init.called)
- for hdlr in eset.handlers:
+ for hdlr in mock_handlers.return_value:
self.assertFalse(hdlr.handles.called)
self.assertFalse(hdlr.ignore.called)
self.assertItemsEqual(eset.entries, dict())
@@ -462,7 +461,7 @@ class TestCfgEntrySet(TestEntrySet):
metadata = Mock()
# test basic entry, no validation, no filters, etc.
- eset._generate_data.return_value = "data"
+ eset._generate_data.return_value = ("data", None)
eset.get_handlers.return_value = []
bound = eset.bind_entry(entry, metadata)
eset.bind_info_to_entry.assert_called_with(entry, metadata)
@@ -475,7 +474,7 @@ class TestCfgEntrySet(TestEntrySet):
# test empty entry
entry = reset()
- eset._generate_data.return_value = ""
+ eset._generate_data.return_value = ("", None)
bound = eset.bind_entry(entry, metadata)
eset.bind_info_to_entry.assert_called_with(entry, metadata)
eset._generate_data.assert_called_with(entry, metadata)
@@ -486,7 +485,9 @@ class TestCfgEntrySet(TestEntrySet):
# test filters
entry = reset()
- eset._generate_data.return_value = "initial data"
+ generator = Mock()
+ generator.specific = Specificity(all=True)
+ eset._generate_data.return_value = ("initial data", generator)
filters = [Mock(), Mock()]
filters[0].modify_data.return_value = "modified data"
filters[1].modify_data.return_value = "final data"
@@ -508,7 +509,7 @@ class TestCfgEntrySet(TestEntrySet):
entry.set("encoding", "base64")
mock_b64encode.return_value = "base64 data"
eset.get_handlers.return_value = []
- eset._generate_data.return_value = "data"
+ eset._generate_data.return_value = ("data", None)
bound = eset.bind_entry(entry, metadata)
eset.bind_info_to_entry.assert_called_with(entry, metadata)
eset._generate_data.assert_called_with(entry, metadata)
@@ -559,7 +560,7 @@ class TestCfgEntrySet(TestEntrySet):
def reset():
for e in eset.entries.values():
- if e.specific is not None:
+ if hasattr(e.specific, "reset_mock"):
e.specific.reset_mock()
metadata = Mock()
@@ -576,7 +577,7 @@ class TestCfgEntrySet(TestEntrySet):
[eset.entries['test1.txt'],
eset.entries['test3.txt']])
for entry in eset.entries.values():
- if entry.specific is not None:
+ if hasattr(entry.specific.matches, "called"):
self.assertFalse(entry.specific.matches.called)
reset()
@@ -584,20 +585,22 @@ class TestCfgEntrySet(TestEntrySet):
[eset.entries['test6.txt']])
eset.entries['test6.txt'].specific.matches.assert_called_with(metadata)
for ename, entry in eset.entries.items():
- if ename != 'test6.txt' and entry.specific is not None:
+ if (ename != 'test6.txt' and
+ hasattr(entry.specific.matches, "called")):
self.assertFalse(entry.specific.matches.called)
reset()
self.assertItemsEqual(eset.get_handlers(metadata, CfgFilter), [])
eset.entries['test7.txt'].specific.matches.assert_called_with(metadata)
for ename, entry in eset.entries.items():
- if ename != 'test7.txt' and entry.specific is not None:
+ if (ename != 'test7.txt' and
+ hasattr(entry.specific.matches, "called")):
self.assertFalse(entry.specific.matches.called)
reset()
self.assertItemsEqual(eset.get_handlers(metadata, Mock), [])
for ename, entry in eset.entries.items():
- if entry.specific is not None:
+ if hasattr(entry.specific.matches, "called"):
self.assertFalse(entry.specific.matches.called)
def test_bind_info_to_entry(self):
@@ -692,7 +695,7 @@ class TestCfgEntrySet(TestEntrySet):
eset._create_data.reset_mock()
# test success
- self.assertEqual(eset._generate_data(entry, metadata),
+ self.assertEqual(eset._generate_data(entry, metadata)[0],
"data")
eset.get_handlers.assert_called_with(metadata, CfgGenerator)
eset.best_matching.assert_called_with(metadata,
@@ -709,7 +712,7 @@ class TestCfgEntrySet(TestEntrySet):
reset()
eset.best_matching.side_effect = PluginExecutionError
self.assertEqual(eset._generate_data(entry, metadata),
- eset._create_data.return_value)
+ (eset._create_data.return_value, None))
eset.get_handlers.assert_called_with(metadata, CfgGenerator)
eset.best_matching.assert_called_with(metadata,
eset.get_handlers.return_value)
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py
index 742946c42..a07fffba1 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py
@@ -339,6 +339,7 @@ class TestXMLMetadataConfig(TestXMLFileBacked):
@patch('Bcfg2.Utils.locked', Mock(return_value=False))
@patch('fcntl.lockf', Mock())
+ @patch("Bcfg2.Server.Plugins.Metadata.XMLMetadataConfig.load_xml")
@patch('os.open')
@patch('os.fdopen')
@patch('os.unlink')
@@ -346,7 +347,7 @@ class TestXMLMetadataConfig(TestXMLFileBacked):
@patch('os.path.islink')
@patch('os.readlink')
def test_write_xml(self, mock_readlink, mock_islink, mock_rename,
- mock_unlink, mock_fdopen, mock_open):
+ mock_unlink, mock_fdopen, mock_open, mock_load_xml):
fname = "clients.xml"
config = self.get_obj(fname)
fpath = os.path.join(self.metadata.data, fname)
@@ -360,6 +361,7 @@ class TestXMLMetadataConfig(TestXMLFileBacked):
mock_unlink.reset_mock()
mock_fdopen.reset_mock()
mock_open.reset_mock()
+ mock_load_xml.reset_mock()
mock_islink.return_value = False
@@ -371,6 +373,7 @@ class TestXMLMetadataConfig(TestXMLFileBacked):
self.assertTrue(mock_fdopen.return_value.write.called)
mock_islink.assert_called_with(fpath)
mock_rename.assert_called_with(tmpfile, fpath)
+ mock_load_xml.assert_called_with()
# test: clients.xml.new is locked the first time we write it
def rv(fname, mode):
@@ -389,6 +392,7 @@ class TestXMLMetadataConfig(TestXMLFileBacked):
self.assertTrue(mock_fdopen.return_value.write.called)
mock_islink.assert_called_with(fpath)
mock_rename.assert_called_with(tmpfile, fpath)
+ mock_load_xml.assert_called_with()
# test writing a symlinked clients.xml
reset()
@@ -397,6 +401,7 @@ class TestXMLMetadataConfig(TestXMLFileBacked):
mock_readlink.return_value = linkdest
config.write_xml(fpath, get_clients_test_tree())
mock_rename.assert_called_with(tmpfile, linkdest)
+ mock_load_xml.assert_called_with()
# test failure of os.rename()
reset()
@@ -830,21 +835,18 @@ class TestMetadata(_TestMetadata, TestClientRunHooks, TestDatabaseBacked):
self.assertEqual(metadata.groups['group4'].category, 'category1')
self.assertEqual(metadata.default, "group1")
- all_groups = []
- negated_groups = []
+ all_groups = set()
+ negated_groups = set()
for group in get_groups_test_tree().xpath("//Groups/Client//*") + \
get_groups_test_tree().xpath("//Groups/Group//*"):
if group.tag == 'Group' and not group.getchildren():
if group.get("negate", "false").lower() == 'true':
- negated_groups.append(group.get("name"))
+ negated_groups.add(group.get("name"))
else:
- all_groups.append(group.get("name"))
- self.assertItemsEqual([g.name
- for g in metadata.group_membership.values()],
- all_groups)
- self.assertItemsEqual([g.name
- for g in metadata.negated_groups.values()],
- negated_groups)
+ all_groups.add(group.get("name"))
+ self.assertItemsEqual(metadata.ordered_groups, all_groups)
+ self.assertItemsEqual(metadata.group_membership.keys(), all_groups)
+ self.assertItemsEqual(metadata.negated_groups.keys(), negated_groups)
@patch("Bcfg2.Server.Plugins.Metadata.XMLMetadataConfig.load_xml", Mock())
def test_set_profile(self):
@@ -885,10 +887,13 @@ class TestMetadata(_TestMetadata, TestClientRunHooks, TestDatabaseBacked):
metadata = self.load_clients_data(metadata=self.load_groups_data())
if not metadata._use_db:
metadata.clients_xml.write = Mock()
+ metadata.core.build_metadata = Mock()
+ metadata.core.build_metadata.side_effect = \
+ lambda c: metadata.get_initial_metadata(c)
+
metadata.set_profile("client1", "group2", None)
mock_update_client.assert_called_with("client1",
dict(profile="group2"))
- metadata.clients_xml.write.assert_any_call()
self.assertEqual(metadata.clientgroups["client1"], ["group2"])
metadata.clients_xml.write.reset_mock()
@@ -910,8 +915,8 @@ class TestMetadata(_TestMetadata, TestClientRunHooks, TestDatabaseBacked):
self.assertEqual(metadata.clientgroups["uuid_new"], ["group1"])
@patch("Bcfg2.Server.Plugins.Metadata.XMLMetadataConfig.load_xml", Mock())
- @patch("socket.gethostbyaddr")
- def test_resolve_client(self, mock_gethostbyaddr):
+ @patch("socket.getnameinfo")
+ def test_resolve_client(self, mock_getnameinfo):
metadata = self.load_clients_data(metadata=self.load_groups_data())
metadata.session_cache[('1.2.3.3', None)] = (time.time(), 'client3')
self.assertEqual(metadata.resolve_client(('1.2.3.3', None)), 'client3')
@@ -928,22 +933,22 @@ class TestMetadata(_TestMetadata, TestClientRunHooks, TestDatabaseBacked):
cleanup_cache=True), 'client3')
self.assertEqual(metadata.session_cache, dict())
- mock_gethostbyaddr.return_value = ('client6', [], ['1.2.3.6'])
- self.assertEqual(metadata.resolve_client(('1.2.3.6', None)), 'client6')
- mock_gethostbyaddr.assert_called_with('1.2.3.6')
+ mock_getnameinfo.return_value = ('client6', [], ['1.2.3.6'])
+ self.assertEqual(metadata.resolve_client(('1.2.3.6', 6789)), 'client6')
+ mock_getnameinfo.assert_called_with(('1.2.3.6', 6789), socket.NI_NAMEREQD)
- mock_gethostbyaddr.reset_mock()
- mock_gethostbyaddr.return_value = ('alias3', [], ['1.2.3.7'])
- self.assertEqual(metadata.resolve_client(('1.2.3.7', None)), 'client4')
- mock_gethostbyaddr.assert_called_with('1.2.3.7')
+ mock_getnameinfo.reset_mock()
+ mock_getnameinfo.return_value = ('alias3', [], ['1.2.3.7'])
+ self.assertEqual(metadata.resolve_client(('1.2.3.7', 6789)), 'client4')
+ mock_getnameinfo.assert_called_with(('1.2.3.7', 6789), socket.NI_NAMEREQD)
- mock_gethostbyaddr.reset_mock()
- mock_gethostbyaddr.return_value = None
- mock_gethostbyaddr.side_effect = socket.herror
+ mock_getnameinfo.reset_mock()
+ mock_getnameinfo.return_value = None
+ mock_getnameinfo.side_effect = socket.herror
self.assertRaises(Bcfg2.Server.Plugin.MetadataConsistencyError,
metadata.resolve_client,
- ('1.2.3.8', None))
- mock_gethostbyaddr.assert_called_with('1.2.3.8')
+ ('1.2.3.8', 6789))
+ mock_getnameinfo.assert_called_with(('1.2.3.8', 6789), socket.NI_NAMEREQD)
@patch("Bcfg2.Server.Plugins.Metadata.XMLMetadataConfig.load_xml", Mock())
@patch("Bcfg2.Server.Plugins.Metadata.XMLMetadataConfig.write_xml", Mock())
@@ -1485,30 +1490,30 @@ class TestMetadata_NoClientsXML(TestMetadataBase):
"1.2.3.8"))
@patch("Bcfg2.Server.Plugins.Metadata.XMLMetadataConfig.load_xml", Mock())
- @patch("socket.gethostbyaddr")
- def test_resolve_client(self, mock_gethostbyaddr):
+ @patch("socket.getnameinfo")
+ def test_resolve_client(self, mock_getnameinfo):
metadata = self.load_clients_data(metadata=self.load_groups_data())
metadata.session_cache[('1.2.3.3', None)] = (time.time(), 'client3')
self.assertEqual(metadata.resolve_client(('1.2.3.3', None)), 'client3')
metadata.session_cache[('1.2.3.3', None)] = (time.time() - 100,
'client3')
- mock_gethostbyaddr.return_value = ("client3", [], ['1.2.3.3'])
+ mock_getnameinfo.return_value = ("client3", [], ['1.2.3.3'])
self.assertEqual(metadata.resolve_client(('1.2.3.3', None),
cleanup_cache=True), 'client3')
self.assertEqual(metadata.session_cache, dict())
- mock_gethostbyaddr.return_value = ('client6', [], ['1.2.3.6'])
- self.assertEqual(metadata.resolve_client(('1.2.3.6', None)), 'client6')
- mock_gethostbyaddr.assert_called_with('1.2.3.6')
+ mock_getnameinfo.return_value = ('client6', [], ['1.2.3.6'])
+ self.assertEqual(metadata.resolve_client(('1.2.3.6', 6789), socket.NI_NAMEREQD), 'client6')
+ mock_getnameinfo.assert_called_with(('1.2.3.6', 6789), socket.NI_NAMEREQD)
- mock_gethostbyaddr.reset_mock()
- mock_gethostbyaddr.return_value = None
- mock_gethostbyaddr.side_effect = socket.herror
+ mock_getnameinfo.reset_mock()
+ mock_getnameinfo.return_value = None
+ mock_getnameinfo.side_effect = socket.herror
self.assertRaises(Bcfg2.Server.Plugin.MetadataConsistencyError,
metadata.resolve_client,
- ('1.2.3.8', None))
- mock_gethostbyaddr.assert_called_with('1.2.3.8')
+ ('1.2.3.8', 6789), socket.NI_NAMEREQD)
+ mock_getnameinfo.assert_called_with(('1.2.3.8', 6789), socket.NI_NAMEREQD)
def test_handle_clients_xml_event(self):
pass
diff --git a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProbes.py b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProbes.py
index 0794db62e..2face023f 100644
--- a/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProbes.py
+++ b/testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestProbes.py
@@ -1,4 +1,5 @@
import os
+import re
import sys
import copy
import time
@@ -295,7 +296,9 @@ text
def inner():
return self.get_obj(core)
- return inner()
+ rv = inner()
+ rv.allowed_cgroups = [re.compile("^.*$")]
+ return rv
def test__init(self):
mock_load_data = Mock()
@@ -466,7 +469,7 @@ text
def test_load_data_db(self):
probes = self.get_probes_object(use_db=True)
probes.load_data()
- probes._load_data_db.assert_any_call()
+ probes._load_data_db.assert_any_call(client=None)
self.assertFalse(probes._load_data_xml.called)
@patch("lxml.etree.parse")
@@ -591,6 +594,37 @@ text
self.assertEqual(probes.cgroups[cname],
self.get_test_cgroups()[cname])
+ # test again, with an explicit list of allowed groups
+ probes.allowed_cgroups = [re.compile(r'^.*s$')]
+ for cname, cdata in self.get_test_probedata().items():
+ client = Mock()
+ client.hostname = cname
+ cgroups = []
+ cprobedata = ClientProbeDataSet()
+ for pname, pdata in cdata.items():
+ dataitem = lxml.etree.Element("Probe", name=pname)
+ if pname == "text":
+ # add some groups to the plaintext test to test
+ # group parsing
+ data = [pdata]
+ for group in self.get_test_cgroups()[cname]:
+ data.append("group:%s" % group)
+ dataitem.text = "\n".join(data)
+ else:
+ dataitem.text = str(pdata)
+
+ probes.ReceiveDataItem(client, dataitem, cgroups, cprobedata)
+
+ probes.cgroups[client.hostname] = cgroups
+ probes.probedata[client.hostname] = cprobedata
+ self.assertIn(client.hostname, probes.probedata)
+ self.assertIn(pname, probes.probedata[cname])
+ self.assertEqual(pdata, probes.probedata[cname][pname])
+ self.assertIn(client.hostname, probes.cgroups)
+ self.assertEqual(probes.cgroups[cname],
+ [g for g in self.get_test_cgroups()[cname]
+ if g.endswith("s")])
+
def test_get_additional_groups(self):
TestConnector.test_get_additional_groups(self)
diff --git a/testsuite/Testsrc/test_code_checks.py b/testsuite/Testsrc/test_code_checks.py
index a38710fd4..e1214a942 100644
--- a/testsuite/Testsrc/test_code_checks.py
+++ b/testsuite/Testsrc/test_code_checks.py
@@ -79,7 +79,9 @@ no_checks = {
"TCheetah.py",
"TGenshi.py"],
}
-
+if sys.version_info < (2, 6):
+ # multiprocessing core requires py2.6
+ no_checks['lib/Bcfg2/Server'].append('MultiprocessingCore.py')
try:
any
@@ -186,7 +188,7 @@ class CodeTestCase(Bcfg2TestCase):
cmd = self.command + self.full_args + extra_args + \
[os.path.join(srcpath, f) for f in files]
proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, env=self.get_env())
- print(proc.communicate()[0])
+ print(proc.communicate()[0].decode())
self.assertEqual(proc.wait(), 0)
def _test_errors(self, files, extra_args=None):
@@ -198,7 +200,7 @@ class CodeTestCase(Bcfg2TestCase):
cmd = self.command + self.error_args + extra_args + \
[os.path.join(srcpath, f) for f in files]
proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, env=self.get_env())
- print(proc.communicate()[0])
+ print(proc.communicate()[0].decode())
self.assertEqual(proc.wait(), 0)
@skipIf(not os.path.exists(srcpath), "%s does not exist" % srcpath)
@@ -321,7 +323,7 @@ class TestPylint(CodeTestCase):
args = self.command + self.error_args + extra_args + \
[os.path.join(srcpath, p) for p in files]
pylint = Popen(args, stdout=PIPE, stderr=STDOUT, env=self.get_env())
- output = pylint.communicate()[0]
+ output = pylint.communicate()[0].decode()
rv = pylint.wait()
for line in output.splitlines():
diff --git a/testsuite/before_install.sh b/testsuite/before_install.sh
index 5f1a59aaf..2c80036cd 100755
--- a/testsuite/before_install.sh
+++ b/testsuite/before_install.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/bash -ex
# before_install script for Travis-CI
@@ -8,6 +8,7 @@ sudo apt-get update -qq
sudo apt-get install -qq swig libxml2-utils
if [[ "$WITH_OPTIONAL_DEPS" == "yes" ]]; then
if [[ ${PYVER:0:1} == "2" ]]; then
- sudo apt-get install -qq python-selinux python-pylibacl yum
+ sudo apt-get install -y yum libaugeas0 augeas-lenses libacl1-dev \
+ libssl-dev
fi
fi
diff --git a/testsuite/common.py b/testsuite/common.py
index e26d0be61..7471795a6 100644
--- a/testsuite/common.py
+++ b/testsuite/common.py
@@ -13,6 +13,7 @@ import re
import sys
import codecs
import unittest
+import lxml.etree
from mock import patch, MagicMock, _patch, DEFAULT
from Bcfg2.Compat import wraps
@@ -222,8 +223,11 @@ class Bcfg2TestCase(unittest.TestCase):
lines = ['First has %d, Second has %d: %r' % diff
for diff in differences]
diffMsg = '\n'.join(lines)
- standardMsg = self._truncateMessage(standardMsg, diffMsg)
- msg = self._formatMessage(msg, standardMsg)
+ standardMsg += diffMsg
+ if msg is None:
+ msg = standardMsg
+ else:
+ msg = "%s : %s" % (standardMsg, msg)
self.fail(msg)
if not hasattr(unittest.TestCase, "assertRegexpMatches"):
@@ -262,24 +266,43 @@ class Bcfg2TestCase(unittest.TestCase):
"%s is not less than or equal to %s")
def assertXMLEqual(self, el1, el2, msg=None):
- """ Test that the two XML trees given are equal. Both
- elements and all children are expected to have ``name``
- attributes. """
- self.assertEqual(el1.tag, el2.tag, msg=msg)
- self.assertEqual(el1.text, el2.text, msg=msg)
- self.assertItemsEqual(el1.attrib.items(), el2.attrib.items(), msg=msg)
+ """ Test that the two XML trees given are equal. """
+ if msg is None:
+ msg = "XML trees are not equal: %s"
+ else:
+ msg += ": %s"
+ fullmsg = msg + "\nFirst: %s" % lxml.etree.tostring(el1) + \
+ "\nSecond: %s" % lxml.etree.tostring(el2)
+
+ self.assertEqual(el1.tag, el2.tag, msg=fullmsg % "Tags differ")
+ if el1.text is not None and el2.text is not None:
+ self.assertEqual(el1.text.strip(), el2.text.strip(),
+ msg=fullmsg % "Text content differs")
+ else:
+ self.assertEqual(el1.text, el2.text,
+ msg=fullmsg % "Text content differs")
+ self.assertItemsEqual(el1.attrib.items(), el2.attrib.items(),
+ msg=fullmsg % "Attributes differ")
self.assertEqual(len(el1.getchildren()),
- len(el2.getchildren()))
+ len(el2.getchildren()),
+ msg=fullmsg % "Different numbers of children")
+ matched = []
for child1 in el1.getchildren():
- cname = child1.get("name")
- self.assertIsNotNone(cname,
- msg="Element %s has no 'name' attribute" %
- child1.tag)
- children2 = el2.xpath("%s[@name='%s']" % (child1.tag, cname))
- self.assertEqual(len(children2), 1,
- msg="More than one %s element named %s" % \
- (child1.tag, cname))
- self.assertXMLEqual(child1, children2[0], msg=msg)
+ for child2 in el2.xpath(child1.tag):
+ if child2 in matched:
+ continue
+ try:
+ self.assertXMLEqual(child1, child2)
+ matched.append(child2)
+ break
+ except AssertionError:
+ continue
+ else:
+ assert False, \
+ fullmsg % ("Element %s is missing from second" %
+ lxml.etree.tostring(child1))
+ self.assertItemsEqual(el2.getchildren(), matched,
+ msg=fullmsg % "Second has extra element(s)")
class DBModelTestCase(Bcfg2TestCase):
@@ -394,4 +417,3 @@ try:
re_type = re._pattern_type
except AttributeError:
re_type = type(re.compile(""))
-
diff --git a/testsuite/ext/exception_messages.py b/testsuite/ext/exception_messages.py
index 877ba42a1..cd3d7112c 100644
--- a/testsuite/ext/exception_messages.py
+++ b/testsuite/ext/exception_messages.py
@@ -1,16 +1,30 @@
-from logilab import astng
-from pylint.interfaces import IASTNGChecker
+try:
+ from logilab import astng as ast
+ from pylint.interfaces import IASTNGChecker as IChecker
+ PYLINT = 0 # pylint 0.something
+except ImportError:
+ import astroid as ast
+ from pylint.interfaces import IAstroidChecker as IChecker
+ PYLINT = 1 # pylint 1.something
from pylint.checkers import BaseChecker
from pylint.checkers.utils import safe_infer
+if PYLINT == 0:
+ # this is not quite correct; later versions of pylint 0.* wanted a
+ # three-tuple for messages as well
+ msg = ('Exception raised without arguments',
+ 'Used when an exception is raised without any arguments')
+else:
+ msg = ('Exception raised without arguments',
+ 'exception-without-args',
+ 'Used when an exception is raised without any arguments')
+msgs = {'R9901': msg}
+
class ExceptionMessageChecker(BaseChecker):
- __implements__ = IASTNGChecker
+ __implements__ = IChecker
name = 'Exception Messages'
- msgs = \
- {'R9901': ('Exception raised without arguments',
- 'Used when an exception is raised without any arguments')}
options = (
('exceptions-without-args',
dict(default=('NotImplementedError',),
@@ -23,9 +37,9 @@ class ExceptionMessageChecker(BaseChecker):
def visit_raise(self, node):
if node.exc is None:
return
- if isinstance(node.exc, astng.Name):
+ if isinstance(node.exc, ast.Name):
raised = safe_infer(node.exc)
- if (isinstance(raised, astng.Class) and
+ if (isinstance(raised, ast.Class) and
raised.name not in self.config.exceptions_without_args):
self.add_message('R9901', node=node.exc)
diff --git a/testsuite/install.sh b/testsuite/install.sh
index 1ca89f40f..9de5b8c6d 100755
--- a/testsuite/install.sh
+++ b/testsuite/install.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/bash -ex
# install script for Travis-CI
@@ -7,20 +7,13 @@ pip install -r testsuite/requirements.txt --use-mirrors
PYVER=$(python -c 'import sys;print(".".join(str(v) for v in sys.version_info[0:2]))')
if [[ "$WITH_OPTIONAL_DEPS" == "yes" ]]; then
- pip install --use-mirrors genshi PyYAML pyinotify
- if [[ $PYVER == "2.5" ]]; then
- # markdown 2.2+ doesn't work on py2.5
- pip install --use-mirrors simplejson 'markdown<2.2'
- fi
+ pip install --use-mirrors genshi PyYAML pyinotify boto 'django<1.5' \
+ pylibacl
+ easy_install https://fedorahosted.org/released/python-augeas/python-augeas-0.4.1.tar.gz
if [[ ${PYVER:0:1} == "2" ]]; then
# django supports py3k, but South doesn't, and the django bits
# in bcfg2 require South
- pip install cheetah 'django<1.5' 'South<0.8' M2Crypto
- fi
-else
- # python < 2.6 requires M2Crypto for SSL communication, not just
- # for encryption support
- if [[ $PYVER == "2.5" || $PYVER == "2.4" ]]; then
- pip install --use-mirrors M2crypto
+ pip install cheetah 'South<0.8'
+ pip install m2crypto
fi
fi
diff --git a/testsuite/pylintrc.conf b/testsuite/pylintrc.conf
index 14ccd1d23..653c68426 100644
--- a/testsuite/pylintrc.conf
+++ b/testsuite/pylintrc.conf
@@ -156,7 +156,7 @@ zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
-generated-members=objects,DoesNotExist,isoformat,filter,save,count,get,add,id
+generated-members=objects,DoesNotExist,isoformat,filter,save,count,get,add,id,MultipleObjectsReturned
[MISCELLANEOUS]
diff --git a/testsuite/requirements.txt b/testsuite/requirements.txt
index 2d6dbc557..898249389 100644
--- a/testsuite/requirements.txt
+++ b/testsuite/requirements.txt
@@ -2,6 +2,6 @@ lxml
nose
mock
sphinx
-pylint
+pylint<1.0
pep8
python-daemon