ruby-dbus 0.5.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.
Files changed (50) hide show
  1. data/COPYING +504 -0
  2. data/NEWS +137 -0
  3. data/README +53 -0
  4. data/Rakefile +54 -0
  5. data/VERSION +1 -0
  6. data/doc/tutorial/index.html +356 -0
  7. data/doc/tutorial/index.markdown +467 -0
  8. data/examples/gdbus/gdbus +255 -0
  9. data/examples/gdbus/gdbus.glade +184 -0
  10. data/examples/gdbus/launch.sh +4 -0
  11. data/examples/no-introspect/nm-test.rb +21 -0
  12. data/examples/no-introspect/tracker-test.rb +16 -0
  13. data/examples/rhythmbox/playpause.rb +25 -0
  14. data/examples/service/call_service.rb +25 -0
  15. data/examples/service/service_newapi.rb +51 -0
  16. data/examples/simple/call_introspect.rb +34 -0
  17. data/examples/utils/listnames.rb +11 -0
  18. data/examples/utils/notify.rb +19 -0
  19. data/lib/dbus.rb +91 -0
  20. data/lib/dbus/auth.rb +258 -0
  21. data/lib/dbus/bus.rb +816 -0
  22. data/lib/dbus/core_ext/class/attribute.rb +91 -0
  23. data/lib/dbus/core_ext/kernel/singleton_class.rb +14 -0
  24. data/lib/dbus/core_ext/module/remove_method.rb +12 -0
  25. data/lib/dbus/error.rb +44 -0
  26. data/lib/dbus/export.rb +132 -0
  27. data/lib/dbus/introspect.rb +553 -0
  28. data/lib/dbus/marshall.rb +443 -0
  29. data/lib/dbus/matchrule.rb +100 -0
  30. data/lib/dbus/message.rb +310 -0
  31. data/lib/dbus/type.rb +222 -0
  32. data/ruby-dbus.gemspec +18 -0
  33. data/test/binding_test.rb +56 -0
  34. data/test/bus_driver_test.rb +22 -0
  35. data/test/dbus-launch-simple +35 -0
  36. data/test/dbus-limited-session.conf +28 -0
  37. data/test/server_robustness_test.rb +41 -0
  38. data/test/server_test.rb +53 -0
  39. data/test/service_newapi.rb +129 -0
  40. data/test/session_bus_test_manual.rb +20 -0
  41. data/test/signal_test.rb +64 -0
  42. data/test/t1 +4 -0
  43. data/test/t2.rb +66 -0
  44. data/test/t3-ticket27.rb +18 -0
  45. data/test/t5-report-dbus-interface.rb +58 -0
  46. data/test/t6-loop.rb +82 -0
  47. data/test/test_env +13 -0
  48. data/test/test_server +39 -0
  49. data/test/variant_test.rb +66 -0
  50. metadata +117 -0
@@ -0,0 +1,18 @@
1
+ # -*- ruby -*-
2
+ require "rubygems"
3
+ require "rake"
4
+
5
+ GEMSPEC = Gem::Specification.new do |s|
6
+ s.name = "ruby-dbus"
7
+ # s.rubyforge_project = nil
8
+ s.summary = "Ruby module for interaction with D-Bus"
9
+ # s.description = FIXME
10
+ s.version = File.read("VERSION").strip
11
+ s.author = "Ruby DBus Team"
12
+ s.email = "ruby-dbus-devel@lists.luon.net"
13
+ s.homepage = "http://trac.luon.net/data/ruby-dbus/"
14
+ s.files = FileList["{doc/tutorial,examples,lib,test}/**/*", "Rakefile", "ruby-dbus.gemspec", "VERSION"].to_a.sort
15
+ s.require_path = "lib"
16
+ s.has_rdoc = true
17
+ s.extra_rdoc_files = ["COPYING", "README", "NEWS"]
18
+ end
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ # Test the binding of dbus concepts to ruby concepts
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ class BindingTest < Test::Unit::TestCase
7
+ def setup
8
+ @bus = DBus::SessionBus.instance
9
+ @svc = @bus.service("org.ruby.service")
10
+ @base = @svc.object "/org/ruby/MyInstance"
11
+ @base.introspect
12
+ @base.default_iface = "org.ruby.SampleInterface"
13
+ end
14
+
15
+ # https://trac.luon.net/ruby-dbus/ticket/36#comment:3
16
+ def test_class_inheritance
17
+ derived = @svc.object "/org/ruby/MyDerivedInstance"
18
+ derived.introspect
19
+
20
+ # it should inherit from the parent
21
+ assert_not_nil derived["org.ruby.SampleInterface"]
22
+ end
23
+
24
+ # https://trac.luon.net/ruby-dbus/ticket/36
25
+ # Interfaces and methods/signals appeared on all classes
26
+ def test_separation_of_classes
27
+ test2 = @svc.object "/org/ruby/MyInstance2"
28
+ test2.introspect
29
+
30
+ # it should have its own interface
31
+ assert_not_nil test2["org.ruby.Test2"]
32
+ # but not an interface of the Test class
33
+ assert_nil test2["org.ruby.SampleInterface"]
34
+
35
+ # and the parent should not get polluted by the child
36
+ assert_nil @base["org.ruby.Test2"]
37
+ end
38
+
39
+ def test_translating_errors_into_exceptions
40
+ # this is a generic call that will reply with the specified error
41
+ @base.Error "org.example.Fail", "as you wish"
42
+ assert false, "should have raised"
43
+ rescue DBus::Error => e
44
+ assert_equal "org.example.Fail", e.name
45
+ assert_equal "as you wish", e.message
46
+ end
47
+
48
+ def test_generic_dbus_error
49
+ # this is a generic call that will reply with the specified error
50
+ @base.will_raise_error_failed
51
+ assert false, "should have raised"
52
+ rescue DBus::Error => e
53
+ assert_equal "org.freedesktop.DBus.Error.Failed", e.name
54
+ assert_equal "failed as designed", e.message
55
+ end
56
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # Test the methods of the bus driver
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ def d(msg)
7
+ puts msg if $DEBUG
8
+ end
9
+
10
+ class BusDriverTest < Test::Unit::TestCase
11
+ def setup
12
+ @bus = DBus::SessionBus.instance
13
+ @svc = @bus.service("org.ruby.service")
14
+ @svc.object("/").introspect
15
+ end
16
+
17
+ def test_exists
18
+ assert @svc.exists?, "could not find the service"
19
+ nonsvc = @bus.service "org.ruby.nosuchservice"
20
+ assert ! nonsvc.exists?, "found a service that should not exist"
21
+ end
22
+ end
@@ -0,0 +1,35 @@
1
+ #! /bin/sh
2
+ # A wrapper for DBus tests
3
+ # Reimplementing dbus-launch because it is in dbus-1-x11.rpm
4
+ # Sets up a private session bus and call the specified program
5
+ set -o errexit
6
+
7
+ # This launches the bus daemon,
8
+ # exports DBUS_SESSION_BUS_ADDRESS and sets DBUS_SESSION_BUS_PID
9
+ my_dbus_launch () {
10
+ # reimplementing dbus-launch because it is in dbus-1-x11.rpm
11
+ PF=`mktemp dbus.pid.XXXXXX` || exit
12
+ AF=`mktemp dbus.addr.XXXXXX` || exit
13
+ RM_FILES="$RM_FILES $PF $AF"
14
+
15
+ dbus-daemon --config-file=dbus-limited-session.conf --print-address=3 3>$AF --print-pid=4 4>$PF &
16
+ # wait for the daemon to print the info
17
+ TRIES=0
18
+ while [ ! -s $AF -o ! -s $PF ]; do
19
+ sleep 0.1
20
+ TRIES=`expr $TRIES + 1`
21
+ if [ $TRIES -gt 100 ]; then echo "dbus-daemon failed?"; exit 1; fi
22
+ done
23
+ DBUS_SESSION_BUS_PID=$(cat $PF)
24
+ export DBUS_SESSION_BUS_ADDRESS=$(cat $AF)
25
+ KILLS="$KILLS $DBUS_SESSION_BUS_PID"
26
+ # dbus-monitor &
27
+ }
28
+
29
+ my_dbus_launch
30
+
31
+ # Clean up at exit.
32
+ trap "kill \$KILLS; rm -rf \$RM_FILES" EXIT TERM INT
33
+
34
+ # run the payload; the return value is passed on
35
+ "$@"
@@ -0,0 +1,28 @@
1
+ <!-- This configuration file controls the testing message bus.
2
+ It is based on a session bus config. -->
3
+
4
+ <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
5
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
6
+ <busconfig>
7
+ <!-- Our well-known bus type, don't change this -->
8
+ <type>session</type>
9
+
10
+ <listen>unix:tmpdir=/tmp</listen>
11
+ <listen>tcp:host=localhost,port=0,family=ipv4</listen>
12
+
13
+ <standard_session_servicedirs />
14
+
15
+ <policy context="default">
16
+ <!-- Allow everything to be sent -->
17
+ <allow send_destination="*" eavesdrop="true"/>
18
+ <!-- Allow everything to be received -->
19
+ <allow eavesdrop="true"/>
20
+ <!-- Allow anyone to own anything -->
21
+ <allow own="*"/>
22
+ </policy>
23
+
24
+ <!-- Do not increase the limits.
25
+ Instead, lower some so that we can test resource leaks. -->
26
+ <limit name="max_match_rules_per_connection">50</limit><!-- was 512 -->
27
+
28
+ </busconfig>
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ # Test that a server survives various error cases
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ class ServerRobustnessTest < Test::Unit::TestCase
7
+ def setup
8
+ @bus = DBus::SessionBus.instance
9
+ @svc = @bus.service("org.ruby.service")
10
+ end
11
+
12
+ # https://trac.luon.net/ruby-dbus/ticket/31
13
+ # the server should not crash
14
+ def test_no_such_path_with_introspection
15
+ obj = @svc.object "/org/ruby/NotMyInstance"
16
+ obj.introspect
17
+ assert false, "should have raised"
18
+ rescue DBus::Error => e
19
+ assert_no_match(/timeout/, e.to_s)
20
+ end
21
+
22
+ def test_no_such_path_without_introspection
23
+ obj = @svc.object "/org/ruby/NotMyInstance"
24
+ ifc = DBus::ProxyObjectInterface.new(obj, "org.ruby.SampleInterface")
25
+ ifc.define_method("the_answer", "out n:i")
26
+ ifc.the_answer
27
+ assert false, "should have raised"
28
+ rescue DBus::Error => e
29
+ assert_no_match(/timeout/, e.to_s)
30
+ end
31
+
32
+ def test_a_method_that_raises
33
+ obj = @svc.object "/org/ruby/MyInstance"
34
+ obj.introspect
35
+ obj.default_iface = "org.ruby.SampleInterface"
36
+ obj.will_raise
37
+ assert false, "should have raised"
38
+ rescue DBus::Error => e
39
+ assert_no_match(/timeout/, e.to_s)
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # Test that a server survives various error cases
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ class Foo < DBus::Object
7
+ dbus_interface "org.ruby.ServerTest" do
8
+ dbus_signal :signal_without_arguments
9
+ dbus_signal :signal_with_argument, "epsilon:d"
10
+ end
11
+
12
+ dbus_signal :signal_without_interface
13
+ rescue DBus::Object::UndefinedInterface => e
14
+ # raised by the preceding signal declaration
15
+ end
16
+
17
+ class Bar < DBus::Object
18
+ dbus_interface "org.ruby.ServerTest" do
19
+ # a valid Ruby symbol but an invalid DBus name; Ticket#38
20
+ dbus_signal :signal_with_a_bang!
21
+ end
22
+ rescue DBus::InvalidMethodName
23
+ # raised by the preceding signal declaration
24
+ end
25
+
26
+ class ServerTest < Test::Unit::TestCase
27
+ def setup
28
+ @bus = DBus::SessionBus.instance
29
+ @svc = @bus.request_service "org.ruby.server-test"
30
+ end
31
+
32
+ def teardown
33
+ @bus.proxy.ReleaseName "org.ruby.server-test"
34
+ end
35
+
36
+ def test_unexporting_an_object
37
+ obj = Foo.new "/org/ruby/Foo"
38
+ @svc.export obj
39
+ assert @svc.unexport(obj)
40
+ end
41
+
42
+ def test_unexporting_an_object_not_exported
43
+ obj = Foo.new "/org/ruby/Foo"
44
+ assert !@svc.unexport(obj)
45
+ end
46
+
47
+ def test_emiting_signals
48
+ obj = Foo.new "/org/ruby/Foo"
49
+ @svc.export obj
50
+ obj.signal_without_arguments
51
+ obj.signal_with_argument(-0.1)
52
+ end
53
+ end
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # find the library without external help
4
+ $:.unshift File.expand_path("../../lib", __FILE__)
5
+
6
+ require 'dbus'
7
+
8
+ def d(msg)
9
+ puts "#{$$} #{msg}" if $DEBUG
10
+ end
11
+
12
+ class Test < DBus::Object
13
+ # Create an interface aggregating all upcoming dbus_method defines.
14
+ dbus_interface "org.ruby.SampleInterface" do
15
+ dbus_method :hello, "in name:s, in name2:s" do |name, name2|
16
+ puts "hello(#{name}, #{name2})"
17
+ end
18
+
19
+ dbus_method :test_variant, "in stuff:v" do |variant|
20
+ p variant
21
+ end
22
+
23
+ dbus_method :bounce_variant, "in stuff:v, out chaff:v" do |variant|
24
+ [variant]
25
+ end
26
+
27
+ dbus_method :variant_size, "in stuff:v, out size:u" do |variant|
28
+ [variant.size]
29
+ end
30
+
31
+ dbus_method :the_answer, "out answer:i" do
32
+ 42
33
+ end
34
+
35
+ dbus_method :will_raise, "" do
36
+ raise "Handle this"
37
+ end
38
+
39
+ dbus_method :will_raise_error_failed, "" do
40
+ raise DBus.error, "failed as designed"
41
+ end
42
+
43
+ dbus_method :Error, "in name:s, in description:s" do |name, description|
44
+ raise DBus.error(name), description
45
+ end
46
+
47
+ dbus_signal :SomethingJustHappened, "toto:s, tutu:u"
48
+ end
49
+
50
+ dbus_interface "org.ruby.AnotherInterface" do
51
+ dbus_method :ThatsALongMethodNameIThink do
52
+ puts "ThatsALongMethodNameIThink"
53
+ end
54
+ dbus_method :Reverse, "in instr:s, out outstr:s" do |instr|
55
+ outstr = instr.split(//).reverse.join
56
+ puts "got: #{instr}, replying: #{outstr}"
57
+ [outstr]
58
+ end
59
+ end
60
+
61
+ dbus_interface "org.ruby.Ticket30" do
62
+ dbus_method :Sybilla, 'in choices:av, out advice:s' do |choices|
63
+ ["Do #{choices[0]}"]
64
+ end
65
+ end
66
+
67
+ dbus_interface "org.ruby.Loop" do
68
+ # starts doing something long, but returns immediately
69
+ # and sends a signal when done
70
+ dbus_method :LongTaskBegin, 'in delay:i' do |delay|
71
+ # FIXME did not complain about mismatch between signature and block args
72
+ d "Long task began"
73
+ task = Thread.new do
74
+ d "Long task thread started (#{delay}s)"
75
+ sleep delay
76
+ d "Long task will signal end"
77
+ self.LongTaskEnd
78
+ end
79
+ task.abort_on_exception = true # protect from test case bugs
80
+ end
81
+
82
+ dbus_signal :LongTaskEnd
83
+ end
84
+ end
85
+
86
+ class Derived < Test
87
+ end
88
+
89
+ class Test2 < DBus::Object
90
+ dbus_interface "org.ruby.Test2" do
91
+ dbus_method :hi, "in name:s, out greeting:s" do |name|
92
+ "Hi, #{name}!"
93
+ end
94
+ end
95
+ end
96
+
97
+ bus = DBus::SessionBus.instance
98
+ service = bus.request_service("org.ruby.service")
99
+ myobj = Test.new("/org/ruby/MyInstance")
100
+ service.export(myobj)
101
+ derived = Derived.new "/org/ruby/MyDerivedInstance"
102
+ service.export derived
103
+ test2 = Test2.new "/org/ruby/MyInstance2"
104
+ service.export test2
105
+
106
+ # introspect every other connection, Ticket #34
107
+ # (except the one that activates us - it has already emitted
108
+ # NOC by the time we run this. Therefore the test for #34 will not work
109
+ # by running t2.rb alone, one has to run t1 before it; 'rake' does it)
110
+ mr = DBus::MatchRule.new.from_s "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'"
111
+ bus.add_match(mr) do |msg|
112
+ new_unique_name = msg.params[2]
113
+ unless new_unique_name.empty?
114
+ d "RRRING #{new_unique_name}"
115
+ bus.introspect_data(new_unique_name, "/") do
116
+ # ignore the result
117
+ end
118
+ end
119
+ end
120
+
121
+ puts "listening"
122
+ main = DBus::Main.new
123
+ main << bus
124
+ begin
125
+ main.run
126
+ rescue SystemCallError
127
+ # the test driver will kill the bus, that's OK
128
+ end
129
+
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require "test/unit"
3
+ require "dbus"
4
+
5
+ def d(msg)
6
+ puts msg if $DEBUG
7
+ end
8
+
9
+ class SessionBusAddressTest < Test::Unit::TestCase
10
+ def setup
11
+ # test getting the session bus address even if unset in ENV (Issue#4)
12
+ ENV.delete "DBUS_SESSION_BUS_ADDRESS"
13
+ @bus = DBus::SessionBus.instance
14
+ @svc = @bus.service("org.freedesktop.DBus")
15
+ end
16
+
17
+ def test_connection
18
+ assert @svc.exists?
19
+ end
20
+ end
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+ # Test the signal handlers
3
+ require "test/unit"
4
+ require "dbus"
5
+
6
+ def d(msg)
7
+ puts "#{$$} #{msg}" if $DEBUG
8
+ end
9
+
10
+ class SignalHandlerTest < Test::Unit::TestCase
11
+ def setup
12
+ @session_bus = DBus::SessionBus.instance
13
+ svc = @session_bus.service("org.ruby.service")
14
+ @obj = svc.object("/org/ruby/MyInstance")
15
+ @obj.introspect # necessary
16
+ @obj.default_iface = "org.ruby.Loop"
17
+
18
+ @loop = DBus::Main.new
19
+ @loop << @session_bus
20
+ end
21
+
22
+ # testing for commit 017c83 (kkaempf)
23
+ def test_overriding_a_handler
24
+ counter = 0
25
+
26
+ @obj.on_signal "LongTaskEnd" do
27
+ d "+10"
28
+ counter += 10
29
+ end
30
+ @obj.on_signal "LongTaskEnd" do
31
+ d "+1"
32
+ counter += 1
33
+ end
34
+
35
+ d "will begin"
36
+ @obj.LongTaskBegin 3
37
+
38
+ quitter = Thread.new do
39
+ d "sleep before quit"
40
+ # FIXME if we sleep for too long
41
+ # the socket will be drained and we deadlock in a select.
42
+ # It could be worked around by sending ourselves a Unix signal
43
+ # (with a dummy handler) to interrupt the select
44
+ sleep 1
45
+ d "will quit"
46
+ @loop.quit
47
+ end
48
+ @loop.run
49
+
50
+ assert_equal 1, counter
51
+ end
52
+
53
+ def test_too_many_rules
54
+ 100.times do
55
+ @obj.on_signal "Whichever" do
56
+ puts "not called"
57
+ end
58
+ end
59
+ end
60
+
61
+ def test_removing_a_nonexistent_rule
62
+ @obj.on_signal "DoesNotExist"
63
+ end
64
+ end