github.com/zhongdalu/gf@v1.0.0/third/golang.org/x/sys/windows/svc/mgr/mgr_test.go (about) 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 5 // +build windows 6 7 package mgr_test 8 9 import ( 10 "os" 11 "path/filepath" 12 "sort" 13 "strings" 14 "syscall" 15 "testing" 16 "time" 17 18 "github.com/zhongdalu/gf/third/golang.org/x/sys/windows/svc/mgr" 19 ) 20 21 func TestOpenLanManServer(t *testing.T) { 22 m, err := mgr.Connect() 23 if err != nil { 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.") 26 } 27 t.Fatalf("SCM connection failed: %s", err) 28 } 29 defer m.Disconnect() 30 31 s, err := m.OpenService("LanmanServer") 32 if err != nil { 33 t.Fatalf("OpenService(lanmanserver) failed: %s", err) 34 } 35 defer s.Close() 36 37 _, err = s.Config() 38 if err != nil { 39 t.Fatalf("Config failed: %s", err) 40 } 41 } 42 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. 46 for i := 0; ; i++ { 47 s, err := m.OpenService(name) 48 if err != nil { 49 break 50 } 51 s.Close() 52 53 if i > 10 { 54 t.Fatalf("service %s already exists", name) 55 } 56 time.Sleep(300 * time.Millisecond) 57 } 58 59 s, err := m.CreateService(name, exepath, c) 60 if err != nil { 61 t.Fatalf("CreateService(%s) failed: %v", name, err) 62 } 63 defer s.Close() 64 } 65 66 func depString(d []string) string { 67 if len(d) == 0 { 68 return "" 69 } 70 for i := range d { 71 d[i] = strings.ToLower(d[i]) 72 } 73 ss := sort.StringSlice(d) 74 ss.Sort() 75 return strings.Join([]string(ss), " ") 76 } 77 78 func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config { 79 is, err := s.Config() 80 if err != nil { 81 t.Fatalf("Config failed: %s", err) 82 } 83 if should.DisplayName != is.DisplayName { 84 t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName) 85 } 86 if should.StartType != is.StartType { 87 t.Fatalf("config mismatch: StartType is %v, but should have %v", is.StartType, should.StartType) 88 } 89 if should.Description != is.Description { 90 t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.Description) 91 } 92 if depString(should.Dependencies) != depString(is.Dependencies) { 93 t.Fatalf("config mismatch: Dependencies is %v, but should have %v", is.Dependencies, should.Dependencies) 94 } 95 return is 96 } 97 98 func testRecoveryActions(t *testing.T, s *mgr.Service, should []mgr.RecoveryAction) { 99 is, err := s.RecoveryActions() 100 if err != nil { 101 t.Fatalf("RecoveryActions failed: %s", err) 102 } 103 if len(should) != len(is) { 104 t.Errorf("recovery action mismatch: contains %v actions, but should have %v", len(is), len(should)) 105 } 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) 109 } 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) 112 } 113 } 114 } 115 116 func testResetPeriod(t *testing.T, s *mgr.Service, should uint32) { 117 is, err := s.ResetPeriod() 118 if err != nil { 119 t.Fatalf("ResetPeriod failed: %s", err) 120 } 121 if should != is { 122 t.Errorf("reset period mismatch: reset period is %v, but should have %v", is, should) 123 } 124 } 125 126 func testSetRecoveryActions(t *testing.T, s *mgr.Service) { 127 r := []mgr.RecoveryAction{ 128 mgr.RecoveryAction{ 129 Type: mgr.NoAction, 130 Delay: 60000 * time.Millisecond, 131 }, 132 mgr.RecoveryAction{ 133 Type: mgr.ServiceRestart, 134 Delay: 4 * time.Minute, 135 }, 136 mgr.RecoveryAction{ 137 Type: mgr.ServiceRestart, 138 Delay: time.Minute, 139 }, 140 mgr.RecoveryAction{ 141 Type: mgr.RunCommand, 142 Delay: 4000 * time.Millisecond, 143 }, 144 } 145 146 // 4 recovery actions with reset period 147 err := s.SetRecoveryActions(r, uint32(10000)) 148 if err != nil { 149 t.Fatalf("SetRecoveryActions failed: %v", err) 150 } 151 testRecoveryActions(t, s, r) 152 testResetPeriod(t, s, uint32(10000)) 153 154 // Infinite reset period 155 err = s.SetRecoveryActions(r, syscall.INFINITE) 156 if err != nil { 157 t.Fatalf("SetRecoveryActions failed: %v", err) 158 } 159 testRecoveryActions(t, s, r) 160 testResetPeriod(t, s, syscall.INFINITE) 161 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) 166 } 167 168 // Delete all recovery actions and reset period 169 err = s.ResetRecoveryActions() 170 if err != nil { 171 t.Fatalf("ResetRecoveryActions failed: %v", err) 172 } 173 testRecoveryActions(t, s, nil) 174 testResetPeriod(t, s, 0) 175 } 176 177 func testRebootMessage(t *testing.T, s *mgr.Service, should string) { 178 err := s.SetRebootMessage(should) 179 if err != nil { 180 t.Fatalf("SetRebootMessage failed: %v", err) 181 } 182 is, err := s.RebootMessage() 183 if err != nil { 184 t.Fatalf("RebootMessage failed: %v", err) 185 } 186 if should != is { 187 t.Errorf("reboot message mismatch: message is %q, but should have %q", is, should) 188 } 189 } 190 191 func testRecoveryCommand(t *testing.T, s *mgr.Service, should string) { 192 err := s.SetRecoveryCommand(should) 193 if err != nil { 194 t.Fatalf("SetRecoveryCommand failed: %v", err) 195 } 196 is, err := s.RecoveryCommand() 197 if err != nil { 198 t.Fatalf("RecoveryCommand failed: %v", err) 199 } 200 if should != is { 201 t.Errorf("recovery command mismatch: command is %q, but should have %q", is, should) 202 } 203 } 204 205 func remove(t *testing.T, s *mgr.Service) { 206 err := s.Delete() 207 if err != nil { 208 t.Fatalf("Delete failed: %s", err) 209 } 210 } 211 212 func TestMyService(t *testing.T) { 213 if testing.Short() { 214 t.Skip("skipping test in short mode - it modifies system services") 215 } 216 217 const name = "myservice" 218 219 m, err := mgr.Connect() 220 if err != nil { 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.") 223 } 224 t.Fatalf("SCM connection failed: %s", err) 225 } 226 defer m.Disconnect() 227 228 c := mgr.Config{ 229 StartType: mgr.StartDisabled, 230 DisplayName: "my service", 231 Description: "my service is just a test", 232 Dependencies: []string{"LanmanServer", "W32Time"}, 233 } 234 235 exename := os.Args[0] 236 exepath, err := filepath.Abs(exename) 237 if err != nil { 238 t.Fatalf("filepath.Abs(%s) failed: %s", exename, err) 239 } 240 241 install(t, m, name, exepath, c) 242 243 s, err := m.OpenService(name) 244 if err != nil { 245 t.Fatalf("service %s is not installed", name) 246 } 247 defer s.Close() 248 249 c.BinaryPathName = exepath 250 c = testConfig(t, s, c) 251 252 c.StartType = mgr.StartManual 253 err = s.UpdateConfig(c) 254 if err != nil { 255 t.Fatalf("UpdateConfig failed: %v", err) 256 } 257 258 testConfig(t, s, c) 259 260 svcnames, err := m.ListServices() 261 if err != nil { 262 t.Fatalf("ListServices failed: %v", err) 263 } 264 var myserviceIsInstalled bool 265 for _, sn := range svcnames { 266 if sn == name { 267 myserviceIsInstalled = true 268 break 269 } 270 } 271 if !myserviceIsInstalled { 272 t.Errorf("ListServices failed to find %q service", name) 273 } 274 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 280 281 remove(t, s) 282 }