ruby-dbus 0.16.0 → 0.17.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.
- checksums.yaml +4 -4
- data/NEWS.md +16 -0
- data/README.md +3 -5
- data/Rakefile +25 -7
- data/VERSION +1 -1
- data/doc/Reference.md +84 -1
- data/examples/doc/_extract_examples +5 -0
- data/examples/gdbus/gdbus +20 -19
- data/examples/service/call_service.rb +1 -1
- data/lib/dbus/auth.rb +8 -8
- data/lib/dbus/bus.rb +16 -8
- data/lib/dbus/core_ext/class/attribute.rb +1 -1
- data/lib/dbus/introspect.rb +69 -20
- data/lib/dbus/marshall.rb +1 -1
- data/lib/dbus/message_queue.rb +6 -5
- data/lib/dbus/object.rb +264 -13
- data/lib/dbus/proxy_object.rb +7 -0
- data/lib/dbus/proxy_object_interface.rb +1 -0
- data/lib/dbus/type.rb +18 -0
- data/ruby-dbus.gemspec +5 -3
- data/spec/main_loop_spec.rb +1 -1
- data/spec/property_spec.rb +53 -3
- data/spec/service_newapi.rb +20 -66
- data/spec/signal_spec.rb +3 -3
- data/spec/spec_helper.rb +18 -6
- data/spec/tools/dbus-limited-session.conf +4 -0
- metadata +22 -8
data/lib/dbus/object.rb
CHANGED
@@ -7,9 +7,11 @@
|
|
7
7
|
# See the file "COPYING" for the exact licensing terms.
|
8
8
|
|
9
9
|
require "thread"
|
10
|
-
|
10
|
+
require_relative "core_ext/class/attribute"
|
11
11
|
|
12
12
|
module DBus
|
13
|
+
PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties".freeze
|
14
|
+
|
13
15
|
# Exported object type
|
14
16
|
# = Exportable D-Bus object class
|
15
17
|
#
|
@@ -58,7 +60,7 @@ module DBus
|
|
58
60
|
meth.rets.zip(retdata).each do |rsig, rdata|
|
59
61
|
reply.add_param(rsig.type, rdata)
|
60
62
|
end
|
61
|
-
rescue => ex
|
63
|
+
rescue StandardError => ex
|
62
64
|
dbus_msg_exc = msg.annotate_exception(ex)
|
63
65
|
reply = ErrorMessage.from_exception(dbus_msg_exc).reply_to(msg)
|
64
66
|
end
|
@@ -85,45 +87,294 @@ module DBus
|
|
85
87
|
end
|
86
88
|
end
|
87
89
|
|
88
|
-
#
|
89
|
-
|
90
|
+
# Forgetting to declare the interface for a method/signal/property
|
91
|
+
# is a ScriptError.
|
92
|
+
class UndefinedInterface < ScriptError # rubocop:disable Lint/InheritException
|
90
93
|
def initialize(sym)
|
91
|
-
super "No interface specified for #{sym}"
|
94
|
+
super "No interface specified for #{sym}. Enclose it in dbus_interface."
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# A read-write property accessing an instance variable.
|
99
|
+
# A combination of `attr_accessor` and {.dbus_accessor}.
|
100
|
+
#
|
101
|
+
# PropertiesChanged signal will be emitted whenever `foo_bar=` is used
|
102
|
+
# but not when @foo_bar is written directly.
|
103
|
+
#
|
104
|
+
# @param ruby_name [Symbol] :foo_bar is exposed as FooBar;
|
105
|
+
# use dbus_name to override
|
106
|
+
# @param type a signature like "s" or "a(uus)" or Type::STRING
|
107
|
+
# @param dbus_name [String] if not given it is made
|
108
|
+
# by CamelCasing the ruby_name. foo_bar becomes FooBar
|
109
|
+
# to convert the Ruby convention to the DBus convention.
|
110
|
+
# @return [void]
|
111
|
+
def self.dbus_attr_accessor(ruby_name, type, dbus_name: nil)
|
112
|
+
attr_accessor(ruby_name)
|
113
|
+
dbus_accessor(ruby_name, type, dbus_name: dbus_name)
|
114
|
+
end
|
115
|
+
|
116
|
+
# A read-only property accessing an instance variable.
|
117
|
+
# A combination of `attr_reader` and {.dbus_reader}.
|
118
|
+
#
|
119
|
+
# Whenever the property value gets changed from "inside" the object,
|
120
|
+
# you should emit the `PropertiesChanged` signal by calling
|
121
|
+
#
|
122
|
+
# object[DBus::PROPERTY_INTERFACE].PropertiesChanged(interface_name, {dbus_name.to_s => value}, [])
|
123
|
+
#
|
124
|
+
# or, omitting the value in the signal,
|
125
|
+
#
|
126
|
+
# object[DBus::PROPERTY_INTERFACE].PropertiesChanged(interface_name, {}, [dbus_name.to_s])
|
127
|
+
#
|
128
|
+
# @param (see .dbus_attr_accessor)
|
129
|
+
# @return (see .dbus_attr_accessor)
|
130
|
+
def self.dbus_attr_reader(ruby_name, type, dbus_name: nil)
|
131
|
+
attr_reader(ruby_name)
|
132
|
+
dbus_reader(ruby_name, type, dbus_name: dbus_name)
|
133
|
+
end
|
134
|
+
|
135
|
+
# A write-only property accessing an instance variable.
|
136
|
+
# A combination of `attr_writer` and {.dbus_writer}.
|
137
|
+
#
|
138
|
+
# @param (see .dbus_attr_accessor)
|
139
|
+
# @return (see .dbus_attr_accessor)
|
140
|
+
def self.dbus_attr_writer(ruby_name, type, dbus_name: nil)
|
141
|
+
attr_writer(ruby_name)
|
142
|
+
dbus_writer(ruby_name, type, dbus_name: dbus_name)
|
143
|
+
end
|
144
|
+
|
145
|
+
# A read-write property using a pair of reader/writer methods
|
146
|
+
# (which must already exist).
|
147
|
+
# (To directly access an instance variable, use {.dbus_attr_accessor} instead)
|
148
|
+
#
|
149
|
+
# Uses {.dbus_watcher} to set up the PropertiesChanged signal.
|
150
|
+
#
|
151
|
+
# @param (see .dbus_attr_accessor)
|
152
|
+
# @return (see .dbus_attr_accessor)
|
153
|
+
def self.dbus_accessor(ruby_name, type, dbus_name: nil)
|
154
|
+
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
155
|
+
|
156
|
+
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
157
|
+
property = Property.new(dbus_name, type, :readwrite, ruby_name: ruby_name)
|
158
|
+
@@cur_intf.define(property)
|
159
|
+
|
160
|
+
dbus_watcher(ruby_name, dbus_name: dbus_name)
|
161
|
+
end
|
162
|
+
|
163
|
+
# A read-only property accessing a reader method (which must already exist).
|
164
|
+
# (To directly access an instance variable, use {.dbus_attr_reader} instead)
|
165
|
+
#
|
166
|
+
# Whenever the property value gets changed from "inside" the object,
|
167
|
+
# you should emit the `PropertiesChanged` signal by calling
|
168
|
+
#
|
169
|
+
# object[DBus::PROPERTY_INTERFACE].PropertiesChanged(interface_name, {dbus_name.to_s => value}, [])
|
170
|
+
#
|
171
|
+
# or, omitting the value in the signal,
|
172
|
+
#
|
173
|
+
# object[DBus::PROPERTY_INTERFACE].PropertiesChanged(interface_name, {}, [dbus_name.to_s])
|
174
|
+
#
|
175
|
+
# @param (see .dbus_attr_accessor)
|
176
|
+
# @return (see .dbus_attr_accessor)
|
177
|
+
def self.dbus_reader(ruby_name, type, dbus_name: nil)
|
178
|
+
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
179
|
+
|
180
|
+
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
181
|
+
property = Property.new(dbus_name, type, :read, ruby_name: ruby_name)
|
182
|
+
@@cur_intf.define(property)
|
183
|
+
end
|
184
|
+
|
185
|
+
# A write-only property accessing a writer method (which must already exist).
|
186
|
+
# (To directly access an instance variable, use {.dbus_attr_writer} instead)
|
187
|
+
#
|
188
|
+
# Uses {.dbus_watcher} to set up the PropertiesChanged signal.
|
189
|
+
#
|
190
|
+
# @param (see .dbus_attr_accessor)
|
191
|
+
# @return (see .dbus_attr_accessor)
|
192
|
+
def self.dbus_writer(ruby_name, type, dbus_name: nil)
|
193
|
+
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
194
|
+
|
195
|
+
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
196
|
+
property = Property.new(dbus_name, type, :write, ruby_name: ruby_name)
|
197
|
+
@@cur_intf.define(property)
|
198
|
+
|
199
|
+
dbus_watcher(ruby_name, dbus_name: dbus_name)
|
200
|
+
end
|
201
|
+
|
202
|
+
# Enables automatic sending of the PropertiesChanged signal.
|
203
|
+
# For *ruby_name* `foo_bar`, wrap `foo_bar=` so that it sends
|
204
|
+
# the signal for FooBar.
|
205
|
+
# The original version remains as `_original_foo_bar=`.
|
206
|
+
#
|
207
|
+
# @param ruby_name [Symbol] :foo_bar and :foo_bar= both mean the same thing
|
208
|
+
# @param dbus_name [String] if not given it is made
|
209
|
+
# by CamelCasing the ruby_name. foo_bar becomes FooBar
|
210
|
+
# to convert the Ruby convention to the DBus convention.
|
211
|
+
# @return [void]
|
212
|
+
def self.dbus_watcher(ruby_name, dbus_name: nil)
|
213
|
+
raise UndefinedInterface, ruby_name if @@cur_intf.nil?
|
214
|
+
cur_intf = @@cur_intf
|
215
|
+
|
216
|
+
ruby_name = ruby_name.to_s.sub(/=$/, "").to_sym
|
217
|
+
ruby_name_eq = "#{ruby_name}=".to_sym
|
218
|
+
original_ruby_name_eq = "_original_#{ruby_name_eq}"
|
219
|
+
|
220
|
+
dbus_name = make_dbus_name(ruby_name, dbus_name: dbus_name)
|
221
|
+
|
222
|
+
# the argument order is alias_method(new_name, existing_name)
|
223
|
+
alias_method original_ruby_name_eq, ruby_name_eq
|
224
|
+
define_method ruby_name_eq do |value|
|
225
|
+
public_send(original_ruby_name_eq, value)
|
226
|
+
|
227
|
+
# TODO: respect EmitsChangedSignal to use invalidated_properties instead
|
228
|
+
# PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
|
229
|
+
PropertiesChanged(cur_intf.name, { dbus_name.to_s => value }, [])
|
92
230
|
end
|
93
231
|
end
|
94
232
|
|
95
233
|
# Defines an exportable method on the object with the given name _sym_,
|
96
234
|
# _prototype_ and the code in a block.
|
97
|
-
|
235
|
+
# @param prototype [Prototype]
|
236
|
+
def self.dbus_method(sym, prototype = "", &block)
|
98
237
|
raise UndefinedInterface, sym if @@cur_intf.nil?
|
99
|
-
@@cur_intf.define(Method.new(sym.to_s).from_prototype(
|
100
|
-
|
238
|
+
@@cur_intf.define(Method.new(sym.to_s).from_prototype(prototype))
|
239
|
+
|
240
|
+
ruby_name = Object.make_method_name(@@cur_intf.name, sym.to_s)
|
241
|
+
# ::Module#define_method(name) { body }
|
242
|
+
define_method(ruby_name, &block)
|
101
243
|
end
|
102
244
|
|
103
245
|
# Emits a signal from the object with the given _interface_, signal
|
104
246
|
# _sig_ and arguments _args_.
|
247
|
+
# @param intf [Interface]
|
248
|
+
# @param sig [Signal]
|
249
|
+
# @param args arguments for the signal
|
105
250
|
def emit(intf, sig, *args)
|
106
251
|
@service.bus.emit(@service, self, intf, sig, *args)
|
107
252
|
end
|
108
253
|
|
109
254
|
# Defines a signal for the object with a given name _sym_ and _prototype_.
|
110
|
-
def self.dbus_signal(sym,
|
255
|
+
def self.dbus_signal(sym, prototype = "")
|
111
256
|
raise UndefinedInterface, sym if @@cur_intf.nil?
|
112
257
|
cur_intf = @@cur_intf
|
113
|
-
signal = Signal.new(sym.to_s).from_prototype(
|
114
|
-
cur_intf.define(Signal.new(sym.to_s).from_prototype(
|
258
|
+
signal = Signal.new(sym.to_s).from_prototype(prototype)
|
259
|
+
cur_intf.define(Signal.new(sym.to_s).from_prototype(prototype))
|
260
|
+
|
261
|
+
# ::Module#define_method(name) { body }
|
115
262
|
define_method(sym.to_s) do |*args|
|
116
263
|
emit(cur_intf, signal, *args)
|
117
264
|
end
|
118
265
|
end
|
119
266
|
|
120
|
-
####################################################################
|
121
|
-
|
122
267
|
# Helper method that returns a method name generated from the interface
|
123
268
|
# name _intfname_ and method name _methname_.
|
124
269
|
# @api private
|
125
270
|
def self.make_method_name(intfname, methname)
|
126
271
|
"#{intfname}%%#{methname}"
|
127
272
|
end
|
273
|
+
|
274
|
+
# TODO: borrow a proven implementation
|
275
|
+
# @param str [String]
|
276
|
+
# @return [String]
|
277
|
+
# @api private
|
278
|
+
def self.camelize(str)
|
279
|
+
str.split(/_/).map(&:capitalize).join("")
|
280
|
+
end
|
281
|
+
|
282
|
+
# Make a D-Bus conventional name, CamelCased.
|
283
|
+
# @param ruby_name [String,Symbol] eg :do_something
|
284
|
+
# @param dbus_name [String,Symbol,nil] use this if given
|
285
|
+
# @return [Symbol] eg DoSomething
|
286
|
+
def self.make_dbus_name(ruby_name, dbus_name: nil)
|
287
|
+
dbus_name ||= camelize(ruby_name.to_s)
|
288
|
+
dbus_name.to_sym
|
289
|
+
end
|
290
|
+
|
291
|
+
# @param interface_name [String]
|
292
|
+
# @param property_name [String]
|
293
|
+
# @return [Property]
|
294
|
+
# @raise [DBus::Error]
|
295
|
+
# @api private
|
296
|
+
def dbus_lookup_property(interface_name, property_name)
|
297
|
+
# what should happen for unknown properties
|
298
|
+
# plasma: InvalidArgs (propname), UnknownInterface (interface)
|
299
|
+
# systemd: UnknownProperty
|
300
|
+
interface = intfs[interface_name]
|
301
|
+
if !interface
|
302
|
+
raise DBus.error("org.freedesktop.DBus.Error.UnknownProperty"),
|
303
|
+
"Property '#{interface_name}.#{property_name}' (on object '#{@path}') not found: no such interface"
|
304
|
+
end
|
305
|
+
|
306
|
+
property = interface.properties[property_name.to_sym]
|
307
|
+
if !property
|
308
|
+
raise DBus.error("org.freedesktop.DBus.Error.UnknownProperty"),
|
309
|
+
"Property '#{interface_name}.#{property_name}' (on object '#{@path}') not found"
|
310
|
+
end
|
311
|
+
|
312
|
+
property
|
313
|
+
end
|
314
|
+
|
315
|
+
####################################################################
|
316
|
+
|
317
|
+
# use the above defined methods to declare the property-handling
|
318
|
+
# interfaces and methods
|
319
|
+
|
320
|
+
dbus_interface PROPERTY_INTERFACE do
|
321
|
+
dbus_method :Get, "in interface_name:s, in property_name:s, out value:v" do |interface_name, property_name|
|
322
|
+
property = dbus_lookup_property(interface_name, property_name)
|
323
|
+
|
324
|
+
if property.readable?
|
325
|
+
ruby_name = property.ruby_name
|
326
|
+
value = public_send(ruby_name)
|
327
|
+
[value]
|
328
|
+
else
|
329
|
+
raise DBus.error("org.freedesktop.DBus.Error.PropertyWriteOnly"),
|
330
|
+
"Property '#{interface_name}.#{property_name}' (on object '#{@path}') is not readable"
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
dbus_method :Set, "in interface_name:s, in property_name:s, in val:v" do |interface_name, property_name, value|
|
335
|
+
property = dbus_lookup_property(interface_name, property_name)
|
336
|
+
|
337
|
+
if property.writable?
|
338
|
+
ruby_name_eq = "#{property.ruby_name}="
|
339
|
+
public_send(ruby_name_eq, value)
|
340
|
+
else
|
341
|
+
raise DBus.error("org.freedesktop.DBus.Error.PropertyReadOnly"),
|
342
|
+
"Property '#{interface_name}.#{property_name}' (on object '#{@path}') is not writable"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
dbus_method :GetAll, "in interface_name:s, out value:a{sv}" do |interface_name|
|
347
|
+
interface = intfs[interface_name]
|
348
|
+
if !interface
|
349
|
+
raise DBus.error("org.freedesktop.DBus.Error.UnknownProperty"),
|
350
|
+
"Properties '#{interface_name}.*' (on object '#{@path}') not found: no such interface"
|
351
|
+
end
|
352
|
+
|
353
|
+
p_hash = {}
|
354
|
+
interface.properties.each do |p_name, property|
|
355
|
+
next unless property.readable?
|
356
|
+
|
357
|
+
ruby_name = property.ruby_name
|
358
|
+
begin
|
359
|
+
# D-Bus spec says:
|
360
|
+
# > If GetAll is called with a valid interface name for which some
|
361
|
+
# > properties are not accessible to the caller (for example, due
|
362
|
+
# > to per-property access control implemented in the service),
|
363
|
+
# > those properties should be silently omitted from the result
|
364
|
+
# > array.
|
365
|
+
# so we will silently omit properties that fail to read.
|
366
|
+
# Get'ting them individually will send DBus.Error
|
367
|
+
p_hash[p_name.to_s] = public_send(ruby_name)
|
368
|
+
rescue StandardError
|
369
|
+
DBus.logger.debug "Property '#{interface_name}.#{p_name}' (on object '#{@path}')" \
|
370
|
+
" has raised during GetAll, omitting it"
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
[p_hash]
|
375
|
+
end
|
376
|
+
|
377
|
+
dbus_signal :PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
|
378
|
+
end
|
128
379
|
end
|
129
380
|
end
|
data/lib/dbus/proxy_object.rb
CHANGED
@@ -44,6 +44,7 @@ module DBus
|
|
44
44
|
end
|
45
45
|
|
46
46
|
# Returns the interfaces of the object.
|
47
|
+
# @return [Array<String>] names of the interfaces
|
47
48
|
def interfaces
|
48
49
|
introspect unless introspected
|
49
50
|
@interfaces.keys
|
@@ -129,6 +130,11 @@ module DBus
|
|
129
130
|
####################################################
|
130
131
|
private
|
131
132
|
|
133
|
+
# rubocop:disable Style/MethodMissing
|
134
|
+
# but https://github.com/rubocop-hq/ruby-style-guide#no-method-missing
|
135
|
+
# and http://blog.marc-andre.ca/2010/11/15/methodmissing-politely/
|
136
|
+
# have a point to be investigated
|
137
|
+
|
132
138
|
# Handles all unkown methods, mostly to route method calls to the
|
133
139
|
# default interface.
|
134
140
|
def method_missing(name, *args, &reply_handler)
|
@@ -150,5 +156,6 @@ module DBus
|
|
150
156
|
raise NoMethodError, "undefined method `#{name}' for DBus interface `#{@default_iface}' on object `#{@path}'"
|
151
157
|
end
|
152
158
|
end
|
159
|
+
# rubocop:enable Style/MethodMissing
|
153
160
|
end # class ProxyObject
|
154
161
|
end
|
data/lib/dbus/type.rb
CHANGED
@@ -9,6 +9,24 @@
|
|
9
9
|
# See the file "COPYING" for the exact licensing terms.
|
10
10
|
|
11
11
|
module DBus
|
12
|
+
# Like a {Signature} but containing only a single complete type.
|
13
|
+
#
|
14
|
+
# For documentation purposes only.
|
15
|
+
class SingleCompleteType < String; end
|
16
|
+
|
17
|
+
# Zero or more {SingleCompleteType}s; its own type code is "g".
|
18
|
+
# For example "ssv" for a method taking two Strings and a Variant/
|
19
|
+
#
|
20
|
+
# For documentation purposes only.
|
21
|
+
class Signature < String; end
|
22
|
+
|
23
|
+
# Similar to {Signature} but for {DBus::Object.define_method},
|
24
|
+
# contains names and direction of the parameters.
|
25
|
+
# For example "in query:s, in case_sensitive:b, out results:ao".
|
26
|
+
#
|
27
|
+
# For documentation purposes only.
|
28
|
+
class Prototype < String; end
|
29
|
+
|
12
30
|
# = D-Bus type module
|
13
31
|
#
|
14
32
|
# This module containts the constants of the types specified in the D-Bus
|
data/ruby-dbus.gemspec
CHANGED
@@ -18,15 +18,17 @@ GEMSPEC = Gem::Specification.new do |s|
|
|
18
18
|
]
|
19
19
|
s.require_path = "lib"
|
20
20
|
|
21
|
-
s.required_ruby_version = ">= 2.
|
21
|
+
s.required_ruby_version = ">= 2.1.0"
|
22
|
+
|
23
|
+
s.add_dependency "rexml"
|
22
24
|
|
23
25
|
# This is optional
|
24
26
|
# s.add_runtime_dependency "nokogiri"
|
25
27
|
|
26
|
-
s.add_development_dependency "coveralls"
|
27
28
|
s.add_development_dependency "packaging_rake_tasks"
|
28
29
|
s.add_development_dependency "rake"
|
29
30
|
s.add_development_dependency "rspec", "~> 3"
|
30
|
-
s.add_development_dependency "rubocop", "= 0.
|
31
|
+
s.add_development_dependency "rubocop", "= 0.50.0"
|
31
32
|
s.add_development_dependency "simplecov"
|
33
|
+
s.add_development_dependency "simplecov-lcov"
|
32
34
|
end
|
data/spec/main_loop_spec.rb
CHANGED
data/spec/property_spec.rb
CHANGED
@@ -4,8 +4,8 @@ require "dbus"
|
|
4
4
|
|
5
5
|
describe "PropertyTest" do
|
6
6
|
before(:each) do
|
7
|
-
session_bus = DBus::ASessionBus.new
|
8
|
-
@svc = session_bus.service("org.ruby.service")
|
7
|
+
@session_bus = DBus::ASessionBus.new
|
8
|
+
@svc = @session_bus.service("org.ruby.service")
|
9
9
|
@obj = @svc.object("/org/ruby/MyInstance")
|
10
10
|
@iface = @obj["org.ruby.SampleInterface"]
|
11
11
|
end
|
@@ -21,6 +21,10 @@ describe "PropertyTest" do
|
|
21
21
|
expect(iface["ReadMe"]).to eq("READ ME")
|
22
22
|
end
|
23
23
|
|
24
|
+
it "gets an error when reading a property whose implementation raises" do
|
25
|
+
expect { @iface["Explosive"] }.to raise_error(DBus::Error, /Something failed/)
|
26
|
+
end
|
27
|
+
|
24
28
|
it "tests property nonreading" do
|
25
29
|
expect { @iface["WriteMe"] }.to raise_error(DBus::Error, /not readable/)
|
26
30
|
end
|
@@ -31,7 +35,7 @@ describe "PropertyTest" do
|
|
31
35
|
end
|
32
36
|
|
33
37
|
# https://github.com/mvidner/ruby-dbus/pull/19
|
34
|
-
it "tests service select timeout" do
|
38
|
+
it "tests service select timeout", slow: true do
|
35
39
|
@iface["ReadOrWriteMe"] = "VALUE"
|
36
40
|
expect(@iface["ReadOrWriteMe"]).to eq("VALUE")
|
37
41
|
# wait for the service to become idle
|
@@ -64,4 +68,50 @@ describe "PropertyTest" do
|
|
64
68
|
it "tests unknown property writing" do
|
65
69
|
expect { @iface["Spoon"] = "FPRK" }.to raise_error(DBus::Error, /not found/)
|
66
70
|
end
|
71
|
+
|
72
|
+
it "errors for a property on an unknown interface" do
|
73
|
+
# our idiomatic way would error out on interface lookup already,
|
74
|
+
# so do it the low level way
|
75
|
+
prop_if = @obj[DBus::PROPERTY_INTERFACE]
|
76
|
+
expect { prop_if.Get("org.ruby.NoSuchInterface", "SomeProperty") }.to raise_error(DBus::Error) do |e|
|
77
|
+
expect(e.name).to match(/UnknownProperty/)
|
78
|
+
expect(e.message).to match(/no such interface/)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "errors for GetAll on an unknown interface" do
|
83
|
+
# no idiomatic way?
|
84
|
+
# so do it the low level way
|
85
|
+
prop_if = @obj[DBus::PROPERTY_INTERFACE]
|
86
|
+
expect { prop_if.GetAll("org.ruby.NoSuchInterface") }.to raise_error(DBus::Error) do |e|
|
87
|
+
expect(e.name).to match(/UnknownProperty/)
|
88
|
+
expect(e.message).to match(/no such interface/)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "receives a PropertiesChanged signal", slow: true do
|
93
|
+
received = {}
|
94
|
+
|
95
|
+
# TODO: for client side, provide a helper on_properties_changed,
|
96
|
+
# or automate it even more in ProxyObject, ProxyObjectInterface
|
97
|
+
prop_if = @obj[DBus::PROPERTY_INTERFACE]
|
98
|
+
prop_if.on_signal("PropertiesChanged") do |_interface_name, changed_props, _invalidated_props|
|
99
|
+
received.merge!(changed_props)
|
100
|
+
end
|
101
|
+
|
102
|
+
@iface["ReadOrWriteMe"] = "VALUE"
|
103
|
+
|
104
|
+
# loop to process the signal. complicated :-( see signal_spec.rb
|
105
|
+
loop = DBus::Main.new
|
106
|
+
loop << @session_bus
|
107
|
+
quitter = Thread.new do
|
108
|
+
sleep 1
|
109
|
+
loop.quit
|
110
|
+
end
|
111
|
+
loop.run
|
112
|
+
# quitter has told loop.run to quit
|
113
|
+
quitter.join
|
114
|
+
|
115
|
+
expect(received["ReadOrWriteMe"]).to eq("VALUE")
|
116
|
+
end
|
67
117
|
end
|
data/spec/service_newapi.rb
CHANGED
@@ -59,6 +59,26 @@ class Test < DBus::Object
|
|
59
59
|
dbus_method :mirror_byte_array, "in bytes:ay, out mirrored:ay" do |bytes|
|
60
60
|
[bytes]
|
61
61
|
end
|
62
|
+
|
63
|
+
# Properties:
|
64
|
+
# ReadMe:string, returns "READ ME" at first, then what WriteMe received
|
65
|
+
# WriteMe:string
|
66
|
+
# ReadOrWriteMe:string, returns "READ OR WRITE ME" at first
|
67
|
+
dbus_attr_accessor :read_or_write_me, "s"
|
68
|
+
dbus_attr_reader :read_me, "s"
|
69
|
+
|
70
|
+
def write_me=(value)
|
71
|
+
@read_me = value
|
72
|
+
end
|
73
|
+
dbus_writer :write_me, "s"
|
74
|
+
|
75
|
+
dbus_attr_writer :password, "s"
|
76
|
+
|
77
|
+
# a property that raises when client tries to read it
|
78
|
+
def explosive
|
79
|
+
raise "Something failed"
|
80
|
+
end
|
81
|
+
dbus_reader :explosive, "s"
|
62
82
|
end
|
63
83
|
|
64
84
|
# closing and reopening the same interface
|
@@ -118,72 +138,6 @@ class Test < DBus::Object
|
|
118
138
|
dbus_signal :LongTaskStart
|
119
139
|
dbus_signal :LongTaskEnd
|
120
140
|
end
|
121
|
-
|
122
|
-
# Properties:
|
123
|
-
# ReadMe:string, returns "READ ME" at first, then what WriteMe received
|
124
|
-
# WriteMe:string
|
125
|
-
# ReadOrWriteMe:string, returns "READ OR WRITE ME" at first
|
126
|
-
dbus_interface PROPERTY_INTERFACE do
|
127
|
-
dbus_method :Get, "in interface:s, in propname:s, out value:v" do |interface, propname|
|
128
|
-
unless interface == INTERFACE
|
129
|
-
raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
|
130
|
-
"Interface '#{interface}' not found on object '#{@path}'"
|
131
|
-
end
|
132
|
-
|
133
|
-
case propname
|
134
|
-
when "ReadMe"
|
135
|
-
[@read_me]
|
136
|
-
when "ReadOrWriteMe"
|
137
|
-
[@read_or_write_me]
|
138
|
-
when "WriteMe"
|
139
|
-
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
|
140
|
-
"Property '#{interface}.#{propname}' (on object '#{@path}') is not readable"
|
141
|
-
else
|
142
|
-
# what should happen for unknown properties
|
143
|
-
# plasma: InvalidArgs (propname), UnknownInterface (interface)
|
144
|
-
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
|
145
|
-
"Property '#{interface}.#{propname}' not found on object '#{@path}'"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
dbus_method :Set, "in interface:s, in propname:s, in value:v" do |interface, propname, value|
|
150
|
-
unless interface == INTERFACE
|
151
|
-
raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
|
152
|
-
"Interface '#{interface}' not found on object '#{@path}'"
|
153
|
-
end
|
154
|
-
|
155
|
-
case propname
|
156
|
-
when "ReadMe"
|
157
|
-
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
|
158
|
-
"Property '#{interface}.#{propname}' (on object '#{@path}') is not writable"
|
159
|
-
when "ReadOrWriteMe"
|
160
|
-
@read_or_write_me = value
|
161
|
-
self.PropertiesChanged(interface, { propname => value }, [])
|
162
|
-
when "WriteMe"
|
163
|
-
@read_me = value
|
164
|
-
self.PropertiesChanged(interface, { "ReadMe" => value }, [])
|
165
|
-
else
|
166
|
-
raise DBus.error("org.freedesktop.DBus.Error.InvalidArgs"),
|
167
|
-
"Property '#{interface}.#{propname}' not found on object '#{@path}'"
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
dbus_method :GetAll, "in interface:s, out value:a{sv}" do |interface|
|
172
|
-
unless interface == INTERFACE
|
173
|
-
raise DBus.error("org.freedesktop.DBus.Error.UnknownInterface"),
|
174
|
-
"Interface '#{interface}' not found on object '#{@path}'"
|
175
|
-
end
|
176
|
-
|
177
|
-
[
|
178
|
-
{
|
179
|
-
"ReadMe" => @read_me,
|
180
|
-
"ReadOrWriteMe" => @read_or_write_me
|
181
|
-
}
|
182
|
-
]
|
183
|
-
end
|
184
|
-
|
185
|
-
dbus_signal :PropertiesChanged, "interface:s, changed_properties:a{sv}, invalidated_properties:as"
|
186
|
-
end
|
187
141
|
end
|
188
142
|
|
189
143
|
class Derived < Test
|
data/spec/signal_spec.rb
CHANGED
@@ -29,7 +29,7 @@ describe "SignalHandlerTest" do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# testing for commit 017c83 (kkaempf)
|
32
|
-
it "tests overriding a handler" do
|
32
|
+
it "tests overriding a handler", slow: true do
|
33
33
|
DBus.logger.debug "Inside test_overriding_a_handler"
|
34
34
|
counter = 0
|
35
35
|
|
@@ -52,7 +52,7 @@ describe "SignalHandlerTest" do
|
|
52
52
|
expect(counter).to eq(1)
|
53
53
|
end
|
54
54
|
|
55
|
-
it "tests on signal overload" do
|
55
|
+
it "tests on signal overload", slow: true do
|
56
56
|
DBus.logger.debug "Inside test_on_signal_overload"
|
57
57
|
counter = 0
|
58
58
|
started = false
|
@@ -74,7 +74,7 @@ describe "SignalHandlerTest" do
|
|
74
74
|
expect { @intf.on_signal "to", "many", "yarrrrr!" }.to raise_error(ArgumentError)
|
75
75
|
end
|
76
76
|
|
77
|
-
it "is possible to add signal handlers from within handlers" do
|
77
|
+
it "is possible to add signal handlers from within handlers", slow: true do
|
78
78
|
ended = false
|
79
79
|
@intf.on_signal "LongTaskStart" do
|
80
80
|
@intf.on_signal "LongTaskEnd" do
|
data/spec/spec_helper.rb
CHANGED
@@ -2,8 +2,7 @@ coverage = if ENV["COVERAGE"]
|
|
2
2
|
ENV["COVERAGE"] == "true"
|
3
3
|
else
|
4
4
|
# heuristics: enable for interactive builds (but not in OBS)
|
5
|
-
|
6
|
-
ENV["DISPLAY"] || ENV["TRAVIS"]
|
5
|
+
ENV["DISPLAY"]
|
7
6
|
end
|
8
7
|
|
9
8
|
if coverage
|
@@ -15,11 +14,24 @@ if coverage
|
|
15
14
|
# do not cover the activesupport helpers
|
16
15
|
SimpleCov.add_filter "/core_ext/"
|
17
16
|
|
18
|
-
# use coveralls for on-line code coverage reporting at Travis CI
|
19
|
-
if ENV["TRAVIS"]
|
20
|
-
require "coveralls"
|
21
|
-
end
|
22
17
|
SimpleCov.start
|
18
|
+
|
19
|
+
# additionally use the LCOV format for on-line code coverage reporting at CI
|
20
|
+
if ENV["COVERAGE_LCOV"] == "true"
|
21
|
+
require "simplecov-lcov"
|
22
|
+
|
23
|
+
SimpleCov::Formatter::LcovFormatter.config do |c|
|
24
|
+
c.report_with_single_file = true
|
25
|
+
# this is the default Coveralls GitHub Action location
|
26
|
+
# https://github.com/marketplace/actions/coveralls-github-action
|
27
|
+
c.single_report_path = "coverage/lcov.info"
|
28
|
+
end
|
29
|
+
|
30
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
31
|
+
SimpleCov::Formatter::HTMLFormatter,
|
32
|
+
SimpleCov::Formatter::LcovFormatter
|
33
|
+
]
|
34
|
+
end
|
23
35
|
end
|
24
36
|
|
25
37
|
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
@@ -25,4 +25,8 @@
|
|
25
25
|
Instead, lower some so that we can test resource leaks. -->
|
26
26
|
<limit name="max_match_rules_per_connection">50</limit><!-- was 512 -->
|
27
27
|
|
28
|
+
<!--
|
29
|
+
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
|
30
|
+
-->
|
31
|
+
<apparmor mode="disabled"/>
|
28
32
|
</busconfig>
|