github.com/yandex/pandora@v0.5.32/core/engine/instance_test.go (about)

     1  package engine
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/mock"
    11  	"github.com/stretchr/testify/require"
    12  	"github.com/yandex/pandora/core"
    13  	coremock "github.com/yandex/pandora/core/mocks"
    14  	"github.com/yandex/pandora/core/schedule"
    15  )
    16  
    17  func Test_Instance(t *testing.T) {
    18  	var (
    19  		provider       *coremock.Provider
    20  		aggregator     *coremock.Aggregator
    21  		sched          core.Schedule
    22  		newScheduleErr error
    23  		gun            *coremock.Gun
    24  		newGunErr      error
    25  		ctx            context.Context
    26  		metrics        Metrics
    27  
    28  		ins          *instance
    29  		insCreateErr error
    30  
    31  		newSchedule func() (core.Schedule, error)
    32  		newGun      func() (core.Gun, error)
    33  	)
    34  
    35  	var beforeEach = func(metricPrefix string) {
    36  		provider = &coremock.Provider{}
    37  		aggregator = &coremock.Aggregator{}
    38  		gun = &coremock.Gun{}
    39  		newGunErr = nil
    40  		sched = &coremock.Schedule{}
    41  		newScheduleErr = nil
    42  		ctx = context.Background()
    43  		metrics = NewMetrics(metricPrefix)
    44  		newSchedule = func() (core.Schedule, error) { return sched, newScheduleErr }
    45  		newGun = func() (core.Gun, error) { return gun, newGunErr }
    46  	}
    47  
    48  	var justBeforeEach = func() {
    49  		deps := instanceDeps{
    50  			newSchedule: newSchedule,
    51  			newGun:      newGun,
    52  			instanceSharedDeps: instanceSharedDeps{
    53  				provider:        provider,
    54  				metrics:         metrics,
    55  				aggregator:      aggregator,
    56  				discardOverflow: false,
    57  			},
    58  		}
    59  		ins, insCreateErr = newInstance(ctx, newNopLogger(), "pool_0", 0, deps)
    60  	}
    61  
    62  	var afterEach = func() {
    63  		if newGunErr == nil && newScheduleErr == nil {
    64  			assert.Equal(t, int64(1), metrics.InstanceStart.Get())
    65  			assert.Equal(t, int64(1), metrics.InstanceFinish.Get())
    66  		}
    67  	}
    68  
    69  	t.Run("all ok", func(t *testing.T) {
    70  		var beforeEachCtx = func() {
    71  			const times = 5
    72  			sched = schedule.NewOnce(times)
    73  			gun.On("Bind", aggregator, mock.Anything).Return(nil).Once()
    74  			var acquired int
    75  			provider.On("Acquire").Return(func() (core.Ammo, bool) {
    76  				acquired++
    77  				return acquired, true
    78  			}).Times(times)
    79  			for i := 1; i <= times; i++ {
    80  				gun.On("Shoot", i).Once()
    81  				provider.On("Release", i).Once()
    82  			}
    83  		}
    84  		var justBeforeEachCtx = func() {
    85  			require.NoError(t, insCreateErr)
    86  		}
    87  		t.Run("start ok", func(t *testing.T) {
    88  			beforeEach("start-ok")
    89  			beforeEachCtx()
    90  			justBeforeEachCtx()
    91  			justBeforeEach()
    92  
    93  			err := ins.Run(ctx)
    94  			require.NoError(t, err)
    95  			gun.AssertExpectations(t)
    96  			provider.AssertExpectations(t)
    97  
    98  			afterEach()
    99  		})
   100  
   101  		t.Run("gun implements io.Closer / close called on instance close", func(t *testing.T) {
   102  			beforeEach("gun-implements-io")
   103  			beforeEachCtx()
   104  			closeGun := mockGunCloser{gun}
   105  			closeGun.On("Close").Return(nil)
   106  			newGun = func() (core.Gun, error) {
   107  				return closeGun, nil
   108  			}
   109  			justBeforeEachCtx()
   110  			justBeforeEach()
   111  
   112  			err := ins.Run(ctx)
   113  			require.NoError(t, err)
   114  			closeGun.AssertNotCalled(t, "Close")
   115  			err = ins.Close()
   116  			require.NoError(t, err)
   117  			closeGun.AssertExpectations(t)
   118  			provider.AssertExpectations(t)
   119  
   120  			afterEach()
   121  		})
   122  	})
   123  
   124  	t.Run("context canceled after run / start fail", func(t *testing.T) {
   125  		beforeEach("context-canceled-after-run")
   126  
   127  		var cancel context.CancelFunc
   128  		ctx, cancel = context.WithTimeout(context.Background(), 10*time.Millisecond)
   129  		_ = cancel
   130  		sched := sched.(*coremock.Schedule)
   131  		sched.On("Next").Return(time.Now().Add(5*time.Second), true)
   132  		sched.On("Left").Return(1)
   133  		gun.On("Bind", aggregator, mock.Anything).Return(nil)
   134  		provider.On("Acquire").Return(struct{}{}, true)
   135  		provider.On("Release", mock.Anything).Return()
   136  
   137  		justBeforeEach()
   138  
   139  		err := ins.Run(ctx)
   140  		assert.Error(t, err)
   141  		assert.Equal(t, context.DeadlineExceeded, err)
   142  		gun.AssertExpectations(t)
   143  		provider.AssertExpectations(t)
   144  
   145  		afterEach()
   146  	})
   147  
   148  	t.Run("context canceled before run / nothing acquired and schedule not started", func(t *testing.T) {
   149  		beforeEach("context-canceled-before-run")
   150  		var cancel context.CancelFunc
   151  		ctx, cancel = context.WithCancel(ctx)
   152  		cancel()
   153  		gun.On("Bind", aggregator, mock.Anything).Return(nil)
   154  		justBeforeEach()
   155  
   156  		err := ins.Run(ctx)
   157  		require.Equal(t, context.Canceled, err)
   158  		gun.AssertExpectations(t)
   159  		provider.AssertExpectations(t)
   160  
   161  		afterEach()
   162  	})
   163  
   164  	t.Run("schedule create failed / instance create failed", func(t *testing.T) {
   165  		beforeEach("schedule-create-failed")
   166  		sched = nil
   167  		newScheduleErr = errors.New("test err")
   168  		justBeforeEach()
   169  
   170  		require.Equal(t, newScheduleErr, insCreateErr)
   171  
   172  		afterEach()
   173  	})
   174  
   175  	t.Run("gun create failed / instance create failed", func(t *testing.T) {
   176  		beforeEach("gun-create-failed")
   177  		gun = nil
   178  		newGunErr = errors.New("test err")
   179  		justBeforeEach()
   180  
   181  		require.Equal(t, newGunErr, insCreateErr)
   182  		afterEach()
   183  	})
   184  }
   185  
   186  type mockGunCloser struct {
   187  	*coremock.Gun
   188  }
   189  
   190  func (_m mockGunCloser) Close() error {
   191  	ret := _m.Called()
   192  
   193  	var r0 error
   194  	if rf, ok := ret.Get(0).(func() error); ok {
   195  		r0 = rf()
   196  	} else {
   197  		r0 = ret.Error(0)
   198  	}
   199  	return r0
   200  }