github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  }