ruby-dbus 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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