mgr_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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.DisplayName != is.DisplayName {
  72. t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName)
  73. }
  74. if should.StartType != is.StartType {
  75. t.Fatalf("config mismatch: StartType is %v, but should have %v", is.StartType, should.StartType)
  76. }
  77. if should.Description != is.Description {
  78. t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.Description)
  79. }
  80. if depString(should.Dependencies) != depString(is.Dependencies) {
  81. t.Fatalf("config mismatch: Dependencies is %v, but should have %v", is.Dependencies, should.Dependencies)
  82. }
  83. return is
  84. }
  85. func testRecoveryActions(t *testing.T, s *mgr.Service, should []mgr.RecoveryAction) {
  86. is, err := s.RecoveryActions()
  87. if err != nil {
  88. t.Fatalf("RecoveryActions failed: %s", err)
  89. }
  90. if len(should) != len(is) {
  91. t.Errorf("recovery action mismatch: contains %v actions, but should have %v", len(is), len(should))
  92. }
  93. for i, _ := range is {
  94. if should[i].Type != is[i].Type {
  95. t.Errorf("recovery action mismatch: Type is %v, but should have %v", is[i].Type, should[i].Type)
  96. }
  97. if should[i].Delay != is[i].Delay {
  98. t.Errorf("recovery action mismatch: Delay is %v, but should have %v", is[i].Delay, should[i].Delay)
  99. }
  100. }
  101. }
  102. func testResetPeriod(t *testing.T, s *mgr.Service, should uint32) {
  103. is, err := s.ResetPeriod()
  104. if err != nil {
  105. t.Fatalf("ResetPeriod failed: %s", err)
  106. }
  107. if should != is {
  108. t.Errorf("reset period mismatch: reset period is %v, but should have %v", is, should)
  109. }
  110. }
  111. func testSetRecoveryActions(t *testing.T, s *mgr.Service) {
  112. r := []mgr.RecoveryAction{
  113. mgr.RecoveryAction{
  114. Type: mgr.NoAction,
  115. Delay: 60000 * time.Millisecond,
  116. },
  117. mgr.RecoveryAction{
  118. Type: mgr.ServiceRestart,
  119. Delay: 4 * time.Minute,
  120. },
  121. mgr.RecoveryAction{
  122. Type: mgr.ServiceRestart,
  123. Delay: time.Minute,
  124. },
  125. mgr.RecoveryAction{
  126. Type: mgr.RunCommand,
  127. Delay: 4000 * time.Millisecond,
  128. },
  129. }
  130. // 4 recovery actions with reset period
  131. err := s.SetRecoveryActions(r, uint32(10000))
  132. if err != nil {
  133. t.Fatalf("SetRecoveryActions failed: %v", err)
  134. }
  135. testRecoveryActions(t, s, r)
  136. testResetPeriod(t, s, uint32(10000))
  137. // Infinite reset period
  138. err = s.SetRecoveryActions(r, syscall.INFINITE)
  139. if err != nil {
  140. t.Fatalf("SetRecoveryActions failed: %v", err)
  141. }
  142. testRecoveryActions(t, s, r)
  143. testResetPeriod(t, s, syscall.INFINITE)
  144. // nil recovery actions
  145. err = s.SetRecoveryActions(nil, 0)
  146. if err.Error() != "recoveryActions cannot be nil" {
  147. t.Fatalf("SetRecoveryActions failed with unexpected error message of %q", err)
  148. }
  149. // Delete all recovery actions and reset period
  150. err = s.ResetRecoveryActions()
  151. if err != nil {
  152. t.Fatalf("ResetRecoveryActions failed: %v", err)
  153. }
  154. testRecoveryActions(t, s, nil)
  155. testResetPeriod(t, s, 0)
  156. }
  157. func testRebootMessage(t *testing.T, s *mgr.Service, should string) {
  158. err := s.SetRebootMessage(should)
  159. if err != nil {
  160. t.Fatalf("SetRebootMessage failed: %v", err)
  161. }
  162. is, err := s.RebootMessage()
  163. if err != nil {
  164. t.Fatalf("RebootMessage failed: %v", err)
  165. }
  166. if should != is {
  167. t.Errorf("reboot message mismatch: message is %q, but should have %q", is, should)
  168. }
  169. }
  170. func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) {
  171. err := s.SetRecoveryCommand(should)
  172. if err != nil {
  173. t.Fatalf("SetRecoveryCommand failed: %v", err)
  174. }
  175. is, err := s.RecoveryCommand()
  176. if err != nil {
  177. t.Fatalf("RecoveryCommand failed: %v", err)
  178. }
  179. if should != is {
  180. t.Errorf("recovery command mismatch: command is %q, but should have %q", is, should)
  181. }
  182. }
  183. func remove(t *testing.T, s *mgr.Service) {
  184. err := s.Delete()
  185. if err != nil {
  186. t.Fatalf("Delete failed: %s", err)
  187. }
  188. }
  189. func TestMyService(t *testing.T) {
  190. if testing.Short() {
  191. t.Skip("skipping test in short mode - it modifies system services")
  192. }
  193. const name = "myservice"
  194. m, err := mgr.Connect()
  195. if err != nil {
  196. if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
  197. t.Skip("Skipping test: we don't have rights to manage services.")
  198. }
  199. t.Fatalf("SCM connection failed: %s", err)
  200. }
  201. defer m.Disconnect()
  202. c := mgr.Config{
  203. StartType: mgr.StartDisabled,
  204. DisplayName: "my service",
  205. Description: "my service is just a test",
  206. Dependencies: []string{"LanmanServer", "W32Time"},
  207. }
  208. exename := os.Args[0]
  209. exepath, err := filepath.Abs(exename)
  210. if err != nil {
  211. t.Fatalf("filepath.Abs(%s) failed: %s", exename, err)
  212. }
  213. install(t, m, name, exepath, c)
  214. s, err := m.OpenService(name)
  215. if err != nil {
  216. t.Fatalf("service %s is not installed", name)
  217. }
  218. defer s.Close()
  219. c.BinaryPathName = exepath
  220. c = testConfig(t, s, c)
  221. c.StartType = mgr.StartManual
  222. err = s.UpdateConfig(c)
  223. if err != nil {
  224. t.Fatalf("UpdateConfig failed: %v", err)
  225. }
  226. testConfig(t, s, c)
  227. svcnames, err := m.ListServices()
  228. if err != nil {
  229. t.Fatalf("ListServices failed: %v", err)
  230. }
  231. var myserviceIsInstalled bool
  232. for _, sn := range svcnames {
  233. if sn == name {
  234. myserviceIsInstalled = true
  235. break
  236. }
  237. }
  238. if !myserviceIsInstalled {
  239. t.Errorf("ListServices failed to find %q service", name)
  240. }
  241. testSetRecoveryActions(t, s)
  242. testRebootMessage(t, s, "myservice failed")
  243. testRebootMessage(t, s, "") // delete reboot message
  244. testRecoveryCommand(t, s, "sc query myservice")
  245. testRecoveryCommand(t, s, "") // delete recovery command
  246. remove(t, s)
  247. }