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 }