94
94
log.setLevel(logging.DEBUG)
96
bus = dbus.SystemBus()
98
mandos_dbus_object = get_mandos_dbus_object(bus)
100
mandos_serv = dbus.Interface(
101
mandos_dbus_object, dbus_interface=server_dbus_interface)
97
bus = dbus.SystemBus()
98
log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
99
dbus_busname, server_dbus_path)
100
mandos_dbus_objc = bus.get_object(dbus_busname,
102
except dbus.exceptions.DBusException:
103
log.critical("Could not connect to Mandos server")
106
mandos_serv = dbus.Interface(mandos_dbus_objc,
107
dbus_interface=server_dbus_interface)
102
108
mandos_serv_object_manager = dbus.Interface(
103
mandos_dbus_object, dbus_interface=dbus.OBJECT_MANAGER_IFACE)
105
managed_objects = get_managed_objects(mandos_serv_object_manager)
108
for path, ifs_and_props in managed_objects.items():
110
all_clients[path] = ifs_and_props[client_dbus_interface]
114
# Compile dict of (clientpath: properties) to process
109
mandos_dbus_objc, dbus_interface=dbus.OBJECT_MANAGER_IFACE)
111
# Filter out log message from dbus module
112
dbus_logger = logging.getLogger("dbus.proxies")
113
class NullFilter(logging.Filter):
114
def filter(self, record):
116
dbus_filter = NullFilter()
118
dbus_logger.addFilter(dbus_filter)
119
log.debug("D-Bus: %s:%s:%s.GetManagedObjects()", dbus_busname,
120
server_dbus_path, dbus.OBJECT_MANAGER_IFACE)
121
mandos_clients = {path: ifs_and_props[client_dbus_interface]
122
for path, ifs_and_props in
123
mandos_serv_object_manager
124
.GetManagedObjects().items()
125
if client_dbus_interface in ifs_and_props}
126
except dbus.exceptions.DBusException as e:
127
log.critical("Failed to access Mandos server through D-Bus:"
131
# restore dbus logger
132
dbus_logger.removeFilter(dbus_filter)
134
# Compile dict of (clients: properties) to process
115
137
if not clientnames:
116
clients = all_clients
138
clients = {objpath: properties
139
for objpath, properties in mandos_clients.items()}
119
141
for name in clientnames:
120
for objpath, properties in all_clients.items():
142
for objpath, properties in mandos_clients.items():
121
143
if properties["Name"] == name:
122
144
clients[objpath] = properties
232
254
>>> rfc3339_duration_to_delta("")
233
255
Traceback (most recent call last):
235
ValueError: Invalid RFC 3339 duration: ""
257
ValueError: Invalid RFC 3339 duration: u''
236
258
>>> # Must start with "P":
237
259
>>> rfc3339_duration_to_delta("1D")
238
260
Traceback (most recent call last):
240
ValueError: Invalid RFC 3339 duration: "1D"
262
ValueError: Invalid RFC 3339 duration: u'1D'
241
263
>>> # Must use correct order
242
264
>>> rfc3339_duration_to_delta("PT1S2M")
243
265
Traceback (most recent call last):
245
ValueError: Invalid RFC 3339 duration: "PT1S2M"
267
ValueError: Invalid RFC 3339 duration: u'PT1S2M'
246
268
>>> # Time needs time marker
247
269
>>> rfc3339_duration_to_delta("P1H2S")
248
270
Traceback (most recent call last):
250
ValueError: Invalid RFC 3339 duration: "P1H2S"
272
ValueError: Invalid RFC 3339 duration: u'P1H2S'
251
273
>>> # Weeks can not be combined with anything else
252
274
>>> rfc3339_duration_to_delta("P1D2W")
253
275
Traceback (most recent call last):
255
ValueError: Invalid RFC 3339 duration: "P1D2W"
277
ValueError: Invalid RFC 3339 duration: u'P1D2W'
256
278
>>> rfc3339_duration_to_delta("P2W2H")
257
279
Traceback (most recent call last):
259
ValueError: Invalid RFC 3339 duration: "P2W2H"
281
ValueError: Invalid RFC 3339 duration: u'P2W2H'
262
284
# Parsing an RFC 3339 duration with regular expressions is not
424
446
options.remove = True
427
def get_mandos_dbus_object(bus):
428
log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
429
dbus_busname, server_dbus_path)
430
with if_dbus_exception_log_with_exception_and_exit(
431
"Could not connect to Mandos server: %s"):
432
mandos_dbus_object = bus.get_object(dbus_busname,
434
return mandos_dbus_object
437
@contextlib.contextmanager
438
def if_dbus_exception_log_with_exception_and_exit(*args, **kwargs):
441
except dbus.exceptions.DBusException as e:
442
log.critical(*(args + (e,)), **kwargs)
446
def get_managed_objects(object_manager):
447
log.debug("D-Bus: %s:%s:%s.GetManagedObjects()", dbus_busname,
448
server_dbus_path, dbus.OBJECT_MANAGER_IFACE)
449
with if_dbus_exception_log_with_exception_and_exit(
450
"Failed to access Mandos server through D-Bus:\n%s"):
451
with SilenceLogger("dbus.proxies"):
452
managed_objects = object_manager.GetManagedObjects()
453
return managed_objects
456
class SilenceLogger(object):
457
"Simple context manager to silence a particular logger"
458
def __init__(self, loggername):
459
self.logger = logging.getLogger(loggername)
462
self.logger.addFilter(self.nullfilter)
465
class NullFilter(logging.Filter):
466
def filter(self, record):
469
nullfilter = NullFilter()
471
def __exit__(self, exc_type, exc_val, exc_tb):
472
self.logger.removeFilter(self.nullfilter)
475
449
def commands_from_options(options):
594
568
self.mandos.RemoveClient(client.__dbus_object_path__)
597
class OutputCmd(Command):
598
"""Abstract class for commands outputting client details"""
571
class PrintCmd(Command):
572
"""Abstract class for commands printing client details"""
599
573
all_keywords = ("Name", "Enabled", "Timeout", "LastCheckedOK",
600
574
"Created", "Interval", "Host", "KeyID",
601
575
"Fingerprint", "CheckerRunning", "LastEnabled",
603
577
"LastApprovalRequest", "ApprovalDelay",
604
578
"ApprovalDuration", "Checker", "ExtendedTimeout",
605
579
"Expires", "LastCheckerStatus")
607
580
def run(self, clients, bus=None, mandos=None):
608
581
print(self.output(clients.values()))
610
582
def output(self, clients):
611
583
raise NotImplementedError()
614
class DumpJSONCmd(OutputCmd):
586
class DumpJSONCmd(PrintCmd):
615
587
def output(self, clients):
616
588
data = {client["Name"]:
617
589
{key: self.dbus_boolean_to_bool(client[key])
618
590
for key in self.all_keywords}
619
for client in clients}
591
for client in clients.values()}
620
592
return json.dumps(data, indent=4, separators=(',', ': '))
623
594
def dbus_boolean_to_bool(value):
624
595
if isinstance(value, dbus.Boolean):
842
class TestCaseWithAssertLogs(unittest.TestCase):
843
"""unittest.TestCase.assertLogs only exists in Python 3.4"""
845
if not hasattr(unittest.TestCase, "assertLogs"):
846
@contextlib.contextmanager
847
def assertLogs(self, logger, level=logging.INFO):
848
capturing_handler = self.CapturingLevelHandler(level)
849
old_level = logger.level
850
old_propagate = logger.propagate
851
logger.addHandler(capturing_handler)
852
logger.setLevel(level)
853
logger.propagate = False
855
yield capturing_handler.watcher
857
logger.propagate = old_propagate
858
logger.removeHandler(capturing_handler)
859
logger.setLevel(old_level)
860
self.assertGreater(len(capturing_handler.watcher.records),
863
class CapturingLevelHandler(logging.Handler):
864
def __init__(self, level, *args, **kwargs):
865
logging.Handler.__init__(self, *args, **kwargs)
866
self.watcher = self.LoggingWatcher([], [])
867
def emit(self, record):
868
self.watcher.records.append(record)
869
self.watcher.output.append(self.format(record))
871
LoggingWatcher = collections.namedtuple("LoggingWatcher",
876
class Test_string_to_delta(TestCaseWithAssertLogs):
809
class Test_string_to_delta(unittest.TestCase):
877
810
def test_handles_basic_rfc3339(self):
878
811
self.assertEqual(string_to_delta("PT0S"),
879
812
datetime.timedelta())
883
816
datetime.timedelta(0, 1))
884
817
self.assertEqual(string_to_delta("PT2H"),
885
818
datetime.timedelta(0, 7200))
887
819
def test_falls_back_to_pre_1_6_1_with_warning(self):
888
with self.assertLogs(log, logging.WARNING):
889
value = string_to_delta("2h")
820
# assertLogs only exists in Python 3.4
821
if hasattr(self, "assertLogs"):
822
with self.assertLogs(log, logging.WARNING):
823
value = string_to_delta("2h")
825
class WarningFilter(logging.Filter):
826
"""Don't show, but record the presence of, warnings"""
827
def filter(self, record):
828
is_warning = record.levelno >= logging.WARNING
829
self.found = is_warning or getattr(self, "found",
831
return not is_warning
832
warning_filter = WarningFilter()
833
log.addFilter(warning_filter)
835
value = string_to_delta("2h")
837
log.removeFilter(warning_filter)
838
self.assertTrue(getattr(warning_filter, "found", False))
890
839
self.assertEqual(value, datetime.timedelta(0, 7200))
893
842
class Test_check_option_syntax(unittest.TestCase):
895
self.parser = argparse.ArgumentParser()
896
add_command_line_options(self.parser)
898
def test_actions_requires_client_or_all(self):
899
for action, value in self.actions.items():
900
options = self.parser.parse_args()
901
setattr(options, action, value)
902
with self.assertParseError():
903
self.check_option_syntax(options)
905
843
# This mostly corresponds to the definition from has_actions() in
906
844
# check_option_syntax()
955
897
def check_option_syntax(self, options):
956
898
check_option_syntax(self.parser, options)
958
def test_actions_all_conflicts_with_verbose(self):
900
def test_actions_requires_client_or_all(self):
959
901
for action, value in self.actions.items():
960
902
options = self.parser.parse_args()
961
903
setattr(options, action, value)
963
options.verbose = True
964
904
with self.assertParseError():
965
905
self.check_option_syntax(options)
967
def test_actions_with_client_conflicts_with_verbose(self):
907
def test_actions_conflicts_with_verbose(self):
968
908
for action, value in self.actions.items():
969
909
options = self.parser.parse_args()
970
910
setattr(options, action, value)
971
911
options.verbose = True
972
options.client = ["foo"]
973
912
with self.assertParseError():
974
913
self.check_option_syntax(options)
1001
940
options.all = True
1002
941
self.check_option_syntax(options)
1004
def test_any_action_is_ok_with_one_client(self):
1005
for action, value in self.actions.items():
1006
options = self.parser.parse_args()
1007
setattr(options, action, value)
1008
options.client = ["foo"]
943
def test_is_enabled_fails_without_client(self):
944
options = self.parser.parse_args()
945
options.is_enabled = True
946
with self.assertParseError():
1009
947
self.check_option_syntax(options)
1011
def test_one_client_with_all_actions_except_is_enabled(self):
949
def test_is_enabled_works_with_one_client(self):
1012
950
options = self.parser.parse_args()
1013
for action, value in self.actions.items():
1014
if action == "is_enabled":
1016
setattr(options, action, value)
951
options.is_enabled = True
1017
952
options.client = ["foo"]
1018
953
self.check_option_syntax(options)
1020
def test_two_clients_with_all_actions_except_is_enabled(self):
1021
options = self.parser.parse_args()
1022
for action, value in self.actions.items():
1023
if action == "is_enabled":
1025
setattr(options, action, value)
1026
options.client = ["foo", "barbar"]
1027
self.check_option_syntax(options)
1029
def test_two_clients_are_ok_with_actions_except_is_enabled(self):
1030
for action, value in self.actions.items():
1031
if action == "is_enabled":
1033
options = self.parser.parse_args()
1034
setattr(options, action, value)
1035
options.client = ["foo", "barbar"]
1036
self.check_option_syntax(options)
1038
def test_is_enabled_fails_without_client(self):
1039
options = self.parser.parse_args()
1040
options.is_enabled = True
1041
with self.assertParseError():
1042
self.check_option_syntax(options)
1044
955
def test_is_enabled_fails_with_two_clients(self):
1045
956
options = self.parser.parse_args()
1046
957
options.is_enabled = True
1060
971
self.check_option_syntax(options)
1063
class Test_get_mandos_dbus_object(TestCaseWithAssertLogs):
1064
def test_calls_and_returns_get_object_on_bus(self):
1065
class MockBus(object):
1067
def get_object(mockbus_self, busname, dbus_path):
1068
# Note that "self" is still the testcase instance,
1069
# this MockBus instance is in "mockbus_self".
1070
self.assertEqual(busname, dbus_busname)
1071
self.assertEqual(dbus_path, server_dbus_path)
1072
mockbus_self.called = True
1075
mockbus = get_mandos_dbus_object(bus=MockBus())
1076
self.assertIsInstance(mockbus, MockBus)
1077
self.assertTrue(mockbus.called)
1079
def test_logs_and_exits_on_dbus_error(self):
1080
class MockBusFailing(object):
1081
def get_object(self, busname, dbus_path):
1082
raise dbus.exceptions.DBusException("Test")
1084
with self.assertLogs(log, logging.CRITICAL):
1085
with self.assertRaises(SystemExit) as e:
1086
bus = get_mandos_dbus_object(bus=MockBusFailing())
1088
if isinstance(e.exception.code, int):
1089
self.assertNotEqual(e.exception.code, 0)
1091
self.assertIsNotNone(e.exception.code)
1094
class Test_get_managed_objects(TestCaseWithAssertLogs):
1095
def test_calls_and_returns_GetManagedObjects(self):
1096
managed_objects = {"/clients/foo": { "Name": "foo"}}
1097
class MockObjectManager(object):
1098
def GetManagedObjects(self):
1099
return managed_objects
1100
retval = get_managed_objects(MockObjectManager())
1101
self.assertDictEqual(managed_objects, retval)
1103
def test_logs_and_exits_on_dbus_error(self):
1104
dbus_logger = logging.getLogger("dbus.proxies")
1106
class MockObjectManagerFailing(object):
1107
def GetManagedObjects(self):
1108
dbus_logger.error("Test")
1109
raise dbus.exceptions.DBusException("Test")
1111
class CountingHandler(logging.Handler):
1113
def emit(self, record):
1116
counting_handler = CountingHandler()
1118
dbus_logger.addHandler(counting_handler)
1121
with self.assertLogs(log, logging.CRITICAL) as watcher:
1122
with self.assertRaises(SystemExit) as e:
1123
get_managed_objects(MockObjectManagerFailing())
1125
dbus_logger.removeFilter(counting_handler)
1127
# Make sure the dbus logger was suppressed
1128
self.assertEqual(counting_handler.count, 0)
1130
# Test that the dbus_logger still works
1131
with self.assertLogs(dbus_logger, logging.ERROR):
1132
dbus_logger.error("Test")
1134
if isinstance(e.exception.code, int):
1135
self.assertNotEqual(e.exception.code, 0)
1137
self.assertIsNotNone(e.exception.code)
1140
class Test_commands_from_options(unittest.TestCase):
974
class Test_command_from_options(unittest.TestCase):
1141
975
def setUp(self):
1142
976
self.parser = argparse.ArgumentParser()
1143
977
add_command_line_options(self.parser)
1145
def test_is_enabled(self):
1146
self.assert_command_from_args(["--is-enabled", "foo"],
1149
978
def assert_command_from_args(self, args, command_cls,
1151
980
"""Assert that parsing ARGS should result in an instance of
1158
987
self.assertIsInstance(command, command_cls)
1159
988
for key, value in cmd_attrs.items():
1160
989
self.assertEqual(getattr(command, key), value)
1162
def test_is_enabled_short(self):
1163
self.assert_command_from_args(["-V", "foo"], IsEnabledCmd)
1165
def test_approve(self):
1166
self.assert_command_from_args(["--approve", "foo"],
1169
def test_approve_short(self):
1170
self.assert_command_from_args(["-A", "foo"], ApproveCmd)
1172
def test_deny(self):
1173
self.assert_command_from_args(["--deny", "foo"], DenyCmd)
1175
def test_deny_short(self):
1176
self.assert_command_from_args(["-D", "foo"], DenyCmd)
1178
def test_remove(self):
1179
self.assert_command_from_args(["--remove", "foo"],
1182
def test_deny_before_remove(self):
1183
options = self.parser.parse_args(["--deny", "--remove",
1185
check_option_syntax(self.parser, options)
1186
commands = commands_from_options(options)
1187
self.assertEqual(len(commands), 2)
1188
self.assertIsInstance(commands[0], DenyCmd)
1189
self.assertIsInstance(commands[1], RemoveCmd)
1191
def test_deny_before_remove_reversed(self):
1192
options = self.parser.parse_args(["--remove", "--deny",
1194
check_option_syntax(self.parser, options)
1195
commands = commands_from_options(options)
1196
self.assertEqual(len(commands), 2)
1197
self.assertIsInstance(commands[0], DenyCmd)
1198
self.assertIsInstance(commands[1], RemoveCmd)
1200
def test_remove_short(self):
1201
self.assert_command_from_args(["-r", "foo"], RemoveCmd)
1203
def test_dump_json(self):
1204
self.assert_command_from_args(["--dump-json"], DumpJSONCmd)
990
def test_print_table(self):
991
self.assert_command_from_args([], PrintTableCmd,
994
def test_print_table_verbose(self):
995
self.assert_command_from_args(["--verbose"], PrintTableCmd,
998
def test_print_table_verbose_short(self):
999
self.assert_command_from_args(["-v"], PrintTableCmd,
1206
1002
def test_enable(self):
1207
1003
self.assert_command_from_args(["--enable", "foo"], EnableCmd)
1231
1027
self.assert_command_from_args(["--stop-checker", "foo"],
1232
1028
StopCheckerCmd)
1234
def test_approve_by_default(self):
1235
self.assert_command_from_args(["--approve-by-default", "foo"],
1236
ApproveByDefaultCmd)
1030
def test_remove(self):
1031
self.assert_command_from_args(["--remove", "foo"],
1238
def test_deny_by_default(self):
1239
self.assert_command_from_args(["--deny-by-default", "foo"],
1034
def test_remove_short(self):
1035
self.assert_command_from_args(["-r", "foo"], RemoveCmd)
1242
1037
def test_checker(self):
1243
1038
self.assert_command_from_args(["--checker", ":", "foo"],
1251
1046
self.assert_command_from_args(["-c", ":", "foo"],
1252
1047
SetCheckerCmd, value_to_set=":")
1254
def test_host(self):
1255
self.assert_command_from_args(["--host", "foo.example.org",
1257
value_to_set="foo.example.org")
1259
def test_host_short(self):
1260
self.assert_command_from_args(["-H", "foo.example.org",
1262
value_to_set="foo.example.org")
1264
def test_secret_devnull(self):
1265
self.assert_command_from_args(["--secret", os.path.devnull,
1266
"foo"], SetSecretCmd,
1269
def test_secret_tempfile(self):
1270
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1271
value = b"secret\0xyzzy\nbar"
1274
self.assert_command_from_args(["--secret", f.name,
1275
"foo"], SetSecretCmd,
1278
def test_secret_devnull_short(self):
1279
self.assert_command_from_args(["-s", os.path.devnull, "foo"],
1280
SetSecretCmd, value_to_set=b"")
1282
def test_secret_tempfile_short(self):
1283
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1284
value = b"secret\0xyzzy\nbar"
1287
self.assert_command_from_args(["-s", f.name, "foo"],
1291
1049
def test_timeout(self):
1292
1050
self.assert_command_from_args(["--timeout", "PT5M", "foo"],
1324
1090
"foo"], SetApprovalDurationCmd,
1325
1091
value_to_set=1000)
1327
def test_print_table(self):
1328
self.assert_command_from_args([], PrintTableCmd,
1331
def test_print_table_verbose(self):
1332
self.assert_command_from_args(["--verbose"], PrintTableCmd,
1335
def test_print_table_verbose_short(self):
1336
self.assert_command_from_args(["-v"], PrintTableCmd,
1093
def test_host(self):
1094
self.assert_command_from_args(["--host", "foo.example.org",
1096
value_to_set="foo.example.org")
1098
def test_host_short(self):
1099
self.assert_command_from_args(["-H", "foo.example.org",
1101
value_to_set="foo.example.org")
1103
def test_secret_devnull(self):
1104
self.assert_command_from_args(["--secret", os.path.devnull,
1105
"foo"], SetSecretCmd,
1108
def test_secret_tempfile(self):
1109
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1110
value = b"secret\0xyzzy\nbar"
1113
self.assert_command_from_args(["--secret", f.name,
1114
"foo"], SetSecretCmd,
1117
def test_secret_devnull_short(self):
1118
self.assert_command_from_args(["-s", os.path.devnull, "foo"],
1119
SetSecretCmd, value_to_set=b"")
1121
def test_secret_tempfile_short(self):
1122
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1123
value = b"secret\0xyzzy\nbar"
1126
self.assert_command_from_args(["-s", f.name, "foo"],
1130
def test_approve(self):
1131
self.assert_command_from_args(["--approve", "foo"],
1134
def test_approve_short(self):
1135
self.assert_command_from_args(["-A", "foo"], ApproveCmd)
1137
def test_deny(self):
1138
self.assert_command_from_args(["--deny", "foo"], DenyCmd)
1140
def test_deny_short(self):
1141
self.assert_command_from_args(["-D", "foo"], DenyCmd)
1143
def test_dump_json(self):
1144
self.assert_command_from_args(["--dump-json"], DumpJSONCmd)
1146
def test_is_enabled(self):
1147
self.assert_command_from_args(["--is-enabled", "foo"],
1150
def test_is_enabled_short(self):
1151
self.assert_command_from_args(["-V", "foo"], IsEnabledCmd)
1153
def test_deny_before_remove(self):
1154
options = self.parser.parse_args(["--deny", "--remove",
1156
check_option_syntax(self.parser, options)
1157
commands = commands_from_options(options)
1158
self.assertEqual(len(commands), 2)
1159
self.assertIsInstance(commands[0], DenyCmd)
1160
self.assertIsInstance(commands[1], RemoveCmd)
1162
def test_deny_before_remove_reversed(self):
1163
options = self.parser.parse_args(["--remove", "--deny",
1165
check_option_syntax(self.parser, options)
1166
commands = commands_from_options(options)
1167
self.assertEqual(len(commands), 2)
1168
self.assertIsInstance(commands[0], DenyCmd)
1169
self.assertIsInstance(commands[1], RemoveCmd)
1340
1172
class TestCmd(unittest.TestCase):
1341
1173
"""Abstract class for tests of command classes"""
1343
1174
def setUp(self):
1344
1175
testcase = self
1345
1176
class MockClient(object):
1547
1372
return super(TestDumpJSONCmd, self).setUp()
1549
1373
def test_normal(self):
1550
output = DumpJSONCmd().output(self.clients.values())
1551
json_data = json.loads(output)
1374
json_data = json.loads(DumpJSONCmd().output(self.clients))
1552
1375
self.assertDictEqual(json_data, self.expected_json)
1554
1376
def test_one_client(self):
1555
output = DumpJSONCmd().output(self.one_client.values())
1556
json_data = json.loads(output)
1377
clients = self.one_client
1378
json_data = json.loads(DumpJSONCmd().output(clients))
1557
1379
expected_json = {"foo": self.expected_json["foo"]}
1558
1380
self.assertDictEqual(json_data, expected_json)
1662
1483
for rows in columns)
1663
1484
for line in range(num_lines))
1664
1485
self.assertEqual(output, expected_output)
1666
1486
def test_one_client(self):
1667
1487
output = PrintTableCmd().output(self.one_client.values())
1668
expected_output = "\n".join((
1669
"Name Enabled Timeout Last Successful Check",
1670
"foo Yes 00:05:00 2019-02-03T00:00:00 ",
1488
expected_output = """
1489
Name Enabled Timeout Last Successful Check
1490
foo Yes 00:05:00 2019-02-03T00:00:00
1672
1492
self.assertEqual(output, expected_output)
1495
class Unique(object):
1496
"""Class for objects which exist only to be unique objects, since
1497
unittest.mock.sentinel only exists in Python 3.3"""
1675
1500
class TestPropertyCmd(TestCmd):
1676
1501
"""Abstract class for tests of PropertyCmd classes"""
1677
1502
def runTest(self):
1684
1509
for clientpath in self.clients:
1685
1510
client = self.bus.get_object(dbus_busname, clientpath)
1686
1511
old_value = client.attributes[self.propname]
1687
self.assertNotIsInstance(old_value, self.Unique)
1688
client.attributes[self.propname] = self.Unique()
1512
self.assertNotIsInstance(old_value, Unique)
1513
client.attributes[self.propname] = Unique()
1689
1514
self.run_command(value_to_set, self.clients)
1690
1515
for clientpath in self.clients:
1691
1516
client = self.bus.get_object(dbus_busname, clientpath)
1692
1517
value = client.attributes[self.propname]
1693
self.assertNotIsInstance(value, self.Unique)
1518
self.assertNotIsInstance(value, Unique)
1694
1519
self.assertEqual(value, value_to_get)
1696
class Unique(object):
1697
"""Class for objects which exist only to be unique objects,
1698
since unittest.mock.sentinel only exists in Python 3.3"""
1700
1520
def run_command(self, value, clients):
1701
1521
self.command().run(clients, self.bus)
1704
class TestEnableCmd(TestPropertyCmd):
1706
propname = "Enabled"
1707
values_to_set = [dbus.Boolean(True)]
1710
class TestDisableCmd(TestPropertyCmd):
1711
command = DisableCmd
1712
propname = "Enabled"
1713
values_to_set = [dbus.Boolean(False)]
1524
class TestEnableCmd(TestCmd):
1525
def test_enable(self):
1526
for clientpath in self.clients:
1527
client = self.bus.get_object(dbus_busname, clientpath)
1528
client.attributes["Enabled"] = False
1530
EnableCmd().run(self.clients, self.bus)
1532
for clientpath in self.clients:
1533
client = self.bus.get_object(dbus_busname, clientpath)
1534
self.assertTrue(client.attributes["Enabled"])
1537
class TestDisableCmd(TestCmd):
1538
def test_disable(self):
1539
DisableCmd().run(self.clients, self.bus)
1540
for clientpath in self.clients:
1541
client = self.bus.get_object(dbus_busname, clientpath)
1542
self.assertFalse(client.attributes["Enabled"])
1716
1545
class TestBumpTimeoutCmd(TestPropertyCmd):