1#!/usr/bin/python3
2
3# This program is free software; you can redistribute it and/or modify it under
4# the terms of the GNU Lesser General Public License as published by the Free
5# Software Foundation; either version 3 of the License, or (at your option) any
6# later version.  See http://www.gnu.org/copyleft/lgpl.html for the full text
7# of the license.
8
9__author__ = 'Martin Pitt'
10__copyright__ = '(c) 2013 Canonical Ltd.'
11
12import os
13import re
14import shutil
15import subprocess
16import sys
17import unittest
18import tracemalloc
19
20import dbusmock
21
22tracemalloc.start(25)
23have_loginctl = shutil.which('loginctl')
24
25
26@unittest.skipUnless(have_loginctl, 'loginctl not installed')
27@unittest.skipUnless(os.path.exists('/run/systemd/system'), '/run/systemd/system does not exist')
28class TestLogind(dbusmock.DBusTestCase):
29    '''Test mocking logind'''
30
31    @classmethod
32    def setUpClass(cls):
33        cls.start_system_bus()
34        cls.dbus_con = cls.get_dbus(True)
35
36        if have_loginctl:
37            out = subprocess.check_output(['loginctl', '--version'],
38                                          universal_newlines=True)
39            cls.version = re.search(r'(\d+)', out.splitlines()[0]).group(1)
40
41    def setUp(self):
42        self.p_mock = None
43
44    def tearDown(self):
45        if self.p_mock:
46            self.p_mock.stdout.close()
47            self.p_mock.terminate()
48            self.p_mock.wait()
49
50    def test_empty(self):
51        (self.p_mock, _) = self.spawn_server_template('logind', {}, stdout=subprocess.PIPE)
52        cmd = ['loginctl']
53        if self.version >= '209':
54            cmd.append('--no-legend')
55        out = subprocess.check_output(cmd + ['list-sessions'],
56                                      universal_newlines=True)
57        self.assertEqual(out, '')
58
59        out = subprocess.check_output(cmd + ['list-seats'],
60                                      universal_newlines=True)
61        self.assertEqual(out, '')
62
63        out = subprocess.check_output(cmd + ['list-users'],
64                                      universal_newlines=True)
65        self.assertEqual(out, '')
66
67    def test_session(self):
68        (self.p_mock, obj_logind) = self.spawn_server_template('logind', {}, stdout=subprocess.PIPE)
69
70        obj_logind.AddSession('c1', 'seat0', 500, 'joe', True)
71
72        out = subprocess.check_output(['loginctl', 'list-seats'],
73                                      universal_newlines=True)
74        self.assertRegex(out, r'(^|\n)seat0\s+')
75
76        out = subprocess.check_output(['loginctl', 'show-seat', 'seat0'],
77                                      universal_newlines=True)
78        self.assertRegex(out, 'Id=seat0')
79        if self.version <= '208':
80            self.assertRegex(out, 'ActiveSession=c1')
81            self.assertRegex(out, 'Sessions=c1')
82
83        out = subprocess.check_output(['loginctl', 'list-users'],
84                                      universal_newlines=True)
85        self.assertRegex(out, r'(^|\n)\s*500\s+joe\s*($|\n)')
86
87        # note, this does an actual getpwnam() in the client, so we cannot call
88        # this with hardcoded user names; get from actual user in the system
89        # out = subprocess.check_output(['loginctl', 'show-user', 'joe'],
90        #                               universal_newlines=True)
91        # self.assertRegex(out, 'UID=500')
92        # self.assertRegex(out, 'GID=500')
93        # self.assertRegex(out, 'Name=joe')
94        # self.assertRegex(out, 'Sessions=c1')
95        # self.assertRegex(out, 'State=active')
96
97        out = subprocess.check_output(['loginctl', 'list-sessions'],
98                                      universal_newlines=True)
99        self.assertRegex(out, 'c1 +500 +joe +seat0')
100
101        out = subprocess.check_output(['loginctl', 'show-session', 'c1'],
102                                      universal_newlines=True)
103        self.assertRegex(out, 'Id=c1')
104        self.assertRegex(out, 'Class=user')
105        self.assertRegex(out, 'Active=yes')
106        self.assertRegex(out, 'State=active')
107        self.assertRegex(out, 'Name=joe')
108
109    def test_properties(self):
110        (self.p_mock, obj_logind) = self.spawn_server_template('logind', {}, stdout=subprocess.PIPE)
111        props = obj_logind.GetAll('org.freedesktop.login1.Manager',
112                                  interface='org.freedesktop.DBus.Properties')
113        self.assertEqual(props['PreparingForSleep'], False)
114        self.assertEqual(props['IdleSinceHint'], 0)
115
116    def test_inhibit(self):
117        (self.p_mock, obj_logind) = self.spawn_server_template('logind', {}, stdout=subprocess.PIPE)
118
119        # what, who, why, mode
120        fd = obj_logind.Inhibit('suspend', 'testcode', 'purpose', 'delay')
121
122        # Our inhibitor is held
123        out = subprocess.check_output(['systemd-inhibit'],
124                                      universal_newlines=True)
125        self.assertRegex(out, 'testcode +[0-9]+ +[^ ]* +[0-9]+ +[^ ]* +suspend purpose delay')
126
127        del fd
128        # No inhibitor is held
129        out = subprocess.check_output(['systemd-inhibit'],
130                                      universal_newlines=True)
131        self.assertRegex(out, 'No inhibitors')
132
133
134if __name__ == '__main__':
135    # avoid writing to stderr
136    unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout))
137