1032
1180
self.values_to_set)
1033
1181
for value_to_set, value_to_get in zip(self.values_to_set,
1034
1182
values_to_get):
1035
for client in self.clients:
1036
old_value = client.attributes[self.property]
1183
for clientpath in self.clients:
1184
client = self.bus.get_object(dbus_busname, clientpath)
1185
old_value = client.attributes[self.propname]
1037
1186
self.assertNotIsInstance(old_value, Unique)
1038
client.attributes[self.property] = Unique()
1187
client.attributes[self.propname] = Unique()
1039
1188
self.run_command(value_to_set, self.clients)
1040
for client in self.clients:
1041
value = client.attributes[self.property]
1189
for clientpath in self.clients:
1190
client = self.bus.get_object(dbus_busname, clientpath)
1191
value = client.attributes[self.propname]
1042
1192
self.assertNotIsInstance(value, Unique)
1043
1193
self.assertEqual(value, value_to_get)
1044
1194
def run_command(self, value, clients):
1045
self.command().run(None, clients)
1195
self.command().run(clients, self.bus)
1047
1197
class TestBumpTimeoutCmd(TestPropertyCmd):
1048
1198
command = BumpTimeoutCmd
1049
property = "LastCheckedOK"
1199
propname = "LastCheckedOK"
1050
1200
values_to_set = [""]
1052
1202
class TestStartCheckerCmd(TestPropertyCmd):
1053
1203
command = StartCheckerCmd
1054
property = "CheckerRunning"
1204
propname = "CheckerRunning"
1055
1205
values_to_set = [dbus.Boolean(True)]
1057
1207
class TestStopCheckerCmd(TestPropertyCmd):
1058
1208
command = StopCheckerCmd
1059
property = "CheckerRunning"
1209
propname = "CheckerRunning"
1060
1210
values_to_set = [dbus.Boolean(False)]
1062
1212
class TestApproveByDefaultCmd(TestPropertyCmd):
1063
1213
command = ApproveByDefaultCmd
1064
property = "ApprovedByDefault"
1214
propname = "ApprovedByDefault"
1065
1215
values_to_set = [dbus.Boolean(True)]
1067
1217
class TestDenyByDefaultCmd(TestPropertyCmd):
1068
1218
command = DenyByDefaultCmd
1069
property = "ApprovedByDefault"
1219
propname = "ApprovedByDefault"
1070
1220
values_to_set = [dbus.Boolean(False)]
1072
class TestValueArgumentPropertyCmd(TestPropertyCmd):
1073
"""Abstract class for tests of PropertyCmd classes using the
1074
ValueArgumentMixIn"""
1222
class TestPropertyValueCmd(TestPropertyCmd):
1223
"""Abstract class for tests of PropertyValueCmd classes"""
1075
1224
def runTest(self):
1076
if type(self) is TestValueArgumentPropertyCmd:
1225
if type(self) is TestPropertyValueCmd:
1078
return super(TestValueArgumentPropertyCmd, self).runTest()
1227
return super(TestPropertyValueCmd, self).runTest()
1079
1228
def run_command(self, value, clients):
1080
self.command(value).run(None, clients)
1229
self.command(value).run(clients, self.bus)
1082
class TestSetCheckerCmd(TestValueArgumentPropertyCmd):
1231
class TestSetCheckerCmd(TestPropertyValueCmd):
1083
1232
command = SetCheckerCmd
1084
property = "Checker"
1233
propname = "Checker"
1085
1234
values_to_set = ["", ":", "fping -q -- %s"]
1087
class TestSetHostCmd(TestValueArgumentPropertyCmd):
1236
class TestSetHostCmd(TestPropertyValueCmd):
1088
1237
command = SetHostCmd
1090
1239
values_to_set = ["192.0.2.3", "foo.example.org"]
1092
class TestSetSecretCmd(TestValueArgumentPropertyCmd):
1241
class TestSetSecretCmd(TestPropertyValueCmd):
1093
1242
command = SetSecretCmd
1095
values_to_set = [open("/dev/null", "rb"),
1244
values_to_set = [io.BytesIO(b""),
1096
1245
io.BytesIO(b"secret\0xyzzy\nbar")]
1097
1246
values_to_get = [b"", b"secret\0xyzzy\nbar"]
1099
class TestSetTimeoutCmd(TestValueArgumentPropertyCmd):
1248
class TestSetTimeoutCmd(TestPropertyValueCmd):
1100
1249
command = SetTimeoutCmd
1101
property = "Timeout"
1102
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1103
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1250
propname = "Timeout"
1251
values_to_set = [datetime.timedelta(),
1252
datetime.timedelta(minutes=5),
1253
datetime.timedelta(seconds=1),
1254
datetime.timedelta(weeks=1),
1255
datetime.timedelta(weeks=52)]
1256
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1105
class TestSetExtendedTimeoutCmd(TestValueArgumentPropertyCmd):
1258
class TestSetExtendedTimeoutCmd(TestPropertyValueCmd):
1106
1259
command = SetExtendedTimeoutCmd
1107
property = "ExtendedTimeout"
1108
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1109
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1260
propname = "ExtendedTimeout"
1261
values_to_set = [datetime.timedelta(),
1262
datetime.timedelta(minutes=5),
1263
datetime.timedelta(seconds=1),
1264
datetime.timedelta(weeks=1),
1265
datetime.timedelta(weeks=52)]
1266
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1111
class TestSetIntervalCmd(TestValueArgumentPropertyCmd):
1268
class TestSetIntervalCmd(TestPropertyValueCmd):
1112
1269
command = SetIntervalCmd
1113
property = "Interval"
1114
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1115
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1270
propname = "Interval"
1271
values_to_set = [datetime.timedelta(),
1272
datetime.timedelta(minutes=5),
1273
datetime.timedelta(seconds=1),
1274
datetime.timedelta(weeks=1),
1275
datetime.timedelta(weeks=52)]
1276
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1117
class TestSetApprovalDelayCmd(TestValueArgumentPropertyCmd):
1278
class TestSetApprovalDelayCmd(TestPropertyValueCmd):
1118
1279
command = SetApprovalDelayCmd
1119
property = "ApprovalDelay"
1120
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1121
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1280
propname = "ApprovalDelay"
1281
values_to_set = [datetime.timedelta(),
1282
datetime.timedelta(minutes=5),
1283
datetime.timedelta(seconds=1),
1284
datetime.timedelta(weeks=1),
1285
datetime.timedelta(weeks=52)]
1286
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1123
class TestSetApprovalDurationCmd(TestValueArgumentPropertyCmd):
1288
class TestSetApprovalDurationCmd(TestPropertyValueCmd):
1124
1289
command = SetApprovalDurationCmd
1125
property = "ApprovalDuration"
1126
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1127
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1290
propname = "ApprovalDuration"
1291
values_to_set = [datetime.timedelta(),
1292
datetime.timedelta(minutes=5),
1293
datetime.timedelta(seconds=1),
1294
datetime.timedelta(weeks=1),
1295
datetime.timedelta(weeks=52)]
1296
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1129
class TestOptions(unittest.TestCase):
1298
class Test_command_from_options(unittest.TestCase):
1130
1299
def setUp(self):
1131
1300
self.parser = argparse.ArgumentParser()
1132
1301
add_command_line_options(self.parser)
1133
def assert_command_from_args(self, args, command_cls, **cmd_attrs):
1302
def assert_command_from_args(self, args, command_cls,
1134
1304
"""Assert that parsing ARGS should result in an instance of
1135
1305
COMMAND_CLS with (optionally) all supplied attributes (CMD_ATTRS)."""
1136
1306
options = self.parser.parse_args(args)
1307
check_option_syntax(self.parser, options)
1137
1308
commands = commands_from_options(options)
1138
1309
self.assertEqual(len(commands), 1)
1139
1310
command = commands[0]
1140
1311
self.assertIsInstance(command, command_cls)
1141
1312
for key, value in cmd_attrs.items():
1142
1313
self.assertEqual(getattr(command, key), value)
1143
def test_default_is_show_table(self):
1314
def test_print_table(self):
1144
1315
self.assert_command_from_args([], PrintTableCmd,
1146
def test_show_table_verbose(self):
1318
def test_print_table_verbose(self):
1147
1319
self.assert_command_from_args(["--verbose"], PrintTableCmd,
1322
def test_print_table_verbose_short(self):
1323
self.assert_command_from_args(["-v"], PrintTableCmd,
1149
1326
def test_enable(self):
1150
1327
self.assert_command_from_args(["--enable", "foo"], EnableCmd)
1329
def test_enable_short(self):
1330
self.assert_command_from_args(["-e", "foo"], EnableCmd)
1151
1332
def test_disable(self):
1152
1333
self.assert_command_from_args(["--disable", "foo"],
1336
def test_disable_short(self):
1337
self.assert_command_from_args(["-d", "foo"], DisableCmd)
1339
def test_bump_timeout(self):
1340
self.assert_command_from_args(["--bump-timeout", "foo"],
1343
def test_bump_timeout_short(self):
1344
self.assert_command_from_args(["-b", "foo"], BumpTimeoutCmd)
1346
def test_start_checker(self):
1347
self.assert_command_from_args(["--start-checker", "foo"],
1350
def test_stop_checker(self):
1351
self.assert_command_from_args(["--stop-checker", "foo"],
1354
def test_remove(self):
1355
self.assert_command_from_args(["--remove", "foo"],
1358
def test_remove_short(self):
1359
self.assert_command_from_args(["-r", "foo"], RemoveCmd)
1361
def test_checker(self):
1362
self.assert_command_from_args(["--checker", ":", "foo"],
1363
SetCheckerCmd, value_to_set=":")
1365
def test_checker_empty(self):
1366
self.assert_command_from_args(["--checker", "", "foo"],
1367
SetCheckerCmd, value_to_set="")
1369
def test_checker_short(self):
1370
self.assert_command_from_args(["-c", ":", "foo"],
1371
SetCheckerCmd, value_to_set=":")
1373
def test_timeout(self):
1374
self.assert_command_from_args(["--timeout", "PT5M", "foo"],
1376
value_to_set=300000)
1378
def test_timeout_short(self):
1379
self.assert_command_from_args(["-t", "PT5M", "foo"],
1381
value_to_set=300000)
1383
def test_extended_timeout(self):
1384
self.assert_command_from_args(["--extended-timeout", "PT15M",
1386
SetExtendedTimeoutCmd,
1387
value_to_set=900000)
1389
def test_interval(self):
1390
self.assert_command_from_args(["--interval", "PT2M", "foo"],
1392
value_to_set=120000)
1394
def test_interval_short(self):
1395
self.assert_command_from_args(["-i", "PT2M", "foo"],
1397
value_to_set=120000)
1399
def test_approve_by_default(self):
1400
self.assert_command_from_args(["--approve-by-default", "foo"],
1401
ApproveByDefaultCmd)
1403
def test_deny_by_default(self):
1404
self.assert_command_from_args(["--deny-by-default", "foo"],
1407
def test_approval_delay(self):
1408
self.assert_command_from_args(["--approval-delay", "PT30S",
1409
"foo"], SetApprovalDelayCmd,
1412
def test_approval_duration(self):
1413
self.assert_command_from_args(["--approval-duration", "PT1S",
1414
"foo"], SetApprovalDurationCmd,
1417
def test_host(self):
1418
self.assert_command_from_args(["--host", "foo.example.org",
1420
value_to_set="foo.example.org")
1422
def test_host_short(self):
1423
self.assert_command_from_args(["-H", "foo.example.org",
1425
value_to_set="foo.example.org")
1427
def test_secret_devnull(self):
1428
self.assert_command_from_args(["--secret", os.path.devnull,
1429
"foo"], SetSecretCmd,
1432
def test_secret_tempfile(self):
1433
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1434
value = b"secret\0xyzzy\nbar"
1437
self.assert_command_from_args(["--secret", f.name,
1438
"foo"], SetSecretCmd,
1441
def test_secret_devnull_short(self):
1442
self.assert_command_from_args(["-s", os.path.devnull, "foo"],
1443
SetSecretCmd, value_to_set=b"")
1445
def test_secret_tempfile_short(self):
1446
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1447
value = b"secret\0xyzzy\nbar"
1450
self.assert_command_from_args(["-s", f.name, "foo"],
1454
def test_approve(self):
1455
self.assert_command_from_args(["--approve", "foo"],
1458
def test_approve_short(self):
1459
self.assert_command_from_args(["-A", "foo"], ApproveCmd)
1461
def test_deny(self):
1462
self.assert_command_from_args(["--deny", "foo"], DenyCmd)
1464
def test_deny_short(self):
1465
self.assert_command_from_args(["-D", "foo"], DenyCmd)
1467
def test_dump_json(self):
1468
self.assert_command_from_args(["--dump-json"], DumpJSONCmd)
1470
def test_is_enabled(self):
1471
self.assert_command_from_args(["--is-enabled", "foo"],
1474
def test_is_enabled_short(self):
1475
self.assert_command_from_args(["-V", "foo"], IsEnabledCmd)
1477
def test_deny_before_remove(self):
1478
options = self.parser.parse_args(["--deny", "--remove",
1480
check_option_syntax(self.parser, options)
1481
commands = commands_from_options(options)
1482
self.assertEqual(len(commands), 2)
1483
self.assertIsInstance(commands[0], DenyCmd)
1484
self.assertIsInstance(commands[1], RemoveCmd)
1486
def test_deny_before_remove_reversed(self):
1487
options = self.parser.parse_args(["--remove", "--deny",
1489
check_option_syntax(self.parser, options)
1490
commands = commands_from_options(options)
1491
self.assertEqual(len(commands), 2)
1492
self.assertIsInstance(commands[0], DenyCmd)
1493
self.assertIsInstance(commands[1], RemoveCmd)
1496
class Test_check_option_syntax(unittest.TestCase):
1497
# This mostly corresponds to the definition from has_actions() in
1498
# check_option_syntax()
1500
# The actual values set here are not that important, but we do
1501
# at least stick to the correct types, even though they are
1505
"bump_timeout": True,
1506
"start_checker": True,
1507
"stop_checker": True,
1511
"timeout": datetime.timedelta(),
1512
"extended_timeout": datetime.timedelta(),
1513
"interval": datetime.timedelta(),
1514
"approved_by_default": True,
1515
"approval_delay": datetime.timedelta(),
1516
"approval_duration": datetime.timedelta(),
1518
"secret": io.BytesIO(b"x"),
1524
self.parser = argparse.ArgumentParser()
1525
add_command_line_options(self.parser)
1527
@contextlib.contextmanager
1528
def assertParseError(self):
1529
with self.assertRaises(SystemExit) as e:
1530
with self.temporarily_suppress_stderr():
1532
# Exit code from argparse is guaranteed to be "2". Reference:
1533
# https://docs.python.org/3/library
1534
# /argparse.html#exiting-methods
1535
self.assertEqual(e.exception.code, 2)
1538
@contextlib.contextmanager
1539
def temporarily_suppress_stderr():
1540
null = os.open(os.path.devnull, os.O_RDWR)
1541
stderrcopy = os.dup(sys.stderr.fileno())
1542
os.dup2(null, sys.stderr.fileno())
1548
os.dup2(stderrcopy, sys.stderr.fileno())
1549
os.close(stderrcopy)
1551
def check_option_syntax(self, options):
1552
check_option_syntax(self.parser, options)
1554
def test_actions_requires_client_or_all(self):
1555
for action, value in self.actions.items():
1556
options = self.parser.parse_args()
1557
setattr(options, action, value)
1558
with self.assertParseError():
1559
self.check_option_syntax(options)
1561
def test_actions_conflicts_with_verbose(self):
1562
for action, value in self.actions.items():
1563
options = self.parser.parse_args()
1564
setattr(options, action, value)
1565
options.verbose = True
1566
with self.assertParseError():
1567
self.check_option_syntax(options)
1569
def test_dump_json_conflicts_with_verbose(self):
1570
options = self.parser.parse_args()
1571
options.dump_json = True
1572
options.verbose = True
1573
with self.assertParseError():
1574
self.check_option_syntax(options)
1576
def test_dump_json_conflicts_with_action(self):
1577
for action, value in self.actions.items():
1578
options = self.parser.parse_args()
1579
setattr(options, action, value)
1580
options.dump_json = True
1581
with self.assertParseError():
1582
self.check_option_syntax(options)
1584
def test_all_can_not_be_alone(self):
1585
options = self.parser.parse_args()
1587
with self.assertParseError():
1588
self.check_option_syntax(options)
1590
def test_all_is_ok_with_any_action(self):
1591
for action, value in self.actions.items():
1592
options = self.parser.parse_args()
1593
setattr(options, action, value)
1595
self.check_option_syntax(options)
1597
def test_is_enabled_fails_without_client(self):
1598
options = self.parser.parse_args()
1599
options.is_enabled = True
1600
with self.assertParseError():
1601
self.check_option_syntax(options)
1603
def test_is_enabled_works_with_one_client(self):
1604
options = self.parser.parse_args()
1605
options.is_enabled = True
1606
options.client = ["foo"]
1607
self.check_option_syntax(options)
1609
def test_is_enabled_fails_with_two_clients(self):
1610
options = self.parser.parse_args()
1611
options.is_enabled = True
1612
options.client = ["foo", "barbar"]
1613
with self.assertParseError():
1614
self.check_option_syntax(options)
1616
def test_remove_can_only_be_combined_with_action_deny(self):
1617
for action, value in self.actions.items():
1618
if action in {"remove", "deny"}:
1620
options = self.parser.parse_args()
1621
setattr(options, action, value)
1623
options.remove = True
1624
with self.assertParseError():
1625
self.check_option_syntax(options)
1157
1629
def should_only_run_tests():