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.
@@ -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
@@ -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
  ]
@@ -5,28 +5,71 @@
5
5
  require_relative "spec_helper"
6
6
  require "dbus"
7
7
 
8
- describe "ThreadSafetyTest" do
9
- it "tests thread competition" do
10
- print "Thread competition: "
11
- jobs = []
12
- 5.times do
13
- jobs << Thread.new do
14
- Thread.current.abort_on_exception = true
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.times do |i|
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.18.1
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: 2022-07-13 00:00:00.000000000 Z
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
- rubyforge_project:
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