1package dbus 2 3import ( 4 "encoding/binary" 5 "io" 6 "io/ioutil" 7 "testing" 8 "time" 9) 10 11func TestSessionBus(t *testing.T) { 12 _, err := SessionBus() 13 if err != nil { 14 t.Error(err) 15 } 16} 17 18func TestSystemBus(t *testing.T) { 19 _, err := SystemBus() 20 if err != nil { 21 t.Error(err) 22 } 23} 24 25func TestSend(t *testing.T) { 26 bus, err := SessionBus() 27 if err != nil { 28 t.Fatal(err) 29 } 30 ch := make(chan *Call, 1) 31 msg := &Message{ 32 Type: TypeMethodCall, 33 Flags: 0, 34 Headers: map[HeaderField]Variant{ 35 FieldDestination: MakeVariant(bus.Names()[0]), 36 FieldPath: MakeVariant(ObjectPath("/org/freedesktop/DBus")), 37 FieldInterface: MakeVariant("org.freedesktop.DBus.Peer"), 38 FieldMember: MakeVariant("Ping"), 39 }, 40 } 41 call := bus.Send(msg, ch) 42 <-ch 43 if call.Err != nil { 44 t.Error(call.Err) 45 } 46} 47 48func TestFlagNoReplyExpectedSend(t *testing.T) { 49 bus, err := SessionBus() 50 if err != nil { 51 t.Fatal(err) 52 } 53 done := make(chan struct{}) 54 go func() { 55 bus.BusObject().Call("org.freedesktop.DBus.ListNames", FlagNoReplyExpected) 56 close(done) 57 }() 58 select { 59 case <-done: 60 case <-time.After(1 * time.Second): 61 t.Error("Failed to announce that the call was done") 62 } 63} 64 65func TestRemoveSignal(t *testing.T) { 66 bus, err := NewConn(nil) 67 if err != nil { 68 t.Error(err) 69 } 70 signals := bus.signalHandler.(*defaultSignalHandler).signals 71 ch := make(chan *Signal) 72 ch2 := make(chan *Signal) 73 for _, ch := range []chan *Signal{ch, ch2, ch, ch2, ch2, ch} { 74 bus.Signal(ch) 75 } 76 signals = bus.signalHandler.(*defaultSignalHandler).signals 77 if len(signals) != 6 { 78 t.Errorf("remove signal: signals length not equal: got '%d', want '6'", len(signals)) 79 } 80 bus.RemoveSignal(ch) 81 signals = bus.signalHandler.(*defaultSignalHandler).signals 82 if len(signals) != 3 { 83 t.Errorf("remove signal: signals length not equal: got '%d', want '3'", len(signals)) 84 } 85 signals = bus.signalHandler.(*defaultSignalHandler).signals 86 for _, bch := range signals { 87 if bch != ch2 { 88 t.Errorf("remove signal: removed signal present: got '%v', want '%v'", bch, ch2) 89 } 90 } 91} 92 93type rwc struct { 94 io.Reader 95 io.Writer 96} 97 98func (rwc) Close() error { return nil } 99 100type fakeAuth struct { 101} 102 103func (fakeAuth) FirstData() (name, resp []byte, status AuthStatus) { 104 return []byte("name"), []byte("resp"), AuthOk 105} 106 107func (fakeAuth) HandleData(data []byte) (resp []byte, status AuthStatus) { 108 return nil, AuthOk 109} 110 111func TestCloseBeforeSignal(t *testing.T) { 112 reader, pipewriter := io.Pipe() 113 defer pipewriter.Close() 114 defer reader.Close() 115 116 bus, err := NewConn(rwc{Reader: reader, Writer: ioutil.Discard}) 117 if err != nil { 118 t.Fatal(err) 119 } 120 // give ch a buffer so sends won't block 121 ch := make(chan *Signal, 1) 122 bus.Signal(ch) 123 124 go func() { 125 _, err := pipewriter.Write([]byte("REJECTED name\r\nOK myuuid\r\n")) 126 if err != nil { 127 t.Errorf("error writing to pipe: %v", err) 128 } 129 }() 130 131 err = bus.Auth([]Auth{fakeAuth{}}) 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 err = bus.Close() 137 if err != nil { 138 t.Fatal(err) 139 } 140 141 msg := &Message{ 142 Type: TypeSignal, 143 Headers: map[HeaderField]Variant{ 144 FieldInterface: MakeVariant("foo.bar"), 145 FieldMember: MakeVariant("bar"), 146 FieldPath: MakeVariant(ObjectPath("/baz")), 147 }, 148 } 149 err = msg.EncodeTo(pipewriter, binary.LittleEndian) 150 if err != nil { 151 t.Fatal(err) 152 } 153} 154 155type server struct{} 156 157func (server) Double(i int64) (int64, *Error) { 158 return 2 * i, nil 159} 160 161func BenchmarkCall(b *testing.B) { 162 b.StopTimer() 163 b.ReportAllocs() 164 var s string 165 bus, err := SessionBus() 166 if err != nil { 167 b.Fatal(err) 168 } 169 name := bus.Names()[0] 170 obj := bus.BusObject() 171 b.StartTimer() 172 for i := 0; i < b.N; i++ { 173 err := obj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&s) 174 if err != nil { 175 b.Fatal(err) 176 } 177 if s != name { 178 b.Errorf("got %s, wanted %s", s, name) 179 } 180 } 181} 182 183func BenchmarkCallAsync(b *testing.B) { 184 b.StopTimer() 185 b.ReportAllocs() 186 bus, err := SessionBus() 187 if err != nil { 188 b.Fatal(err) 189 } 190 name := bus.Names()[0] 191 obj := bus.BusObject() 192 c := make(chan *Call, 50) 193 done := make(chan struct{}) 194 go func() { 195 for i := 0; i < b.N; i++ { 196 v := <-c 197 if v.Err != nil { 198 b.Error(v.Err) 199 } 200 s := v.Body[0].(string) 201 if s != name { 202 b.Errorf("got %s, wanted %s", s, name) 203 } 204 } 205 close(done) 206 }() 207 b.StartTimer() 208 for i := 0; i < b.N; i++ { 209 obj.Go("org.freedesktop.DBus.GetNameOwner", 0, c, name) 210 } 211 <-done 212} 213 214func BenchmarkServe(b *testing.B) { 215 b.StopTimer() 216 srv, err := SessionBus() 217 if err != nil { 218 b.Fatal(err) 219 } 220 cli, err := SessionBusPrivate() 221 if err != nil { 222 b.Fatal(err) 223 } 224 if err = cli.Auth(nil); err != nil { 225 b.Fatal(err) 226 } 227 if err = cli.Hello(); err != nil { 228 b.Fatal(err) 229 } 230 benchmarkServe(b, srv, cli) 231} 232 233func BenchmarkServeAsync(b *testing.B) { 234 b.StopTimer() 235 srv, err := SessionBus() 236 if err != nil { 237 b.Fatal(err) 238 } 239 cli, err := SessionBusPrivate() 240 if err != nil { 241 b.Fatal(err) 242 } 243 if err = cli.Auth(nil); err != nil { 244 b.Fatal(err) 245 } 246 if err = cli.Hello(); err != nil { 247 b.Fatal(err) 248 } 249 benchmarkServeAsync(b, srv, cli) 250} 251 252func BenchmarkServeSameConn(b *testing.B) { 253 b.StopTimer() 254 bus, err := SessionBus() 255 if err != nil { 256 b.Fatal(err) 257 } 258 259 benchmarkServe(b, bus, bus) 260} 261 262func BenchmarkServeSameConnAsync(b *testing.B) { 263 b.StopTimer() 264 bus, err := SessionBus() 265 if err != nil { 266 b.Fatal(err) 267 } 268 269 benchmarkServeAsync(b, bus, bus) 270} 271 272func benchmarkServe(b *testing.B, srv, cli *Conn) { 273 var r int64 274 var err error 275 dest := srv.Names()[0] 276 srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test") 277 obj := cli.Object(dest, "/org/guelfey/DBus/Test") 278 b.StartTimer() 279 for i := 0; i < b.N; i++ { 280 err = obj.Call("org.guelfey.DBus.Test.Double", 0, int64(i)).Store(&r) 281 if err != nil { 282 b.Fatal(err) 283 } 284 if r != 2*int64(i) { 285 b.Errorf("got %d, wanted %d", r, 2*int64(i)) 286 } 287 } 288} 289 290func benchmarkServeAsync(b *testing.B, srv, cli *Conn) { 291 dest := srv.Names()[0] 292 srv.Export(server{}, "/org/guelfey/DBus/Test", "org.guelfey.DBus.Test") 293 obj := cli.Object(dest, "/org/guelfey/DBus/Test") 294 c := make(chan *Call, 50) 295 done := make(chan struct{}) 296 go func() { 297 for i := 0; i < b.N; i++ { 298 v := <-c 299 if v.Err != nil { 300 b.Fatal(v.Err) 301 } 302 i, r := v.Args[0].(int64), v.Body[0].(int64) 303 if 2*i != r { 304 b.Errorf("got %d, wanted %d", r, 2*i) 305 } 306 } 307 close(done) 308 }() 309 b.StartTimer() 310 for i := 0; i < b.N; i++ { 311 obj.Go("org.guelfey.DBus.Test.Double", 0, c, int64(i)) 312 } 313 <-done 314} 315 316func TestGetKey(t *testing.T) { 317 keys := "host=1.2.3.4,port=5678,family=ipv4" 318 if host := getKey(keys, "host"); host != "1.2.3.4" { 319 t.Error(`Expected "1.2.3.4", got`, host) 320 } 321 if port := getKey(keys, "port"); port != "5678" { 322 t.Error(`Expected "5678", got`, port) 323 } 324 if family := getKey(keys, "family"); family != "ipv4" { 325 t.Error(`Expected "ipv4", got`, family) 326 } 327} 328