// // Copyright 2019 AT&T Intellectual Property // Copyright 2019 Nokia // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package common import ( "github.com/stretchr/testify/assert" "sync" "sync/atomic" "testing" "time" ) var max int32 var counter int32 var poolGlob *Pool type instance struct{} func(instance) up(){ tmpc := atomic.AddInt32(&counter, 1) swapped:= false for !swapped { tmpm := atomic.LoadInt32(&max) if tmpc >tmpm { swapped = atomic.CompareAndSwapInt32(&max, tmpm, tmpc) } else { break } } } func(instance) down(){ atomic.AddInt32(&counter, - 1) } func TestPoolMax(t *testing.T){ counter = 0 max = 0 validateMaxLimit(1, 1, t) counter = 0 max = 0 validateMaxLimit(1, 2, t) counter = 0 max = 0 validateMaxLimit(5, 10, t) } func validateMaxLimit(size int, iterations int, t *testing.T) { poolGlob = NewPool(size, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) group := sync.WaitGroup{} for i := 0; i < iterations; i++ { group.Add(1) go func() { getPutInstance() group.Done() }() } time.Sleep(time.Second) group.Wait() assert.Equal(t, int32(size), max) } func getPutInstance() { inst := poolGlob.Get().(instance) inst.up() time.Sleep(time.Millisecond*10) inst.down() poolGlob.Put(inst) } func TestNewPool(t *testing.T){ size := 5 pool := NewPool(size, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) assert.NotNil(t, pool) assert.NotNil(t, pool.New) assert.NotNil(t, pool.Destroy) assert.NotNil(t, pool.pool) assert.Equal(t, cap(pool.pool), size, "the capacity of the pool should be " + string(size)) } func TestGetCreated(t *testing.T) { pool := NewPool(1, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) pool.Get() available, created := pool.Stats() assert.Equal(t, 0, available, "number of available objects in the pool should be 0") assert.Equal(t, 1, created, "number of created objects in the pool should be 1") pool.Close() } func TestGetAndPut(t *testing.T) { pool := NewPool(1, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) pool.Put(pool.Get()) available, created := pool.Stats() assert.Equal(t, 1, available, "number of available objects in the pool should be 1") assert.Equal(t, 1, created, "number of created objects in the pool should be 1") pool.Close() } func TestPutOutOfCapacity(t *testing.T) { pool := NewPool(1, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) pool.Put(pool.Get()) pool.Put(new(instance)) available, created := pool.Stats() assert.Equal(t, 1, available, "number of available objects in the pool should be 1") assert.Equal(t, 1, created, "number of created objects in the pool should be 1") pool.Close() } func TestNotInitializedPut(t *testing.T) { var poolEmpty Pool poolEmpty.Put(new(instance)) available, created := poolEmpty.Stats() assert.Equal(t, 0, available, "number of available objects in the pool should be 0") assert.Equal(t, 0, created, "number of created objects in the pool should be 0") } func TestPutNilObject(t *testing.T) { var poolEmpty Pool poolEmpty.Put(nil) available, created := poolEmpty.Stats() assert.Equal(t, 0, available, "number of available objects in the pool should be 0") assert.Equal(t, 0, created, "number of created objects in the pool should be 0") } func TestGet(t *testing.T) { pool := NewPool(2, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) i1 := pool.Get() i2 := pool.Get() available, created := pool.Stats() assert.Equal(t, 0, available, "number of available objects in the pool should be 0") assert.Equal(t, 2, created, "number of created objects in the pool should be 2") pool.Put(i1) pool.Put(i2) pool.Put(new(instance)) available, created = pool.Stats() assert.Equal(t, 2, available, "number of available objects in the pool should be 2") assert.Equal(t, 2, created, "number of created objects in the pool should be 2") } func TestClose(t *testing.T) { pool := NewPool(3, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) i1 := pool.Get() i2 := pool.Get() i3 := pool.Get() available, created := pool.Stats() assert.Equal(t, 0, available, "number of available objects in the pool should be 0") assert.Equal(t, 3, created, "number of created objects in the pool should be 3") pool.Put(i1) pool.Put(i2) pool.Put(i3) available, created = pool.Stats() assert.Equal(t, 3, available, "number of available objects in the pool should be 3") assert.Equal(t, 3, created, "number of created objects in the pool should be 3") pool.Close() i := pool.Get() assert.Nil(t, i) available, created = pool.Stats() assert.Equal(t, 0, available, "number of available objects in the pool should be 0") assert.Equal(t, 0, created, "number of created objects in the pool should be 0") } func TestPoolPutPanicsOnClosedChannel(t *testing.T){ pool := NewPool(1, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) close(pool.pool) assert.Panics(t, func(){pool.Put(instance{})}) } func TestPoolClosePanicsOnClosedChannel(t *testing.T) { pool := NewPool(1, func() interface{} { inst := instance{} return inst }, func(obj interface{}) { }, ) close(pool.pool) assert.Panics(t, func(){pool.Close()}) }