1 package dbus
2
3 import (
4 "context"
5 "testing"
6 "time"
7 )
8
9 type objectGoContextServer struct {
10 t *testing.T
11 sleep time.Duration
12 }
13
14 func (o objectGoContextServer) Sleep() *Error {
15 o.t.Log("Got object call and sleeping for ", o.sleep)
16 time.Sleep(o.sleep)
17 o.t.Log("Completed sleeping for ", o.sleep)
18 return nil
19 }
20
21 func TestObjectGoWithContextTimeout(t *testing.T) {
22 bus, err := ConnectSessionBus()
23 if err != nil {
24 t.Fatalf("Unexpected error connecting to session bus: %s", err)
25 }
26 defer bus.Close()
27
28 name := bus.Names()[0]
29 bus.Export(objectGoContextServer{t, time.Second}, "/org/dannin/DBus/Test", "org.dannin.DBus.Test")
30 ctx, cancel := context.WithTimeout(context.Background(), time.Second)
31 defer cancel()
32 select {
33 case call := <-bus.Object(name, "/org/dannin/DBus/Test").GoWithContext(ctx, "org.dannin.DBus.Test.Sleep", 0, nil).Done:
34 if call.Err != ctx.Err() {
35 t.Fatal("Expected ", ctx.Err(), " but got ", call.Err)
36 }
37 case <-time.After(2 * time.Second):
38 t.Fatal("Expected call to not respond in time")
39 }
40 }
41
42 func TestObjectGoWithContext(t *testing.T) {
43 bus, err := ConnectSessionBus()
44 if err != nil {
45 t.Fatalf("Unexpected error connecting to session bus: %s", err)
46 }
47 defer bus.Close()
48
49 name := bus.Names()[0]
50 bus.Export(objectGoContextServer{t, time.Millisecond}, "/org/dannin/DBus/Test", "org.dannin.DBus.Test")
51 ctx, cancel := context.WithTimeout(context.Background(), time.Second)
52 defer cancel()
53 select {
54 case call := <-bus.Object(name, "/org/dannin/DBus/Test").GoWithContext(ctx, "org.dannin.DBus.Test.Sleep", 0, nil).Done:
55 if call.Err != ctx.Err() {
56 t.Fatal("Expected ", ctx.Err(), " but got ", call.Err)
57 }
58 case <-time.After(time.Second):
59 t.Fatal("Expected call to respond in 1 Millisecond")
60 }
61 }
62
63 type nopServer struct{}
64
65 func (_ nopServer) Nop() *Error {
66 return nil
67 }
68
69 func TestObjectSignalHandling(t *testing.T) {
70 bus, err := ConnectSessionBus()
71 if err != nil {
72 t.Fatalf("Unexpected error connecting to session bus: %s", err)
73 }
74 defer bus.Close()
75
76 name := bus.Names()[0]
77 path := ObjectPath("/org/godbus/DBus/TestSignals")
78 otherPath := ObjectPath("/org/other/godbus/DBus/TestSignals")
79 iface := "org.godbus.DBus.TestSignals"
80 otherIface := "org.godbus.DBus.OtherTestSignals"
81 err = bus.Export(nopServer{}, path, iface)
82 if err != nil {
83 t.Fatalf("Unexpected error registering nop server: %v", err)
84 }
85
86 obj := bus.Object(name, path)
87 if err := bus.AddMatchSignal(
88 WithMatchInterface(iface),
89 WithMatchMember("Heartbeat"),
90 WithMatchObjectPath(path),
91 ); err != nil {
92 t.Fatal(err)
93 }
94
95 ch := make(chan *Signal, 5)
96 bus.Signal(ch)
97
98 go func() {
99 defer func() {
100 if err := recover(); err != nil {
101 t.Errorf("Caught panic in emitter goroutine: %v", err)
102 }
103 }()
104
105 emit := func(path ObjectPath, name string, values ...interface{}) {
106 t.Helper()
107 if err := bus.Emit(path, name, values...); err != nil {
108 t.Error("Emit:", err)
109 }
110 }
111
112
113 emit(path, iface+".Heartbeat", uint32(1))
114 emit(path, iface+".Heartbeat", uint32(2))
115
116 emit(otherPath, iface+".Heartbeat", uint32(3))
117 emit(otherPath, otherIface+".Heartbeat", uint32(4))
118 emit(path, iface+".Updated", false)
119
120 emit(path, iface+".Heartbeat", uint32(5))
121
122 time.Sleep(100 * time.Millisecond)
123 emit(path, iface+".Heartbeat", uint32(6))
124 }()
125
126 checkSignal := func(ch chan *Signal, value uint32) {
127 t.Helper()
128
129 const timeout = 50 * time.Millisecond
130 var sig *Signal
131
132 select {
133 case sig = <-ch:
134
135 case <-time.After(timeout):
136 t.Fatalf("Failed to fetch signal in specified timeout %s", timeout)
137 }
138
139 if sig.Path != path {
140 t.Errorf("signal.Path mismatch: %s != %s", path, sig.Path)
141 }
142
143 name := iface + ".Heartbeat"
144 if sig.Name != name {
145 t.Errorf("signal.Name mismatch: %s != %s", name, sig.Name)
146 }
147
148 if len(sig.Body) != 1 {
149 t.Errorf("Invalid signal body length: %d", len(sig.Body))
150 return
151 }
152
153 if sig.Body[0] != interface{}(value) {
154 t.Errorf("signal value mismatch: %d != %d", value, sig.Body[0])
155 }
156 }
157
158 checkSignal(ch, 1)
159 checkSignal(ch, 2)
160 checkSignal(ch, 5)
161
162 obj.RemoveMatchSignal(iface, "Heartbeat", WithMatchObjectPath(obj.Path()))
163 select {
164 case sig := <-ch:
165 t.Errorf("Got signal after removing subscription: %v", sig)
166 case <-time.After(200 * time.Millisecond):
167 }
168 }
169
View as plain text