github.com/observiq/bindplane-agent@v1.51.0/internal/service/service_windows_test.go (about)

     1  // Copyright  observIQ, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package service
    16  
    17  import (
    18  	"errors"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/observiq/bindplane-agent/internal/service/mocks"
    23  	"github.com/stretchr/testify/mock"
    24  	"github.com/stretchr/testify/require"
    25  	"go.uber.org/zap"
    26  	"golang.org/x/sys/windows/svc"
    27  )
    28  
    29  func TestWindowsServiceHandler(t *testing.T) {
    30  	t.Run("Normal start/stop", func(t *testing.T) {
    31  		rSvc := &mocks.MockRunnableService{}
    32  
    33  		rSvc.On("Start", mock.Anything).Return(nil)
    34  		rSvc.On("Error").Return((<-chan error)(make(chan error)))
    35  		rSvc.On("Stop", mock.Anything).Return(nil)
    36  
    37  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
    38  
    39  		changeChan := make(chan svc.ChangeRequest)
    40  		statusChan := make(chan svc.Status, 6)
    41  		svcHandlerDone := make(chan struct{})
    42  
    43  		var isSvcSpecificStatus bool
    44  		var statusCode uint32
    45  		go func() {
    46  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
    47  			close(svcHandlerDone)
    48  		}()
    49  
    50  		select {
    51  		case status := <-statusChan:
    52  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
    53  		case <-time.After(time.Second):
    54  			t.Fatalf("Timed out waiting for service status change to start pending")
    55  		}
    56  
    57  		select {
    58  		case status := <-statusChan:
    59  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
    60  		case <-time.After(time.Second):
    61  			t.Fatalf("Timed out waiting for service status change to running")
    62  		}
    63  
    64  		changeChan <- svc.ChangeRequest{
    65  			Cmd:           svc.Interrogate,
    66  			CurrentStatus: svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown},
    67  		}
    68  
    69  		select {
    70  		case status := <-statusChan:
    71  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
    72  		case <-time.After(time.Second):
    73  			t.Fatalf("Timed out waiting for interrogate response")
    74  		}
    75  
    76  		changeChan <- svc.ChangeRequest{
    77  			Cmd: svc.Stop,
    78  		}
    79  
    80  		select {
    81  		case status := <-statusChan:
    82  			require.Equal(t, svc.Status{State: svc.StopPending}, status)
    83  		case <-time.After(time.Second):
    84  			t.Fatalf("Timed out waiting for status change to stop pending")
    85  		}
    86  
    87  		select {
    88  		case status := <-statusChan:
    89  			require.Equal(t, svc.Status{State: svc.Stopped}, status)
    90  		case <-time.After(time.Second):
    91  			t.Fatalf("Timed out waiting for status change to stopped")
    92  		}
    93  
    94  		select {
    95  		case <-svcHandlerDone: // OK
    96  		case <-time.After(time.Second):
    97  			t.Fatalf("Timed out waiting for service handler to return")
    98  		}
    99  
   100  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   101  		require.Equal(t, uint32(0), statusCode, "status code was not 0")
   102  	})
   103  
   104  	t.Run("Start fails", func(t *testing.T) {
   105  		rSvc := &mocks.MockRunnableService{}
   106  
   107  		startError := errors.New("Failed to start service")
   108  
   109  		rSvc.On("Start", mock.Anything).Return(startError)
   110  		rSvc.On("Error").Return((<-chan error)(make(chan error)))
   111  		rSvc.On("Stop", mock.Anything).Return(nil)
   112  
   113  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   114  
   115  		changeChan := make(chan svc.ChangeRequest)
   116  		statusChan := make(chan svc.Status, 6)
   117  		svcHandlerDone := make(chan struct{})
   118  
   119  		var isSvcSpecificStatus bool
   120  		var statusCode uint32
   121  		go func() {
   122  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
   123  			close(svcHandlerDone)
   124  		}()
   125  
   126  		select {
   127  		case status := <-statusChan:
   128  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
   129  		case <-time.After(time.Second):
   130  			t.Fatalf("Timed out waiting for service status change to start pending")
   131  		}
   132  
   133  		select {
   134  		case <-svcHandlerDone: // OK
   135  		case <-time.After(time.Second):
   136  			t.Fatalf("Timed out waiting for service handler to return")
   137  		}
   138  
   139  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   140  		require.Equal(t, statusCodeServiceException, statusCode, "status code was not ServiceException")
   141  	})
   142  
   143  	t.Run("Unexpected service error", func(t *testing.T) {
   144  		rSvc := &mocks.MockRunnableService{}
   145  
   146  		svcErr := errors.New("service unexpectedly failed")
   147  		errChan := make(chan error, 1)
   148  		errChan <- svcErr
   149  
   150  		rSvc.On("Start", mock.Anything).Return(nil)
   151  		rSvc.On("Error").Return((<-chan error)(errChan))
   152  		rSvc.On("Stop", mock.Anything).Return(nil)
   153  
   154  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   155  
   156  		changeChan := make(chan svc.ChangeRequest)
   157  		statusChan := make(chan svc.Status, 6)
   158  		svcHandlerDone := make(chan struct{})
   159  
   160  		var isSvcSpecificStatus bool
   161  		var statusCode uint32
   162  		go func() {
   163  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
   164  			close(svcHandlerDone)
   165  		}()
   166  
   167  		select {
   168  		case status := <-statusChan:
   169  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
   170  		case <-time.After(time.Second):
   171  			t.Fatalf("Timed out waiting for service status change to start pending")
   172  		}
   173  
   174  		select {
   175  		case status := <-statusChan:
   176  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   177  		case <-time.After(time.Second):
   178  			t.Fatalf("Timed out waiting for service status change to running")
   179  		}
   180  
   181  		select {
   182  		case status := <-statusChan:
   183  			require.Equal(t, svc.Status{State: svc.StopPending}, status)
   184  		case <-time.After(time.Second):
   185  			t.Fatalf("Timed out waiting for status change to stop pending")
   186  		}
   187  
   188  		select {
   189  		case status := <-statusChan:
   190  			require.Equal(t, svc.Status{State: svc.Stopped}, status)
   191  		case <-time.After(time.Second):
   192  			t.Fatalf("Timed out waiting for status change to stopped")
   193  		}
   194  
   195  		select {
   196  		case <-svcHandlerDone: // OK
   197  		case <-time.After(time.Second):
   198  			t.Fatalf("Timed out waiting for service handler to return")
   199  		}
   200  
   201  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   202  		require.Equal(t, statusCodeServiceException, statusCode, "status code was not ServiceException")
   203  	})
   204  
   205  	t.Run("Shutdown error", func(t *testing.T) {
   206  		rSvc := &mocks.MockRunnableService{}
   207  		stopError := errors.New("Failed to start service")
   208  
   209  		rSvc.On("Start", mock.Anything).Return(nil)
   210  		rSvc.On("Error").Return((<-chan error)(make(chan error)))
   211  		rSvc.On("Stop", mock.Anything).Return(stopError)
   212  
   213  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   214  
   215  		changeChan := make(chan svc.ChangeRequest)
   216  		statusChan := make(chan svc.Status, 6)
   217  		svcHandlerDone := make(chan struct{})
   218  
   219  		var isSvcSpecificStatus bool
   220  		var statusCode uint32
   221  		go func() {
   222  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
   223  			close(svcHandlerDone)
   224  		}()
   225  
   226  		select {
   227  		case status := <-statusChan:
   228  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
   229  		case <-time.After(time.Second):
   230  			t.Fatalf("Timed out waiting for service status change to start pending")
   231  		}
   232  
   233  		select {
   234  		case status := <-statusChan:
   235  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   236  		case <-time.After(time.Second):
   237  			t.Fatalf("Timed out waiting for service status change to running")
   238  		}
   239  
   240  		changeChan <- svc.ChangeRequest{
   241  			Cmd:           svc.Interrogate,
   242  			CurrentStatus: svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown},
   243  		}
   244  
   245  		select {
   246  		case status := <-statusChan:
   247  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   248  		case <-time.After(time.Second):
   249  			t.Fatalf("Timed out waiting for interrogate response")
   250  		}
   251  
   252  		changeChan <- svc.ChangeRequest{
   253  			Cmd: svc.Stop,
   254  		}
   255  
   256  		select {
   257  		case status := <-statusChan:
   258  			require.Equal(t, svc.Status{State: svc.StopPending}, status)
   259  		case <-time.After(time.Second):
   260  			t.Fatalf("Timed out waiting for status change to stop pending")
   261  		}
   262  
   263  		select {
   264  		case status := <-statusChan:
   265  			require.Equal(t, svc.Status{State: svc.Stopped}, status)
   266  		case <-time.After(time.Second):
   267  			t.Fatalf("Timed out waiting for status change to stopped")
   268  		}
   269  
   270  		select {
   271  		case <-svcHandlerDone: // OK
   272  		case <-time.After(time.Second):
   273  			t.Fatalf("Timed out waiting for service handler to return")
   274  		}
   275  
   276  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   277  		require.Equal(t, statusCodeServiceException, statusCode, "status code was not ServiceException")
   278  	})
   279  
   280  	t.Run("Shutdown takes too long", func(t *testing.T) {
   281  		setWindowsServiceTimeout(t, 10*time.Millisecond)
   282  		rSvc := &mocks.MockRunnableService{}
   283  
   284  		blockStopChan := make(chan struct{}, 1)
   285  		t.Cleanup(func() {
   286  			blockStopChan <- struct{}{}
   287  		})
   288  
   289  		rSvc.On("Start", mock.Anything).Return(nil)
   290  		rSvc.On("Error").Return((<-chan error)(make(chan error)))
   291  		rSvc.On("Stop", mock.Anything).Run(func(args mock.Arguments) { <-blockStopChan }).Return(nil)
   292  
   293  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   294  
   295  		changeChan := make(chan svc.ChangeRequest)
   296  		statusChan := make(chan svc.Status, 6)
   297  		svcHandlerDone := make(chan struct{})
   298  
   299  		var isSvcSpecificStatus bool
   300  		var statusCode uint32
   301  		go func() {
   302  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
   303  			close(svcHandlerDone)
   304  		}()
   305  
   306  		select {
   307  		case status := <-statusChan:
   308  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
   309  		case <-time.After(time.Second):
   310  			t.Fatalf("Timed out waiting for service status change to start pending")
   311  		}
   312  
   313  		select {
   314  		case status := <-statusChan:
   315  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   316  		case <-time.After(time.Second):
   317  			t.Fatalf("Timed out waiting for service status change to running")
   318  		}
   319  
   320  		changeChan <- svc.ChangeRequest{
   321  			Cmd:           svc.Interrogate,
   322  			CurrentStatus: svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown},
   323  		}
   324  
   325  		select {
   326  		case status := <-statusChan:
   327  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   328  		case <-time.After(time.Second):
   329  			t.Fatalf("Timed out waiting for interrogate response")
   330  		}
   331  
   332  		changeChan <- svc.ChangeRequest{
   333  			Cmd: svc.Stop,
   334  		}
   335  
   336  		select {
   337  		case status := <-statusChan:
   338  			require.Equal(t, svc.Status{State: svc.StopPending}, status)
   339  		case <-time.After(time.Second):
   340  			t.Fatalf("Timed out waiting for status change to stop pending")
   341  		}
   342  
   343  		select {
   344  		case status := <-statusChan:
   345  			require.Equal(t, svc.Status{State: svc.Stopped}, status)
   346  		case <-time.After(time.Second):
   347  			t.Fatalf("Timed out waiting for status change to stopped")
   348  		}
   349  
   350  		select {
   351  		case <-svcHandlerDone: // OK
   352  		case <-time.After(time.Second):
   353  			t.Fatalf("Timed out waiting for service handler to return")
   354  		}
   355  
   356  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   357  		require.Equal(t, statusCodeServiceException, statusCode, "status code was not ServiceException")
   358  	})
   359  
   360  	t.Run("Shutdown error after unexpected error", func(t *testing.T) {
   361  		rSvc := &mocks.MockRunnableService{}
   362  		stopError := errors.New("Failed to start service")
   363  		svcErr := errors.New("service unexpectedly failed")
   364  		errChan := make(chan error, 1)
   365  		errChan <- svcErr
   366  
   367  		rSvc.On("Start", mock.Anything).Return(nil)
   368  		rSvc.On("Error").Return((<-chan error)(errChan))
   369  		rSvc.On("Stop", mock.Anything).Return(stopError)
   370  
   371  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   372  
   373  		changeChan := make(chan svc.ChangeRequest)
   374  		statusChan := make(chan svc.Status, 6)
   375  		svcHandlerDone := make(chan struct{})
   376  
   377  		var isSvcSpecificStatus bool
   378  		var statusCode uint32
   379  		go func() {
   380  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
   381  			close(svcHandlerDone)
   382  		}()
   383  
   384  		select {
   385  		case status := <-statusChan:
   386  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
   387  		case <-time.After(time.Second):
   388  			t.Fatalf("Timed out waiting for service status change to start pending")
   389  		}
   390  
   391  		select {
   392  		case status := <-statusChan:
   393  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   394  		case <-time.After(time.Second):
   395  			t.Fatalf("Timed out waiting for service status change to running")
   396  		}
   397  
   398  		select {
   399  		case status := <-statusChan:
   400  			require.Equal(t, svc.Status{State: svc.StopPending}, status)
   401  		case <-time.After(time.Second):
   402  			t.Fatalf("Timed out waiting for status change to stop pending")
   403  		}
   404  
   405  		select {
   406  		case status := <-statusChan:
   407  			require.Equal(t, svc.Status{State: svc.Stopped}, status)
   408  		case <-time.After(time.Second):
   409  			t.Fatalf("Timed out waiting for status change to stopped")
   410  		}
   411  
   412  		select {
   413  		case <-svcHandlerDone: // OK
   414  		case <-time.After(time.Second):
   415  			t.Fatalf("Timed out waiting for service handler to return")
   416  		}
   417  
   418  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   419  		require.Equal(t, statusCodeServiceException, statusCode, "status code was not ServiceException")
   420  	})
   421  
   422  	t.Run("Unhandled command", func(t *testing.T) {
   423  		rSvc := &mocks.MockRunnableService{}
   424  
   425  		rSvc.On("Start", mock.Anything).Return(nil)
   426  		rSvc.On("Error").Return((<-chan error)(make(chan error)))
   427  		rSvc.On("Stop", mock.Anything).Return(nil)
   428  
   429  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   430  
   431  		changeChan := make(chan svc.ChangeRequest)
   432  		statusChan := make(chan svc.Status, 6)
   433  		svcHandlerDone := make(chan struct{})
   434  
   435  		var isSvcSpecificStatus bool
   436  		var statusCode uint32
   437  		go func() {
   438  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
   439  			close(svcHandlerDone)
   440  		}()
   441  
   442  		select {
   443  		case status := <-statusChan:
   444  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
   445  		case <-time.After(time.Second):
   446  			t.Fatalf("Timed out waiting for service status change to start pending")
   447  		}
   448  
   449  		select {
   450  		case status := <-statusChan:
   451  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   452  		case <-time.After(time.Second):
   453  			t.Fatalf("Timed out waiting for service status change to running")
   454  		}
   455  
   456  		changeChan <- svc.ChangeRequest{
   457  			Cmd:           svc.Interrogate,
   458  			CurrentStatus: svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown},
   459  		}
   460  
   461  		select {
   462  		case status := <-statusChan:
   463  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   464  		case <-time.After(time.Second):
   465  			t.Fatalf("Timed out waiting for interrogate response")
   466  		}
   467  
   468  		changeChan <- svc.ChangeRequest{
   469  			Cmd: svc.DeviceEvent,
   470  		}
   471  
   472  		select {
   473  		case status := <-statusChan:
   474  			require.Equal(t, svc.Status{State: svc.StopPending}, status)
   475  		case <-time.After(time.Second):
   476  			t.Fatalf("Timed out waiting for status change to stop pending")
   477  		}
   478  
   479  		select {
   480  		case status := <-statusChan:
   481  			require.Equal(t, svc.Status{State: svc.Stopped}, status)
   482  		case <-time.After(time.Second):
   483  			t.Fatalf("Timed out waiting for status change to stopped")
   484  		}
   485  
   486  		select {
   487  		case <-svcHandlerDone: // OK
   488  		case <-time.After(time.Second):
   489  			t.Fatalf("Timed out waiting for service handler to return")
   490  		}
   491  
   492  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   493  		require.Equal(t, uint32(statusCodeInvalidServiceCommand), statusCode, "status code was not InvalidServiceCommand")
   494  	})
   495  
   496  	t.Run("Unhandled command with shutdown error", func(t *testing.T) {
   497  		rSvc := &mocks.MockRunnableService{}
   498  
   499  		stopError := errors.New("Failed to start service")
   500  		rSvc.On("Start", mock.Anything).Return(nil)
   501  		rSvc.On("Error").Return((<-chan error)(make(chan error)))
   502  		rSvc.On("Stop", mock.Anything).Return(stopError)
   503  
   504  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   505  
   506  		changeChan := make(chan svc.ChangeRequest)
   507  		statusChan := make(chan svc.Status, 6)
   508  		svcHandlerDone := make(chan struct{})
   509  
   510  		var isSvcSpecificStatus bool
   511  		var statusCode uint32
   512  		go func() {
   513  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{"service-name"}, changeChan, statusChan)
   514  			close(svcHandlerDone)
   515  		}()
   516  
   517  		select {
   518  		case status := <-statusChan:
   519  			require.Equal(t, svc.Status{State: svc.StartPending}, status)
   520  		case <-time.After(time.Second):
   521  			t.Fatalf("Timed out waiting for service status change to start pending")
   522  		}
   523  
   524  		select {
   525  		case status := <-statusChan:
   526  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   527  		case <-time.After(time.Second):
   528  			t.Fatalf("Timed out waiting for service status change to running")
   529  		}
   530  
   531  		changeChan <- svc.ChangeRequest{
   532  			Cmd:           svc.Interrogate,
   533  			CurrentStatus: svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown},
   534  		}
   535  
   536  		select {
   537  		case status := <-statusChan:
   538  			require.Equal(t, svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}, status)
   539  		case <-time.After(time.Second):
   540  			t.Fatalf("Timed out waiting for interrogate response")
   541  		}
   542  
   543  		changeChan <- svc.ChangeRequest{
   544  			Cmd: svc.DeviceEvent,
   545  		}
   546  
   547  		select {
   548  		case status := <-statusChan:
   549  			require.Equal(t, svc.Status{State: svc.StopPending}, status)
   550  		case <-time.After(time.Second):
   551  			t.Fatalf("Timed out waiting for status change to stop pending")
   552  		}
   553  
   554  		select {
   555  		case status := <-statusChan:
   556  			require.Equal(t, svc.Status{State: svc.Stopped}, status)
   557  		case <-time.After(time.Second):
   558  			t.Fatalf("Timed out waiting for status change to stopped")
   559  		}
   560  
   561  		select {
   562  		case <-svcHandlerDone: // OK
   563  		case <-time.After(time.Second):
   564  			t.Fatalf("Timed out waiting for service handler to return")
   565  		}
   566  
   567  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   568  		require.Equal(t, uint32(statusCodeServiceException), statusCode, "status code was not ServiceException")
   569  	})
   570  
   571  	t.Run("No service name", func(t *testing.T) {
   572  		rSvc := &mocks.MockRunnableService{}
   573  
   574  		svcHandler := newWindowsServiceHandler(zap.NewNop(), rSvc)
   575  
   576  		changeChan := make(chan svc.ChangeRequest)
   577  		statusChan := make(chan svc.Status, 6)
   578  		svcHandlerDone := make(chan struct{})
   579  
   580  		var isSvcSpecificStatus bool
   581  		var statusCode uint32
   582  		go func() {
   583  			isSvcSpecificStatus, statusCode = svcHandler.Execute([]string{}, changeChan, statusChan)
   584  			close(svcHandlerDone)
   585  		}()
   586  
   587  		select {
   588  		case <-svcHandlerDone: // OK
   589  		case <-time.After(time.Second):
   590  			t.Fatalf("Timed out waiting for service handler to return")
   591  		}
   592  
   593  		require.Equal(t, false, isSvcSpecificStatus, "status code marked as service specific")
   594  		require.Equal(t, uint32(statusCodeInvalidServiceName), statusCode, "status code was not InvalidServiceName")
   595  	})
   596  }
   597  
   598  func setWindowsServiceTimeout(t *testing.T, d time.Duration) {
   599  	old := windowsServiceShutdownTimeout
   600  	windowsServiceShutdownTimeout = d
   601  	t.Cleanup(func() {
   602  		windowsServiceShutdownTimeout = old
   603  	})
   604  }