149
122
help="Select all clients")
150
123
parser.add_argument("-v", "--verbose", action="store_true",
151
124
help="Print all fields")
152
parser.add_argument("-j", "--dump-json", dest="commands",
153
action="append_const", default=[],
154
const=command.DumpJSON(),
125
parser.add_argument("-j", "--dump-json", action="store_true",
155
126
help="Dump client data in JSON format")
156
127
enable_disable = parser.add_mutually_exclusive_group()
157
enable_disable.add_argument("-e", "--enable", dest="commands",
158
action="append_const", default=[],
159
const=command.Enable(),
128
enable_disable.add_argument("-e", "--enable", action="store_true",
160
129
help="Enable client")
161
enable_disable.add_argument("-d", "--disable", dest="commands",
162
action="append_const", default=[],
163
const=command.Disable(),
130
enable_disable.add_argument("-d", "--disable",
164
132
help="disable client")
165
parser.add_argument("-b", "--bump-timeout", dest="commands",
166
action="append_const", default=[],
167
const=command.BumpTimeout(),
133
parser.add_argument("-b", "--bump-timeout", action="store_true",
168
134
help="Bump timeout for client")
169
135
start_stop_checker = parser.add_mutually_exclusive_group()
170
136
start_stop_checker.add_argument("--start-checker",
172
action="append_const", default=[],
173
const=command.StartChecker(),
174
138
help="Start checker for client")
175
start_stop_checker.add_argument("--stop-checker", dest="commands",
176
action="append_const", default=[],
177
const=command.StopChecker(),
139
start_stop_checker.add_argument("--stop-checker",
178
141
help="Stop checker for client")
179
parser.add_argument("-V", "--is-enabled", dest="commands",
180
action="append_const", default=[],
181
const=command.IsEnabled(),
142
parser.add_argument("-V", "--is-enabled", action="store_true",
182
143
help="Check if client is enabled")
183
parser.add_argument("-r", "--remove", dest="commands",
184
action="append_const", default=[],
185
const=command.Remove(),
144
parser.add_argument("-r", "--remove", action="store_true",
186
145
help="Remove client")
187
parser.add_argument("-c", "--checker", dest="commands",
188
action="append", default=[],
189
metavar="COMMAND", type=command.SetChecker,
146
parser.add_argument("-c", "--checker",
190
147
help="Set checker command for client")
192
"-t", "--timeout", dest="commands", action="append",
193
default=[], metavar="TIME",
194
type=command.SetTimeout.argparse(string_to_delta),
195
help="Set timeout for client")
197
"--extended-timeout", dest="commands", action="append",
198
default=[], metavar="TIME",
199
type=command.SetExtendedTimeout.argparse(string_to_delta),
200
help="Set extended timeout for client")
202
"-i", "--interval", dest="commands", action="append",
203
default=[], metavar="TIME",
204
type=command.SetInterval.argparse(string_to_delta),
205
help="Set checker interval for client")
148
parser.add_argument("-t", "--timeout", type=string_to_delta,
149
help="Set timeout for client")
150
parser.add_argument("--extended-timeout", type=string_to_delta,
151
help="Set extended timeout for client")
152
parser.add_argument("-i", "--interval", type=string_to_delta,
153
help="Set checker interval for client")
206
154
approve_deny_default = parser.add_mutually_exclusive_group()
207
155
approve_deny_default.add_argument(
208
"--approve-by-default", dest="commands",
209
action="append_const", default=[],
210
const=command.ApproveByDefault(),
156
"--approve-by-default", action="store_true",
157
default=None, dest="approved_by_default",
211
158
help="Set client to be approved by default")
212
159
approve_deny_default.add_argument(
213
"--deny-by-default", dest="commands",
214
action="append_const", default=[],
215
const=command.DenyByDefault(),
160
"--deny-by-default", action="store_false",
161
dest="approved_by_default",
216
162
help="Set client to be denied by default")
218
"--approval-delay", dest="commands", action="append",
219
default=[], metavar="TIME",
220
type=command.SetApprovalDelay.argparse(string_to_delta),
221
help="Set delay before client approve/deny")
223
"--approval-duration", dest="commands", action="append",
224
default=[], metavar="TIME",
225
type=command.SetApprovalDuration.argparse(string_to_delta),
226
help="Set duration of one client approval")
227
parser.add_argument("-H", "--host", dest="commands",
228
action="append", default=[], metavar="STRING",
229
type=command.SetHost,
230
help="Set host for client")
232
"-s", "--secret", dest="commands", action="append",
233
default=[], metavar="FILENAME",
234
type=command.SetSecret.argparse(argparse.FileType(mode="rb")),
235
help="Set password blob (file) for client")
163
parser.add_argument("--approval-delay", type=string_to_delta,
164
help="Set delay before client approve/deny")
165
parser.add_argument("--approval-duration", type=string_to_delta,
166
help="Set duration of one client approval")
167
parser.add_argument("-H", "--host", help="Set host for client")
168
parser.add_argument("-s", "--secret",
169
type=argparse.FileType(mode="rb"),
170
help="Set password blob (file) for client")
236
171
approve_deny = parser.add_mutually_exclusive_group()
237
172
approve_deny.add_argument(
238
"-A", "--approve", dest="commands", action="append_const",
239
default=[], const=command.Approve(),
173
"-A", "--approve", action="store_true",
240
174
help="Approve any current client request")
241
approve_deny.add_argument("-D", "--deny", dest="commands",
242
action="append_const", default=[],
243
const=command.Deny(),
175
approve_deny.add_argument("-D", "--deny", action="store_true",
244
176
help="Deny any current client request")
245
177
parser.add_argument("--debug", action="store_true",
246
178
help="Debug mode (show D-Bus commands)")
438
369
"""Apply additional restrictions on options, not expressible in
441
def has_commands(options, commands=None):
443
commands = (command.Enable,
446
command.StartChecker,
452
command.SetExtendedTimeout,
454
command.ApproveByDefault,
455
command.DenyByDefault,
456
command.SetApprovalDelay,
457
command.SetApprovalDuration,
462
return any(isinstance(cmd, commands)
463
for cmd in options.commands)
372
def has_actions(options):
373
return any((options.enable,
375
options.bump_timeout,
376
options.start_checker,
377
options.stop_checker,
380
options.checker is not None,
381
options.timeout is not None,
382
options.extended_timeout is not None,
383
options.interval is not None,
384
options.approved_by_default is not None,
385
options.approval_delay is not None,
386
options.approval_duration is not None,
387
options.host is not None,
388
options.secret is not None,
465
if has_commands(options) and not (options.client or options.all):
392
if has_actions(options) and not (options.client or options.all):
466
393
parser.error("Options require clients names or --all.")
467
if options.verbose and has_commands(options):
394
if options.verbose and has_actions(options):
468
395
parser.error("--verbose can only be used alone.")
469
if (has_commands(options, (command.DumpJSON,))
470
and (options.verbose or len(options.commands) > 1)):
396
if options.dump_json and (options.verbose
397
or has_actions(options)):
471
398
parser.error("--dump-json can only be used alone.")
472
if options.all and not has_commands(options):
399
if options.all and not has_actions(options):
473
400
parser.error("--all requires an action.")
474
if (has_commands(options, (command.IsEnabled,))
475
and len(options.client) > 1):
401
if options.is_enabled and len(options.client) > 1:
476
402
parser.error("--is-enabled requires exactly one client")
477
if (len(options.commands) > 1
478
and has_commands(options, (command.Remove,))
479
and not has_commands(options, (command.Deny,))):
480
parser.error("--remove can only be combined with --deny")
404
options.remove = False
405
if has_actions(options) and not options.deny:
406
parser.error("--remove can only be combined with --deny")
407
options.remove = True
413
class SystemBus(object):
487
415
object_manager_iface = "org.freedesktop.DBus.ObjectManager"
488
416
def get_managed_objects(self, busname, objectpath):
633
549
return new_object
636
class pydbus_adapter:
637
class SystemBus(dbus.MandosBus):
638
def __init__(self, module=pydbus):
640
self.bus = self.pydbus.SystemBus()
642
@contextlib.contextmanager
643
def convert_exception(self, exception_class=dbus.Error):
646
except gi.repository.GLib.Error as e:
647
# This does what "raise from" would do
648
exc = exception_class(*e.args)
652
def call_method(self, methodname, busname, objectpath,
654
proxy_object = self.get(busname, objectpath)
655
log.debug("D-Bus: %s:%s:%s.%s(%s)", busname, objectpath,
656
interface, methodname,
657
", ".join(repr(a) for a in args))
658
method = getattr(proxy_object[interface], methodname)
659
with self.convert_exception():
662
def get(self, busname, objectpath):
663
log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
665
with self.convert_exception(dbus.ConnectFailed):
666
if sys.version_info.major <= 2:
667
with warnings.catch_warnings():
668
warnings.filterwarnings(
669
"ignore", "", DeprecationWarning,
670
r"^xml\.etree\.ElementTree$")
671
return self.bus.get(busname, objectpath)
673
return self.bus.get(busname, objectpath)
675
def set_property(self, busname, objectpath, interface, key,
677
proxy_object = self.get(busname, objectpath)
678
log.debug("D-Bus: %s:%s:%s.Set(%r, %r, %r)", busname,
679
objectpath, self.properties_iface, interface,
681
setattr(proxy_object[interface], key, value)
683
class CachingBus(SystemBus):
684
"""A caching layer for pydbus_adapter.SystemBus"""
685
def __init__(self, *args, **kwargs):
686
self.object_cache = {}
687
super(pydbus_adapter.CachingBus,
688
self).__init__(*args, **kwargs)
689
def get(self, busname, objectpath):
691
return self.object_cache[(busname, objectpath)]
693
new_object = (super(pydbus_adapter.CachingBus, self)
694
.get(busname, objectpath))
695
self.object_cache[(busname, objectpath)] = new_object
699
class dbussy_adapter:
700
class SystemBus(dbus.SystemBus):
703
def __init__(self, dbussy, ravel):
706
self.bus = ravel.system_bus()
708
@contextlib.contextmanager
709
def convert_exception(self, exception_class=dbus.Error):
712
except self.dbussy.DBusError as e:
713
# This does what "raise from" would do
714
exc = exception_class(*e.args)
718
def call_method(self, methodname, busname, objectpath,
720
proxy_object = self.get_object(busname, objectpath)
721
log.debug("D-Bus: %s:%s:%s.%s(%s)", busname, objectpath,
722
interface, methodname,
723
", ".join(repr(a) for a in args))
724
iface = proxy_object.get_interface(interface)
725
method = getattr(iface, methodname)
726
with self.convert_exception(dbus.Error):
727
value = method(*args)
728
# DBussy returns values either as an empty list or as a
729
# list of one element with the return value
731
return self.type_filter(value[0])
733
def get_object(self, busname, objectpath):
734
log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
736
with self.convert_exception(dbus.ConnectFailed):
737
return self.bus[busname][objectpath]
739
def type_filter(self, value):
740
"""Convert the most bothersome types to Python types"""
741
# A D-Bus Variant value is represented as the Python type
742
# Tuple[dbussy.DBUS.Signature, Any]
743
if isinstance(value, tuple):
745
and isinstance(value[0],
746
self.dbussy.DBUS.Signature)):
747
return self.type_filter(value[1])
748
elif isinstance(value, self.dbussy.DBUS.ObjectPath):
750
# Also recurse into dictionaries
751
elif isinstance(value, dict):
752
return {self.type_filter(key):
753
self.type_filter(subval)
754
for key, subval in value.items()}
757
def set_property(self, busname, objectpath, interface, key,
759
proxy_object = self.get_object(busname, objectpath)
760
log.debug("D-Bus: %s:%s:%s.Set(%r, %r, %r)", busname,
761
objectpath, self.properties_iface, interface,
764
# DBussy wants a Byte Array to be a sequence of
765
# values, not a byte string
767
setattr(proxy_object.get_interface(interface), key, value)
769
class MandosBus(SystemBus, dbus.MandosBus):
772
class CachingBus(MandosBus):
773
"""A caching layer for dbussy_adapter.MandosBus"""
774
def __init__(self, *args, **kwargs):
775
self.object_cache = {}
776
super(dbussy_adapter.CachingBus, self).__init__(*args,
778
def get_object(self, busname, objectpath):
780
return self.object_cache[(busname, objectpath)]
783
dbussy_adapter.CachingBus,
784
self).get_object(busname, objectpath)
785
self.object_cache[(busname, objectpath)] = new_object
789
552
def commands_from_options(options):
791
commands = list(options.commands)
793
def find_cmd(cmd, commands):
795
for i, c in enumerate(commands):
796
if isinstance(c, cmd):
800
# If command.Remove is present, move any instances of command.Deny
801
# to occur ahead of command.Remove.
802
index_of_remove = find_cmd(command.Remove, commands)
803
before_remove = commands[:index_of_remove]
804
after_remove = commands[index_of_remove:]
806
for cmd in after_remove:
807
if isinstance(cmd, command.Deny):
808
before_remove.append(cmd)
556
if options.is_enabled:
557
commands.append(command.IsEnabled())
560
commands.append(command.Approve())
563
commands.append(command.Deny())
566
commands.append(command.Remove())
568
if options.dump_json:
569
commands.append(command.DumpJSON())
572
commands.append(command.Enable())
575
commands.append(command.Disable())
577
if options.bump_timeout:
578
commands.append(command.BumpTimeout())
580
if options.start_checker:
581
commands.append(command.StartChecker())
583
if options.stop_checker:
584
commands.append(command.StopChecker())
586
if options.approved_by_default is not None:
587
if options.approved_by_default:
588
commands.append(command.ApproveByDefault())
810
cleaned_after.append(cmd)
811
if cleaned_after != after_remove:
812
commands = before_remove + cleaned_after
590
commands.append(command.DenyByDefault())
592
if options.checker is not None:
593
commands.append(command.SetChecker(options.checker))
595
if options.host is not None:
596
commands.append(command.SetHost(options.host))
598
if options.secret is not None:
599
commands.append(command.SetSecret(options.secret))
601
if options.timeout is not None:
602
commands.append(command.SetTimeout(options.timeout))
604
if options.extended_timeout:
606
command.SetExtendedTimeout(options.extended_timeout))
608
if options.interval is not None:
609
commands.append(command.SetInterval(options.interval))
611
if options.approval_delay is not None:
613
command.SetApprovalDelay(options.approval_delay))
615
if options.approval_duration is not None:
617
command.SetApprovalDuration(options.approval_duration))
814
619
# If no command option has been given, show table of clients,
815
620
# optionally verbosely
1232
1024
def test_actions_all_conflicts_with_verbose(self):
1233
1025
for action, value in self.actions.items():
1234
args = self.actionargs(action, value, "--all",
1026
options = self.parser.parse_args()
1027
setattr(options, action, value)
1029
options.verbose = True
1236
1030
with self.assertParseError():
1237
self.parse_args(args)
1031
self.check_option_syntax(options)
1239
1033
def test_actions_with_client_conflicts_with_verbose(self):
1240
1034
for action, value in self.actions.items():
1241
args = self.actionargs(action, value, "--verbose",
1035
options = self.parser.parse_args()
1036
setattr(options, action, value)
1037
options.verbose = True
1038
options.client = ["client"]
1243
1039
with self.assertParseError():
1244
self.parse_args(args)
1040
self.check_option_syntax(options)
1246
1042
def test_dump_json_conflicts_with_verbose(self):
1247
args = ["--dump-json", "--verbose"]
1043
options = self.parser.parse_args()
1044
options.dump_json = True
1045
options.verbose = True
1248
1046
with self.assertParseError():
1249
self.parse_args(args)
1047
self.check_option_syntax(options)
1251
1049
def test_dump_json_conflicts_with_action(self):
1252
1050
for action, value in self.actions.items():
1253
args = self.actionargs(action, value, "--dump-json")
1051
options = self.parser.parse_args()
1052
setattr(options, action, value)
1053
options.dump_json = True
1254
1054
with self.assertParseError():
1255
self.parse_args(args)
1055
self.check_option_syntax(options)
1257
1057
def test_all_can_not_be_alone(self):
1058
options = self.parser.parse_args()
1259
1060
with self.assertParseError():
1260
self.parse_args(args)
1061
self.check_option_syntax(options)
1262
1063
def test_all_is_ok_with_any_action(self):
1263
1064
for action, value in self.actions.items():
1264
args = self.actionargs(action, value, "--all")
1265
self.parse_args(args)
1065
options = self.parser.parse_args()
1066
setattr(options, action, value)
1068
self.check_option_syntax(options)
1267
1070
def test_any_action_is_ok_with_one_client(self):
1268
1071
for action, value in self.actions.items():
1269
args = self.actionargs(action, value, "client")
1270
self.parse_args(args)
1072
options = self.parser.parse_args()
1073
setattr(options, action, value)
1074
options.client = ["client"]
1075
self.check_option_syntax(options)
1272
1077
def test_one_client_with_all_actions_except_is_enabled(self):
1078
options = self.parser.parse_args()
1273
1079
for action, value in self.actions.items():
1274
if action == "--is-enabled":
1080
if action == "is_enabled":
1276
args = self.actionargs(action, value, "client")
1277
self.parse_args(args)
1082
setattr(options, action, value)
1083
options.client = ["client"]
1084
self.check_option_syntax(options)
1279
1086
def test_two_clients_with_all_actions_except_is_enabled(self):
1087
options = self.parser.parse_args()
1280
1088
for action, value in self.actions.items():
1281
if action == "--is-enabled":
1089
if action == "is_enabled":
1283
args = self.actionargs(action, value, "client1",
1285
self.parse_args(args)
1091
setattr(options, action, value)
1092
options.client = ["client1", "client2"]
1093
self.check_option_syntax(options)
1287
1095
def test_two_clients_are_ok_with_actions_except_is_enabled(self):
1288
1096
for action, value in self.actions.items():
1289
if action == "--is-enabled":
1097
if action == "is_enabled":
1291
args = self.actionargs(action, value, "client1",
1293
self.parse_args(args)
1099
options = self.parser.parse_args()
1100
setattr(options, action, value)
1101
options.client = ["client1", "client2"]
1102
self.check_option_syntax(options)
1295
1104
def test_is_enabled_fails_without_client(self):
1296
args = ["--is-enabled"]
1105
options = self.parser.parse_args()
1106
options.is_enabled = True
1297
1107
with self.assertParseError():
1298
self.parse_args(args)
1108
self.check_option_syntax(options)
1300
1110
def test_is_enabled_fails_with_two_clients(self):
1301
args = ["--is-enabled", "client1", "client2"]
1111
options = self.parser.parse_args()
1112
options.is_enabled = True
1113
options.client = ["client1", "client2"]
1302
1114
with self.assertParseError():
1303
self.parse_args(args)
1115
self.check_option_syntax(options)
1305
1117
def test_remove_can_only_be_combined_with_action_deny(self):
1306
1118
for action, value in self.actions.items():
1307
if action in {"--remove", "--deny"}:
1119
if action in {"remove", "deny"}:
1309
args = self.actionargs(action, value, "--all",
1121
options = self.parser.parse_args()
1122
setattr(options, action, value)
1124
options.remove = True
1311
1125
with self.assertParseError():
1312
self.parse_args(args)
1126
self.check_option_syntax(options)
1315
1129
class Test_dbus_exceptions(unittest.TestCase):
1729
1516
self.assertIs(obj1, obj1b)
1732
class Test_pydbus_adapter_SystemBus(TestCaseWithAssertLogs):
1734
def Stub_pydbus_func(self, func):
1736
"""stub pydbus module"""
1739
def get(busname, objectpath):
1740
DBusObject = collections.namedtuple(
1741
"DBusObject", ("methodname",))
1742
return {"interface":
1743
DBusObject(methodname=func)}
1746
def call_method(self, bus, methodname, busname, objectpath,
1748
with self.assertLogs(log, logging.DEBUG):
1749
return bus.call_method(methodname, busname, objectpath,
1752
def test_call_method_returns(self):
1753
expected_method_return = Unique()
1754
method_args = (Unique(), Unique())
1756
self.assertEqual(len(method_args), len(args))
1757
for marg, arg in zip(method_args, args):
1758
self.assertIs(marg, arg)
1759
return expected_method_return
1760
stub_pydbus = self.Stub_pydbus_func(func)
1761
bus = pydbus_adapter.SystemBus(stub_pydbus)
1762
ret = self.call_method(bus, "methodname", "busname",
1763
"objectpath", "interface",
1765
self.assertIs(ret, expected_method_return)
1767
def test_call_method_handles_exception(self):
1768
dbus_logger = logging.getLogger("dbus.proxies")
1771
raise gi.repository.GLib.Error()
1773
stub_pydbus = self.Stub_pydbus_func(func)
1774
bus = pydbus_adapter.SystemBus(stub_pydbus)
1776
with self.assertRaises(dbus.Error) as e:
1777
self.call_method(bus, "methodname", "busname",
1778
"objectpath", "interface")
1780
self.assertNotIsInstance(e.exception, dbus.ConnectFailed)
1782
def test_get_converts_to_correct_exception(self):
1783
bus = pydbus_adapter.SystemBus(
1784
self.fake_pydbus_raises_exception_on_connect)
1785
with self.assertRaises(dbus.ConnectFailed):
1786
self.call_method(bus, "methodname", "busname",
1787
"objectpath", "interface")
1789
class fake_pydbus_raises_exception_on_connect:
1790
"""fake dbus-python module"""
1793
def get(busname, objectpath):
1794
raise gi.repository.GLib.Error()
1795
Bus = collections.namedtuple("Bus", ["get"])
1798
def test_set_property_uses_setattr(self):
1805
def get(busname, objectpath):
1806
return {"interface": obj}
1807
bus = pydbus_adapter.SystemBus(pydbus_spy)
1809
bus.set_property("busname", "objectpath", "interface", "key",
1811
self.assertIs(value, obj.key)
1813
def test_get_suppresses_xml_deprecation_warning(self):
1814
if sys.version_info.major >= 3:
1816
class stub_pydbus_get:
1819
def get(busname, objectpath):
1820
warnings.warn_explicit(
1821
"deprecated", DeprecationWarning,
1822
"xml.etree.ElementTree", 0)
1823
bus = pydbus_adapter.SystemBus(stub_pydbus_get)
1824
with warnings.catch_warnings(record=True) as w:
1825
warnings.simplefilter("always")
1826
bus.get("busname", "objectpath")
1827
self.assertEqual(0, len(w))
1830
class Test_pydbus_adapter_CachingBus(unittest.TestCase):
1832
"""stub pydbus module"""
1835
def get(busname, objectpath):
1839
self.bus = pydbus_adapter.CachingBus(self.stub_pydbus)
1841
def test_returns_distinct_objectpaths(self):
1842
obj1 = self.bus.get("busname", "objectpath1")
1843
self.assertIsInstance(obj1, Unique)
1844
obj2 = self.bus.get("busname", "objectpath2")
1845
self.assertIsInstance(obj2, Unique)
1846
self.assertIsNot(obj1, obj2)
1848
def test_returns_distinct_busnames(self):
1849
obj1 = self.bus.get("busname1", "objectpath")
1850
self.assertIsInstance(obj1, Unique)
1851
obj2 = self.bus.get("busname2", "objectpath")
1852
self.assertIsInstance(obj2, Unique)
1853
self.assertIsNot(obj1, obj2)
1855
def test_returns_distinct_both(self):
1856
obj1 = self.bus.get("busname1", "objectpath")
1857
self.assertIsInstance(obj1, Unique)
1858
obj2 = self.bus.get("busname2", "objectpath")
1859
self.assertIsInstance(obj2, Unique)
1860
self.assertIsNot(obj1, obj2)
1862
def test_returns_same(self):
1863
obj1 = self.bus.get("busname", "objectpath")
1864
self.assertIsInstance(obj1, Unique)
1865
obj2 = self.bus.get("busname", "objectpath")
1866
self.assertIsInstance(obj2, Unique)
1867
self.assertIs(obj1, obj2)
1869
def test_returns_same_old(self):
1870
obj1 = self.bus.get("busname1", "objectpath1")
1871
self.assertIsInstance(obj1, Unique)
1872
obj2 = self.bus.get("busname2", "objectpath2")
1873
self.assertIsInstance(obj2, Unique)
1874
obj1b = self.bus.get("busname1", "objectpath1")
1875
self.assertIsInstance(obj1b, Unique)
1876
self.assertIsNot(obj1, obj2)
1877
self.assertIsNot(obj2, obj1b)
1878
self.assertIs(obj1, obj1b)
1881
class Test_dbussy_adapter_SystemBus(TestCaseWithAssertLogs):
1885
class ObjectPath(str):
1887
class DBusError(Exception):
1890
def fake_ravel_func(self, func):
1894
class DBusInterfaceProxy:
1896
def methodname(*args):
1897
return [func(*args)]
1900
def get_interface(interface):
1901
if interface == "interface":
1902
return DBusInterfaceProxy()
1903
return {"busname": {"objectpath": DBusObject()}}
1906
def call_method(self, bus, methodname, busname, objectpath,
1908
with self.assertLogs(log, logging.DEBUG):
1909
return bus.call_method(methodname, busname, objectpath,
1912
def test_call_method_returns(self):
1913
expected_method_return = Unique()
1914
method_args = (Unique(), Unique())
1916
self.assertEqual(len(method_args), len(args))
1917
for marg, arg in zip(method_args, args):
1918
self.assertIs(marg, arg)
1919
return expected_method_return
1920
fake_ravel = self.fake_ravel_func(func)
1921
bus = dbussy_adapter.SystemBus(self.dummy_dbussy, fake_ravel)
1922
ret = self.call_method(bus, "methodname", "busname",
1923
"objectpath", "interface",
1925
self.assertIs(ret, expected_method_return)
1927
def test_call_method_filters_objectpath(self):
1929
return method_return
1930
fake_ravel = self.fake_ravel_func(func)
1931
bus = dbussy_adapter.SystemBus(self.dummy_dbussy, fake_ravel)
1932
method_return = (self.dummy_dbussy.DBUS
1933
.ObjectPath("objectpath"))
1934
ret = self.call_method(bus, "methodname", "busname",
1935
"objectpath", "interface")
1936
self.assertEqual("objectpath", ret)
1937
self.assertNotIsInstance(ret,
1938
self.dummy_dbussy.DBUS.ObjectPath)
1940
def test_call_method_filters_objectpaths_in_dict(self):
1941
ObjectPath = self.dummy_dbussy.DBUS.ObjectPath
1943
return method_return
1944
fake_ravel = self.fake_ravel_func(func)
1945
bus = dbussy_adapter.SystemBus(self.dummy_dbussy, fake_ravel)
1947
ObjectPath("objectpath_key_1"):
1948
ObjectPath("objectpath_value_1"),
1949
ObjectPath("objectpath_key_2"):
1950
ObjectPath("objectpath_value_2"),
1952
ret = self.call_method(bus, "methodname", "busname",
1953
"objectpath", "interface")
1954
expected_method_return = {str(key): str(value)
1956
method_return.items()}
1957
for key, value in ret.items():
1958
self.assertNotIsInstance(key, ObjectPath)
1959
self.assertNotIsInstance(value, ObjectPath)
1960
self.assertEqual(expected_method_return, ret)
1961
self.assertIsInstance(ret, dict)
1963
def test_call_method_filters_objectpaths_in_dict_in_dict(self):
1964
ObjectPath = self.dummy_dbussy.DBUS.ObjectPath
1966
return method_return
1967
fake_ravel = self.fake_ravel_func(func)
1968
bus = dbussy_adapter.SystemBus(self.dummy_dbussy, fake_ravel)
1970
ObjectPath("key1"): {
1971
ObjectPath("key11"): ObjectPath("value11"),
1972
ObjectPath("key12"): ObjectPath("value12"),
1974
ObjectPath("key2"): {
1975
ObjectPath("key21"): ObjectPath("value21"),
1976
ObjectPath("key22"): ObjectPath("value22"),
1979
ret = self.call_method(bus, "methodname", "busname",
1980
"objectpath", "interface")
1981
expected_method_return = {
1982
"key1": {"key11": "value11",
1983
"key12": "value12"},
1984
"key2": {"key21": "value21",
1985
"key22": "value22"},
1987
self.assertEqual(expected_method_return, ret)
1988
for key, value in ret.items():
1989
self.assertIsInstance(value, dict)
1990
self.assertEqual(expected_method_return[key], value)
1991
self.assertNotIsInstance(key, ObjectPath)
1992
for inner_key, inner_value in value.items():
1993
self.assertIsInstance(value, dict)
1995
expected_method_return[key][inner_key],
1997
self.assertNotIsInstance(key, ObjectPath)
1999
def test_call_method_filters_objectpaths_in_dict_three_deep(self):
2000
ObjectPath = self.dummy_dbussy.DBUS.ObjectPath
2002
return method_return
2003
fake_ravel = self.fake_ravel_func(func)
2004
bus = dbussy_adapter.SystemBus(self.dummy_dbussy, fake_ravel)
2006
ObjectPath("key1"): {
2007
ObjectPath("key2"): {
2008
ObjectPath("key3"): ObjectPath("value"),
2012
ret = self.call_method(bus, "methodname", "busname",
2013
"objectpath", "interface")
2014
expected_method_return = {"key1": {"key2": {"key3": "value"}}}
2015
self.assertEqual(expected_method_return, ret)
2016
self.assertIsInstance(ret, dict)
2017
self.assertNotIsInstance(next(iter(ret.keys())), ObjectPath)
2018
self.assertIsInstance(ret["key1"], dict)
2019
self.assertNotIsInstance(next(iter(ret["key1"].keys())),
2021
self.assertIsInstance(ret["key1"]["key2"], dict)
2022
self.assertNotIsInstance(
2023
next(iter(ret["key1"]["key2"].keys())),
2025
self.assertEqual("value", ret["key1"]["key2"]["key3"])
2026
self.assertNotIsInstance(ret["key1"]["key2"]["key3"],
2027
self.dummy_dbussy.DBUS.ObjectPath)
2029
def test_call_method_handles_exception(self):
2031
raise self.dummy_dbussy.DBusError()
2033
fake_ravel = self.fake_ravel_func(func)
2034
bus = dbussy_adapter.SystemBus(self.dummy_dbussy, fake_ravel)
2036
with self.assertRaises(dbus.Error) as e:
2037
self.call_method(bus, "methodname", "busname",
2038
"objectpath", "interface")
2040
self.assertNotIsInstance(e.exception, dbus.ConnectFailed)
2042
def test_get_object_converts_to_correct_exception(self):
2043
class fake_ravel_raises_exception_on_connect:
2048
def __getitem__(key):
2049
if key == "objectpath":
2050
raise self.dummy_dbussy.DBusError()
2051
raise Exception(key)
2052
return {"busname": Bus()}
2054
raise self.dummy_dbussy.DBusError()
2055
bus = dbussy_adapter.SystemBus(
2057
fake_ravel_raises_exception_on_connect)
2058
with self.assertRaises(dbus.ConnectFailed):
2059
self.call_method(bus, "methodname", "busname",
2060
"objectpath", "interface")
2063
1519
class Test_commands_from_options(unittest.TestCase):
2065
1521
def setUp(self):
2826
2227
if __name__ == "__main__":
2827
options = parse_test_args()
2830
extra_test_prefix = options.prefix
2831
if extra_test_prefix is not None:
2832
if not (unittest.main(argv=[""], exit=False)
2833
.result.wasSuccessful()):
2835
class ExtraTestLoader(unittest.TestLoader):
2836
testMethodPrefix = extra_test_prefix
2837
# Call using ./scriptname --check [--verbose]
2838
unittest.main(argv=[""], testLoader=ExtraTestLoader())
2840
unittest.main(argv=[""])
2229
if should_only_run_tests():
2230
# Call using ./tdd-python-script --check [--verbose]
2844
2235
logging.shutdown()
2848
# (lambda (&optional extra)
2849
# (if (not (funcall run-tests-in-test-buffer default-directory
2851
# (funcall show-test-buffer-in-test-window)
2852
# (funcall remove-test-window)
2853
# (if extra (message "Extra tests run successfully!"))))
2854
# run-tests-in-test-buffer:
2855
# (lambda (dir &optional extra)
2856
# (with-current-buffer (get-buffer-create "*Test*")
2857
# (setq buffer-read-only nil
2858
# default-directory dir)
2860
# (compilation-mode))
2861
# (let ((process-result
2862
# (let ((inhibit-read-only t))
2863
# (process-file-shell-command
2864
# (funcall get-command-line extra) nil "*Test*"))))
2865
# (and (numberp process-result)
2866
# (= process-result 0))))
2868
# (lambda (&optional extra)
2869
# (let ((quoted-script
2870
# (shell-quote-argument (funcall get-script-name))))
2872
# (concat "%s --check" (if extra " --prefix=atest" ""))
2876
# (if (fboundp 'file-local-name)
2877
# (file-local-name (buffer-file-name))
2878
# (or (file-remote-p (buffer-file-name) 'localname)
2879
# (buffer-file-name))))
2880
# remove-test-window:
2882
# (let ((test-window (get-buffer-window "*Test*")))
2883
# (if test-window (delete-window test-window))))
2884
# show-test-buffer-in-test-window:
2886
# (when (not (get-buffer-window-list "*Test*"))
2887
# (setq next-error-last-buffer (get-buffer "*Test*"))
2888
# (let* ((side (if (>= (window-width) 146) 'right 'bottom))
2889
# (display-buffer-overriding-action
2890
# `((display-buffer-in-side-window) (side . ,side)
2891
# (window-height . fit-window-to-buffer)
2892
# (window-width . fit-window-to-buffer))))
2893
# (display-buffer "*Test*"))))
2896
# (let* ((run-extra-tests (lambda () (interactive)
2897
# (funcall run-tests t)))
2898
# (inner-keymap `(keymap (116 . ,run-extra-tests))) ; t
2899
# (outer-keymap `(keymap (3 . ,inner-keymap)))) ; C-c
2900
# (setq minor-mode-overriding-map-alist
2901
# (cons `(run-tests . ,outer-keymap)
2902
# minor-mode-overriding-map-alist)))
2903
# (add-hook 'after-save-hook run-tests 90 t))