/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos-ctl

  • Committer: Teddy Hogeborn
  • Date: 2019-03-06 22:07:48 UTC
  • Revision ID: teddy@recompile.se-20190306220748-wfxlbmehw0mny8mn
mandos-ctl: Fix bugs

* mandos-ctl (SetSecretCommand): Argument is file object, not string.
  (commands_from_options): Fix "command" to "commands" throughout. Add
                           option argument to SetCheckerCmd().
  (TestSetSecretCmd): Set file objects, not byte strings.

Show diffs side-by-side

added added

removed removed

Lines of Context:
43
43
import unittest
44
44
import logging
45
45
import io
46
 
import tempfile
47
 
import contextlib
48
46
 
49
47
import dbus
50
48
 
300
298
    """Abstract class for Actions for setting one client property"""
301
299
    def run_on_one_client(self, client, properties):
302
300
        """Set the Client's D-Bus property"""
303
 
        log.debug("D-Bus: %s:%s:%s.Set(%r, %r, %r)", busname,
304
 
                  client.__dbus_object_path__,
305
 
                  dbus.PROPERTIES_IFACE, client_interface,
306
 
                  self.property, self.value_to_set
307
 
                  if not isinstance(self.value_to_set, dbus.Boolean)
308
 
                  else bool(self.value_to_set))
309
301
        client.Set(client_interface, self.property, self.value_to_set,
310
302
                   dbus_interface=dbus.PROPERTIES_IFACE)
311
303
 
323
315
    @value_to_set.setter
324
316
    def value_to_set(self, value):
325
317
        """When setting, convert value to a datetime.timedelta"""
326
 
        self._vts = int(round(value.total_seconds() * 1000))
 
318
        self._vts = string_to_delta(value).total_seconds() * 1000
327
319
 
328
320
# Actual (non-abstract) command classes
329
321
 
437
429
 
438
430
class RemoveCmd(Command):
439
431
    def run_on_one_client(self, client, properties):
440
 
        log.debug("D-Bus: %s:%s:%s.RemoveClient(%r)", busname,
441
 
                  server_path, server_interface,
442
 
                  str(client.__dbus_object_path__))
443
432
        self.mandos.RemoveClient(client.__dbus_object_path__)
444
433
 
445
434
class ApproveCmd(Command):
446
435
    def run_on_one_client(self, client, properties):
447
 
        log.debug("D-Bus: %s:%s.Approve(True)",
448
 
                  client.__dbus_object_path__, client_interface)
449
436
        client.Approve(dbus.Boolean(True),
450
437
                       dbus_interface=client_interface)
451
438
 
452
439
class DenyCmd(Command):
453
440
    def run_on_one_client(self, client, properties):
454
 
        log.debug("D-Bus: %s:%s.Approve(False)",
455
 
                  client.__dbus_object_path__, client_interface)
456
441
        client.Approve(dbus.Boolean(False),
457
442
                       dbus_interface=client_interface)
458
443
 
519
504
                             MillisecondsValueArgumentMixIn):
520
505
    property = "ApprovalDuration"
521
506
 
 
507
def has_actions(options):
 
508
    return any((options.enable,
 
509
                options.disable,
 
510
                options.bump_timeout,
 
511
                options.start_checker,
 
512
                options.stop_checker,
 
513
                options.is_enabled,
 
514
                options.remove,
 
515
                options.checker is not None,
 
516
                options.timeout is not None,
 
517
                options.extended_timeout is not None,
 
518
                options.interval is not None,
 
519
                options.approved_by_default is not None,
 
520
                options.approval_delay is not None,
 
521
                options.approval_duration is not None,
 
522
                options.host is not None,
 
523
                options.secret is not None,
 
524
                options.approve,
 
525
                options.deny))
 
526
 
522
527
def add_command_line_options(parser):
523
528
    parser.add_argument("--version", action="version",
524
529
                        version="%(prog)s {}".format(version),
550
555
                        help="Remove client")
551
556
    parser.add_argument("-c", "--checker",
552
557
                        help="Set checker command for client")
553
 
    parser.add_argument("-t", "--timeout", type=string_to_delta,
 
558
    parser.add_argument("-t", "--timeout",
554
559
                        help="Set timeout for client")
555
 
    parser.add_argument("--extended-timeout", type=string_to_delta,
 
560
    parser.add_argument("--extended-timeout",
556
561
                        help="Set extended timeout for client")
557
 
    parser.add_argument("-i", "--interval", type=string_to_delta,
 
562
    parser.add_argument("-i", "--interval",
558
563
                        help="Set checker interval for client")
559
564
    approve_deny_default = parser.add_mutually_exclusive_group()
560
565
    approve_deny_default.add_argument(
565
570
        "--deny-by-default", action="store_false",
566
571
        dest="approved_by_default",
567
572
        help="Set client to be denied by default")
568
 
    parser.add_argument("--approval-delay", type=string_to_delta,
 
573
    parser.add_argument("--approval-delay",
569
574
                        help="Set delay before client approve/deny")
570
 
    parser.add_argument("--approval-duration", type=string_to_delta,
 
575
    parser.add_argument("--approval-duration",
571
576
                        help="Set duration of one client approval")
572
577
    parser.add_argument("-H", "--host", help="Set host for client")
573
578
    parser.add_argument("-s", "--secret",
579
584
        help="Approve any current client request")
580
585
    approve_deny.add_argument("-D", "--deny", action="store_true",
581
586
                              help="Deny any current client request")
582
 
    parser.add_argument("--debug", action="store_true",
583
 
                        help="Debug mode (show D-Bus commands)")
584
587
    parser.add_argument("--check", action="store_true",
585
588
                        help="Run self-test")
586
589
    parser.add_argument("client", nargs="*", help="Client name")
660
663
    return commands
661
664
 
662
665
 
663
 
def check_option_syntax(parser, options):
664
 
    """Apply additional restrictions on options, not expressible in
665
 
argparse"""
666
 
 
667
 
    def has_actions(options):
668
 
        return any((options.enable,
669
 
                    options.disable,
670
 
                    options.bump_timeout,
671
 
                    options.start_checker,
672
 
                    options.stop_checker,
673
 
                    options.is_enabled,
674
 
                    options.remove,
675
 
                    options.checker is not None,
676
 
                    options.timeout is not None,
677
 
                    options.extended_timeout is not None,
678
 
                    options.interval is not None,
679
 
                    options.approved_by_default is not None,
680
 
                    options.approval_delay is not None,
681
 
                    options.approval_duration is not None,
682
 
                    options.host is not None,
683
 
                    options.secret is not None,
684
 
                    options.approve,
685
 
                    options.deny))
 
666
def main():
 
667
    parser = argparse.ArgumentParser()
 
668
 
 
669
    add_command_line_options(parser)
 
670
 
 
671
    options = parser.parse_args()
686
672
 
687
673
    if has_actions(options) and not (options.client or options.all):
688
674
        parser.error("Options require clients names or --all.")
696
682
    if options.is_enabled and len(options.client) > 1:
697
683
        parser.error("--is-enabled requires exactly one client")
698
684
 
699
 
 
700
 
def main():
701
 
    parser = argparse.ArgumentParser()
702
 
 
703
 
    add_command_line_options(parser)
704
 
 
705
 
    options = parser.parse_args()
706
 
 
707
 
    check_option_syntax(parser, options)
708
 
 
709
685
    clientnames = options.client
710
686
 
711
 
    if options.debug:
712
 
        log.setLevel(logging.DEBUG)
713
 
 
714
687
    try:
715
688
        bus = dbus.SystemBus()
716
 
        log.debug("D-Bus: Connect to: (name=%r, path=%r)", busname,
717
 
                  server_path)
718
689
        mandos_dbus_objc = bus.get_object(busname, server_path)
719
690
    except dbus.exceptions.DBusException:
720
691
        log.critical("Could not connect to Mandos server")
733
704
    dbus_filter = NullFilter()
734
705
    try:
735
706
        dbus_logger.addFilter(dbus_filter)
736
 
        log.debug("D-Bus: %s:%s:%s.GetManagedObjects()", busname,
737
 
                  server_path, dbus.OBJECT_MANAGER_IFACE)
738
707
        mandos_clients = {path: ifs_and_props[client_interface]
739
708
                          for path, ifs_and_props in
740
709
                          mandos_serv_object_manager
1123
1092
class TestSetSecretCmd(TestValueArgumentPropertyCmd):
1124
1093
    command = SetSecretCmd
1125
1094
    property = "Secret"
1126
 
    values_to_set = [io.BytesIO(b""),
 
1095
    values_to_set = [open("/dev/null", "rb"),
1127
1096
                     io.BytesIO(b"secret\0xyzzy\nbar")]
1128
1097
    values_to_get = [b"", b"secret\0xyzzy\nbar"]
1129
1098
 
1130
1099
class TestSetTimeoutCmd(TestValueArgumentPropertyCmd):
1131
1100
    command = SetTimeoutCmd
1132
1101
    property = "Timeout"
1133
 
    values_to_set = [datetime.timedelta(),
1134
 
                     datetime.timedelta(minutes=5),
1135
 
                     datetime.timedelta(seconds=1),
1136
 
                     datetime.timedelta(weeks=1),
1137
 
                     datetime.timedelta(weeks=52)]
1138
 
    values_to_get = [0, 300000, 1000, 604800000, 31449600000]
 
1102
    values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
 
1103
    values_to_get = [0, 300000, 1000, 120000, 31449600000]
1139
1104
 
1140
1105
class TestSetExtendedTimeoutCmd(TestValueArgumentPropertyCmd):
1141
1106
    command = SetExtendedTimeoutCmd
1142
1107
    property = "ExtendedTimeout"
1143
 
    values_to_set = [datetime.timedelta(),
1144
 
                     datetime.timedelta(minutes=5),
1145
 
                     datetime.timedelta(seconds=1),
1146
 
                     datetime.timedelta(weeks=1),
1147
 
                     datetime.timedelta(weeks=52)]
1148
 
    values_to_get = [0, 300000, 1000, 604800000, 31449600000]
 
1108
    values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
 
1109
    values_to_get = [0, 300000, 1000, 120000, 31449600000]
1149
1110
 
1150
1111
class TestSetIntervalCmd(TestValueArgumentPropertyCmd):
1151
1112
    command = SetIntervalCmd
1152
1113
    property = "Interval"
1153
 
    values_to_set = [datetime.timedelta(),
1154
 
                     datetime.timedelta(minutes=5),
1155
 
                     datetime.timedelta(seconds=1),
1156
 
                     datetime.timedelta(weeks=1),
1157
 
                     datetime.timedelta(weeks=52)]
1158
 
    values_to_get = [0, 300000, 1000, 604800000, 31449600000]
 
1114
    values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
 
1115
    values_to_get = [0, 300000, 1000, 120000, 31449600000]
1159
1116
 
1160
1117
class TestSetApprovalDelayCmd(TestValueArgumentPropertyCmd):
1161
1118
    command = SetApprovalDelayCmd
1162
1119
    property = "ApprovalDelay"
1163
 
    values_to_set = [datetime.timedelta(),
1164
 
                     datetime.timedelta(minutes=5),
1165
 
                     datetime.timedelta(seconds=1),
1166
 
                     datetime.timedelta(weeks=1),
1167
 
                     datetime.timedelta(weeks=52)]
1168
 
    values_to_get = [0, 300000, 1000, 604800000, 31449600000]
 
1120
    values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
 
1121
    values_to_get = [0, 300000, 1000, 120000, 31449600000]
1169
1122
 
1170
1123
class TestSetApprovalDurationCmd(TestValueArgumentPropertyCmd):
1171
1124
    command = SetApprovalDurationCmd
1172
1125
    property = "ApprovalDuration"
1173
 
    values_to_set = [datetime.timedelta(),
1174
 
                     datetime.timedelta(minutes=5),
1175
 
                     datetime.timedelta(seconds=1),
1176
 
                     datetime.timedelta(weeks=1),
1177
 
                     datetime.timedelta(weeks=52)]
1178
 
    values_to_get = [0, 300000, 1000, 604800000, 31449600000]
 
1126
    values_to_set = ["P0D", "PT5M", "PT1S", "PT120S", "P1Y"]
 
1127
    values_to_get = [0, 300000, 1000, 120000, 31449600000]
1179
1128
 
1180
 
class Test_command_from_options(unittest.TestCase):
 
1129
class TestOptions(unittest.TestCase):
1181
1130
    def setUp(self):
1182
1131
        self.parser = argparse.ArgumentParser()
1183
1132
        add_command_line_options(self.parser)
1185
1134
        """Assert that parsing ARGS should result in an instance of
1186
1135
COMMAND_CLS with (optionally) all supplied attributes (CMD_ATTRS)."""
1187
1136
        options = self.parser.parse_args(args)
1188
 
        check_option_syntax(self.parser, options)
1189
1137
        commands = commands_from_options(options)
1190
1138
        self.assertEqual(len(commands), 1)
1191
1139
        command = commands[0]
1192
1140
        self.assertIsInstance(command, command_cls)
1193
1141
        for key, value in cmd_attrs.items():
1194
1142
            self.assertEqual(getattr(command, key), value)
1195
 
    def test_print_table(self):
 
1143
    def test_default_is_show_table(self):
1196
1144
        self.assert_command_from_args([], PrintTableCmd,
1197
1145
                                      verbose=False)
1198
 
 
1199
 
    def test_print_table_verbose(self):
 
1146
    def test_show_table_verbose(self):
1200
1147
        self.assert_command_from_args(["--verbose"], PrintTableCmd,
1201
1148
                                      verbose=True)
1202
 
 
1203
 
    def test_print_table_verbose_short(self):
1204
 
        self.assert_command_from_args(["-v"], PrintTableCmd,
1205
 
                                      verbose=True)
1206
 
 
1207
1149
    def test_enable(self):
1208
1150
        self.assert_command_from_args(["--enable", "foo"], EnableCmd)
1209
 
 
1210
 
    def test_enable_short(self):
1211
 
        self.assert_command_from_args(["-e", "foo"], EnableCmd)
1212
 
 
1213
1151
    def test_disable(self):
1214
1152
        self.assert_command_from_args(["--disable", "foo"],
1215
1153
                                      DisableCmd)
1216
1154
 
1217
 
    def test_disable_short(self):
1218
 
        self.assert_command_from_args(["-d", "foo"], DisableCmd)
1219
 
 
1220
 
    def test_bump_timeout(self):
1221
 
        self.assert_command_from_args(["--bump-timeout", "foo"],
1222
 
                                      BumpTimeoutCmd)
1223
 
 
1224
 
    def test_bump_timeout_short(self):
1225
 
        self.assert_command_from_args(["-b", "foo"], BumpTimeoutCmd)
1226
 
 
1227
 
    def test_start_checker(self):
1228
 
        self.assert_command_from_args(["--start-checker", "foo"],
1229
 
                                      StartCheckerCmd)
1230
 
 
1231
 
    def test_stop_checker(self):
1232
 
        self.assert_command_from_args(["--stop-checker", "foo"],
1233
 
                                      StopCheckerCmd)
1234
 
 
1235
 
    def test_remove(self):
1236
 
        self.assert_command_from_args(["--remove", "foo"],
1237
 
                                      RemoveCmd)
1238
 
 
1239
 
    def test_remove_short(self):
1240
 
        self.assert_command_from_args(["-r", "foo"], RemoveCmd)
1241
 
 
1242
 
    def test_checker(self):
1243
 
        self.assert_command_from_args(["--checker", ":", "foo"],
1244
 
                                      SetCheckerCmd, value_to_set=":")
1245
 
 
1246
 
    def test_checker_empty(self):
1247
 
        self.assert_command_from_args(["--checker", "", "foo"],
1248
 
                                      SetCheckerCmd, value_to_set="")
1249
 
 
1250
 
    def test_checker_short(self):
1251
 
        self.assert_command_from_args(["-c", ":", "foo"],
1252
 
                                      SetCheckerCmd, value_to_set=":")
1253
 
 
1254
 
    def test_timeout(self):
1255
 
        self.assert_command_from_args(["--timeout", "PT5M", "foo"],
1256
 
                                      SetTimeoutCmd,
1257
 
                                      value_to_set=300000)
1258
 
 
1259
 
    def test_timeout_short(self):
1260
 
        self.assert_command_from_args(["-t", "PT5M", "foo"],
1261
 
                                      SetTimeoutCmd,
1262
 
                                      value_to_set=300000)
1263
 
 
1264
 
    def test_extended_timeout(self):
1265
 
        self.assert_command_from_args(["--extended-timeout", "PT15M",
1266
 
                                       "foo"],
1267
 
                                      SetExtendedTimeoutCmd,
1268
 
                                      value_to_set=900000)
1269
 
 
1270
 
    def test_interval(self):
1271
 
        self.assert_command_from_args(["--interval", "PT2M", "foo"],
1272
 
                                      SetIntervalCmd,
1273
 
                                      value_to_set=120000)
1274
 
 
1275
 
    def test_interval_short(self):
1276
 
        self.assert_command_from_args(["-i", "PT2M", "foo"],
1277
 
                                      SetIntervalCmd,
1278
 
                                      value_to_set=120000)
1279
 
 
1280
 
    def test_approve_by_default(self):
1281
 
        self.assert_command_from_args(["--approve-by-default", "foo"],
1282
 
                                      ApproveByDefaultCmd)
1283
 
 
1284
 
    def test_deny_by_default(self):
1285
 
        self.assert_command_from_args(["--deny-by-default", "foo"],
1286
 
                                      DenyByDefaultCmd)
1287
 
 
1288
 
    def test_approval_delay(self):
1289
 
        self.assert_command_from_args(["--approval-delay", "PT30S",
1290
 
                                       "foo"], SetApprovalDelayCmd,
1291
 
                                      value_to_set=30000)
1292
 
 
1293
 
    def test_approval_duration(self):
1294
 
        self.assert_command_from_args(["--approval-duration", "PT1S",
1295
 
                                       "foo"], SetApprovalDurationCmd,
1296
 
                                      value_to_set=1000)
1297
 
 
1298
 
    def test_host(self):
1299
 
        self.assert_command_from_args(["--host", "foo.example.org",
1300
 
                                       "foo"], SetHostCmd,
1301
 
                                      value_to_set="foo.example.org")
1302
 
 
1303
 
    def test_host_short(self):
1304
 
        self.assert_command_from_args(["-H", "foo.example.org",
1305
 
                                       "foo"], SetHostCmd,
1306
 
                                      value_to_set="foo.example.org")
1307
 
 
1308
 
    def test_secret_devnull(self):
1309
 
        self.assert_command_from_args(["--secret", os.path.devnull,
1310
 
                                       "foo"], SetSecretCmd,
1311
 
                                      value_to_set=b"")
1312
 
 
1313
 
    def test_secret_tempfile(self):
1314
 
        with tempfile.NamedTemporaryFile(mode="r+b") as f:
1315
 
            value = b"secret\0xyzzy\nbar"
1316
 
            f.write(value)
1317
 
            f.seek(0)
1318
 
            self.assert_command_from_args(["--secret", f.name,
1319
 
                                           "foo"], SetSecretCmd,
1320
 
                                          value_to_set=value)
1321
 
 
1322
 
    def test_secret_devnull_short(self):
1323
 
        self.assert_command_from_args(["-s", os.path.devnull, "foo"],
1324
 
                                      SetSecretCmd, value_to_set=b"")
1325
 
 
1326
 
    def test_secret_tempfile_short(self):
1327
 
        with tempfile.NamedTemporaryFile(mode="r+b") as f:
1328
 
            value = b"secret\0xyzzy\nbar"
1329
 
            f.write(value)
1330
 
            f.seek(0)
1331
 
            self.assert_command_from_args(["-s", f.name, "foo"],
1332
 
                                          SetSecretCmd,
1333
 
                                          value_to_set=value)
1334
 
 
1335
 
    def test_approve(self):
1336
 
        self.assert_command_from_args(["--approve", "foo"],
1337
 
                                      ApproveCmd)
1338
 
 
1339
 
    def test_approve_short(self):
1340
 
        self.assert_command_from_args(["-A", "foo"], ApproveCmd)
1341
 
 
1342
 
    def test_deny(self):
1343
 
        self.assert_command_from_args(["--deny", "foo"], DenyCmd)
1344
 
 
1345
 
    def test_deny_short(self):
1346
 
        self.assert_command_from_args(["-D", "foo"], DenyCmd)
1347
 
 
1348
 
    def test_dump_json(self):
1349
 
        self.assert_command_from_args(["--dump-json"], DumpJSONCmd)
1350
 
 
1351
 
    def test_is_enabled(self):
1352
 
        self.assert_command_from_args(["--is-enabled", "foo"],
1353
 
                                      IsEnabledCmd)
1354
 
 
1355
 
    def test_is_enabled_short(self):
1356
 
        self.assert_command_from_args(["-V", "foo"], IsEnabledCmd)
1357
 
 
1358
 
 
1359
 
class Test_check_option_syntax(unittest.TestCase):
1360
 
    # This mostly corresponds to the definition from has_actions() in
1361
 
    # check_option_syntax()
1362
 
    actions = {
1363
 
        # The actual values set here are not that important, but we do
1364
 
        # at least stick to the correct types, even though they are
1365
 
        # never used
1366
 
        "enable": True,
1367
 
        "disable": True,
1368
 
        "bump_timeout": True,
1369
 
        "start_checker": True,
1370
 
        "stop_checker": True,
1371
 
        "is_enabled": True,
1372
 
        "remove": True,
1373
 
        "checker": "x",
1374
 
        "timeout": datetime.timedelta(),
1375
 
        "extended_timeout": datetime.timedelta(),
1376
 
        "interval": datetime.timedelta(),
1377
 
        "approved_by_default": True,
1378
 
        "approval_delay": datetime.timedelta(),
1379
 
        "approval_duration": datetime.timedelta(),
1380
 
        "host": "x",
1381
 
        "secret": io.BytesIO(b"x"),
1382
 
        "approve": True,
1383
 
        "deny": True,
1384
 
    }
1385
 
 
1386
 
    def setUp(self):
1387
 
        self.parser = argparse.ArgumentParser()
1388
 
        add_command_line_options(self.parser)
1389
 
 
1390
 
    @contextlib.contextmanager
1391
 
    def assertParseError(self):
1392
 
        with self.assertRaises(SystemExit) as e:
1393
 
            with self.temporarily_suppress_stderr():
1394
 
                yield
1395
 
        # Exit code from argparse is guaranteed to be "2".  Reference:
1396
 
        # https://docs.python.org/3/library/argparse.html#exiting-methods
1397
 
        self.assertEqual(e.exception.code, 2)
1398
 
 
1399
 
    @staticmethod
1400
 
    @contextlib.contextmanager
1401
 
    def temporarily_suppress_stderr():
1402
 
        null = os.open(os.path.devnull, os.O_RDWR)
1403
 
        stderrcopy = os.dup(sys.stderr.fileno())
1404
 
        os.dup2(null, sys.stderr.fileno())
1405
 
        os.close(null)
1406
 
        try:
1407
 
            yield
1408
 
        finally:
1409
 
            # restore stderr
1410
 
            os.dup2(stderrcopy, sys.stderr.fileno())
1411
 
            os.close(stderrcopy)
1412
 
 
1413
 
    def check_option_syntax(self, options):
1414
 
        check_option_syntax(self.parser, options)
1415
 
 
1416
 
    def test_actions_requires_client_or_all(self):
1417
 
        for action, value in self.actions.items():
1418
 
            options = self.parser.parse_args()
1419
 
            setattr(options, action, value)
1420
 
            with self.assertParseError():
1421
 
                self.check_option_syntax(options)
1422
 
 
1423
 
    def test_actions_conflicts_with_verbose(self):
1424
 
        for action, value in self.actions.items():
1425
 
            options = self.parser.parse_args()
1426
 
            setattr(options, action, value)
1427
 
            options.verbose = True
1428
 
            with self.assertParseError():
1429
 
                self.check_option_syntax(options)
1430
 
 
1431
 
    def test_dump_json_conflicts_with_verbose(self):
1432
 
        options = self.parser.parse_args()
1433
 
        options.dump_json = True
1434
 
        options.verbose = True
1435
 
        with self.assertParseError():
1436
 
            self.check_option_syntax(options)
1437
 
 
1438
 
    def test_dump_json_conflicts_with_action(self):
1439
 
        for action, value in self.actions.items():
1440
 
            options = self.parser.parse_args()
1441
 
            setattr(options, action, value)
1442
 
            options.dump_json = True
1443
 
            with self.assertParseError():
1444
 
                self.check_option_syntax(options)
1445
 
 
1446
 
    def test_all_can_not_be_alone(self):
1447
 
        options = self.parser.parse_args()
1448
 
        options.all = True
1449
 
        with self.assertParseError():
1450
 
            self.check_option_syntax(options)
1451
 
 
1452
 
    def test_all_is_ok_with_any_action(self):
1453
 
        for action, value in self.actions.items():
1454
 
            options = self.parser.parse_args()
1455
 
            setattr(options, action, value)
1456
 
            options.all = True
1457
 
            self.check_option_syntax(options)
1458
 
 
1459
 
    def test_is_enabled_fails_without_client(self):
1460
 
        options = self.parser.parse_args()
1461
 
        options.is_enabled = True
1462
 
        with self.assertParseError():
1463
 
            self.check_option_syntax(options)
1464
 
 
1465
 
    def test_is_enabled_works_with_one_client(self):
1466
 
        options = self.parser.parse_args()
1467
 
        options.is_enabled = True
1468
 
        options.client = ["foo"]
1469
 
        self.check_option_syntax(options)
1470
 
 
1471
 
    def test_is_enabled_fails_with_two_clients(self):
1472
 
        options = self.parser.parse_args()
1473
 
        options.is_enabled = True
1474
 
        options.client = ["foo", "barbar"]
1475
 
        with self.assertParseError():
1476
 
            self.check_option_syntax(options)
1477
 
 
1478
1155
 
1479
1156
 
1480
1157
def should_only_run_tests():