diff options
Diffstat (limited to 'testsuite/Testsrc/Testlib')
12 files changed, 658 insertions, 162 deletions
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) |