ruby-dbus 0.23.0.beta1 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,97 @@
1
+ <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3
+ <node>
4
+ <interface name="org.freedesktop.DBus.Introspectable">
5
+ <method name="Introspect">
6
+ <arg direction="out" type="s"/>
7
+ </method>
8
+ </interface>
9
+ <interface name="org.freedesktop.DBus">
10
+ <method name="Hello">
11
+ <arg direction="out" type="s"/>
12
+ </method>
13
+ <method name="RequestName">
14
+ <arg direction="in" type="s"/>
15
+ <arg direction="in" type="u"/>
16
+ <arg direction="out" type="u"/>
17
+ </method>
18
+ <method name="ReleaseName">
19
+ <arg direction="in" type="s"/>
20
+ <arg direction="out" type="u"/>
21
+ </method>
22
+ <method name="StartServiceByName">
23
+ <arg direction="in" type="s"/>
24
+ <arg direction="in" type="u"/>
25
+ <arg direction="out" type="u"/>
26
+ </method>
27
+ <method name="UpdateActivationEnvironment">
28
+ <arg direction="in" type="a{ss}"/>
29
+ </method>
30
+ <method name="NameHasOwner">
31
+ <arg direction="in" type="s"/>
32
+ <arg direction="out" type="b"/>
33
+ </method>
34
+ <method name="ListNames">
35
+ <arg direction="out" type="as"/>
36
+ </method>
37
+ <method name="ListActivatableNames">
38
+ <arg direction="out" type="as"/>
39
+ </method>
40
+ <method name="AddMatch">
41
+ <arg direction="in" type="s"/>
42
+ </method>
43
+ <method name="RemoveMatch">
44
+ <arg direction="in" type="s"/>
45
+ </method>
46
+ <method name="GetNameOwner">
47
+ <arg direction="in" type="s"/>
48
+ <arg direction="out" type="s"/>
49
+ </method>
50
+ <method name="ListQueuedOwners">
51
+ <arg direction="in" type="s"/>
52
+ <arg direction="out" type="as"/>
53
+ </method>
54
+ <method name="GetConnectionUnixUser">
55
+ <arg direction="in" type="s"/>
56
+ <arg direction="out" type="u"/>
57
+ </method>
58
+ <method name="GetConnectionUnixProcessID">
59
+ <arg direction="in" type="s"/>
60
+ <arg direction="out" type="u"/>
61
+ </method>
62
+ <method name="GetAdtAuditSessionData">
63
+ <arg direction="in" type="s"/>
64
+ <arg direction="out" type="ay"/>
65
+ </method>
66
+ <method name="GetConnectionSELinuxSecurityContext">
67
+ <arg direction="in" type="s"/>
68
+ <arg direction="out" type="ay"/>
69
+ </method>
70
+ <method name="ReloadConfig">
71
+ </method>
72
+ <method name="GetId">
73
+ <arg direction="out" type="s"/>
74
+ </method>
75
+ <method name="GetConnectionCredentials">
76
+ <arg direction="in" type="s"/>
77
+ <arg direction="out" type="a{sv}"/>
78
+ </method>
79
+ <property name="Features" type="as" access="read">
80
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
81
+ </property>
82
+ <property name="Interfaces" type="as" access="read">
83
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
84
+ </property>
85
+ <signal name="NameOwnerChanged">
86
+ <arg type="s"/>
87
+ <arg type="s"/>
88
+ <arg type="s"/>
89
+ </signal>
90
+ <signal name="NameLost">
91
+ <arg type="s"/>
92
+ </signal>
93
+ <signal name="NameAcquired">
94
+ <arg type="s"/>
95
+ </signal>
96
+ </interface>
97
+ </node>
@@ -22,11 +22,12 @@ module DBus
22
22
  # p manager.ListImages
23
23
  class ProxyService < NodeTree
24
24
  # @return [BusName,nil] The service name.
25
- # May be nil for peer connections
25
+ # Will be nil for a {PeerConnection}
26
26
  attr_reader :name
27
27
  # @return [Connection] The connection we're using.
28
28
  attr_reader :connection
29
29
 
30
+ # @param connection [Connection] The connection we're using.
30
31
  def initialize(name, connection)
31
32
  @name = BusName.new(name)
32
33
  @connection = connection
@@ -76,7 +77,7 @@ module DBus
76
77
  # Perform a recursive retrospection on the given current _node_
77
78
  # on the given _path_.
78
79
  def rec_introspect(node, path)
79
- xml = bus.introspect_data(@name, path)
80
+ xml = connection.introspect_data(@name, path)
80
81
  intfs, subnodes = IntrospectXMLParser.new(xml).parse
81
82
  subnodes.each do |nodename|
82
83
  subnode = node[nodename] = Node.new(nodename)
@@ -92,4 +93,15 @@ module DBus
92
93
  node.object = ProxyObjectFactory.new(xml, @connection, @name, path).build
93
94
  end
94
95
  end
96
+
97
+ # A hack for pretending that a {PeerConnection} has a single unnamed {ProxyService}
98
+ # so that we can get {ProxyObject}s from it.
99
+ class ProxyPeerService < ProxyService
100
+ # @param connection [Connection] The peer connection we're using.
101
+ def initialize(connection)
102
+ # this way we disallow ProxyService taking a nil name by accident
103
+ super(":0.0", connection)
104
+ @name = nil
105
+ end
106
+ end
95
107
  end
data/lib/dbus.rb CHANGED
@@ -26,6 +26,7 @@ require_relative "dbus/api_options"
26
26
  require_relative "dbus/auth"
27
27
  require_relative "dbus/bus"
28
28
  require_relative "dbus/bus_name"
29
+ require_relative "dbus/connection"
29
30
  require_relative "dbus/data"
30
31
  require_relative "dbus/emits_changed_signal"
31
32
  require_relative "dbus/error"
data/ruby-dbus.gemspec CHANGED
@@ -9,7 +9,7 @@ GEMSPEC = Gem::Specification.new do |s|
9
9
  s.summary = "Ruby module for interaction with D-Bus"
10
10
  s.description = "Pure Ruby module for interaction with D-Bus IPC system"
11
11
  s.version = File.read("VERSION").strip
12
- s.license = "LGPL-2.1"
12
+ s.license = "LGPL-2.1-or-later"
13
13
  s.author = "Ruby DBus Team"
14
14
  s.email = "martin.github@vidner.net"
15
15
  s.homepage = "https://github.com/mvidner/ruby-dbus"
@@ -21,7 +21,6 @@ describe DBus::BusConnection do
21
21
  end
22
22
 
23
23
  context "when the name is taken already", tag_service: true do
24
- # formerly it returned Service, now ObjectServer takes its role
25
24
  it "raises NameRequestError... too late" do
26
25
  name = "org.ruby.service"
27
26
  expect do
@@ -36,10 +35,10 @@ describe DBus::BusConnection do
36
35
  end
37
36
  end
38
37
 
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"
38
+ # This only works with our special bus setup
39
+ context "when we're not allowed to own the name", tag_limited_bus: true do
40
+ it "raises an error... too late" do
41
+ name = "org.rubygems.ruby_dbus.NobodyCanOwnThisName"
43
42
  expect do
44
43
  bus.request_service(name)
45
44
  _unrelated_call = bus.proxy.GetId.first
@@ -50,28 +49,41 @@ describe DBus::BusConnection do
50
49
 
51
50
  describe "#request_name", tag_bus: true do
52
51
  context "when the name request succeeds" do
53
- it "returns something which can export objects" do
52
+ it "returns a success code" do
54
53
  name = "org.rubygems.ruby_dbus.RequestNameTest"
55
- expect { bus.request_name(name) }.to_not raise_error
56
- bus.proxy.ReleaseName(name)
54
+ expect(bus.request_name(name)).to eq DBus::Connection::REQUEST_NAME_REPLY_PRIMARY_OWNER
55
+ # second time, considered also a success
56
+ expect(bus.request_name(name)).to eq DBus::Connection::REQUEST_NAME_REPLY_ALREADY_OWNER
57
+ bus.release_name(name)
57
58
  end
58
59
  end
59
60
 
60
61
  context "when the name is taken already", tag_service: true do
61
- # formerly it returned Service, now ObjectServer takes its role
62
62
  it "raises NameRequestError" do
63
63
  name = "org.ruby.service"
64
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)
65
+ bus.request_name(name)
66
+ end.to raise_error(DBus::Connection::NameRequestError)
67
+ end
68
+ end
69
+
70
+ context "when the name is taken already but we request queuing", tag_service: true do
71
+ it "raises NameRequestError but we are queued" do
72
+ name = "org.ruby.service"
73
+ owning = nil
74
+ # TODO: we do not expect the handlers to run
75
+ bus.on_name_acquired { owning = true }
76
+ bus.on_name_lost { owning = false }
77
+ expect do
78
+ bus.request_name(name, queue: true)
67
79
  end.to raise_error(DBus::Connection::NameRequestError)
80
+ expect(bus.release_name(name)).to eq DBus::BusConnection::RELEASE_NAME_REPLY_RELEASED
68
81
  end
69
82
  end
70
83
 
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"
84
+ context "when we're not allowed to own the name", tag_limited_bus: true do
85
+ it "raises an error" do
86
+ name = "org.rubygems.ruby_dbus.NobodyCanOwnThisName"
75
87
  expect do
76
88
  bus.request_name(name)
77
89
  end.to raise_error(DBus::Error, /not allowed to own the service/)
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ describe DBus::PeerConnection do
8
+ let(:address) { ENV["DBUS_SESSION_BUS_ADDRESS"] }
9
+ subject { described_class.new(address) }
10
+
11
+ describe "#peer_service" do
12
+ it "returns a PeerService with a nil name" do
13
+ svc = subject.peer_service
14
+ expect(svc).to be_a(DBus::ProxyService)
15
+ expect(svc.name).to be_nil
16
+ end
17
+ end
18
+
19
+ describe "#add_match, #remove_match" do
20
+ it "doesn't crash trying to call AddMatch, RemoveMatch" do
21
+ mr = DBus::MatchRule.new
22
+ mr.member = "StateUpdated"
23
+ mr.interface = "org.PulseAudio.Core1.Device"
24
+ handler = ->(_msg) {}
25
+
26
+ # Cheating a bit with the mocking:
27
+ # a PulseAudio peer connection would error with
28
+ # > DBus::Error: Method "AddMatch" with signature "s" on interface
29
+ # > "org.freedesktop.DBus" doesn't exist
30
+ # but here we do have a bus at the other end, which replies with
31
+ # > DBus::Error: Client tried to send a message other than Hello without being registered
32
+ # where "registering" is a libdbus-1 thing meaning "internal bookkeeping and send Hello"
33
+ expect { subject.add_match(mr, &handler) }.to_not raise_error
34
+ expect { subject.remove_match(mr) }.to_not raise_error
35
+ end
36
+ end
37
+ end
data/spec/dbus_spec.rb ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env rspec
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "spec_helper"
5
+ require "dbus"
6
+
7
+ describe DBus do
8
+ describe ".session_bus", tag_bus: true do
9
+ it "returns a BusConnection" do
10
+ expect(DBus.session_bus).to be_a(DBus::BusConnection)
11
+ end
12
+ end
13
+
14
+ describe ".system_bus" do
15
+ # coverage obsession: mock it out,
16
+ # system bus may not exist during RPM builds
17
+ it "calls SystemBus.instance" do
18
+ expect(DBus::SystemBus).to receive(:instance)
19
+ DBus.system_bus
20
+ end
21
+ end
22
+ end
@@ -23,7 +23,7 @@ class TestChild < DBus::Object
23
23
  end
24
24
 
25
25
  dbus_interface "org.ruby.TestChild" do
26
- dbus_attr_reader :name, "s"
26
+ dbus_reader_attr_accessor :name, "s"
27
27
  end
28
28
  end
29
29
 
@@ -183,16 +183,14 @@ class Test < DBus::Object
183
183
  dbus_interface "org.ruby.TestParent" do
184
184
  dbus_method :New, "in name:s, out opath:o" do |name|
185
185
  child = TestChild.new("#{path}/#{name}")
186
- connection.object_server.export(child)
186
+ object_server.export(child)
187
187
  [child.path]
188
188
  end
189
189
 
190
190
  dbus_method :Delete, "in opath:o" do |opath|
191
191
  raise ArgumentError unless opath.start_with?(path)
192
192
 
193
- svr = connection.object_server
194
- obj = svr.get_node(opath)&.object
195
- svr.unexport(obj)
193
+ object_server.unexport(opath)
196
194
  end
197
195
  end
198
196
 
@@ -200,6 +198,7 @@ class Test < DBus::Object
200
198
  dbus_method :the_answer, "out answer:i" do
201
199
  [0]
202
200
  end
201
+
203
202
  dbus_method :interfaces, "out answer:i" do
204
203
  # 'Shadowed' from the Ruby side, meaning ProxyObject#interfaces
205
204
  # will return the list of interfaces rather than calling this method.
@@ -55,26 +55,9 @@ describe DBus::ObjectServer do
55
55
  o
56
56
  end
57
57
 
58
- # which is right?
59
- # current behavior
60
- it "a) silently uses the new object" do
58
+ it "raises an error" do
61
59
  server.export(obj1)
62
- server.export(obj2)
63
-
64
- expect(server).to_not receive(:unexport).with(obj1)
65
- expect(server[path].which).to eq 2
66
- end
67
-
68
- xit "b) unexports the other object first" do
69
- server.export(obj1)
70
-
71
- expect(server).to receive(:unexport).with(obj1)
72
- server.export(obj2)
73
- end
74
-
75
- xit "c) raises an error" do
76
- server.export(obj1)
77
- expect { server.export(obj2) }.to raise_error(RuntimeError)
60
+ expect { server.export(obj2) }.to raise_error(RuntimeError, /there is already an object/)
78
61
  end
79
62
  end
80
63
  end
@@ -85,10 +68,20 @@ describe DBus::ObjectServer do
85
68
  @svc = bus.object_server
86
69
  end
87
70
 
88
- it "returns the unexported object" do
71
+ it "returns the unexported leaf object" do
89
72
  obj = DBus::Object.new "/org/ruby/Foo"
90
73
  @svc.export obj
91
- expect(@svc.unexport(obj)).to be_a DBus::Object
74
+ expect(@svc.unexport(obj)).to be_equal(obj)
75
+ end
76
+
77
+ it "returns the unexported leaf object, if specified by its path" do
78
+ obj = DBus::Object.new "/org/ruby/Foo"
79
+ @svc.export obj
80
+ expect(@svc.unexport(obj.path)).to be_equal(obj)
81
+
82
+ obj = DBus::Object.new "/org/ruby/Foo"
83
+ @svc.export obj
84
+ expect(@svc.unexport(DBus::ObjectPath.new(obj.path))).to be_equal(obj)
92
85
  end
93
86
 
94
87
  it "returns false if the object was never exported" do
@@ -96,9 +89,50 @@ describe DBus::ObjectServer do
96
89
  expect(@svc.unexport(obj)).to be false
97
90
  end
98
91
 
99
- it "raises when argument is not a DBus::Object" do
100
- path = "/org/ruby/Foo"
101
- expect { @svc.unexport(path) }.to raise_error(ArgumentError)
92
+ it "raises false if the path has no node" do
93
+ obj = DBus::Object.new "/org/ruby/Foo"
94
+ @svc.export obj
95
+ expect { @svc.unexport("/org/ruby/NotFoo") }.to raise_error(ArgumentError)
96
+ @svc.unexport obj
97
+ end
98
+
99
+ it "raises false if the path has no object" do
100
+ obj = DBus::Object.new "/org/ruby/Foo"
101
+ @svc.export obj
102
+ expect { @svc.unexport("/org/ruby") }.to raise_error(ArgumentError)
103
+ @svc.unexport obj
104
+ end
105
+
106
+ it "raises when argument is not usable" do
107
+ expect { @svc.unexport(:foo) }.to raise_error(ArgumentError)
108
+ end
109
+
110
+ context "/child_of_root" do
111
+ it "returns the unexported object" do
112
+ obj = DBus::Object.new "/child_of_root"
113
+ @svc.export obj
114
+ expect(@svc.unexport(obj)).to be_equal(obj)
115
+ end
116
+ end
117
+
118
+ context "/ (root)" do
119
+ it "returns the unexported object" do
120
+ obj = DBus::Object.new "/"
121
+ @svc.export obj
122
+ expect(@svc.unexport(obj)).to be_equal(obj)
123
+ end
124
+ end
125
+
126
+ context "not a leaf object" do
127
+ it "maintains objects on child paths" do
128
+ obj = DBus::Object.new "/org/ruby"
129
+ @svc.export obj
130
+ obj2 = DBus::Object.new "/org/ruby/Foo"
131
+ @svc.export obj2
132
+
133
+ @svc.unexport(obj)
134
+ expect(@svc.object("/org/ruby/Foo")).to be_a DBus::Object
135
+ end
102
136
  end
103
137
  end
104
138
  end
data/spec/object_spec.rb CHANGED
@@ -175,4 +175,20 @@ describe DBus::Object do
175
175
  expect { obj.dispatch(msg) }.to_not raise_error
176
176
  end
177
177
  end
178
+
179
+ describe "#emit" do
180
+ context "before the object has been exported" do
181
+ it "raises an explanatory error" do
182
+ obj = ObjectTest.new("/test")
183
+
184
+ intf = DBus::Interface.new("org.example.Test")
185
+ signal = DBus::Signal.new("Ring")
186
+ expect { obj.emit(intf, signal) }
187
+ .to raise_error(
188
+ RuntimeError,
189
+ %r{Cannot emit signal org.example.Test.Ring before /test is exported}
190
+ )
191
+ end
192
+ end
193
+ end
178
194
  end
@@ -5,13 +5,7 @@ require_relative "spec_helper"
5
5
  require "dbus"
6
6
 
7
7
  describe DBus::ProxyService do
8
- context "when a private bus is set up" do
9
- around(:each) do |example|
10
- with_private_bus do
11
- with_service_by_activation(&example)
12
- end
13
- end
14
-
8
+ context "when a private bus is set up", tag_service: true do
15
9
  let(:bus) { DBus::ASessionBus.new }
16
10
 
17
11
  describe "#exists?" do
@@ -26,5 +20,16 @@ describe DBus::ProxyService do
26
20
  expect(svc.exists?).to be false
27
21
  end
28
22
  end
23
+
24
+ # This method is used by dbus-gui-gtk.
25
+ # Deprecate it? In favor of introspecting the tree gradually
26
+ # or move it to the application code?
27
+ describe "#introspect" do
28
+ it "creates the whole node tree" do
29
+ svc = bus.service("org.ruby.service")
30
+ expect { svc.introspect }.to_not raise_error
31
+ expect(svc.root.dig("org", "ruby", "MyInstance")).to be_a DBus::Node
32
+ end
33
+ end
29
34
  end
30
35
  end
@@ -43,6 +43,9 @@
43
43
  <allow eavesdrop="true"/>
44
44
  <!-- Allow anyone to own anything -->
45
45
  <allow own="*"/>
46
+
47
+ <!-- To test how request_name handles bus errors -->
48
+ <deny own="org.rubygems.ruby_dbus.NobodyCanOwnThisName"/>
46
49
  </policy>
47
50
 
48
51
  <!-- Do not increase the limits.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-dbus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0.beta1
4
+ version: 0.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruby DBus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-05 00:00:00.000000000 Z
11
+ date: 2023-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rexml
@@ -124,6 +124,7 @@ files:
124
124
  - doc/Tutorial.md
125
125
  - examples/doc/README.md
126
126
  - examples/doc/_extract_examples
127
+ - examples/no-bus/pulseaudio.rb
127
128
  - examples/no-introspect/nm-test.rb
128
129
  - examples/no-introspect/tracker-test.rb
129
130
  - examples/rhythmbox/playpause.rb
@@ -140,6 +141,7 @@ files:
140
141
  - lib/dbus/auth.rb
141
142
  - lib/dbus/bus.rb
142
143
  - lib/dbus/bus_name.rb
144
+ - lib/dbus/connection.rb
143
145
  - lib/dbus/core_ext/class/attribute.rb
144
146
  - lib/dbus/core_ext/module/redefine_method.rb
145
147
  - lib/dbus/data.rb
@@ -157,6 +159,7 @@ files:
157
159
  - lib/dbus/object_manager.rb
158
160
  - lib/dbus/object_path.rb
159
161
  - lib/dbus/object_server.rb
162
+ - lib/dbus/org.freedesktop.DBus.xml
160
163
  - lib/dbus/platform.rb
161
164
  - lib/dbus/proxy_object.rb
162
165
  - lib/dbus/proxy_object_factory.rb
@@ -175,9 +178,11 @@ files:
175
178
  - spec/bus_spec.rb
176
179
  - spec/byte_array_spec.rb
177
180
  - spec/client_robustness_spec.rb
181
+ - spec/connection_spec.rb
178
182
  - spec/coverage_helper.rb
179
183
  - spec/data/marshall.yaml
180
184
  - spec/data_spec.rb
185
+ - spec/dbus_spec.rb
181
186
  - spec/emits_changed_signal_spec.rb
182
187
  - spec/err_msg_spec.rb
183
188
  - spec/introspect_xml_parser_spec.rb
@@ -217,7 +222,7 @@ files:
217
222
  - spec/zzz_quit_spec.rb
218
223
  homepage: https://github.com/mvidner/ruby-dbus
219
224
  licenses:
220
- - LGPL-2.1
225
+ - LGPL-2.1-or-later
221
226
  metadata: {}
222
227
  post_install_message:
223
228
  rdoc_options: []
@@ -230,9 +235,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
230
235
  version: 2.4.0
231
236
  required_rubygems_version: !ruby/object:Gem::Requirement
232
237
  requirements:
233
- - - ">"
238
+ - - ">="
234
239
  - !ruby/object:Gem::Version
235
- version: 1.3.1
240
+ version: '0'
236
241
  requirements: []
237
242
  rubygems_version: 3.3.26
238
243
  signing_key: