class LoggedInUsersTest(FakeWhoQTest):
    def setUp(self):
        super(LoggedInUsersTest, self).setUp()
        self.logged_users = LoggedInUsers()
        self.sysinfo = SysInfoPluginRegistry()
        self.sysinfo.add(self.logged_users)

    def test_run_adds_header(self):
        self.fake_who("one two three")
        result = self.logged_users.run()

        def check_headers(result):
            self.assertEqual(self.sysinfo.get_headers(),
                             [("Users logged in", "3")])

        return result.addCallback(check_headers)

    def test_order_is_preserved_even_if_asynchronous(self):
        self.fake_who("one two three")
        self.sysinfo.add_header("Before", "1")
        result = self.logged_users.run()
        self.sysinfo.add_header("After", "2")

        def check_headers(result):
            self.assertEqual(self.sysinfo.get_headers(),
                             [("Before", "1"), ("Users logged in", "3"),
                              ("After", "2")])

        return result.addCallback(check_headers)

    def test_ignore_errors_on_command(self):
        self.fake_who("")
        who = open(self.who_path, "w")
        who.write("#!/bin/sh\necho ERROR >&2\nexit 1\n")
        who.close()
        # Nothing bad should happen if who isn't installed, or
        # if anything else happens with the command execution.
        result = self.logged_users.run()

        def check_headers(result):
            self.assertEqual(self.sysinfo.get_headers(), [])

        return result.addCallback(check_headers)
示例#2
0
class SysInfoPluginRegistryTest(HelperTestCase):
    def setUp(self):
        super(SysInfoPluginRegistryTest, self).setUp()
        self.sysinfo = SysInfoPluginRegistry()
        self.sysinfo_logfile = StringIO()
        self.handler = StreamHandler(self.sysinfo_logfile)
        self.logger = getLogger("landscape-sysinfo")
        self.logger.addHandler(self.handler)

    def tearDown(self):
        super(SysInfoPluginRegistryTest, self).tearDown()
        self.logger.removeHandler(self.handler)

    def test_is_plugin_registry(self):
        self.assertTrue(isinstance(self.sysinfo, PluginRegistry))

    def test_add_and_get_headers(self):
        self.sysinfo.add_header("Memory usage", "65%")
        self.sysinfo.add_header("Swap usage", "None")
        self.assertEqual(self.sysinfo.get_headers(), [("Memory usage", "65%"),
                                                      ("Swap usage", "None")])
        self.assertEqual(self.sysinfo.get_notes(), [])
        self.assertEqual(self.sysinfo.get_footnotes(), [])

    def test_add_same_header_twice(self):
        self.sysinfo.add_header("Header1", "Value1")
        self.sysinfo.add_header("Header2", "Value2")
        self.sysinfo.add_header("Header3", "Value3")
        self.sysinfo.add_header("Header2", "Value4")
        self.assertEqual(self.sysinfo.get_headers(), [("Header1", "Value1"),
                                                      ("Header2", "Value4"),
                                                      ("Header3", "Value3")])

    def test_add_header_with_none_value(self):
        self.sysinfo.add_header("Header1", "Value1")
        self.sysinfo.add_header("Header2", None)
        self.sysinfo.add_header("Header3", "Value3")
        self.assertEqual(self.sysinfo.get_headers(), [("Header1", "Value1"),
                                                      ("Header3", "Value3")])
        self.sysinfo.add_header("Header2", "Value2")
        self.assertEqual(self.sysinfo.get_headers(), [("Header1", "Value1"),
                                                      ("Header2", "Value2"),
                                                      ("Header3", "Value3")])

    def test_add_and_get_notes(self):
        self.sysinfo.add_note("Your laptop is burning!")
        self.sysinfo.add_note("Oh, your house too, btw.")
        self.assertEqual(
            self.sysinfo.get_notes(),
            ["Your laptop is burning!", "Oh, your house too, btw."])
        self.assertEqual(self.sysinfo.get_headers(), [])
        self.assertEqual(self.sysinfo.get_footnotes(), [])

    def test_add_and_get_footnotes(self):
        self.sysinfo.add_footnote("Graphs available at http://graph")
        self.sysinfo.add_footnote("Go! Go!")
        self.assertEqual(self.sysinfo.get_footnotes(),
                         ["Graphs available at http://graph", "Go! Go!"])
        self.assertEqual(self.sysinfo.get_headers(), [])
        self.assertEqual(self.sysinfo.get_notes(), [])

    def test_run(self):
        class Plugin(object):
            def __init__(self, deferred):
                self._deferred = deferred

            def register(self, registry):
                pass

            def run(self):
                return self._deferred

        plugin_deferred1 = Deferred()
        plugin_deferred2 = Deferred()

        plugin1 = Plugin(plugin_deferred1)
        plugin2 = Plugin(plugin_deferred2)

        self.sysinfo.add(plugin1)
        self.sysinfo.add(plugin2)

        def check_result(result):
            self.assertEqual(result, [123, 456])

        deferred = self.sysinfo.run()
        deferred.addBoth(check_result)

        self.assertEqual(deferred.called, False)
        plugin_deferred1.callback(123)
        self.assertEqual(deferred.called, False)
        plugin_deferred2.callback(456)
        self.assertEqual(deferred.called, True)

    plugin_exception_message = (
        "There were exceptions while processing one or more plugins. "
        "See %s/sysinfo.log for more information.")

    def test_plugins_run_after_synchronous_error(self):
        """
        Even when a plugin raises a synchronous error, other plugins will
        continue to be run.
        """
        self.log_helper.ignore_errors(ZeroDivisionError)
        plugins_what_run = []

        class BadPlugin(object):
            def register(self, registry):
                pass

            def run(self):
                plugins_what_run.append(self)
                1 / 0

        class GoodPlugin(object):
            def register(self, registry):
                pass

            def run(self):
                plugins_what_run.append(self)
                return succeed(None)

        plugin1 = BadPlugin()
        plugin2 = GoodPlugin()
        self.sysinfo.add(plugin1)
        self.sysinfo.add(plugin2)
        self.sysinfo.run()
        self.assertEqual(plugins_what_run, [plugin1, plugin2])
        log = self.sysinfo_logfile.getvalue()
        message = "BadPlugin plugin raised an exception."
        self.assertIn(message, log)
        self.assertIn("1 / 0", log)
        self.assertIn("ZeroDivisionError", log)

        path = os.path.expanduser("~/.landscape")
        self.assertEqual(self.sysinfo.get_notes(),
                         [self.plugin_exception_message % path])

    def test_asynchronous_errors_logged(self):
        self.log_helper.ignore_errors(ZeroDivisionError)

        class BadPlugin(object):
            def register(self, registry):
                pass

            def run(self):
                return fail(ZeroDivisionError("yay"))

        plugin = BadPlugin()
        self.sysinfo.add(plugin)
        self.sysinfo.run()
        log = self.sysinfo_logfile.getvalue()
        message = "BadPlugin plugin raised an exception."
        self.assertIn(message, log)
        self.assertIn("ZeroDivisionError: yay", log)
        path = os.path.expanduser("~/.landscape")
        self.assertEqual(self.sysinfo.get_notes(),
                         [self.plugin_exception_message % path])

    def test_multiple_exceptions_get_one_note(self):
        self.log_helper.ignore_errors(ZeroDivisionError)

        class RegularBadPlugin(object):
            def register(self, registry):
                pass

            def run(self):
                1 / 0

        class AsyncBadPlugin(object):
            def register(self, registry):
                pass

            def run(self):
                return fail(ZeroDivisionError("Hi"))

        plugin1 = RegularBadPlugin()
        plugin2 = AsyncBadPlugin()
        self.sysinfo.add(plugin1)
        self.sysinfo.add(plugin2)
        self.sysinfo.run()

        path = os.path.expanduser("~/.landscape")
        self.assertEqual(self.sysinfo.get_notes(),
                         [self.plugin_exception_message % path])

    @mock.patch("os.getuid", return_value=0)
    def test_exception_running_as_privileged_user(self, uid_mock):
        """
        If a Plugin fails while running and the sysinfo binary is running with
        a uid of 0, Landscape sysinfo should write to the system logs
        directory.
        """
        class AsyncBadPlugin(object):
            def register(self, registry):
                pass

            def run(self):
                return fail(ZeroDivisionError("Hi"))

        self.log_helper.ignore_errors(ZeroDivisionError)

        plugin = AsyncBadPlugin()
        self.sysinfo.add(plugin)
        self.sysinfo.run()
        uid_mock.assert_called_with()

        path = "/var/log/landscape"
        self.assertEqual(self.sysinfo.get_notes(),
                         [self.plugin_exception_message % path])