ruby-dbus 0.22.1 → 0.23.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
5
+ # Copyright (C) 2023 Martin Vidner
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License, version 2.1 as published by the Free Software Foundation.
10
+ # See the file "COPYING" for the exact licensing terms.
11
+
12
+ module DBus
13
+ # Has a tree of {Node}s, refering to {Object}s or to {ProxyObject}s.
14
+ class NodeTree
15
+ # @return [Node]
16
+ attr_reader :root
17
+
18
+ def initialize
19
+ @root = Node.new("/")
20
+ end
21
+
22
+ # Get the object node corresponding to the given *path*.
23
+ # @param path [ObjectPath]
24
+ # @param create [Boolean] if true, the the {Node}s in the path are created
25
+ # if they do not already exist.
26
+ # @return [Node,nil]
27
+ def get_node(path, create: false)
28
+ n = @root
29
+ path.sub(%r{^/}, "").split("/").each do |elem|
30
+ if !(n[elem])
31
+ return nil if !create
32
+
33
+ n[elem] = Node.new(elem)
34
+ end
35
+ n = n[elem]
36
+ end
37
+ n
38
+ end
39
+ end
40
+
41
+ # = Object path node class
42
+ #
43
+ # Class representing a node on an object path.
44
+ class Node < Hash
45
+ # @return [DBus::Object,DBus::ProxyObject,nil]
46
+ # The D-Bus object contained by the node.
47
+ attr_accessor :object
48
+
49
+ # The name of the node.
50
+ # @return [String] the last component of its object path, or "/"
51
+ attr_reader :name
52
+
53
+ # Create a new node with a given _name_.
54
+ def initialize(name)
55
+ super()
56
+ @name = name
57
+ @object = nil
58
+ end
59
+
60
+ # Return an XML string representation of the node.
61
+ # It is shallow, not recursing into subnodes
62
+ # @param node_opath [String]
63
+ def to_xml(node_opath)
64
+ xml = '<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
65
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
66
+ '
67
+ xml += "<node name=\"#{node_opath}\">\n"
68
+ each_key do |k|
69
+ xml += " <node name=\"#{k}\" />\n"
70
+ end
71
+ @object&.intfs&.each_value do |v|
72
+ xml += v.to_xml
73
+ end
74
+ xml += "</node>"
75
+ xml
76
+ end
77
+
78
+ # Return inspect information of the node.
79
+ def inspect
80
+ # Need something here
81
+ "<DBus::Node #{sub_inspect}>"
82
+ end
83
+
84
+ # Return instance inspect information, used by Node#inspect.
85
+ def sub_inspect
86
+ s = ""
87
+ if !@object.nil?
88
+ s += format("%x ", @object.object_id)
89
+ end
90
+ contents_sub_inspect = keys
91
+ .map { |k| "#{k} => #{self[k].sub_inspect}" }
92
+ .join(",")
93
+ "#{s}{#{contents_sub_inspect}}"
94
+ end
95
+
96
+ # All objects (not paths) under this path (except itself).
97
+ # @return [Array<DBus::Object>]
98
+ def descendant_objects
99
+ children_objects = values.map(&:object).compact
100
+ descendants = values.map(&:descendant_objects)
101
+ flat_descendants = descendants.reduce([], &:+)
102
+ children_objects + flat_descendants
103
+ end
104
+ end
105
+ end
data/lib/dbus/object.rb CHANGED
@@ -26,20 +26,29 @@ module DBus
26
26
  my_class_attribute :intfs
27
27
  self.intfs = {}
28
28
 
29
- # The service that the object is exported by.
30
- attr_writer :service
29
+ # @return [Connection] the connection the object is exported by
30
+ attr_reader :connection
31
31
 
32
32
  @@cur_intf = nil # Interface
33
33
  @@intfs_mutex = Mutex.new
34
34
 
35
35
  # Create a new object with a given _path_.
36
- # Use Service#export to export it.
36
+ # Use ObjectServer#export to export it.
37
37
  def initialize(path)
38
38
  @path = path
39
- @service = nil
39
+ @connection = nil
40
+ end
41
+
42
+ # @param connection [Connection] the connection the object is exported by
43
+ def connection=(connection)
44
+ @connection = connection
45
+ # deprecated, keeping @service for compatibility
46
+ @service = connection&.object_server
40
47
  end
41
48
 
42
49
  # Dispatch a message _msg_ to call exported methods
50
+ # @param msg [Message] only METHOD_CALLS do something
51
+ # @api private
43
52
  def dispatch(msg)
44
53
  case msg.message_type
45
54
  when Message::METHOD_CALL
@@ -69,7 +78,7 @@ module DBus
69
78
  dbus_msg_exc = msg.annotate_exception(e)
70
79
  reply = ErrorMessage.from_exception(dbus_msg_exc).reply_to(msg)
71
80
  end
72
- @service.bus.message_queue.push(reply)
81
+ @connection.message_queue.push(reply)
73
82
  end
74
83
  end
75
84
 
@@ -307,7 +316,7 @@ module DBus
307
316
  # @param sig [Signal]
308
317
  # @param args arguments for the signal
309
318
  def emit(intf, sig, *args)
310
- @service.bus.emit(@service, self, intf, sig, *args)
319
+ @connection.emit(nil, self, intf, sig, *args)
311
320
  end
312
321
 
313
322
  # Defines a signal for the object with a given name _sym_ and _prototype_.
@@ -316,7 +325,7 @@ module DBus
316
325
 
317
326
  cur_intf = @@cur_intf
318
327
  signal = Signal.new(sym.to_s).from_prototype(prototype)
319
- cur_intf.define(Signal.new(sym.to_s).from_prototype(prototype))
328
+ cur_intf.define(signal)
320
329
 
321
330
  # ::Module#define_method(name) { body }
322
331
  define_method(sym.to_s) do |*args|
@@ -14,7 +14,7 @@ module DBus
14
14
  # {https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
15
15
  # org.freedesktop.DBus.ObjectManager}.
16
16
  #
17
- # {Service#export} and {Service#unexport} will look for an ObjectManager
17
+ # {ObjectServer#export} and {ObjectServer#unexport} will look for an ObjectManager
18
18
  # parent in the path hierarchy. If found, it will emit InterfacesAdded
19
19
  # or InterfacesRemoved, as appropriate.
20
20
  module ObjectManager
@@ -23,8 +23,7 @@ module DBus
23
23
  # @return [Hash{ObjectPath => Hash{String => Hash{String => Data::Base}}}]
24
24
  # object -> interface -> property -> value
25
25
  def managed_objects
26
- # FIXME: also fix the "service" concept
27
- descendant_objects = @service.descendants_for(path)
26
+ descendant_objects = connection.object_server.descendants_for(path)
28
27
  descendant_objects.each_with_object({}) do |obj, hash|
29
28
  hash[obj.path] = obj.interfaces_and_properties
30
29
  end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
5
+ # Copyright (C) 2023 Martin Vidner
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License, version 2.1 as published by the Free Software Foundation.
10
+ # See the file "COPYING" for the exact licensing terms.
11
+
12
+ require_relative "node_tree"
13
+
14
+ module DBus
15
+ # The part of a {Connection} that can export {DBus::Object}s to provide
16
+ # services to clients.
17
+ #
18
+ # Note that an ObjectServer does not have a name. Typically a {Connection}
19
+ # has one well known name, but can have none or more.
20
+ #
21
+ # Formerly this class was intermixed with {ProxyService} as Service.
22
+ #
23
+ # @example Usage
24
+ # bus = DBus.session_bus
25
+ # obj = DBus::Object.new("/path") # a subclass more likely
26
+ # bus.object_server.export(obj)
27
+ # bus.request_name("org.example.Test")
28
+ class ObjectServer < NodeTree
29
+ # @return [Connection] The connection we're using.
30
+ attr_reader :connection
31
+
32
+ def initialize(connection)
33
+ @connection = connection
34
+ super()
35
+ end
36
+
37
+ # Retrieves an object at the given _path_
38
+ # @param path [ObjectPath]
39
+ # @return [DBus::Object]
40
+ def object(path)
41
+ node = get_node(path, create: false)
42
+ node&.object
43
+ end
44
+ alias [] object
45
+
46
+ # Export an object
47
+ # @param obj [DBus::Object]
48
+ def export(obj)
49
+ node = get_node(obj.path, create: true)
50
+ # TODO: clarify that this is indeed the right thing, and document
51
+ # raise "At #{obj.path} there is already an object #{node.object.inspect}" if node.object
52
+
53
+ node.object = obj
54
+
55
+ obj.connection = @connection
56
+ object_manager_for(obj)&.object_added(obj)
57
+ end
58
+
59
+ # Undo exporting an object _obj_.
60
+ # Raises ArgumentError if it is not a DBus::Object.
61
+ # Returns the object, or false if _obj_ was not exported.
62
+ # @param obj [DBus::Object]
63
+ def unexport(obj)
64
+ raise ArgumentError, "Expecting a DBus::Object argument" unless obj.is_a?(DBus::Object)
65
+
66
+ last_path_separator_idx = obj.path.rindex("/")
67
+ parent_path = obj.path[1..last_path_separator_idx - 1]
68
+ node_name = obj.path[last_path_separator_idx + 1..-1]
69
+
70
+ parent_node = get_node(parent_path, create: false)
71
+ return false unless parent_node
72
+
73
+ object_manager_for(obj)&.object_removed(obj)
74
+ obj.connection = nil
75
+ parent_node.delete(node_name).object
76
+ end
77
+
78
+ # Find the (closest) parent of *object*
79
+ # implementing the ObjectManager interface, or nil
80
+ # @return [DBus::Object,nil]
81
+ def object_manager_for(object)
82
+ path = object.path
83
+ node_chain = get_node_chain(path)
84
+ om_node = node_chain.reverse_each.find do |node|
85
+ node.object&.is_a? DBus::ObjectManager
86
+ end
87
+ om_node&.object
88
+ end
89
+
90
+ # All objects (not paths) under this path (except itself).
91
+ # @param path [ObjectPath]
92
+ # @return [Array<DBus::Object>]
93
+ # @raise ArgumentError if the *path* does not exist
94
+ def descendants_for(path)
95
+ node = get_node(path, create: false)
96
+ raise ArgumentError, "Object path #{path} doesn't exist" if node.nil?
97
+
98
+ node.descendant_objects
99
+ end
100
+
101
+ #########
102
+
103
+ private
104
+
105
+ #########
106
+
107
+ # @param path [ObjectPath] a path that must exist
108
+ # @return [Array<Node>] nodes from the root to the leaf
109
+ def get_node_chain(path)
110
+ n = @root
111
+ result = [n]
112
+ path.sub(%r{^/}, "").split("/").each do |elem|
113
+ n = n[elem]
114
+ result.push(n)
115
+ end
116
+ result
117
+ end
118
+ end
119
+ end
@@ -10,20 +10,20 @@
10
10
  # See the file "COPYING" for the exact licensing terms.
11
11
 
12
12
  module DBus
13
- # D-Bus proxy object class
14
- #
15
- # Class representing a remote object in an external application.
13
+ # Represents a remote object in an external application.
16
14
  # Typically, calling a method on an instance of a ProxyObject sends a message
17
- # over the bus so that the method is executed remotely on the correctponding
15
+ # over the bus so that the method is executed remotely on the corresponding
18
16
  # object.
19
17
  class ProxyObject
20
18
  # The names of direct subnodes of the object in the tree.
21
19
  attr_accessor :subnodes
22
20
  # Flag determining whether the object has been introspected.
21
+ # @return [Boolean]
23
22
  attr_accessor :introspected
24
23
  # The (remote) destination of the object.
25
24
  attr_reader :destination
26
25
  # The path to the object.
26
+ # @return [ObjectPath]
27
27
  attr_reader :path
28
28
  # The bus the object is reachable via.
29
29
  attr_reader :bus
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of the ruby-dbus project
4
+ # Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
5
+ # Copyright (C) 2023 Martin Vidner
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License, version 2.1 as published by the Free Software Foundation.
10
+ # See the file "COPYING" for the exact licensing terms.
11
+
12
+ require_relative "node_tree"
13
+
14
+ module DBus
15
+ # Used by clients to represent a named service on the other side of the bus.
16
+ #
17
+ # Formerly this class was intermixed with {ObjectServer} as Service.
18
+ #
19
+ # @example Usage
20
+ # svc = DBus.system_bus["org.freedesktop.machine1"]
21
+ # manager = svc["/org/freedesktop/machine1"]
22
+ # p manager.ListImages
23
+ class ProxyService < NodeTree
24
+ # @return [BusName,nil] The service name.
25
+ # May be nil for peer connections
26
+ attr_reader :name
27
+ # @return [Connection] The connection we're using.
28
+ attr_reader :connection
29
+
30
+ def initialize(name, connection)
31
+ @name = BusName.new(name)
32
+ @connection = connection
33
+ super()
34
+ end
35
+
36
+ # Determine whether the service name already exists.
37
+ def exists?
38
+ bus = connection # TODO: raise a better error if this is a peer connection
39
+ bus.proxy.ListNames[0].member?(@name)
40
+ end
41
+
42
+ # Perform an introspection on all the objects on the service
43
+ # (starting recursively from the root).
44
+ def introspect
45
+ raise NotImplementedError if block_given?
46
+
47
+ rec_introspect(@root, "/")
48
+ self
49
+ end
50
+
51
+ # Retrieves an object at the given _path_.
52
+ # @param path [ObjectPath]
53
+ # @return [ProxyObject]
54
+ def [](path)
55
+ object(path, api: ApiOptions::A1)
56
+ end
57
+
58
+ # Retrieves an object at the given _path_
59
+ # whose methods always return an array.
60
+ # @param path [ObjectPath]
61
+ # @param api [ApiOptions]
62
+ # @return [ProxyObject]
63
+ def object(path, api: ApiOptions::A0)
64
+ node = get_node(path, create: true)
65
+ if node.object.nil? || node.object.api != api
66
+ node.object = ProxyObject.new(
67
+ @connection, @name, path,
68
+ api: api
69
+ )
70
+ end
71
+ node.object
72
+ end
73
+
74
+ private
75
+
76
+ # Perform a recursive retrospection on the given current _node_
77
+ # on the given _path_.
78
+ def rec_introspect(node, path)
79
+ xml = bus.introspect_data(@name, path)
80
+ intfs, subnodes = IntrospectXMLParser.new(xml).parse
81
+ subnodes.each do |nodename|
82
+ subnode = node[nodename] = Node.new(nodename)
83
+ subpath = if path == "/"
84
+ "/#{nodename}"
85
+ else
86
+ "#{path}/#{nodename}"
87
+ end
88
+ rec_introspect(subnode, subpath)
89
+ end
90
+ return if intfs.empty?
91
+
92
+ node.object = ProxyObjectFactory.new(xml, @connection, @name, path).build
93
+ end
94
+ end
95
+ end
data/lib/dbus.rb CHANGED
@@ -11,17 +11,14 @@
11
11
  # See the file "COPYING" for the exact licensing terms.
12
12
 
13
13
  module DBus
14
- # Byte signifying big endianness.
14
+ # Protocol character signifying big endianness.
15
15
  BIG_END = "B"
16
- # Byte signifying little endianness.
16
+ # Protocol character signifying little endianness.
17
17
  LIL_END = "l"
18
18
 
19
- # Byte signifying the host's endianness.
20
- HOST_END = if [0x01020304].pack("L").unpack1("V") == 0x01020304
21
- LIL_END
22
- else
23
- BIG_END
24
- end
19
+ # Protocol character signifying the host's endianness.
20
+ # "S": unpack as uint16, native endian
21
+ HOST_END = { 1 => BIG_END, 256 => LIL_END }.fetch("\x00\x01".unpack1("S"))
25
22
  end
26
23
  # ^ That's because dbus/message needs HOST_END early
27
24
 
@@ -34,17 +31,21 @@ require_relative "dbus/emits_changed_signal"
34
31
  require_relative "dbus/error"
35
32
  require_relative "dbus/introspect"
36
33
  require_relative "dbus/logger"
34
+ require_relative "dbus/main"
37
35
  require_relative "dbus/marshall"
38
36
  require_relative "dbus/matchrule"
39
37
  require_relative "dbus/message"
40
38
  require_relative "dbus/message_queue"
39
+ require_relative "dbus/node_tree"
41
40
  require_relative "dbus/object"
42
41
  require_relative "dbus/object_manager"
43
42
  require_relative "dbus/object_path"
43
+ require_relative "dbus/object_server"
44
44
  require_relative "dbus/platform"
45
45
  require_relative "dbus/proxy_object"
46
46
  require_relative "dbus/proxy_object_factory"
47
47
  require_relative "dbus/proxy_object_interface"
48
+ require_relative "dbus/proxy_service"
48
49
  require_relative "dbus/raw_message"
49
50
  require_relative "dbus/type"
50
51
  require_relative "dbus/xml"
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ describe DBus::BusConnection do
8
+ let(:bus) { DBus::ASessionBus.new }
9
+
10
+ # deprecated method
11
+ describe "#request_service", tag_bus: true, tag_deprecated: true do
12
+ context "when the name request succeeds" do
13
+ # Formerly it returned Service, now ObjectServer takes its role.
14
+ # Replacement: server = bus.object_server; bus.request_name(name)
15
+ it "returns something which can export objects" do
16
+ name = "org.rubygems.ruby_dbus.RequestServiceTest"
17
+ server = bus.request_service(name)
18
+ expect(server).to respond_to(:export)
19
+ bus.proxy.ReleaseName(name)
20
+ end
21
+ end
22
+
23
+ context "when the name is taken already", tag_service: true do
24
+ # formerly it returned Service, now ObjectServer takes its role
25
+ it "raises NameRequestError... too late" do
26
+ name = "org.ruby.service"
27
+ expect do
28
+ bus.request_service(name)
29
+ _unrelated_call = bus.proxy.GetId.first
30
+ end.to raise_error(DBus::Connection::NameRequestError)
31
+ # The call fails but it means we did not get the name RIGHT AWAY
32
+ # but we are still queued to get it as soon as the current owner
33
+ # gives it up.
34
+ # So even now we have to the bus to remove us from the queue
35
+ bus.proxy.ReleaseName(name)
36
+ end
37
+ end
38
+
39
+ context "when we're not allowed to own the name", tag_system_bus: true do
40
+ let(:bus) { DBus::ASystemBus.new }
41
+ xit "raises an error... too late" do
42
+ name = "org.rubygems.ruby_dbus.NotAllowedToOwnThisNameAnyway"
43
+ expect do
44
+ bus.request_service(name)
45
+ _unrelated_call = bus.proxy.GetId.first
46
+ end.to raise_error(DBus::Error, /not allowed to own the service/)
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "#request_name", tag_bus: true do
52
+ context "when the name request succeeds" do
53
+ it "returns something which can export objects" do
54
+ name = "org.rubygems.ruby_dbus.RequestNameTest"
55
+ expect { bus.request_name(name) }.to_not raise_error
56
+ bus.proxy.ReleaseName(name)
57
+ end
58
+ end
59
+
60
+ context "when the name is taken already", tag_service: true do
61
+ # formerly it returned Service, now ObjectServer takes its role
62
+ it "raises NameRequestError" do
63
+ name = "org.ruby.service"
64
+ expect do
65
+ # flags: avoid getting the name sometime later, unexpectedly
66
+ bus.request_name(name, flags: DBus::Connection::NAME_FLAG_DO_NOT_QUEUE)
67
+ end.to raise_error(DBus::Connection::NameRequestError)
68
+ end
69
+ end
70
+
71
+ context "when we're not allowed to own the name", tag_system_bus: true do
72
+ let(:bus) { DBus::ASystemBus.new }
73
+ xit "raises an error... too late" do
74
+ name = "org.rubygems.ruby_dbus.NotAllowedToOwnThisNameAnyway"
75
+ expect do
76
+ bus.request_name(name)
77
+ end.to raise_error(DBus::Error, /not allowed to own the service/)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ coverage = if ENV["COVERAGE"]
4
+ ENV["COVERAGE"] == "true"
5
+ else
6
+ # heuristics: enable for interactive builds (but not in OBS)
7
+ ENV["DISPLAY"]
8
+ end
9
+
10
+ if coverage
11
+ require "simplecov"
12
+ SimpleCov.root File.expand_path("..", __dir__)
13
+
14
+ # do not cover specs
15
+ SimpleCov.add_filter "_spec.rb"
16
+ # do not cover the activesupport helpers
17
+ SimpleCov.add_filter "/core_ext/"
18
+ # measure all if/else branches on a line
19
+ SimpleCov.enable_coverage :branch
20
+
21
+ SimpleCov.start
22
+
23
+ # additionally use the LCOV format for on-line code coverage reporting at CI
24
+ if ENV["COVERAGE_LCOV"] == "true"
25
+ require "simplecov-lcov"
26
+
27
+ SimpleCov::Formatter::LcovFormatter.config do |c|
28
+ c.report_with_single_file = true
29
+ # this is the default Coveralls GitHub Action location
30
+ # https://github.com/marketplace/actions/coveralls-github-action
31
+ c.single_report_path = "coverage/lcov.info"
32
+ end
33
+
34
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new [
35
+ SimpleCov::Formatter::HTMLFormatter,
36
+ SimpleCov::Formatter::LcovFormatter
37
+ ]
38
+ end
39
+ end
@@ -5,6 +5,20 @@
5
5
  require_relative "spec_helper"
6
6
  require "dbus"
7
7
 
8
+ describe "DBus.logger" do
9
+ it "will log debug messages if $DEBUG is true" do
10
+ logger_old = DBus.logger
11
+ DBus.logger = nil
12
+ debug_old = $DEBUG
13
+ $DEBUG = true
14
+
15
+ DBus.logger.debug "this debug message will always be shown"
16
+
17
+ $DEBUG = debug_old
18
+ DBus.logger = logger_old
19
+ end
20
+ end
21
+
8
22
  describe "MainLoopTest" do
9
23
  before(:each) do
10
24
  @session_bus = DBus::ASessionBus.new
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ # Pedantic full coverage test.
8
+ # The happy paths are covered via calling classes
9
+ describe DBus::Message do
10
+ describe "#marshall" do
11
+ it "raises when the object path is /org/freedesktop/DBus/Local" do
12
+ m = DBus::Message.new(DBus::Message::SIGNAL)
13
+ # the path is valid, it just must not be sent
14
+ m.path = DBus::ObjectPath.new("/org/freedesktop/DBus/Local")
15
+ m.interface = "org.example.spam"
16
+ m.member = "Spam"
17
+
18
+ expect { m.marshall }.to raise_error(RuntimeError, /Cannot send a message with the reserved path/)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../coverage_helper"
5
+ SimpleCov.command_name "Cockpit Tests (#{Process.pid})" if Object.const_defined? "SimpleCov"
6
+
7
+ # find the library without external help
8
+ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
9
+ require "dbus"
10
+
11
+ SERVICE_NAME = "org.rubygems.ruby_dbus.DBusTests"
12
+ ROOT_OPATH = "/otree/frobber"
13
+
14
+ class DBusTests < DBus::Object
15
+ FROBBER_INTERFACE = "com.redhat.Cockpit.DBusTests.Frobber"
16
+
17
+ dbus_interface FROBBER_INTERFACE do
18
+ dbus_method :HelloWorld, "in greeting:s, out response:s" do |greeting|
19
+ # TODO: return the same thing as the original implementation
20
+ # and try substituting it?
21
+ [format("Word! You said `%s'. I'm Skeleton, btw!", greeting)]
22
+ end
23
+ end
24
+ end
25
+
26
+ bus = DBus::SessionBus.instance
27
+ bus.object_server.export(DBusTests.new(ROOT_OPATH))
28
+ bus.request_name(SERVICE_NAME)
29
+ DBus::Main.new.tap { |m| m << bus }.run