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