blob: f04e367ca7caaa353411aec0babcddd993f1e798 [file] [log] [blame]
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 := SessionBus()
if err != nil {
t.Fatalf("Unexpected error connecting to session bus: %s", err)
}
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 := SessionBus()
if err != nil {
t.Fatalf("Unexpected error connecting to session bus: %s", err)
}
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 fetchSignal(t *testing.T, ch chan *Signal, timeout time.Duration) *Signal {
select {
case sig := <-ch:
return sig
case <-time.After(timeout):
t.Fatalf("Failed to fetch signal in specified timeout %s", timeout)
}
return nil
}
func TestObjectSignalHandling(t *testing.T) {
bus, err := SessionBus()
if err != nil {
t.Fatalf("Unexpected error connecting to session bus: %s", err)
}
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)
obj.AddMatchSignal(iface, "Heartbeat", WithMatchObjectPath(obj.Path()))
ch := make(chan *Signal, 5)
bus.Signal(ch)
go func() {
defer func() {
if err := recover(); err != nil {
t.Errorf("Catched panic in emitter goroutine: %v", err)
}
}()
// desired signals
bus.Emit(path, iface+".Heartbeat", uint32(1))
bus.Emit(path, iface+".Heartbeat", uint32(2))
// undesired signals
bus.Emit(otherPath, iface+".Heartbeat", uint32(3))
bus.Emit(otherPath, otherIface+".Heartbeat", uint32(4))
bus.Emit(path, iface+".Updated", false)
// sentinel
bus.Emit(path, iface+".Heartbeat", uint32(5))
time.Sleep(100 * time.Millisecond)
bus.Emit(path, iface+".Heartbeat", uint32(6))
}()
checkSignal := func(sig *Signal, value uint32) {
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(fetchSignal(t, ch, 50*time.Millisecond), 1)
checkSignal(fetchSignal(t, ch, 50*time.Millisecond), 2)
checkSignal(fetchSignal(t, ch, 50*time.Millisecond), 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):
}
}