ruby-dbus 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
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
- require "dbus/core_ext/class/attribute"
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
- # Dummy undefined interface class.
89
- class UndefinedInterface < ScriptError
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
- def self.dbus_method(sym, protoype = "", &block)
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(protoype))
100
- define_method(Object.make_method_name(@@cur_intf.name, sym.to_s), &block)
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, protoype = "")
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(protoype)
114
- cur_intf.define(Signal.new(sym.to_s).from_prototype(protoype))
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
@@ -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
@@ -87,6 +87,7 @@ module DBus
87
87
  end
88
88
 
89
89
  # Defines a proxied method on the interface.
90
+ # Better name: declare_method
90
91
  def define_method(methodname, prototype)
91
92
  m = Method.new(methodname)
92
93
  m.from_prototype(prototype)
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.0.0"
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.41.2"
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
@@ -70,7 +70,7 @@ describe "MainLoopTest" do
70
70
  @obj.on_signal "LongTaskEnd"
71
71
  end
72
72
 
73
- it "tests loop quit" do
73
+ it "tests loop quit", slow: true do
74
74
  test_loop_quit 1
75
75
  end
76
76
 
@@ -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
@@ -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
- # or in Travis
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>