github.com/observiq/bindplane-agent@v1.51.0/internal/service/service_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  	"context"
    19  	"errors"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/observiq/bindplane-agent/internal/service/mocks"
    24  	"github.com/stretchr/testify/mock"
    25  	"github.com/stretchr/testify/require"
    26  	"go.uber.org/zap"
    27  )
    28  
    29  func TestRunServiceInteractive(t *testing.T) {
    30  	t.Run("Normal start/stop", func(t *testing.T) {
    31  		svc := &mocks.MockRunnableService{}
    32  
    33  		ctx, cancel := context.WithCancel(context.Background())
    34  
    35  		svc.On("Start", mock.Anything).Return(nil)
    36  		svc.On("Error").Return((<-chan error)(make(chan error)))
    37  		svc.On("Stop", mock.Anything).Return(nil)
    38  
    39  		var err error
    40  		svcDone := make(chan struct{})
    41  		go func() {
    42  			err = runServiceInteractive(ctx, zap.NewNop(), svc)
    43  			close(svcDone)
    44  		}()
    45  
    46  		<-time.After(500 * time.Millisecond)
    47  		cancel()
    48  
    49  		select {
    50  		case <-svcDone: // OK
    51  		case <-time.After(1 * time.Second):
    52  			t.Fatalf("Timed out waiting for service done")
    53  		}
    54  
    55  		require.NoError(t, err)
    56  	})
    57  
    58  	t.Run("Start fails", func(t *testing.T) {
    59  		svc := &mocks.MockRunnableService{}
    60  
    61  		startErr := errors.New("failed to start")
    62  
    63  		svc.On("Start", mock.Anything).Return(startErr)
    64  
    65  		ctx, cancel := context.WithCancel(context.Background())
    66  		defer cancel()
    67  
    68  		var err error
    69  		svcDone := make(chan struct{})
    70  		go func() {
    71  			err = runServiceInteractive(ctx, zap.NewNop(), svc)
    72  			close(svcDone)
    73  		}()
    74  
    75  		select {
    76  		case <-svcDone: // OK
    77  		case <-time.After(1 * time.Second):
    78  			t.Fatalf("Timed out waiting for service done")
    79  		}
    80  
    81  		require.Error(t, err)
    82  		require.ErrorIs(t, err, startErr)
    83  	})
    84  
    85  	t.Run("Service errors", func(t *testing.T) {
    86  		svc := &mocks.MockRunnableService{}
    87  
    88  		svcErr := errors.New("service unexpectedly failed")
    89  		errChan := make(chan error, 1)
    90  		errChan <- svcErr
    91  
    92  		svc.On("Start", mock.Anything).Return(nil)
    93  		svc.On("Error").Return((<-chan error)(errChan))
    94  		svc.On("Stop", mock.Anything).Return(nil)
    95  
    96  		ctx, cancel := context.WithCancel(context.Background())
    97  		defer cancel()
    98  
    99  		var err error
   100  		svcDone := make(chan struct{})
   101  		go func() {
   102  			err = runServiceInteractive(ctx, zap.NewNop(), svc)
   103  			close(svcDone)
   104  		}()
   105  
   106  		select {
   107  		case <-svcDone: // OK
   108  		case <-time.After(1 * time.Second):
   109  			t.Fatalf("Timed out waiting for service done")
   110  		}
   111  
   112  		require.Error(t, err)
   113  		require.ErrorIs(t, err, svcErr)
   114  	})
   115  
   116  	t.Run("Stop errors", func(t *testing.T) {
   117  		svc := &mocks.MockRunnableService{}
   118  
   119  		stopErr := errors.New("Stop failed")
   120  
   121  		svc.On("Start", mock.Anything).Return(nil)
   122  		svc.On("Error").Return((<-chan error)(make(chan error)))
   123  		svc.On("Stop", mock.Anything).Return(stopErr)
   124  
   125  		ctx, cancel := context.WithCancel(context.Background())
   126  
   127  		var err error
   128  		svcDone := make(chan struct{})
   129  		go func() {
   130  			err = runServiceInteractive(ctx, zap.NewNop(), svc)
   131  			close(svcDone)
   132  		}()
   133  
   134  		<-time.After(500 * time.Millisecond)
   135  		cancel()
   136  
   137  		select {
   138  		case <-svcDone: // OK
   139  		case <-time.After(1 * time.Second):
   140  			t.Fatalf("Timed out waiting for service done")
   141  		}
   142  
   143  		require.Error(t, err)
   144  		require.ErrorIs(t, err, stopErr)
   145  	})
   146  
   147  	t.Run("Stop errors after error returned", func(t *testing.T) {
   148  		svc := &mocks.MockRunnableService{}
   149  
   150  		stopErr := errors.New("Stop failed")
   151  		svcErr := errors.New("service unexpectedly failed")
   152  		errChan := make(chan error, 1)
   153  		errChan <- svcErr
   154  
   155  		svc.On("Start", mock.Anything).Return(nil)
   156  		svc.On("Error").Return((<-chan error)(errChan))
   157  		svc.On("Stop", mock.Anything).Return(stopErr)
   158  
   159  		ctx, cancel := context.WithCancel(context.Background())
   160  		defer cancel()
   161  
   162  		var err error
   163  		svcDone := make(chan struct{})
   164  		go func() {
   165  			err = runServiceInteractive(ctx, zap.NewNop(), svc)
   166  			close(svcDone)
   167  		}()
   168  
   169  		select {
   170  		case <-svcDone: // OK
   171  		case <-time.After(1 * time.Second):
   172  			t.Fatalf("Timed out waiting for service done")
   173  		}
   174  
   175  		require.Error(t, err)
   176  		require.ErrorIs(t, err, stopErr)
   177  	})
   178  }