417 lines
9.4 KiB
Go
417 lines
9.4 KiB
Go
package dbus
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type tester struct {
|
|
conn *Conn
|
|
sigs chan *Signal
|
|
subSigs map[string]map[string]struct{}
|
|
}
|
|
|
|
type intro struct {
|
|
path ObjectPath
|
|
}
|
|
|
|
func (i *intro) introspectPath(path ObjectPath) string {
|
|
switch path {
|
|
case "/":
|
|
return `<node><node name="com"></node></node>`
|
|
case "/com":
|
|
return `<node><node name="github"></node></node>`
|
|
case "/com/github":
|
|
return `<node><node name="godbus"></node></node>`
|
|
case "/com/github/godbus":
|
|
return `<node><node name="tester"></node></node>`
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (i *intro) LookupInterface(name string) (Interface, bool) {
|
|
if name == "org.freedesktop.DBus.Introspectable" {
|
|
return i, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (i *intro) LookupMethod(name string) (Method, bool) {
|
|
if name == "Introspect" {
|
|
return intro_fn(func() string {
|
|
return i.introspectPath(i.path)
|
|
}), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func newIntro(path ObjectPath) *intro {
|
|
return &intro{path}
|
|
}
|
|
|
|
//Handler
|
|
func (t *tester) LookupObject(path ObjectPath) (ServerObject, bool) {
|
|
if path == "/com/github/godbus/tester" {
|
|
return t, true
|
|
}
|
|
return newIntro(path), true
|
|
}
|
|
|
|
//ServerObject
|
|
func (t *tester) LookupInterface(name string) (Interface, bool) {
|
|
switch name {
|
|
case "com.github.godbus.dbus.Tester":
|
|
return t, true
|
|
case "org.freedesktop.DBus.Introspectable":
|
|
return t, true
|
|
}
|
|
|
|
return nil, false
|
|
}
|
|
|
|
//Interface
|
|
func (t *tester) LookupMethod(name string) (Method, bool) {
|
|
switch name {
|
|
case "Test":
|
|
return t, true
|
|
case "Error":
|
|
return terrfn(func(in string) error {
|
|
return fmt.Errorf(in)
|
|
}), true
|
|
case "Introspect":
|
|
return intro_fn(func() string {
|
|
return `<node>
|
|
<interface name="org.freedesktop.DBus.Introspectable.Introspect">
|
|
<method name="Introspect">
|
|
<arg name="out" type="i" direction="out">
|
|
</method>
|
|
</interface>
|
|
<interface name="com.github.godbus.dbus.Tester">
|
|
<method name="Test">
|
|
<arg name="in" type="i" direction="in">
|
|
<arg name="out" type="i" direction="out">
|
|
</method>
|
|
<signal name="sig1">
|
|
<arg name="out" type="i" direction="out">
|
|
</signal>
|
|
</interface>
|
|
</node>`
|
|
}), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
//Method
|
|
func (t *tester) Call(args ...interface{}) ([]interface{}, error) {
|
|
return args, nil
|
|
}
|
|
|
|
func (t *tester) NumArguments() int {
|
|
return 1
|
|
}
|
|
|
|
func (t *tester) NumReturns() int {
|
|
return 1
|
|
}
|
|
|
|
func (t *tester) ArgumentValue(position int) interface{} {
|
|
return ""
|
|
}
|
|
|
|
func (t *tester) ReturnValue(position int) interface{} {
|
|
return ""
|
|
}
|
|
|
|
type terrfn func(in string) error
|
|
|
|
func (t terrfn) Call(args ...interface{}) ([]interface{}, error) {
|
|
return nil, t(*args[0].(*string))
|
|
}
|
|
|
|
func (t terrfn) NumArguments() int {
|
|
return 1
|
|
}
|
|
|
|
func (t terrfn) NumReturns() int {
|
|
return 0
|
|
}
|
|
|
|
func (t terrfn) ArgumentValue(position int) interface{} {
|
|
return ""
|
|
}
|
|
|
|
func (t terrfn) ReturnValue(position int) interface{} {
|
|
return ""
|
|
}
|
|
|
|
//SignalHandler
|
|
func (t *tester) DeliverSignal(iface, name string, signal *Signal) {
|
|
intf, ok := t.subSigs[iface]
|
|
if !ok {
|
|
return
|
|
}
|
|
if _, ok := intf[name]; !ok {
|
|
return
|
|
}
|
|
t.sigs <- signal
|
|
}
|
|
|
|
func (t *tester) AddSignal(iface, name string) {
|
|
if i, ok := t.subSigs[iface]; ok {
|
|
i[name] = struct{}{}
|
|
} else {
|
|
t.subSigs[iface] = make(map[string]struct{})
|
|
t.subSigs[iface][name] = struct{}{}
|
|
}
|
|
t.conn.BusObject().(*Object).AddMatchSignal(
|
|
iface, name)
|
|
}
|
|
|
|
func (t *tester) Close() {
|
|
t.conn.Close()
|
|
close(t.sigs)
|
|
}
|
|
|
|
func (t *tester) Name() string {
|
|
return t.conn.Names()[0]
|
|
}
|
|
|
|
type intro_fn func() string
|
|
|
|
func (intro intro_fn) Call(args ...interface{}) ([]interface{}, error) {
|
|
return []interface{}{intro()}, nil
|
|
}
|
|
|
|
func (_ intro_fn) NumArguments() int {
|
|
return 0
|
|
}
|
|
|
|
func (_ intro_fn) NumReturns() int {
|
|
return 1
|
|
}
|
|
|
|
func (_ intro_fn) ArgumentValue(position int) interface{} {
|
|
return nil
|
|
}
|
|
|
|
func (_ intro_fn) ReturnValue(position int) interface{} {
|
|
return ""
|
|
}
|
|
|
|
func newTester() (*tester, error) {
|
|
tester := &tester{
|
|
sigs: make(chan *Signal),
|
|
subSigs: make(map[string]map[string]struct{}),
|
|
}
|
|
conn, err := SessionBusPrivateHandler(tester, tester)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = conn.Auth(nil)
|
|
if err != nil {
|
|
conn.Close()
|
|
return nil, err
|
|
}
|
|
err = conn.Hello()
|
|
if err != nil {
|
|
conn.Close()
|
|
return nil, err
|
|
}
|
|
tester.conn = conn
|
|
return tester, nil
|
|
}
|
|
|
|
func TestHandlerCall(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus/tester")
|
|
var out string
|
|
in := "foo"
|
|
err = obj.Call("com.github.godbus.dbus.Tester.Test", 0, in).Store(&out)
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
if out != in {
|
|
t.Errorf("Unexpected error: got %s, expected %s", out, in)
|
|
}
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerCallGenericError(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus/tester")
|
|
var out string
|
|
in := "foo"
|
|
err = obj.Call("com.github.godbus.dbus.Tester.Error", 0, in).Store(&out)
|
|
if err != nil && err.(Error).Body[0].(string) != "foo" {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerCallNonExistent(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus/tester/nonexist")
|
|
var out string
|
|
in := "foo"
|
|
err = obj.Call("com.github.godbus.dbus.Tester.Test", 0, in).Store(&out)
|
|
if err != nil {
|
|
if err.Error() != "Object does not implement the interface" {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
}
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerInvalidFunc(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus/tester")
|
|
var out string
|
|
in := "foo"
|
|
err = obj.Call("com.github.godbus.dbus.Tester.Notexist", 0, in).Store(&out)
|
|
if err == nil {
|
|
t.Errorf("didn't get expected error")
|
|
}
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerInvalidNumArg(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus/tester")
|
|
var out string
|
|
err = obj.Call("com.github.godbus.dbus.Tester.Test", 0).Store(&out)
|
|
if err == nil {
|
|
t.Errorf("didn't get expected error")
|
|
}
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerInvalidArgType(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus/tester")
|
|
var out string
|
|
err = obj.Call("com.github.godbus.dbus.Tester.Test", 0, 2.10).Store(&out)
|
|
if err == nil {
|
|
t.Errorf("didn't get expected error")
|
|
}
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerIntrospect(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus/tester")
|
|
var out string
|
|
err = obj.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&out)
|
|
expected := `<node>
|
|
<interface name="org.freedesktop.DBus.Introspectable.Introspect">
|
|
<method name="Introspect">
|
|
<arg name="out" type="i" direction="out">
|
|
</method>
|
|
</interface>
|
|
<interface name="com.github.godbus.dbus.Tester">
|
|
<method name="Test">
|
|
<arg name="in" type="i" direction="in">
|
|
<arg name="out" type="i" direction="out">
|
|
</method>
|
|
<signal name="sig1">
|
|
<arg name="out" type="i" direction="out">
|
|
</signal>
|
|
</interface>
|
|
</node>`
|
|
if out != expected {
|
|
t.Errorf("didn't get expected return value, expected %s got %s", expected, out)
|
|
}
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerIntrospectPath(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
obj := conn.Object(tester.Name(), "/com/github/godbus")
|
|
var out string
|
|
err = obj.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&out)
|
|
expected := `<node><node name="tester"></node></node>`
|
|
if out != expected {
|
|
t.Errorf("didn't get expected return value, expected %s got %s", expected, out)
|
|
}
|
|
tester.Close()
|
|
}
|
|
|
|
func TestHandlerSignal(t *testing.T) {
|
|
tester, err := newTester()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
conn, err := SessionBus()
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
tester.AddSignal("com.github.godbus.dbus.Tester", "sig1")
|
|
conn.Emit("/com/github/godbus/tester",
|
|
"com.github.godbus.dbus.Tester.sig1", "foo")
|
|
select {
|
|
case sig := <-tester.sigs:
|
|
if sig.Body[0] != "foo" {
|
|
t.Errorf("Unexpected signal got %s, expected %s", sig.Body[0], "foo")
|
|
}
|
|
case <-time.After(time.Second * 10): //overly generous timeout
|
|
t.Errorf("Didn't receive a signal after 10 seconds")
|
|
}
|
|
tester.Close()
|
|
}
|