github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/service/windows/service_windows_test.go (about) 1 // Copyright 2015 Cloudbase Solutions 2 // Copyright 2015 Canonical Ltd. 3 // Licensed under the AGPLv3, see LICENCE file for details. 4 5 // +build !linux windows 6 7 package windows_test 8 9 import ( 10 "fmt" 11 "syscall" 12 13 win "github.com/gabriel-samfira/sys/windows" 14 "github.com/gabriel-samfira/sys/windows/svc" 15 "github.com/juju/errors" 16 "github.com/juju/testing" 17 jc "github.com/juju/testing/checkers" 18 gc "gopkg.in/check.v1" 19 20 "github.com/juju/juju/service/common" 21 "github.com/juju/juju/service/windows" 22 coretesting "github.com/juju/juju/testing" 23 ) 24 25 type serviceManagerSuite struct { 26 coretesting.BaseSuite 27 28 stub *testing.Stub 29 passwdStub *testing.Stub 30 conn *windows.StubMgr 31 getPasswd *windows.StubGetPassword 32 33 name string 34 conf common.Conf 35 36 mgr windows.ServiceManager 37 38 execPath string 39 } 40 41 var _ = gc.Suite(&serviceManagerSuite{}) 42 43 func (s *serviceManagerSuite) SetUpTest(c *gc.C) { 44 s.BaseSuite.SetUpTest(c) 45 var err error 46 s.execPath = `C:\juju\bin\jujud.exe` 47 s.stub = &testing.Stub{} 48 s.passwdStub = &testing.Stub{} 49 s.conn = windows.PatchMgrConnect(s, s.stub) 50 s.getPasswd = windows.PatchGetPassword(s, s.passwdStub) 51 windows.WinChangeServiceConfig2 = func(win.Handle, uint32, *byte) error { 52 return nil 53 } 54 55 // Set up the service. 56 s.name = "machine-1" 57 s.conf = common.Conf{ 58 Desc: "service for " + s.name, 59 ExecStart: s.execPath + " " + s.name, 60 } 61 62 s.mgr, err = windows.NewServiceManager() 63 c.Assert(err, gc.IsNil) 64 65 // Clear services 66 s.conn.Clear() 67 } 68 69 func (s *serviceManagerSuite) TestCreate(c *gc.C) { 70 s.getPasswd.SetPasswd("fake") 71 err := s.mgr.Create(s.name, s.conf) 72 c.Assert(err, gc.IsNil) 73 74 c.Assert(s.getPasswd.Calls(), gc.HasLen, 1) 75 76 exists := s.conn.Exists(s.name) 77 c.Assert(exists, jc.IsTrue) 78 79 svcs := s.conn.List() 80 c.Assert(svcs, gc.HasLen, 1) 81 82 m, ok := s.mgr.(*windows.SvcManager) 83 c.Assert(ok, jc.IsTrue) 84 85 cfg, err := m.Config(s.name) 86 c.Assert(err, gc.IsNil) 87 c.Assert(cfg.ServiceStartName, gc.Equals, windows.JujudUser) 88 89 running, err := s.mgr.Running(s.name) 90 c.Assert(err, gc.IsNil) 91 c.Assert(running, jc.IsFalse) 92 } 93 94 func (s *serviceManagerSuite) TestCreateInvalidPassword(c *gc.C) { 95 passwdError := errors.New("Failed to get password") 96 s.passwdStub.SetErrors(passwdError) 97 98 err := s.mgr.Create(s.name, s.conf) 99 c.Assert(errors.Cause(err), gc.Equals, passwdError) 100 101 c.Assert(s.getPasswd.Calls(), gc.HasLen, 1) 102 103 exists := s.conn.Exists(s.name) 104 c.Assert(exists, jc.IsFalse) 105 } 106 107 func (s *serviceManagerSuite) TestCreateInvalidUser(c *gc.C) { 108 s.getPasswd.SetPasswd("fake") 109 110 err := s.mgr.Create(s.name, s.conf) 111 c.Assert(err, gc.IsNil) 112 113 c.Assert(s.getPasswd.Calls(), gc.HasLen, 1) 114 115 m, ok := s.mgr.(*windows.SvcManager) 116 c.Assert(ok, jc.IsTrue) 117 118 cfg, err := m.Config(s.name) 119 120 c.Assert(err, gc.IsNil) 121 c.Assert(cfg.ServiceStartName, gc.Equals, windows.JujudUser) 122 } 123 124 func (s *serviceManagerSuite) TestCreateAlreadyExists(c *gc.C) { 125 err := s.mgr.Create(s.name, s.conf) 126 c.Assert(err, gc.IsNil) 127 exists := s.conn.Exists(s.name) 128 c.Assert(exists, jc.IsTrue) 129 err = s.mgr.Create(s.name, s.conf) 130 c.Assert(errors.Cause(err), gc.Equals, windows.ERROR_SERVICE_EXISTS) 131 } 132 133 func (s *serviceManagerSuite) TestCreateMultipleServices(c *gc.C) { 134 err := s.mgr.Create("test-service", common.Conf{}) 135 c.Assert(err, gc.IsNil) 136 exists := s.conn.Exists("test-service") 137 c.Assert(exists, jc.IsTrue) 138 139 err = s.mgr.Create("another-test-service", common.Conf{}) 140 c.Assert(err, gc.IsNil) 141 exists = s.conn.Exists("another-test-service") 142 c.Assert(exists, jc.IsTrue) 143 144 svcs := s.conn.List() 145 c.Assert(svcs, gc.HasLen, 2) 146 } 147 148 func (s *serviceManagerSuite) TestStart(c *gc.C) { 149 windows.AddService(s.name, s.execPath, s.stub, svc.Status{State: svc.Stopped}) 150 151 err := s.mgr.Start(s.name) 152 c.Assert(err, gc.IsNil) 153 154 running, err := s.mgr.Running(s.name) 155 c.Assert(err, gc.IsNil) 156 c.Assert(running, jc.IsTrue) 157 } 158 159 func (s *serviceManagerSuite) TestStartTwice(c *gc.C) { 160 windows.AddService(s.name, s.execPath, s.stub, svc.Status{State: svc.Stopped}) 161 162 err := s.mgr.Start(s.name) 163 c.Assert(err, gc.IsNil) 164 165 err = s.mgr.Start(s.name) 166 c.Assert(err, gc.IsNil) 167 168 running, err := s.mgr.Running(s.name) 169 c.Assert(err, gc.IsNil) 170 c.Assert(running, jc.IsTrue) 171 } 172 173 func (s *serviceManagerSuite) TestStartStop(c *gc.C) { 174 windows.AddService(s.name, s.execPath, s.stub, svc.Status{State: svc.Stopped}) 175 176 err := s.mgr.Start(s.name) 177 c.Assert(err, gc.IsNil) 178 179 running, err := s.mgr.Running(s.name) 180 c.Assert(err, gc.IsNil) 181 c.Assert(running, jc.IsTrue) 182 183 err = s.mgr.Stop(s.name) 184 c.Assert(err, gc.IsNil) 185 186 running, err = s.mgr.Running(s.name) 187 c.Assert(err, gc.IsNil) 188 c.Assert(running, jc.IsFalse) 189 } 190 191 func (s *serviceManagerSuite) TestStop(c *gc.C) { 192 windows.AddService(s.name, s.execPath, s.stub, svc.Status{State: svc.Running}) 193 194 running, err := s.mgr.Running(s.name) 195 c.Assert(err, gc.IsNil) 196 c.Assert(running, jc.IsTrue) 197 198 err = s.mgr.Stop(s.name) 199 c.Assert(err, gc.IsNil) 200 201 running, err = s.mgr.Running(s.name) 202 c.Assert(err, gc.IsNil) 203 c.Assert(running, jc.IsFalse) 204 } 205 206 func (s *serviceManagerSuite) TestEnsureRestartOnFailure(c *gc.C) { 207 windows.WinChangeServiceConfig2 = func(win.Handle, uint32, *byte) error { 208 return errors.New("ChangeServiceConfig2: zoinks") 209 } 210 err := s.mgr.Create(s.name, s.conf) 211 c.Assert(err, gc.ErrorMatches, "ChangeServiceConfig2: zoinks") 212 } 213 214 func (s *serviceManagerSuite) TestEnsureRestartOnFailureCloseHandleDoesNotOverwritePreviousError(c *gc.C) { 215 windows.WinChangeServiceConfig2 = func(win.Handle, uint32, *byte) error { 216 return errors.New("ChangeServiceConfig2: zoinks") 217 } 218 s.stub.SetErrors(nil, nil, errors.New("CloseHandle: floosh")) 219 err := s.mgr.Create(s.name, s.conf) 220 c.Assert(err, gc.ErrorMatches, fmt.Sprintf("\\(also close %q handle failed: CloseHandle: floosh\\): ChangeServiceConfig2: zoinks", s.name)) 221 s.stub.CheckCallNames(c, "CreateService", "GetHandle", "CloseHandle", "Close") 222 } 223 224 func (s *serviceManagerSuite) TestEnsureRestartOnFailureCloseHandleReturnsErrorSuccessfully(c *gc.C) { 225 s.stub.SetErrors(nil, nil, errors.New("CloseHandle: floosh")) 226 err := s.mgr.Create(s.name, s.conf) 227 c.Assert(err, gc.ErrorMatches, fmt.Sprintf("close %q handle failed: CloseHandle: floosh", s.name)) 228 s.stub.CheckCallNames(c, "CreateService", "GetHandle", "CloseHandle", "Close") 229 } 230 231 func (s *serviceManagerSuite) TestChangePassword(c *gc.C) { 232 s.getPasswd.SetPasswd("fake") 233 err := s.mgr.Create(s.name, s.conf) 234 c.Assert(err, gc.IsNil) 235 c.Assert(s.getPasswd.Calls(), gc.HasLen, 1) 236 237 exists := s.conn.Exists(s.name) 238 c.Assert(exists, jc.IsTrue) 239 240 m, ok := s.mgr.(*windows.SvcManager) 241 c.Assert(ok, jc.IsTrue) 242 243 cfg, err := m.Config(s.name) 244 c.Assert(err, gc.IsNil) 245 c.Assert(cfg.Password, gc.Equals, "fake") 246 247 err = s.mgr.ChangeServicePassword(s.name, "obviously-better-password") 248 c.Assert(err, gc.IsNil) 249 250 cfg, err = m.Config(s.name) 251 c.Assert(err, gc.IsNil) 252 c.Assert(cfg.Password, gc.Equals, "obviously-better-password") 253 254 } 255 256 func (s *serviceManagerSuite) TestChangePasswordAccessDenied(c *gc.C) { 257 s.getPasswd.SetPasswd("fake") 258 err := s.mgr.Create(s.name, s.conf) 259 c.Assert(err, gc.IsNil) 260 c.Assert(s.getPasswd.Calls(), gc.HasLen, 1) 261 262 m, ok := s.mgr.(*windows.SvcManager) 263 c.Assert(ok, jc.IsTrue) 264 265 cfg, err := m.Config(s.name) 266 c.Assert(err, gc.IsNil) 267 c.Assert(cfg.Password, gc.Equals, "fake") 268 269 s.stub.SetErrors(syscall.ERROR_ACCESS_DENIED) 270 271 err = s.mgr.ChangeServicePassword(s.name, "obviously-better-password") 272 c.Assert(err, gc.IsNil) 273 274 cfg, err = m.Config(s.name) 275 c.Assert(err, gc.IsNil) 276 c.Assert(cfg.Password, gc.Equals, "fake") 277 278 } 279 280 func (s *serviceManagerSuite) TestChangePasswordErrorOut(c *gc.C) { 281 s.getPasswd.SetPasswd("fake") 282 err := s.mgr.Create(s.name, s.conf) 283 c.Assert(err, gc.IsNil) 284 c.Assert(s.getPasswd.Calls(), gc.HasLen, 1) 285 286 m, ok := s.mgr.(*windows.SvcManager) 287 c.Assert(ok, jc.IsTrue) 288 289 cfg, err := m.Config(s.name) 290 c.Assert(err, gc.IsNil) 291 c.Assert(cfg.Password, gc.Equals, "fake") 292 293 s.stub.SetErrors(errors.New("poof")) 294 295 err = s.mgr.ChangeServicePassword(s.name, "obviously-better-password") 296 c.Assert(err, gc.ErrorMatches, "poof") 297 298 cfg, err = m.Config(s.name) 299 c.Assert(err, gc.IsNil) 300 c.Assert(cfg.Password, gc.Equals, "fake") 301 302 } 303 304 func (s *serviceManagerSuite) TestDelete(c *gc.C) { 305 windows.AddService(s.name, s.execPath, s.stub, svc.Status{State: svc.Running}) 306 307 err := s.mgr.Delete(s.name) 308 c.Assert(err, gc.IsNil) 309 exists := s.conn.Exists(s.name) 310 c.Assert(exists, jc.IsFalse) 311 } 312 313 func (s *serviceManagerSuite) TestDeleteInexistent(c *gc.C) { 314 exists := s.conn.Exists(s.name) 315 c.Assert(exists, jc.IsFalse) 316 317 err := s.mgr.Delete(s.name) 318 c.Assert(errors.Cause(err), gc.Equals, windows.ERROR_SERVICE_DOES_NOT_EXIST) 319 } 320 321 func (s *serviceManagerSuite) TestCloseCalled(c *gc.C) { 322 err := s.mgr.Create(s.name, s.conf) 323 c.Assert(err, gc.IsNil) 324 s.stub.CheckCallNames(c, "CreateService", "GetHandle", "CloseHandle", "Close") 325 s.stub.ResetCalls() 326 327 _, err = s.mgr.Running(s.name) 328 c.Assert(err, gc.IsNil) 329 s.stub.CheckCallNames(c, "OpenService", "Query", "Close") 330 s.stub.ResetCalls() 331 332 err = s.mgr.Start(s.name) 333 c.Assert(err, gc.IsNil) 334 s.stub.CheckCallNames(c, "OpenService", "Query", "Close", "OpenService", "Start", "Close") 335 s.stub.ResetCalls() 336 337 err = s.mgr.Stop(s.name) 338 c.Assert(err, gc.IsNil) 339 s.stub.CheckCallNames(c, "OpenService", "Query", "Close", "OpenService", "Control", "Close") 340 s.stub.ResetCalls() 341 342 err = s.mgr.Delete(s.name) 343 c.Assert(err, gc.IsNil) 344 s.stub.CheckCallNames(c, "OpenService", "Close", "OpenService", "Control", "Close") 345 s.stub.ResetCalls() 346 347 }