async def assign_scope(self, app_id: str, proc: Process): """ Assign process (and all unassigned children) to the app-{app_id}.slice/app{app_id}-{pid}.scope cgroup """ app_id = escape_app_id(app_id) sd_slice = SD_SLICE_FORMAT.format(app_id=app_id) sd_unit = SD_UNIT_FORMAT.format(app_id=app_id, unique=proc.pid) # Collect child processes as systemd assigns a scope only to explicitly # specified PIDs. # There's a risk of race as the child processes may exit by the time dbus call # reaches systemd, hence the @retry decorator is applied to the method. pids = [proc.pid] + [ x.pid for x in proc.children(recursive=True) if self.cgroup_change_needed(get_cgroup(x.pid)) ] await self._sd_manager.call_start_transient_unit( sd_unit, "fail", [["PIDs", Variant("au", pids)], ["Slice", Variant("s", sd_slice)]], [], ) LOG.debug("window %s successfully assigned to cgroup %s/%s", app_id, sd_slice, sd_unit)
async def test_scan_all_powered(self) -> None: # GIVEN self.net_connman_manager.stub_set_technologies([ ("/eth", self.sample_tech_props), ( "/wifi", { "Name": Variant("s", "Wifi"), "Type": Variant("s", "wifi"), "Connected": Variant("b", False), "Powered": Variant("b", True), }, ), ]) net_connman_tech = NetConnmanTechnologyStub() self.bus.stub_register_interface("/wifi", "net.connman.Technology", net_connman_tech) mgr = ConnmanManagerImpl(self.bus) await mgr.setup() # WHEN assert len(mgr.technologies) > 0 scanned = await mgr.scan_all() # THEN assert scanned == 1 # only wifi is scanned assert net_connman_tech.scan_called == 1
async def test_track_service_props(self) -> None: # GIVEN mgr = ConnmanManagerImpl(self.bus) svc1_iface = NetConnmanServiceStub() self.bus.stub_register_interface("/svc1", "net.connman.Service", svc1_iface) await mgr.setup() self.net_connman_manager.stub_update_services( [( "/svc1", self.sample_service_props, )], [], ) await asyncio.sleep(0) svcs = mgr.list_services() assert len(svcs) == 1 # WHEN svc1_iface.stub_properties_changed({ "Strength": Variant("i", 56), "State": Variant("s", "online") }) # THEN svcs = mgr.list_services() assert len(svcs) == 1 svc1 = svcs[0] assert svc1.path == "/svc1" assert svc1.name == "Skynet" assert svc1.state == ConnmanServiceState.ONLINE assert svc1.strength == 56
def test_contains_type(): tree = SignatureTree('h') assert signature_contains_type(tree, [0], 'h') assert not signature_contains_type(tree, [0], 'u') tree = SignatureTree('ah') assert signature_contains_type(tree, [[0]], 'h') assert signature_contains_type(tree, [[0]], 'a') assert not signature_contains_type(tree, [[0]], 'u') tree = SignatureTree('av') body = [[ Variant('u', 0), Variant('i', 0), Variant('x', 0), Variant('v', Variant('s', 'hi')) ]] assert signature_contains_type(tree, body, 'u') assert signature_contains_type(tree, body, 'x') assert signature_contains_type(tree, body, 'v') assert signature_contains_type(tree, body, 's') assert not signature_contains_type(tree, body, 'o') tree = SignatureTree('a{sv}') body = { 'foo': Variant('h', 0), 'bar': Variant('i', 0), 'bat': Variant('x', 0), 'baz': Variant('v', Variant('o', '/hi')) } for expected in 'hixvso': assert signature_contains_type(tree, [body], expected) assert not signature_contains_type(tree, [body], 'b')
async def test_services_changed_incomplete_data1(self) -> None: # GIVEN mgr = ConnmanManagerImpl(self.bus) svc1_iface = NetConnmanServiceStub() self.bus.stub_register_interface("/svc1", "net.connman.Service", svc1_iface) await mgr.setup() incomplete_props = { "Name": Variant("s", "Skynet"), "Type": Variant("s", "ethernet"), } # WHEN self.net_connman_manager.stub_update_services( [( "/svc1", incomplete_props, )], [], ) await asyncio.sleep(0) svcs = mgr.list_services() # THEN assert len(svcs) == 1 svc1 = svcs[0] assert svc1.path == "/svc1" assert svc1.name == "Skynet" assert svc1.state == ConnmanServiceState.IDLE
async def test_agent_request_input(self) -> None: # GIVEN self.svc_iface.stub_properties_changed(self.sample_service_props) # WHEN inp = Variant("a{sv}", {"one": Variant("i", 1)}) res = await agent_request_input(self.bus, self.agent, "/svc1", inp) assert res == {"one": Variant("s", "input")}
async def clear(self, instance=None): block = { 'name': Variant('s', self.name), 'full_text': Variant('s', ''), } if instance: block['instance'] = instance await self.i3dstatus.call_show_block(block)
async def test_format(bus_address): bus = await MessageBus(bus_address=bus_address).connect() reply = await bus.request_name(f'org.mpris.MediaPlayer2.format_test') assert reply == RequestNameReply.PRIMARY_OWNER mpris = MprisPlayer() bus.export('/org/mpris/MediaPlayer2', mpris) TITLE = 'A Title' ARTIST = 'An Artist' mpris.metadata = { 'xesam:title': Variant('s', TITLE), 'xesam:artist': Variant('as', [ARTIST]), 'xesam:escapeme': Variant('s', '<hi>'), 'mpris:length': Variant('x', 100000) } playerctl = PlayerctlCli(bus_address) cmd = await playerctl.run('metadata --format "{{artist}} - {{title}}"') assert cmd.stdout == f'{ARTIST} - {TITLE}' cmd = await playerctl.run( 'metadata --format "{{markup_escape(xesam:escapeme)}}"') assert cmd.stdout == '<hi>' cmd = await playerctl.run('metadata --format "{{lc(artist)}}"') assert cmd.stdout == ARTIST.lower() cmd = await playerctl.run('metadata --format "{{uc(title)}}"') assert cmd.stdout == TITLE.upper() cmd = await playerctl.run('metadata --format "{{uc(lc(title))}}"') assert cmd.stdout == TITLE.upper() cmd = await playerctl.run('metadata --format \'{{uc("Hi")}}\'') assert cmd.stdout == "HI" cmd = await playerctl.run('metadata --format "{{mpris:length}}"') assert cmd.stdout == "100000" cmd = await playerctl.run( 'metadata --format \'@{{ uc( "hi" ) }} - {{uc( lc( "HO" ) ) }} . {{lc( uc( title ) ) }}@\'' ) assert cmd.stdout == '@HI - HO . a title@' cmd = await playerctl.run( 'metadata --format \'{{default(xesam:missing, artist)}}\'') assert cmd.stdout == ARTIST cmd = await playerctl.run( 'metadata --format \'{{default(title, artist)}}\'') assert cmd.stdout == TITLE cmd = await playerctl.run('metadata --format \'{{default("", "ok")}}\'') assert cmd.stdout == 'ok' cmd = await playerctl.run('metadata --format \'{{default("ok", "not")}}\'') assert cmd.stdout == 'ok'
async def test_methods(): bus1 = await MessageBus().connect() bus2 = await MessageBus().connect() interface = ExampleInterface('test.interface') export_path = '/test/path' async def call(member, signature='', body=[]): return await bus2.call( Message(destination=bus1.unique_name, path=export_path, interface=interface.name, member=member, signature=signature, body=body)) bus1.export(export_path, interface) body = ['hello world'] reply = await call('echo', 's', body) assert reply.message_type == MessageType.METHOD_RETURN, reply.body[0] assert reply.signature == 's' assert reply.body == body body = ['hello', 'world'] reply = await call('echo_multiple', 'ss', body) assert reply.message_type == MessageType.METHOD_RETURN, reply.body[0] assert reply.signature == 'ss' assert reply.body == body body = [['hello', 'world'], Variant('v', Variant('(ss)', ['hello', 'world'])), { 'foo': Variant('t', 100) }, ['one', ['two', [Variant('s', 'three')]]]] signature = 'asva{sv}(s(s(v)))' SignatureTree(signature).verify(body) reply = await call('echo_containers', signature, body) assert reply.message_type == MessageType.METHOD_RETURN, reply.body[0] assert reply.signature == signature assert reply.body == body reply = await call('ping') assert reply.message_type == MessageType.METHOD_RETURN, reply.body[0] assert reply.signature == '' assert reply.body == [] reply = await call('throws_unexpected_error') assert reply.message_type == MessageType.ERROR, reply.body[0] assert reply.error_name == ErrorType.SERVICE_ERROR.value, reply.body[0] reply = await call('throws_dbus_error') assert reply.message_type == MessageType.ERROR, reply.body[0] assert reply.error_name == 'test.error', reply.body[0] assert reply.body == ['an error ocurred']
def get_vendor_models(self) -> "a(qqa{sv})": models = [] for model_id, publish, subscribe in self.element.vendor_models: models.append([ *model_id, { "Publish": Variant("b", publish), "Subscribe": Variant("b", subscribe), }, ]) return models
async def test_on_service_prop_changed(self) -> None: # GIVEN mgr = ConnmanManagerImpl(self.bus) svc1_iface = NetConnmanServiceStub() self.bus.stub_register_interface("/svc1", "net.connman.Service", svc1_iface) await mgr.setup() self.net_connman_manager.stub_update_services( [( "/svc1", self.sample_service_props, )], [], ) await asyncio.sleep(0) class ServiceListener: def __init__(self, counter) -> None: self.counter = counter def prop_changed(self, svc: ConnmanService) -> None: self.counter.update(["changed"]) cnt: TCounter[str] = Counter() listener = ServiceListener(cnt) svcs = mgr.list_services() assert len(svcs) == 1 svc1 = svcs[0] mgr.on_service_property_changed(svc1, listener.prop_changed) # WHEN svc1_iface.stub_properties_changed({ "Strength": Variant("i", 56), "State": Variant("s", "online") }) # THEN # 2 properties have changed assert cnt["changed"] == 2 # WHEN # After listener is deleted, counter should not change (we should # not keep references to the listener and allow it to be destroyed) del listener svc1_iface.stub_properties_changed({"Strength": Variant("i", 32)}) # THEN # Changes are not registered anymore assert cnt["changed"] == 2
async def publish( self, element_path: str, model: int, data: bytes, force_segmented: bool = False, vendor: Optional[int] = None, ) -> None: options = dict(ForceSegmented=Variant("b", force_segmented)) if vendor: options["Vendor"] = Variant("q", vendor) await self._interface.call_publish(element_path, model, options, data)
async def show(self, full_text, instance=None, markup=None, context=None): block = { 'name': Variant('s', self.name), 'full_text': Variant('s', Block.expand_template(full_text, context)), } if markup is True: markup = "pango" if markup: block['markup'] = Variant('s', markup) if instance: block['instance'] = Variant('s', instance) await self.i3dstatus.call_show_block(block)
async def _send( self, notification: Notification, notification_to_replace: Optional[Notification], ) -> int: """ Asynchronously sends a notification via the Dbus interface. :param notification: Notification to send. :param notification_to_replace: Notification to replace, if any. """ if not self.interface: self.interface = await self._init_dbus() if notification_to_replace: replaces_nid = notification_to_replace.identifier else: replaces_nid = 0 # Create list of actions with default and user-supplied. actions = ["default", "default"] for n, button in enumerate(notification.buttons): actions += [str(n), button.title] hints = {"urgency": self._to_native_urgency[notification.urgency]} # sound if notification.sound: hints["sound-name"] = Variant("s", "message-new-instant") # attachment if notification.attachment: hints["image-path"] = Variant("s", notification.attachment) # Post the new notification and record the platform ID assigned to it. platform_nid = await self.interface.call_notify( # type: ignore self.app_name, # app_name replaces_nid, # replaces_id notification.icon or "", # app_icon notification.title, # summary notification.message, # body actions, # actions hints, # hints -1, # expire_timeout (-1 = default) ) return platform_nid
async def _notify(title, message, urgency, timeout, id): notification = [ "qtile", # Application name id, # id "", # icon title, # summary message, # body [""], # actions { "urgency": Variant("y", urgency) }, # hints timeout ] # timeout bus, msg = await _send_dbus_message(True, MessageType.METHOD_CALL, "org.freedesktop.Notifications", "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "Notify", "susssasa{sv}i", notification) if msg.message_type == MessageType.ERROR: logger.warning("Unable to send notification. " "Is a notification server running?") # a new bus connection is made each time a notification is sent so # we disconnect when the notification is done bus.disconnect()
def unpack_variants(var: Union[Variant, Any], tp: SignatureType = None) -> Any: if not isinstance(var, Variant): if tp is None: return var var = Variant(tp, var) if var.type.token == "(": return [ unpack_variants(v, t) for t, v in zip(var.type.children, var.value) ] if var.type.token == "a": assert len(var.type.children) == 1 childtype = var.type.children[0] if childtype.token == "{": kt, vt = childtype.children # a dict return { unpack_variants(k, kt): unpack_variants(v, vt) for k, v in var.value.items() } if childtype.token == "y": # array of bytes, special case return var.value # This is a list of items return [unpack_variants(v, childtype) for v in var.value] return var.value
async def test_setup(self, ovshell: testing.OpenVarioShellStub) -> None: # GIVEN mgr = ConnmanManagerImpl(await ovshell.os.get_system_bus()) # WHEN await mgr.setup() assert len(mgr.technologies) == 0 self.net_connman_manager.stub_set_technologies([( "/path1", { "Name": Variant("s", "One"), "Type": Variant("s", "wifi"), "Connected": Variant("b", False), "Powered": Variant("b", False), }, )]) # THEN assert len(mgr.technologies) == 1
async def test_setup(self, ovshell: testing.OpenVarioShellStub) -> None: # GIVEN bus = ovshell.os.stub_connect_bus() net_connman_manager = NetConnmanManagerStub() net_connman_manager.stub_set_technologies([( "/path1", { "Name": Variant("s", "One"), "Type": Variant("s", "wifi"), "Connected": Variant("b", False), "Powered": Variant("b", False), }, )]) bus.stub_register_interface("/", "net.connman.Manager", net_connman_manager) mgr = ConnmanManagerImpl(await ovshell.os.get_system_bus()) # WHEN await mgr.setup() # THEN assert len(mgr.technologies) == 1
def test_signal_handling(monkeypatch): def new_update(self, text): self.text = text monkeypatch.setattr("libqtile.widget.bluetooth.Bluetooth.update", new_update) widget = libqtile.widget.bluetooth.Bluetooth() widget.connected = True widget.device = "Mock Bluetooth Device" widget.powered = True widget.update_text() assert widget.text == "Mock Bluetooth Device" widget._signal_received(None, {"Name": Variant("s", "New Device Name")}, None) assert widget.text == "New Device Name" widget._signal_received(None, {"Connected": Variant("b", False)}, None) assert widget.text == "on" widget._signal_received(None, {"Powered": Variant("b", False)}, None) assert widget.text == "off"
async def agent_request_input(bus: BaseMessageBus, impl: ConnmanAgent, service, fields): introspection = await bus.introspect("net.connman", service) proxy = bus.get_proxy_object("net.connman", service, introspection) iface = proxy.get_interface("net.connman.Service") props = await iface.call_get_properties() svc = model.create_service_from_props(service, props) plain_fields = unpack_variants(fields, "a{sv}") try: res = await impl.request_input(svc, plain_fields) except Canceled as e: raise DBusError("net.connman.Agent.Error.Canceled", str(e)) varres = {k: Variant("s", v) for k, v in res.items() if v is not None} return varres
async def send( self, element_path: str, destination: int, key_index: int, data: bytes, force_segmented: bool = False, ) -> None: await self._interface.call_send( element_path, destination, key_index, dict(ForceSegmented=Variant("b", force_segmented)), data, flags=MessageFlag.NO_REPLY_EXPECTED, )
async def test_services_changed(self) -> None: # GIVEN mgr = ConnmanManagerImpl(self.bus) svc1_iface = NetConnmanServiceStub() self.bus.stub_register_interface("/svc1", "net.connman.Service", svc1_iface) await mgr.setup() self.net_connman_manager.stub_update_services( [( "/svc1", self.sample_service_props, )], [], ) await asyncio.sleep(0) # WHEN svcs = mgr.list_services() # THEN assert len(svcs) == 1 svc1 = svcs[0] assert svc1.path == "/svc1" assert svc1.name == "Skynet" assert svc1.state == ConnmanServiceState.IDLE # Manager should be subscribed to service updates now signals = svc1_iface.stub_get_signals() assert signals.keys() == {"property_changed"} # WHEN self.net_connman_manager.stub_update_services( [("/svc1", { "State": Variant("s", "online") })], [], ) # THEN svcs = mgr.list_services() assert len(svcs) == 1 svc1 = svcs[0] assert svc1.path == "/svc1" assert svc1.name == "Skynet" assert svc1.state == ConnmanServiceState.ONLINE
async def request_input( self, service: "o", fields: "a{sv}", # type: ignore ) -> "a{sv}": # type: ignore """This method gets called when trying to connect to a service and some extra input is required. For example a passphrase or the name of a hidden network. The return value should be a dictionary where the keys are the field names and the values are the actual fields. Alternatively an error indicating that the request got canceled can be returned. OperationAborted will be return on a successful cancel request. Most common return field names are "Name" and of course "Passphrase". The dictionary arguments contains field names with their input parameters. In case of WISPr credentials requests and if the user prefers to login through the browser by himself, agent will have to return a LaunchBrowser error (see below). Possible Errors: net.connman.Agent.Error.Canceled net.connman.Agent.Error.LaunchBrowser """ # Fetch the service properties introspection = await self._bus.introspect("net.connman", service) proxy = self._bus.get_proxy_object("net.connman", service, introspection) iface = proxy.get_interface("net.connman.Service") props = await iface.call_get_properties() svc = model.create_service_from_props(service, props) plain_fields = unpack_variants(fields, "a{sv}") print("REQUEST INPUT", svc, plain_fields) try: res = await self._impl.request_input(svc, plain_fields) except Canceled as e: raise DBusError("net.connman.Agent.Error.Canceled", str(e)) varres = {k: Variant("s", v) for k, v in res.items()} return varres
async def test_scan_all(self, ovshell: testing.OpenVarioShellStub) -> None: # GIVEN bus = ovshell.os.stub_connect_bus() net_connman_manager = NetConnmanManagerStub() net_connman_manager.stub_set_technologies([ ( "/eth", { "Name": Variant("s", "Ethernet"), "Type": Variant("s", "ethernet"), "Connected": Variant("b", False), "Powered": Variant("b", False), }, ), ( "/wifi", { "Name": Variant("s", "Wifi"), "Type": Variant("s", "wifi"), "Connected": Variant("b", False), "Powered": Variant("b", False), }, ), ]) net_connman_tech = NetConnmanTechnologyStub() bus.stub_register_interface("/", "net.connman.Manager", net_connman_manager) bus.stub_register_interface("/wifi", "net.connman.Technology", net_connman_tech) mgr = ConnmanManagerImpl(await ovshell.os.get_system_bus()) await mgr.setup() # WHEN assert len(mgr.technologies) > 0 scanned = await mgr.scan_all() # THEN assert scanned == 1 # only wifi is scanned assert net_connman_tech.scan_called == 1
async def test_property_changed_signal(interface_class): bus1 = await MessageBus().connect() bus2 = await MessageBus().connect() await bus2.call( Message(destination='org.freedesktop.DBus', path='/org/freedesktop/DBus', interface='org.freedesktop.DBus', member='AddMatch', signature='s', body=[f'sender={bus1.unique_name}'])) interface = interface_class('test.interface') export_path = '/test/path' bus1.export(export_path, interface) async def wait_for_message(): # TODO timeout future = asyncio.get_event_loop().create_future() def message_handler(signal): if signal.interface == 'org.freedesktop.DBus.Properties': bus2.remove_message_handler(message_handler) future.set_result(signal) bus2.add_message_handler(message_handler) return await future bus2.send( Message(destination=bus1.unique_name, interface=interface.name, path=export_path, member='do_emit_properties_changed')) signal = await wait_for_message() assert signal.interface == 'org.freedesktop.DBus.Properties' assert signal.member == 'PropertiesChanged' assert signal.signature == 'sa{sv}as' assert signal.body == [ interface.name, { 'string_prop': Variant('s', 'asdf') }, ['container_prop'] ]
async def test_get_state(self) -> None: # GIVEN mgr = ConnmanManagerImpl(self.bus) await mgr.setup() await asyncio.sleep(0) # WHEN state = mgr.get_state() # THEN assert state == ConnmanState.UNKNOWN # WHEN self.net_connman_manager.stub_set_properties( {"State": Variant("s", "online")}) state = mgr.get_state() # THEN assert state == ConnmanState.ONLINE
async def test_emoji(bus_address): [mpris] = await setup_mpris('emoji-format-test', bus_address=bus_address) mpris.metadata = {'mpris:length': Variant('x', 100000)} await mpris.ping() playerctl = PlayerctlCli(bus_address) status_emoji_cmd = 'metadata --format \'{{emoji(status)}}\'' mpris.playback_status = 'Playing' cmd = await playerctl.run(status_emoji_cmd) assert cmd.stdout == '▶️', cmd.stderr mpris.playback_status = 'Paused' cmd = await playerctl.run(status_emoji_cmd) assert cmd.stdout == '⏸️', cmd.stderr mpris.playback_status = 'Stopped' cmd = await playerctl.run(status_emoji_cmd) assert cmd.stdout == '⏹️', cmd.stderr volume_emoji_cmd = 'metadata --format \'{{emoji(volume)}}\'' mpris.volume = 0.0 cmd = await playerctl.run(volume_emoji_cmd) assert cmd.stdout == '🔈', cmd.stderr mpris.volume = 0.5 cmd = await playerctl.run(volume_emoji_cmd) assert cmd.stdout == '🔉', cmd.stderr mpris.volume = 1.0 cmd = await playerctl.run(volume_emoji_cmd) assert cmd.stdout == '🔊', cmd.stderr cmd = await playerctl.run('metadata --format \'{{emoji("hi")}}\'') assert cmd.returncode == 1, cmd.stderr cmd = await playerctl.run('metadata --format \'{{emoji(status, volume)}}\'' ) assert cmd.returncode == 1, cmd.stderr await mpris.disconnect()
async def test_tech_power(self) -> None: # GIVEN self.net_connman_manager.stub_set_technologies([ ("/eth", self.sample_tech_props) ]) net_connman_tech = NetConnmanTechnologyStub() self.bus.stub_register_interface("/eth", "net.connman.Technology", net_connman_tech) mgr = ConnmanManagerImpl(self.bus) await mgr.setup() await asyncio.sleep(0) # WHEN techs = mgr.technologies assert len(techs) == 1 tech_eth = techs[0] await mgr.power(tech_eth, on=True) # THEN assert net_connman_tech.props_updated == [("Powered", Variant("b", True))]
def replace_variants(type_, item): if type_.token == 'v' and type(item) is not Variant: item = Variant( item['signature'], replace_variants( SignatureTree(item['signature']).types[0], item['value'])) elif type_.token == 'a': for i, item_child in enumerate(item): if type_.children[0].token == '{': for k, v in item.items(): item[k] = replace_variants(type_.children[0].children[1], v) else: item[i] = replace_variants(type_.children[0], item_child) elif type_.token == '(': for i, item_child in enumerate(item): if type_.children[0].token == '{': assert False else: item[i] = replace_variants(type_.children[i], item_child) return item
def setup(self, ovshell: testing.OpenVarioShellStub) -> None: self.bus = ovshell.os.stub_connect_bus() self.net_connman_manager = NetConnmanManagerStub() self.bus.stub_register_interface("/", "net.connman.Manager", self.net_connman_manager) self.agent = ConnmanAgentStub() self.agentiface = ConnmanAgentInterface(self.agent, self.bus) self.svc_iface = NetConnmanServiceStub() self.bus.stub_register_interface("/svc1", "net.connman.Service", self.svc_iface) self.sample_service_props = { "AutoConnect": Variant("b", False), "Favorite": Variant("b", False), "Name": Variant("s", "Skynet"), "Security": Variant("s", "wpa"), "Strength": Variant("i", 78), "Type": Variant("s", "wifi"), "State": Variant("s", "idle"), }