ruby-dbus 0.18.1 → 0.20.0

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,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