ruby-dbus 0.18.1 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +26 -0
- data/VERSION +1 -1
- data/examples/simple/get_id.rb +4 -2
- data/lib/dbus/auth.rb +305 -218
- data/lib/dbus/bus.rb +57 -15
- data/lib/dbus/introspect.rb +2 -1
- data/lib/dbus/marshall.rb +1 -1
- data/lib/dbus/message_queue.rb +19 -12
- data/lib/dbus/object.rb +31 -3
- data/lib/dbus/object_manager.rb +58 -0
- data/lib/dbus.rb +1 -0
- data/spec/auth_spec.rb +225 -0
- data/spec/node_spec.rb +46 -0
- data/spec/object_manager_spec.rb +33 -0
- data/spec/object_spec.rb +10 -0
- data/spec/proxy_object_interface_spec.rb +35 -0
- data/spec/server_robustness_spec.rb +18 -6
- data/spec/service_newapi.rb +34 -0
- data/spec/service_spec.rb +18 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/thread_safety_spec.rb +55 -12
- data/spec/tools/dbus-limited-session.conf +15 -0
- metadata +8 -4
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env rspec
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "spec_helper"
|
5
|
+
require "dbus"
|
6
|
+
|
7
|
+
describe DBus::ProxyObjectInterface do
|
8
|
+
# TODO: tag tests that need a service, eg "needs-service"
|
9
|
+
# TODO: maybe remove this and rely on a packaged tool
|
10
|
+
around(:each) do |example|
|
11
|
+
with_private_bus do
|
12
|
+
with_service_by_activation(&example)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:bus) { DBus::ASessionBus.new }
|
17
|
+
|
18
|
+
context "when calling org.ruby.service" do
|
19
|
+
let(:svc) { bus["org.ruby.service"] }
|
20
|
+
|
21
|
+
# This is white box testing, knowing the implementation
|
22
|
+
# A better way would be structuring it according to the D-Bus Spec
|
23
|
+
# Or testing the service side doing the right thing? (What if our bugs cancel out)
|
24
|
+
describe "#define_method_from_descriptor" do
|
25
|
+
it "can call a method with multiple OUT arguments" do
|
26
|
+
obj = svc["/org/ruby/MyInstance"]
|
27
|
+
ifc = obj["org.ruby.SampleInterface"]
|
28
|
+
|
29
|
+
even, odd = ifc.EvenOdd([3, 1, 4, 1, 5, 9, 2, 6])
|
30
|
+
expect(even).to eq [4, 2, 6]
|
31
|
+
expect(odd).to eq [3, 1, 1, 5, 9]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -16,7 +16,7 @@ describe "ServerRobustnessTest" do
|
|
16
16
|
it "tests no such path with introspection" do
|
17
17
|
obj = @svc.object "/org/ruby/NotMyInstance"
|
18
18
|
expect { obj.introspect }.to raise_error(DBus::Error) do |e|
|
19
|
-
expect(e).to_not match(/timeout/)
|
19
|
+
expect(e.message).to_not match(/timeout/)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -25,7 +25,19 @@ describe "ServerRobustnessTest" do
|
|
25
25
|
ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
|
26
26
|
ifc.define_method("the_answer", "out n:i")
|
27
27
|
expect { ifc.the_answer }.to raise_error(DBus::Error) do |e|
|
28
|
-
expect(e).to_not match(/timeout/)
|
28
|
+
expect(e.message).to_not match(/timeout/)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "an existing path without an object" do
|
33
|
+
let(:obj) { @svc.object "/org" }
|
34
|
+
|
35
|
+
it "errors without a timeout" do
|
36
|
+
ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
|
37
|
+
ifc.define_method("the_answer", "out n:i")
|
38
|
+
expect { ifc.the_answer }.to raise_error(DBus::Error) do |e|
|
39
|
+
expect(e.message).to_not match(/timeout/)
|
40
|
+
end
|
29
41
|
end
|
30
42
|
end
|
31
43
|
|
@@ -33,7 +45,7 @@ describe "ServerRobustnessTest" do
|
|
33
45
|
obj = @svc.object "/org/ruby/MyInstance"
|
34
46
|
obj.default_iface = "org.ruby.SampleInterface"
|
35
47
|
expect { obj.will_raise }.to raise_error(DBus::Error) do |e|
|
36
|
-
expect(e).to_not match(/timeout/)
|
48
|
+
expect(e.message).to_not match(/timeout/)
|
37
49
|
end
|
38
50
|
end
|
39
51
|
|
@@ -41,7 +53,7 @@ describe "ServerRobustnessTest" do
|
|
41
53
|
obj = @svc.object "/org/ruby/MyInstance"
|
42
54
|
obj.default_iface = "org.ruby.SampleInterface"
|
43
55
|
expect { obj.will_raise_name_error }.to raise_error(DBus::Error) do |e|
|
44
|
-
expect(e).to_not match(/timeout/)
|
56
|
+
expect(e.message).to_not match(/timeout/)
|
45
57
|
end
|
46
58
|
end
|
47
59
|
|
@@ -51,7 +63,7 @@ describe "ServerRobustnessTest" do
|
|
51
63
|
ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
|
52
64
|
ifc.define_method("not_the_answer", "out n:i")
|
53
65
|
expect { ifc.not_the_answer }.to raise_error(DBus::Error) do |e|
|
54
|
-
expect(e).to_not match(/timeout/)
|
66
|
+
expect(e.message).to_not match(/timeout/)
|
55
67
|
end
|
56
68
|
end
|
57
69
|
|
@@ -60,7 +72,7 @@ describe "ServerRobustnessTest" do
|
|
60
72
|
ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.NoSuchInterface")
|
61
73
|
ifc.define_method("the_answer", "out n:i")
|
62
74
|
expect { ifc.the_answer }.to raise_error(DBus::Error) do |e|
|
63
|
-
expect(e).to_not match(/timeout/)
|
75
|
+
expect(e.message).to_not match(/timeout/)
|
64
76
|
end
|
65
77
|
end
|
66
78
|
end
|
data/spec/service_newapi.rb
CHANGED
@@ -10,11 +10,24 @@ require "dbus"
|
|
10
10
|
|
11
11
|
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties"
|
12
12
|
|
13
|
+
class TestChild < DBus::Object
|
14
|
+
def initialize(opath)
|
15
|
+
@name = opath.split("/").last.capitalize
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
dbus_interface "org.ruby.TestChild" do
|
20
|
+
dbus_attr_reader :name, "s"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
13
24
|
class Test < DBus::Object
|
14
25
|
Point2D = Struct.new(:x, :y)
|
15
26
|
|
16
27
|
attr_writer :main_loop
|
17
28
|
|
29
|
+
include DBus::ObjectManager
|
30
|
+
|
18
31
|
INTERFACE = "org.ruby.SampleInterface"
|
19
32
|
def initialize(path)
|
20
33
|
super path
|
@@ -89,6 +102,12 @@ class Test < DBus::Object
|
|
89
102
|
[coords]
|
90
103
|
end
|
91
104
|
|
105
|
+
# Two OUT arguments
|
106
|
+
dbus_method :EvenOdd, "in numbers:ai, out even:ai, out odd:ai" do |numbers|
|
107
|
+
even, odd = numbers.partition(&:even?)
|
108
|
+
[even, odd]
|
109
|
+
end
|
110
|
+
|
92
111
|
# Properties:
|
93
112
|
# ReadMe:string, returns "READ ME" at first, then what WriteMe received
|
94
113
|
# WriteMe:string
|
@@ -155,6 +174,21 @@ class Test < DBus::Object
|
|
155
174
|
end
|
156
175
|
end
|
157
176
|
|
177
|
+
dbus_interface "org.ruby.TestParent" do
|
178
|
+
dbus_method :New, "in name:s, out opath:o" do |name|
|
179
|
+
child = TestChild.new("#{path}/#{name}")
|
180
|
+
@service.export(child)
|
181
|
+
[child.path]
|
182
|
+
end
|
183
|
+
|
184
|
+
dbus_method :Delete, "in opath:o" do |opath|
|
185
|
+
raise ArgumentError unless opath.start_with?(path)
|
186
|
+
|
187
|
+
obj = @service.get_node(opath)&.object
|
188
|
+
@service.unexport(obj)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
158
192
|
dbus_interface "org.ruby.Duplicates" do
|
159
193
|
dbus_method :the_answer, "out answer:i" do
|
160
194
|
[0]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env rspec
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "spec_helper"
|
5
|
+
require "dbus"
|
6
|
+
|
7
|
+
describe "DBus::Service (server role)" do
|
8
|
+
let(:bus) { DBus::ASessionBus.new }
|
9
|
+
# This is the client role, but the server role API is bad
|
10
|
+
# and for the one test there is no difference
|
11
|
+
let(:service) { bus["org.ruby.service"] }
|
12
|
+
|
13
|
+
describe "#descendants_for" do
|
14
|
+
it "raises for not existing path" do
|
15
|
+
expect { service.descendants_for("/notthere") }.to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -31,7 +31,7 @@ if coverage
|
|
31
31
|
c.single_report_path = "coverage/lcov.info"
|
32
32
|
end
|
33
33
|
|
34
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
34
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new [
|
35
35
|
SimpleCov::Formatter::HTMLFormatter,
|
36
36
|
SimpleCov::Formatter::LcovFormatter
|
37
37
|
]
|
data/spec/thread_safety_spec.rb
CHANGED
@@ -5,28 +5,71 @@
|
|
5
5
|
require_relative "spec_helper"
|
6
6
|
require "dbus"
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
class TestSignalRace < DBus::Object
|
9
|
+
dbus_interface "org.ruby.ServerTest" do
|
10
|
+
dbus_signal :signal_without_arguments
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Run *count* threads all doing *body*, wait for their finish
|
15
|
+
def race_threads(count, &body)
|
16
|
+
jobs = count.times.map do |j|
|
17
|
+
Thread.new do
|
18
|
+
Thread.current.abort_on_exception = true
|
19
|
+
|
20
|
+
body.call(j)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
jobs.each(&:join)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Repeat *count* times: { random sleep, *body* }, printing progress
|
27
|
+
def repeat_with_jitter(count, &body)
|
28
|
+
count.times do |i|
|
29
|
+
sleep 0.1 * rand
|
30
|
+
print "#{i} "
|
31
|
+
$stdout.flush
|
15
32
|
|
33
|
+
body.call
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "thread safety" do
|
38
|
+
context "R/W: when the threads call methods with return values" do
|
39
|
+
it "it works with separate bus connections" do
|
40
|
+
race_threads(5) do |_j|
|
16
41
|
# use separate connections to avoid races
|
17
42
|
bus = DBus::ASessionBus.new
|
18
43
|
svc = bus.service("org.ruby.service")
|
19
44
|
obj = svc.object("/org/ruby/MyInstance")
|
20
45
|
obj.default_iface = "org.ruby.SampleInterface"
|
21
46
|
|
22
|
-
10
|
23
|
-
print "#{i} "
|
24
|
-
$stdout.flush
|
47
|
+
repeat_with_jitter(10) do
|
25
48
|
expect(obj.the_answer[0]).to eq(42)
|
26
|
-
sleep 0.1 * rand
|
27
49
|
end
|
28
50
|
end
|
51
|
+
puts
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "W/O: when the threads only send signals" do
|
56
|
+
it "it works with a shared separate bus connection" do
|
57
|
+
race_threads(5) do |j|
|
58
|
+
# shared connection
|
59
|
+
bus = DBus::SessionBus.instance
|
60
|
+
# hackish: we do not actually request the name
|
61
|
+
svc = DBus::Service.new("org.ruby.server-test#{j}", bus)
|
62
|
+
|
63
|
+
obj = TestSignalRace.new "/org/ruby/Foo"
|
64
|
+
svc.export obj
|
65
|
+
|
66
|
+
repeat_with_jitter(10) do
|
67
|
+
obj.signal_without_arguments
|
68
|
+
end
|
69
|
+
|
70
|
+
svc.unexport(obj)
|
71
|
+
end
|
72
|
+
puts
|
29
73
|
end
|
30
|
-
jobs.each(&:join)
|
31
74
|
end
|
32
75
|
end
|
@@ -7,6 +7,20 @@
|
|
7
7
|
<!-- Our well-known bus type, don't change this -->
|
8
8
|
<type>session</type>
|
9
9
|
|
10
|
+
<!-- Authentication:
|
11
|
+
This was useful during refactoring, but meanwhile RSpec mocking has
|
12
|
+
replaced it. -->
|
13
|
+
<!-- Explicitly list all known authentication mechanisms,
|
14
|
+
their order is not important.
|
15
|
+
By default the daemon allows all but this lets me disable some. -->
|
16
|
+
<auth>EXTERNAL</auth>
|
17
|
+
<auth>DBUS_COOKIE_SHA1</auth>
|
18
|
+
<auth>ANONYMOUS</auth>
|
19
|
+
<!-- Insecure, other users could call us and exploit debug APIs/bugs -->
|
20
|
+
<!--
|
21
|
+
<allow_anonymous/>
|
22
|
+
-->
|
23
|
+
|
10
24
|
<listen>unix:tmpdir=/tmp</listen>
|
11
25
|
<listen>tcp:host=127.0.0.1</listen>
|
12
26
|
|
@@ -24,6 +38,7 @@
|
|
24
38
|
<!-- Do not increase the limits.
|
25
39
|
Instead, lower some so that we can test resource leaks. -->
|
26
40
|
<limit name="max_match_rules_per_connection">50</limit><!-- was 512 -->
|
41
|
+
<limit name="reply_timeout">5000</limit><!-- 5 seconds -->
|
27
42
|
|
28
43
|
<!--
|
29
44
|
dbus-daemon[1700]: [session uid=1001 pid=1700] Unable to set up new connection: Failed to get AppArmor confinement information of socket peer: Protocol not available
|
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.
|
4
|
+
version: 0.20.0
|
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:
|
11
|
+
date: 2023-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rexml
|
@@ -155,6 +155,7 @@ files:
|
|
155
155
|
- lib/dbus/message.rb
|
156
156
|
- lib/dbus/message_queue.rb
|
157
157
|
- lib/dbus/object.rb
|
158
|
+
- lib/dbus/object_manager.rb
|
158
159
|
- lib/dbus/object_path.rb
|
159
160
|
- lib/dbus/proxy_object.rb
|
160
161
|
- lib/dbus/proxy_object_factory.rb
|
@@ -164,6 +165,7 @@ files:
|
|
164
165
|
- lib/dbus/xml.rb
|
165
166
|
- ruby-dbus.gemspec
|
166
167
|
- spec/async_spec.rb
|
168
|
+
- spec/auth_spec.rb
|
167
169
|
- spec/binding_spec.rb
|
168
170
|
- spec/bus_and_xml_backend_spec.rb
|
169
171
|
- spec/bus_driver_spec.rb
|
@@ -179,15 +181,18 @@ files:
|
|
179
181
|
- spec/introspection_spec.rb
|
180
182
|
- spec/main_loop_spec.rb
|
181
183
|
- spec/node_spec.rb
|
184
|
+
- spec/object_manager_spec.rb
|
182
185
|
- spec/object_path_spec.rb
|
183
186
|
- spec/object_spec.rb
|
184
187
|
- spec/packet_marshaller_spec.rb
|
185
188
|
- spec/packet_unmarshaller_spec.rb
|
186
189
|
- spec/property_spec.rb
|
190
|
+
- spec/proxy_object_interface_spec.rb
|
187
191
|
- spec/proxy_object_spec.rb
|
188
192
|
- spec/server_robustness_spec.rb
|
189
193
|
- spec/server_spec.rb
|
190
194
|
- spec/service_newapi.rb
|
195
|
+
- spec/service_spec.rb
|
191
196
|
- spec/session_bus_spec.rb
|
192
197
|
- spec/session_bus_spec_manual.rb
|
193
198
|
- spec/signal_spec.rb
|
@@ -220,8 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
220
225
|
- !ruby/object:Gem::Version
|
221
226
|
version: '0'
|
222
227
|
requirements: []
|
223
|
-
|
224
|
-
rubygems_version: 2.7.6.3
|
228
|
+
rubygems_version: 3.3.0.dev
|
225
229
|
signing_key:
|
226
230
|
specification_version: 4
|
227
231
|
summary: Ruby module for interaction with D-Bus
|