1083
1139
class TestSetSecretCmd(TestValueArgumentPropertyCmd):
1084
1140
command = SetSecretCmd
1085
1141
property = "Secret"
1086
values_to_set = [b"", b"secret"]
1142
values_to_set = [io.BytesIO(b""),
1143
io.BytesIO(b"secret\0xyzzy\nbar")]
1144
values_to_get = [b"", b"secret\0xyzzy\nbar"]
1088
1146
class TestSetTimeoutCmd(TestValueArgumentPropertyCmd):
1089
1147
command = SetTimeoutCmd
1090
1148
property = "Timeout"
1091
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1092
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1149
values_to_set = [datetime.timedelta(),
1150
datetime.timedelta(minutes=5),
1151
datetime.timedelta(seconds=1),
1152
datetime.timedelta(weeks=1),
1153
datetime.timedelta(weeks=52)]
1154
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1094
1156
class TestSetExtendedTimeoutCmd(TestValueArgumentPropertyCmd):
1095
1157
command = SetExtendedTimeoutCmd
1096
1158
property = "ExtendedTimeout"
1097
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1098
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1159
values_to_set = [datetime.timedelta(),
1160
datetime.timedelta(minutes=5),
1161
datetime.timedelta(seconds=1),
1162
datetime.timedelta(weeks=1),
1163
datetime.timedelta(weeks=52)]
1164
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1100
1166
class TestSetIntervalCmd(TestValueArgumentPropertyCmd):
1101
1167
command = SetIntervalCmd
1102
1168
property = "Interval"
1103
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1104
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1169
values_to_set = [datetime.timedelta(),
1170
datetime.timedelta(minutes=5),
1171
datetime.timedelta(seconds=1),
1172
datetime.timedelta(weeks=1),
1173
datetime.timedelta(weeks=52)]
1174
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1106
1176
class TestSetApprovalDelayCmd(TestValueArgumentPropertyCmd):
1107
1177
command = SetApprovalDelayCmd
1108
1178
property = "ApprovalDelay"
1109
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1110
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1179
values_to_set = [datetime.timedelta(),
1180
datetime.timedelta(minutes=5),
1181
datetime.timedelta(seconds=1),
1182
datetime.timedelta(weeks=1),
1183
datetime.timedelta(weeks=52)]
1184
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1112
1186
class TestSetApprovalDurationCmd(TestValueArgumentPropertyCmd):
1113
1187
command = SetApprovalDurationCmd
1114
1188
property = "ApprovalDuration"
1115
values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
1116
values_to_get = [0, 300000, 1000, 120000, 31449600000]
1189
values_to_set = [datetime.timedelta(),
1190
datetime.timedelta(minutes=5),
1191
datetime.timedelta(seconds=1),
1192
datetime.timedelta(weeks=1),
1193
datetime.timedelta(weeks=52)]
1194
values_to_get = [0, 300000, 1000, 604800000, 31449600000]
1118
class TestOptions(unittest.TestCase):
1196
class Test_command_from_options(unittest.TestCase):
1119
1197
def setUp(self):
1120
1198
self.parser = argparse.ArgumentParser()
1121
1199
add_command_line_options(self.parser)
1123
1201
"""Assert that parsing ARGS should result in an instance of
1124
1202
COMMAND_CLS with (optionally) all supplied attributes (CMD_ATTRS)."""
1125
1203
options = self.parser.parse_args(args)
1204
check_option_syntax(self.parser, options)
1126
1205
commands = commands_from_options(options)
1127
1206
self.assertEqual(len(commands), 1)
1128
1207
command = commands[0]
1129
1208
self.assertIsInstance(command, command_cls)
1130
1209
for key, value in cmd_attrs.items():
1131
1210
self.assertEqual(getattr(command, key), value)
1132
def test_default_is_show_table(self):
1211
def test_print_table(self):
1133
1212
self.assert_command_from_args([], PrintTableCmd,
1135
def test_show_table_verbose(self):
1215
def test_print_table_verbose(self):
1136
1216
self.assert_command_from_args(["--verbose"], PrintTableCmd,
1219
def test_print_table_verbose_short(self):
1220
self.assert_command_from_args(["-v"], PrintTableCmd,
1138
1223
def test_enable(self):
1139
self.assert_command_from_args(["--enable"], EnableCmd)
1224
self.assert_command_from_args(["--enable", "foo"], EnableCmd)
1226
def test_enable_short(self):
1227
self.assert_command_from_args(["-e", "foo"], EnableCmd)
1140
1229
def test_disable(self):
1141
self.assert_command_from_args(["--disable"], DisableCmd)
1230
self.assert_command_from_args(["--disable", "foo"],
1233
def test_disable_short(self):
1234
self.assert_command_from_args(["-d", "foo"], DisableCmd)
1236
def test_bump_timeout(self):
1237
self.assert_command_from_args(["--bump-timeout", "foo"],
1240
def test_bump_timeout_short(self):
1241
self.assert_command_from_args(["-b", "foo"], BumpTimeoutCmd)
1243
def test_start_checker(self):
1244
self.assert_command_from_args(["--start-checker", "foo"],
1247
def test_stop_checker(self):
1248
self.assert_command_from_args(["--stop-checker", "foo"],
1251
def test_remove(self):
1252
self.assert_command_from_args(["--remove", "foo"],
1255
def test_remove_short(self):
1256
self.assert_command_from_args(["-r", "foo"], RemoveCmd)
1258
def test_checker(self):
1259
self.assert_command_from_args(["--checker", ":", "foo"],
1260
SetCheckerCmd, value_to_set=":")
1262
def test_checker_empty(self):
1263
self.assert_command_from_args(["--checker", "", "foo"],
1264
SetCheckerCmd, value_to_set="")
1266
def test_checker_short(self):
1267
self.assert_command_from_args(["-c", ":", "foo"],
1268
SetCheckerCmd, value_to_set=":")
1270
def test_timeout(self):
1271
self.assert_command_from_args(["--timeout", "PT5M", "foo"],
1273
value_to_set=300000)
1275
def test_timeout_short(self):
1276
self.assert_command_from_args(["-t", "PT5M", "foo"],
1278
value_to_set=300000)
1280
def test_extended_timeout(self):
1281
self.assert_command_from_args(["--extended-timeout", "PT15M",
1283
SetExtendedTimeoutCmd,
1284
value_to_set=900000)
1286
def test_interval(self):
1287
self.assert_command_from_args(["--interval", "PT2M", "foo"],
1289
value_to_set=120000)
1291
def test_interval_short(self):
1292
self.assert_command_from_args(["-i", "PT2M", "foo"],
1294
value_to_set=120000)
1296
def test_approve_by_default(self):
1297
self.assert_command_from_args(["--approve-by-default", "foo"],
1298
ApproveByDefaultCmd)
1300
def test_deny_by_default(self):
1301
self.assert_command_from_args(["--deny-by-default", "foo"],
1304
def test_approval_delay(self):
1305
self.assert_command_from_args(["--approval-delay", "PT30S",
1306
"foo"], SetApprovalDelayCmd,
1309
def test_approval_duration(self):
1310
self.assert_command_from_args(["--approval-duration", "PT1S",
1311
"foo"], SetApprovalDurationCmd,
1314
def test_host(self):
1315
self.assert_command_from_args(["--host", "foo.example.org",
1317
value_to_set="foo.example.org")
1319
def test_host_short(self):
1320
self.assert_command_from_args(["-H", "foo.example.org",
1322
value_to_set="foo.example.org")
1324
def test_secret_devnull(self):
1325
self.assert_command_from_args(["--secret", os.path.devnull,
1326
"foo"], SetSecretCmd,
1329
def test_secret_tempfile(self):
1330
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1331
value = b"secret\0xyzzy\nbar"
1334
self.assert_command_from_args(["--secret", f.name,
1335
"foo"], SetSecretCmd,
1338
def test_secret_devnull_short(self):
1339
self.assert_command_from_args(["-s", os.path.devnull, "foo"],
1340
SetSecretCmd, value_to_set=b"")
1342
def test_secret_tempfile_short(self):
1343
with tempfile.NamedTemporaryFile(mode="r+b") as f:
1344
value = b"secret\0xyzzy\nbar"
1347
self.assert_command_from_args(["-s", f.name, "foo"],
1351
def test_approve(self):
1352
self.assert_command_from_args(["--approve", "foo"],
1355
def test_approve_short(self):
1356
self.assert_command_from_args(["-A", "foo"], ApproveCmd)
1358
def test_deny(self):
1359
self.assert_command_from_args(["--deny", "foo"], DenyCmd)
1361
def test_deny_short(self):
1362
self.assert_command_from_args(["-D", "foo"], DenyCmd)
1364
def test_dump_json(self):
1365
self.assert_command_from_args(["--dump-json"], DumpJSONCmd)
1367
def test_is_enabled(self):
1368
self.assert_command_from_args(["--is-enabled", "foo"],
1371
def test_is_enabled_short(self):
1372
self.assert_command_from_args(["-V", "foo"], IsEnabledCmd)
1374
def test_deny_before_remove(self):
1375
options = self.parser.parse_args(["--deny", "--remove", "foo"])
1376
check_option_syntax(self.parser, options)
1377
commands = commands_from_options(options)
1378
self.assertEqual(len(commands), 2)
1379
self.assertIsInstance(commands[0], DenyCmd)
1380
self.assertIsInstance(commands[1], RemoveCmd)
1382
def test_deny_before_remove_reversed(self):
1383
options = self.parser.parse_args(["--remove", "--deny", "--all"])
1384
check_option_syntax(self.parser, options)
1385
commands = commands_from_options(options)
1386
self.assertEqual(len(commands), 2)
1387
self.assertIsInstance(commands[0], DenyCmd)
1388
self.assertIsInstance(commands[1], RemoveCmd)
1391
class Test_check_option_syntax(unittest.TestCase):
1392
# This mostly corresponds to the definition from has_actions() in
1393
# check_option_syntax()
1395
# The actual values set here are not that important, but we do
1396
# at least stick to the correct types, even though they are
1400
"bump_timeout": True,
1401
"start_checker": True,
1402
"stop_checker": True,
1406
"timeout": datetime.timedelta(),
1407
"extended_timeout": datetime.timedelta(),
1408
"interval": datetime.timedelta(),
1409
"approved_by_default": True,
1410
"approval_delay": datetime.timedelta(),
1411
"approval_duration": datetime.timedelta(),
1413
"secret": io.BytesIO(b"x"),
1419
self.parser = argparse.ArgumentParser()
1420
add_command_line_options(self.parser)
1422
@contextlib.contextmanager
1423
def assertParseError(self):
1424
with self.assertRaises(SystemExit) as e:
1425
with self.temporarily_suppress_stderr():
1427
# Exit code from argparse is guaranteed to be "2". Reference:
1428
# https://docs.python.org/3/library/argparse.html#exiting-methods
1429
self.assertEqual(e.exception.code, 2)
1432
@contextlib.contextmanager
1433
def temporarily_suppress_stderr():
1434
null = os.open(os.path.devnull, os.O_RDWR)
1435
stderrcopy = os.dup(sys.stderr.fileno())
1436
os.dup2(null, sys.stderr.fileno())
1442
os.dup2(stderrcopy, sys.stderr.fileno())
1443
os.close(stderrcopy)
1445
def check_option_syntax(self, options):
1446
check_option_syntax(self.parser, options)
1448
def test_actions_requires_client_or_all(self):
1449
for action, value in self.actions.items():
1450
options = self.parser.parse_args()
1451
setattr(options, action, value)
1452
with self.assertParseError():
1453
self.check_option_syntax(options)
1455
def test_actions_conflicts_with_verbose(self):
1456
for action, value in self.actions.items():
1457
options = self.parser.parse_args()
1458
setattr(options, action, value)
1459
options.verbose = True
1460
with self.assertParseError():
1461
self.check_option_syntax(options)
1463
def test_dump_json_conflicts_with_verbose(self):
1464
options = self.parser.parse_args()
1465
options.dump_json = True
1466
options.verbose = True
1467
with self.assertParseError():
1468
self.check_option_syntax(options)
1470
def test_dump_json_conflicts_with_action(self):
1471
for action, value in self.actions.items():
1472
options = self.parser.parse_args()
1473
setattr(options, action, value)
1474
options.dump_json = True
1475
with self.assertParseError():
1476
self.check_option_syntax(options)
1478
def test_all_can_not_be_alone(self):
1479
options = self.parser.parse_args()
1481
with self.assertParseError():
1482
self.check_option_syntax(options)
1484
def test_all_is_ok_with_any_action(self):
1485
for action, value in self.actions.items():
1486
options = self.parser.parse_args()
1487
setattr(options, action, value)
1489
self.check_option_syntax(options)
1491
def test_is_enabled_fails_without_client(self):
1492
options = self.parser.parse_args()
1493
options.is_enabled = True
1494
with self.assertParseError():
1495
self.check_option_syntax(options)
1497
def test_is_enabled_works_with_one_client(self):
1498
options = self.parser.parse_args()
1499
options.is_enabled = True
1500
options.client = ["foo"]
1501
self.check_option_syntax(options)
1503
def test_is_enabled_fails_with_two_clients(self):
1504
options = self.parser.parse_args()
1505
options.is_enabled = True
1506
options.client = ["foo", "barbar"]
1507
with self.assertParseError():
1508
self.check_option_syntax(options)
1510
def test_remove_can_only_be_combined_with_action_deny(self):
1511
for action, value in self.actions.items():
1512
if action in {"remove", "deny"}:
1514
options = self.parser.parse_args()
1515
setattr(options, action, value)
1517
options.remove = True
1518
with self.assertParseError():
1519
self.check_option_syntax(options)