mgr_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build windows
  5. package mgr_test
  6. import (
  7. "os"
  8. "path/filepath"
  9. "sort"
  10. "strings"
  11. "syscall"
  12. "testing"
  13. "time"
  14. "golang.org/x/sys/windows/svc/mgr"
  15. )
  16. func TestOpenLanManServer(t *testing.T) {
  17. m, err := mgr.Connect()
  18. if err != nil {
  19. if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
  20. t.Skip("Skipping test: we don't have rights to manage services.")
  21. }
  22. t.Fatalf("SCM connection failed: %s", err)
  23. }
  24. defer m.Disconnect()
  25. s, err := m.OpenService("LanmanServer")
  26. if err != nil {
  27. t.Fatalf("OpenService(lanmanserver) failed: %s", err)
  28. }
  29. defer s.Close()
  30. _, err = s.Config()
  31. if err != nil {
  32. t.Fatalf("Config failed: %s", err)
  33. }
  34. }
  35. func install(t *testing.T, m *mgr.Mgr, name, exepath string, c mgr.Config) {
  36. // Sometimes it takes a while for the service to get
  37. // removed after previous test run.
  38. for i := 0; ; i++ {
  39. s, err := m.OpenService(name)
  40. if err != nil {
  41. break
  42. }
  43. s.Close()
  44. if i > 10 {
  45. t.Fatalf("service %s already exists", name)
  46. }
  47. time.Sleep(300 * time.Millisecond)
  48. }
  49. s, err := m.CreateService(name, exepath, c)
  50. if err != nil {
  51. t.Fatalf("CreateService(%s) failed: %v", name, err)
  52. }
  53. defer s.Close()
  54. }
  55. func depString(d []string) string {
  56. if len(d) == 0 {
  57. return ""
  58. }
  59. for i := range d {
  60. d[i] = strings.ToLower(d[i])
  61. }
  62. ss := sort.StringSlice(d)
  63. ss.Sort()
  64. return strings.Join([]string(ss), " ")
  65. }
  66. func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
  67. is, err := s.Config()
  68. if err != nil {
  69. t.Fatalf("Config failed: %s", err)
  70. }
  71. if should.DelayedAutoStart != is.DelayedAutoStart {
  72. t.Fatalf("config mismatch: DelayedAutoStart is %v, but should have %v", is.DelayedAutoStart, should.DelayedAutoStart)
  73. }
  74. if should.DisplayName != is.DisplayName {
  75. t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName)
  76. }
  77. if should.StartType != is.StartType {
  78. t.Fatalf("config mismatch: StartType is %v, but should have %v", is.StartType, should.StartType)
  79. }
  80. if should.Description != is.Description {
  81. t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.Description)
  82. }
  83. if depString(should.Dependencies) != depString(is.Dependencies) {
  84. t.Fatalf("config mismatch: Dependencies is %v, but should have %v", is.Dependencies, should.Dependencies)
  85. }
  86. return is
  87. }
  88. func testRecoveryActions(t *testing.T, s *mgr.Service, should []mgr.RecoveryAction) {
  89. is, err := s.RecoveryActions()
  90. if err != nil {
  91. t.Fatalf("RecoveryActions failed: %s", err)
  92. }
  93. if len(should) != len(is) {
  94. t.Errorf("recovery action mismatch: contains %v actions, but should have %v", len(is), len(should))
  95. }
  96. for i, _ := range is {
  97. if should[i].Type != is[i].Type {
  98. t.Errorf("recovery action mismatch: Type is %v, but should have %v", is[i].Type, should[i].Type)
  99. }
  100. if should[i].Delay != is[i].Delay {
  101. t.Errorf("recovery action mismatch: Delay is %v, but should have %v", is[i].Delay, should[i].Delay)
  102. }
  103. }
  104. }
  105. func testResetPeriod(t *testing.T, s *mgr.Service, should uint32) {
  106. is, err := s.ResetPeriod()
  107. if err != nil {
  108. t.Fatalf("ResetPeriod failed: %s", err)
  109. }
  110. if should != is {
  111. t.Errorf("reset period mismatch: reset period is %v, but should have %v", is, should)
  112. }
  113. }
  114. func testSetRecoveryActions(t *testing.T, s *mgr.Service) {
  115. r := []mgr.RecoveryAction{
  116. mgr.RecoveryAction{
  117. Type: mgr.NoAction,
  118. Delay: 60000 * time.Millisecond,
  119. },
  120. mgr.RecoveryAction{
  121. Type: mgr.ServiceRestart,
  122. Delay: 4 * time.Minute,
  123. },
  124. mgr.RecoveryAction{
  125. Type: mgr.ServiceRestart,
  126. Delay: time.Minute,
  127. },
  128. mgr.RecoveryAction{
  129. Type: mgr.RunCommand,
  130. Delay: 4000 * time.Millisecond,
  131. },
  132. }
  133. // 4 recovery actions with reset period
  134. err := s.SetRecoveryActions(r, uint32(10000))
  135. if err != nil {
  136. t.Fatalf("SetRecoveryActions failed: %v", err)
  137. }
  138. testRecoveryActions(t, s, r)
  139. testResetPeriod(t, s, uint32(10000))
  140. // Infinite reset period
  141. err = s.SetRecoveryActions(r, syscall.INFINITE)
  142. if err != nil {
  143. t.Fatalf("SetRecoveryActions failed: %v", err)
  144. }
  145. testRecoveryActions(t, s, r)
  146. testResetPeriod(t, s, syscall.INFINITE)
  147. // nil recovery actions
  148. err = s.SetRecoveryActions(nil, 0)
  149. if err.Error() != "recoveryActions cannot be nil" {
  150. t.Fatalf("SetRecoveryActions failed with unexpected error message of %q", err)
  151. }
  152. // Delete all recovery actions and reset period
  153. err = s.ResetRecoveryActions()
  154. if err != nil {
  155. t.Fatalf("ResetRecoveryActions failed: %v", err)
  156. }
  157. testRecoveryActions(t, s, nil)
  158. testResetPeriod(t, s, 0)
  159. }
  160. func testRebootMessage(t *testing.T, s *mgr.Service, should string) {
  161. err := s.SetRebootMessage(should)
  162. if err != nil {
  163. t.Fatalf("SetRebootMessage failed: %v", err)
  164. }
  165. is, err := s.RebootMessage()
  166. if err != nil {
  167. t.Fatalf("RebootMessage failed: %v", err)
  168. }
  169. if should != is {
  170. t.Errorf("reboot message mismatch: message is %q, but should have %q", is, should)
  171. }
  172. }
  173. func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) {
  174. err := s.SetRecoveryCommand(should)
  175. if err != nil {
  176. t.Fatalf("SetRecoveryCommand failed: %v", err)
  177. }
  178. is, err := s.RecoveryCommand()
  179. if err != nil {
  180. t.Fatalf("RecoveryCommand failed: %v", err)
  181. }
  182. if should != is {
  183. t.Errorf("recovery command mismatch: command is %q, but should have %q", is, should)
  184. }
  185. }
  186. func remove(t *testing.T, s *mgr.Service) {
  187. err := s.Delete()
  188. if err != nil {
  189. t.Fatalf("Delete failed: %s", err)
  190. }
  191. }
  192. func TestMyService(t *testing.T) {
  193. if testing.Short() {
  194. t.Skip("skipping test in short mode - it modifies system services")
  195. }
  196. const name = "myservice"
  197. m, err := mgr.Connect()
  198. if err != nil {
  199. if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
  200. t.Skip("Skipping test: we don't have rights to manage services.")
  201. }
  202. t.Fatalf("SCM connection failed: %s", err)
  203. }
  204. defer m.Disconnect()
  205. c := mgr.Config{
  206. StartType: mgr.StartDisabled,
  207. DisplayName: "my service",
  208. Description: "my service is just a test",
  209. Dependencies: []string{"LanmanServer", "W32Time"},
  210. }
  211. exename := os.Args[0]
  212. exepath, err := filepath.Abs(exename)
  213. if err != nil {
  214. t.Fatalf("filepath.Abs(%s) failed: %s", exename, err)
  215. }
  216. install(t, m, name, exepath, c)
  217. s, err := m.OpenService(name)
  218. if err != nil {
  219. t.Fatalf("service %s is not installed", name)
  220. }
  221. defer s.Close()
  222. c.BinaryPathName = exepath
  223. c = testConfig(t, s, c)
  224. c.StartType = mgr.StartManual
  225. err = s.UpdateConfig(c)
  226. if err != nil {
  227. t.Fatalf("UpdateConfig failed: %v", err)
  228. }
  229. testConfig(t, s, c)
  230. c.StartType = mgr.StartAutomatic
  231. c.DelayedAutoStart = true
  232. err = s.UpdateConfig(c)
  233. if err != nil {
  234. t.Fatalf("UpdateConfig failed: %v", err)
  235. }
  236. testConfig(t, s, c)
  237. svcnames, err := m.ListServices()
  238. if err != nil {
  239. t.Fatalf("ListServices failed: %v", err)
  240. }
  241. var myserviceIsInstalled bool
  242. for _, sn := range svcnames {
  243. if sn == name {
  244. myserviceIsInstalled = true
  245. break
  246. }
  247. }
  248. if !myserviceIsInstalled {
  249. t.Errorf("ListServices failed to find %q service", name)
  250. }
  251. testSetRecoveryActions(t, s)
  252. testRebootMessage(t, s, "myservice failed")
  253. testRebootMessage(t, s, "") // delete reboot message
  254. testRecoveryCommand(t, s, "sc query myservice")
  255. testRecoveryCommand(t, s, "") // delete recovery command
  256. remove(t, s)
  257. }