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.
18 "golang.org/x/sys/windows/svc/mgr"
21 func TestOpenLanManServer(t *testing.T) {
22 m, err := mgr.Connect()
24 if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
25 t.Skip("Skipping test: we don't have rights to manage services.")
27 t.Fatalf("SCM connection failed: %s", err)
31 s, err := m.OpenService("LanmanServer")
33 t.Fatalf("OpenService(lanmanserver) failed: %s", err)
39 t.Fatalf("Config failed: %s", err)
43 func install(t *testing.T, m *mgr.Mgr, name, exepath string, c mgr.Config) {
44 // Sometimes it takes a while for the service to get
45 // removed after previous test run.
47 s, err := m.OpenService(name)
54 t.Fatalf("service %s already exists", name)
56 time.Sleep(300 * time.Millisecond)
59 s, err := m.CreateService(name, exepath, c)
61 t.Fatalf("CreateService(%s) failed: %v", name, err)
66 func depString(d []string) string {
71 d[i] = strings.ToLower(d[i])
73 ss := sort.StringSlice(d)
75 return strings.Join([]string(ss), " ")
78 func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
81 t.Fatalf("Config failed: %s", err)
83 if should.DisplayName != is.DisplayName {
84 t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName)
86 if should.StartType != is.StartType {
87 t.Fatalf("config mismatch: StartType is %v, but should have %v", is.StartType, should.StartType)
89 if should.Description != is.Description {
90 t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.Description)
92 if depString(should.Dependencies) != depString(is.Dependencies) {
93 t.Fatalf("config mismatch: Dependencies is %v, but should have %v", is.Dependencies, should.Dependencies)
98 func testRecoveryActions(t *testing.T, s *mgr.Service, should []mgr.RecoveryAction) {
99 is, err := s.RecoveryActions()
101 t.Fatalf("RecoveryActions failed: %s", err)
103 if len(should) != len(is) {
104 t.Errorf("recovery action mismatch: contains %v actions, but should have %v", len(is), len(should))
106 for i, _ := range is {
107 if should[i].Type != is[i].Type {
108 t.Errorf("recovery action mismatch: Type is %v, but should have %v", is[i].Type, should[i].Type)
110 if should[i].Delay != is[i].Delay {
111 t.Errorf("recovery action mismatch: Delay is %v, but should have %v", is[i].Delay, should[i].Delay)
116 func testResetPeriod(t *testing.T, s *mgr.Service, should uint32) {
117 is, err := s.ResetPeriod()
119 t.Fatalf("ResetPeriod failed: %s", err)
122 t.Errorf("reset period mismatch: reset period is %v, but should have %v", is, should)
126 func testSetRecoveryActions(t *testing.T, s *mgr.Service) {
127 r := []mgr.RecoveryAction{
130 Delay: 60000 * time.Millisecond,
133 Type: mgr.ServiceRestart,
134 Delay: 4 * time.Minute,
137 Type: mgr.ServiceRestart,
141 Type: mgr.RunCommand,
142 Delay: 4000 * time.Millisecond,
146 // 4 recovery actions with reset period
147 err := s.SetRecoveryActions(r, uint32(10000))
149 t.Fatalf("SetRecoveryActions failed: %v", err)
151 testRecoveryActions(t, s, r)
152 testResetPeriod(t, s, uint32(10000))
154 // Infinite reset period
155 err = s.SetRecoveryActions(r, syscall.INFINITE)
157 t.Fatalf("SetRecoveryActions failed: %v", err)
159 testRecoveryActions(t, s, r)
160 testResetPeriod(t, s, syscall.INFINITE)
162 // nil recovery actions
163 err = s.SetRecoveryActions(nil, 0)
164 if err.Error() != "recoveryActions cannot be nil" {
165 t.Fatalf("SetRecoveryActions failed with unexpected error message of %q", err)
168 // Delete all recovery actions and reset period
169 err = s.ResetRecoveryActions()
171 t.Fatalf("ResetRecoveryActions failed: %v", err)
173 testRecoveryActions(t, s, nil)
174 testResetPeriod(t, s, 0)
177 func testRebootMessage(t *testing.T, s *mgr.Service, should string) {
178 err := s.SetRebootMessage(should)
180 t.Fatalf("SetRebootMessage failed: %v", err)
182 is, err := s.RebootMessage()
184 t.Fatalf("RebootMessage failed: %v", err)
187 t.Errorf("reboot message mismatch: message is %q, but should have %q", is, should)
191 func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) {
192 err := s.SetRecoveryCommand(should)
194 t.Fatalf("SetRecoveryCommand failed: %v", err)
196 is, err := s.RecoveryCommand()
198 t.Fatalf("RecoveryCommand failed: %v", err)
201 t.Errorf("recovery command mismatch: command is %q, but should have %q", is, should)
205 func remove(t *testing.T, s *mgr.Service) {
208 t.Fatalf("Delete failed: %s", err)
212 func TestMyService(t *testing.T) {
214 t.Skip("skipping test in short mode - it modifies system services")
217 const name = "myservice"
219 m, err := mgr.Connect()
221 if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
222 t.Skip("Skipping test: we don't have rights to manage services.")
224 t.Fatalf("SCM connection failed: %s", err)
229 StartType: mgr.StartDisabled,
230 DisplayName: "my service",
231 Description: "my service is just a test",
232 Dependencies: []string{"LanmanServer", "W32Time"},
235 exename := os.Args[0]
236 exepath, err := filepath.Abs(exename)
238 t.Fatalf("filepath.Abs(%s) failed: %s", exename, err)
241 install(t, m, name, exepath, c)
243 s, err := m.OpenService(name)
245 t.Fatalf("service %s is not installed", name)
249 c.BinaryPathName = exepath
250 c = testConfig(t, s, c)
252 c.StartType = mgr.StartManual
253 err = s.UpdateConfig(c)
255 t.Fatalf("UpdateConfig failed: %v", err)
260 svcnames, err := m.ListServices()
262 t.Fatalf("ListServices failed: %v", err)
264 var myserviceIsInstalled bool
265 for _, sn := range svcnames {
267 myserviceIsInstalled = true
271 if !myserviceIsInstalled {
272 t.Errorf("ListServices failed to find %q service", name)
275 testSetRecoveryActions(t, s)
276 testRebootMessage(t, s, "myservice failed")
277 testRebootMessage(t, s, "") // delete reboot message
278 testRecoveryCommand(t, s, "sc query myservice")
279 testRecoveryCommand(t, s, "") // delete recovery command