dbus_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package dbus
  14. import (
  15. "fmt"
  16. "os"
  17. "testing"
  18. godbus "github.com/godbus/dbus"
  19. )
  20. const (
  21. DBusNameFlagDoNotQueue uint32 = 1 << (iota + 1)
  22. )
  23. const (
  24. DBusRequestNameReplyPrimaryOwner uint32 = iota + 1
  25. DBusRequestNameReplyAlreadyOwner
  26. )
  27. const (
  28. DBusReleaseNameReplyReleased uint32 = iota + 1
  29. DBusReleaseNameReplyNotOwner
  30. )
  31. func doDBusTest(t *testing.T, dbus Interface, real bool) {
  32. bus, err := dbus.SystemBus()
  33. if err != nil {
  34. if !real {
  35. t.Errorf("dbus.SystemBus() failed with fake Interface")
  36. }
  37. t.Skipf("D-Bus is not running: %v", err)
  38. }
  39. busObj := bus.BusObject()
  40. id := ""
  41. err = busObj.Call("org.freedesktop.DBus.GetId", 0).Store(&id)
  42. if err != nil {
  43. t.Errorf("expected success, got %v", err)
  44. }
  45. if len(id) == 0 {
  46. t.Errorf("expected non-empty Id, got \"\"")
  47. }
  48. // Switch to the session bus for the rest, since the system bus is more
  49. // locked down (and thus harder to trick into emitting signals).
  50. bus, err = dbus.SessionBus()
  51. if err != nil {
  52. if !real {
  53. t.Errorf("dbus.SystemBus() failed with fake Interface")
  54. }
  55. t.Skipf("D-Bus session bus is not available: %v", err)
  56. }
  57. busObj = bus.BusObject()
  58. name := fmt.Sprintf("io.kubernetes.dbus_test_%d", os.Getpid())
  59. owner := ""
  60. err = busObj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&owner)
  61. if err == nil {
  62. t.Errorf("expected '%s' to be un-owned, but found owner %s", name, owner)
  63. }
  64. dbuserr, ok := err.(godbus.Error)
  65. if !ok {
  66. t.Errorf("expected godbus.Error, but got %#v", err)
  67. }
  68. if dbuserr.Name != "org.freedesktop.DBus.Error.NameHasNoOwner" {
  69. t.Errorf("expected NameHasNoOwner error but got %v", err)
  70. }
  71. sigchan := make(chan *godbus.Signal, 10)
  72. bus.Signal(sigchan)
  73. rule := fmt.Sprintf("type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged',path='/org/freedesktop/DBus',sender='org.freedesktop.DBus',arg0='%s'", name)
  74. err = busObj.Call("org.freedesktop.DBus.AddMatch", 0, rule).Store()
  75. if err != nil {
  76. t.Errorf("expected success, got %v", err)
  77. }
  78. var ret uint32
  79. err = busObj.Call("org.freedesktop.DBus.RequestName", 0, name, DBusNameFlagDoNotQueue).Store(&ret)
  80. if err != nil {
  81. t.Errorf("expected success, got %v", err)
  82. }
  83. if ret != DBusRequestNameReplyPrimaryOwner {
  84. t.Errorf("expected %v, got %v", DBusRequestNameReplyPrimaryOwner, ret)
  85. }
  86. err = busObj.Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&owner)
  87. if err != nil {
  88. t.Errorf("expected success, got %v", err)
  89. }
  90. var changedSignal, acquiredSignal, lostSignal *godbus.Signal
  91. sig1 := <-sigchan
  92. sig2 := <-sigchan
  93. // We get two signals, but the order isn't guaranteed
  94. if sig1.Name == "org.freedesktop.DBus.NameOwnerChanged" {
  95. changedSignal = sig1
  96. acquiredSignal = sig2
  97. } else {
  98. acquiredSignal = sig1
  99. changedSignal = sig2
  100. }
  101. if acquiredSignal.Sender != "org.freedesktop.DBus" || acquiredSignal.Name != "org.freedesktop.DBus.NameAcquired" {
  102. t.Errorf("expected NameAcquired signal, got %v", acquiredSignal)
  103. }
  104. acquiredName := acquiredSignal.Body[0].(string)
  105. if acquiredName != name {
  106. t.Errorf("unexpected NameAcquired arguments: %v", acquiredSignal)
  107. }
  108. if changedSignal.Sender != "org.freedesktop.DBus" || changedSignal.Name != "org.freedesktop.DBus.NameOwnerChanged" {
  109. t.Errorf("expected NameOwnerChanged signal, got %v", changedSignal)
  110. }
  111. changedName := changedSignal.Body[0].(string)
  112. oldOwner := changedSignal.Body[1].(string)
  113. newOwner := changedSignal.Body[2].(string)
  114. if changedName != name || oldOwner != "" || newOwner != owner {
  115. t.Errorf("unexpected NameOwnerChanged arguments: %v", changedSignal)
  116. }
  117. err = busObj.Call("org.freedesktop.DBus.ReleaseName", 0, name).Store(&ret)
  118. if err != nil {
  119. t.Errorf("expected success, got %v", err)
  120. }
  121. if ret != DBusReleaseNameReplyReleased {
  122. t.Errorf("expected %v, got %v", DBusReleaseNameReplyReleased, ret)
  123. }
  124. sig1 = <-sigchan
  125. sig2 = <-sigchan
  126. if sig1.Name == "org.freedesktop.DBus.NameOwnerChanged" {
  127. changedSignal = sig1
  128. lostSignal = sig2
  129. } else {
  130. lostSignal = sig1
  131. changedSignal = sig2
  132. }
  133. if lostSignal.Sender != "org.freedesktop.DBus" || lostSignal.Name != "org.freedesktop.DBus.NameLost" {
  134. t.Errorf("expected NameLost signal, got %v", lostSignal)
  135. }
  136. lostName := lostSignal.Body[0].(string)
  137. if lostName != name {
  138. t.Errorf("unexpected NameLost arguments: %v", lostSignal)
  139. }
  140. if changedSignal.Sender != "org.freedesktop.DBus" || changedSignal.Name != "org.freedesktop.DBus.NameOwnerChanged" {
  141. t.Errorf("expected NameOwnerChanged signal, got %v", changedSignal)
  142. }
  143. changedName = changedSignal.Body[0].(string)
  144. oldOwner = changedSignal.Body[1].(string)
  145. newOwner = changedSignal.Body[2].(string)
  146. if changedName != name || oldOwner != owner || newOwner != "" {
  147. t.Errorf("unexpected NameOwnerChanged arguments: %v", changedSignal)
  148. }
  149. if len(sigchan) != 0 {
  150. t.Errorf("unexpected extra signals (%d)", len(sigchan))
  151. }
  152. // Unregister sigchan
  153. bus.Signal(sigchan)
  154. }
  155. func TestRealDBus(t *testing.T) {
  156. dbus := New()
  157. doDBusTest(t, dbus, true)
  158. }
  159. func TestFakeDBus(t *testing.T) {
  160. uniqueName := ":1.1"
  161. ownedName := ""
  162. fakeSystem := NewFakeConnection()
  163. fakeSystem.SetBusObject(
  164. func(method string, args ...interface{}) ([]interface{}, error) {
  165. if method == "org.freedesktop.DBus.GetId" {
  166. return []interface{}{"foo"}, nil
  167. }
  168. return nil, fmt.Errorf("unexpected method call '%s'", method)
  169. },
  170. )
  171. fakeSession := NewFakeConnection()
  172. fakeSession.SetBusObject(
  173. func(method string, args ...interface{}) ([]interface{}, error) {
  174. if method == "org.freedesktop.DBus.GetNameOwner" {
  175. checkName := args[0].(string)
  176. if checkName != ownedName {
  177. return nil, godbus.Error{Name: "org.freedesktop.DBus.Error.NameHasNoOwner", Body: nil}
  178. }
  179. return []interface{}{uniqueName}, nil
  180. } else if method == "org.freedesktop.DBus.RequestName" {
  181. reqName := args[0].(string)
  182. _ = args[1].(uint32)
  183. if ownedName != "" {
  184. return []interface{}{DBusRequestNameReplyAlreadyOwner}, nil
  185. }
  186. ownedName = reqName
  187. fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameAcquired", reqName)
  188. fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", reqName, "", uniqueName)
  189. return []interface{}{DBusRequestNameReplyPrimaryOwner}, nil
  190. } else if method == "org.freedesktop.DBus.ReleaseName" {
  191. reqName := args[0].(string)
  192. if reqName != ownedName {
  193. return []interface{}{DBusReleaseNameReplyNotOwner}, nil
  194. }
  195. ownedName = ""
  196. fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameOwnerChanged", reqName, uniqueName, "")
  197. fakeSession.EmitSignal("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "NameLost", reqName)
  198. return []interface{}{DBusReleaseNameReplyReleased}, nil
  199. } else if method == "org.freedesktop.DBus.AddMatch" {
  200. return nil, nil
  201. } else {
  202. return nil, fmt.Errorf("unexpected method call '%s'", method)
  203. }
  204. },
  205. )
  206. dbus := NewFake(fakeSystem, fakeSession)
  207. doDBusTest(t, dbus, false)
  208. }