github.com/xmidt-org/webpa-common@v1.11.9/store/circularPool_test.go (about)

     1  package store
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/stretchr/testify/assert"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  const (
    12  	poolSize    = 3
    13  	workerCount = 5
    14  	resource    = "I am a pooled resource!"
    15  	timeout     = time.Duration(10 * time.Millisecond)
    16  )
    17  
    18  func resourceFunc() interface{} {
    19  	return resource
    20  }
    21  
    22  func ExampleResourcePool() {
    23  	pool, err := NewCircularPool(poolSize, poolSize, resourceFunc)
    24  	if err != nil {
    25  		fmt.Println(err)
    26  		return
    27  	}
    28  
    29  	waitGroup := &sync.WaitGroup{}
    30  	waitGroup.Add(workerCount)
    31  
    32  	for repeat := 0; repeat < workerCount; repeat++ {
    33  		go func() {
    34  			defer waitGroup.Done()
    35  
    36  			// check out a resource
    37  			sharedResource := pool.Get().(string)
    38  
    39  			// use it
    40  			fmt.Println(sharedResource)
    41  
    42  			// return it to the pool
    43  			pool.Put(sharedResource)
    44  		}()
    45  	}
    46  
    47  	waitGroup.Wait()
    48  
    49  	// Output:
    50  	// I am a pooled resource!
    51  	// I am a pooled resource!
    52  	// I am a pooled resource!
    53  	// I am a pooled resource!
    54  	// I am a pooled resource!
    55  }
    56  
    57  func TestNewCircularPoolInvalidInitialSize(t *testing.T) {
    58  	assert := assert.New(t)
    59  
    60  	pool, err := NewCircularPool(10, 5, resourceFunc)
    61  	assert.Nil(pool)
    62  	assert.Equal(ErrorInvalidInitialSize, err)
    63  }
    64  
    65  func TestNewCircularPoolInvalidMaxSize(t *testing.T) {
    66  	assert := assert.New(t)
    67  
    68  	pool, err := NewCircularPool(0, 0, resourceFunc)
    69  	assert.Nil(pool)
    70  	assert.Equal(ErrorInvalidMaxSize, err)
    71  
    72  	pool, err = NewCircularPool(0, -1, resourceFunc)
    73  	assert.Nil(pool)
    74  	assert.Equal(ErrorInvalidMaxSize, err)
    75  }
    76  
    77  func TestNewCircularPoolNilNew(t *testing.T) {
    78  	assert := assert.New(t)
    79  
    80  	pool, err := NewCircularPool(poolSize, poolSize, nil)
    81  	assert.Nil(pool)
    82  	assert.Equal(ErrorNewRequired, err)
    83  }
    84  
    85  func TestCircularPoolInitiallyEmpty(t *testing.T) {
    86  	assert := assert.New(t)
    87  	pool, err := NewCircularPool(0, poolSize, resourceFunc)
    88  	assert.NotNil(pool)
    89  	assert.Nil(err)
    90  
    91  	// The pool is empty, so we should get nothing
    92  	value, ok := pool.TryGet()
    93  	assert.Nil(value)
    94  	assert.False(ok)
    95  
    96  	value, ok = pool.GetTimeout(timeout)
    97  	assert.Nil(value)
    98  	assert.False(ok)
    99  
   100  	// GetOrNew should return a new resource
   101  	value = pool.GetOrNew()
   102  	assert.Equal(resource, value)
   103  
   104  	// TryGet and GetTimeout should still get nothing
   105  	value, ok = pool.TryGet()
   106  	assert.Nil(value)
   107  	assert.False(ok)
   108  
   109  	value, ok = pool.GetTimeout(timeout)
   110  	assert.Nil(value)
   111  	assert.False(ok)
   112  
   113  	waitGroup := &sync.WaitGroup{}
   114  	waitGroup.Add(1)
   115  	go func() {
   116  		defer waitGroup.Done()
   117  		value := pool.Get().(string)
   118  		assert.Equal(resource, value)
   119  		pool.Put(value)
   120  	}()
   121  
   122  	pool.Put(resource)
   123  	waitGroup.Wait()
   124  
   125  	// There should now be a resource on the pool
   126  	value, ok = pool.TryGet()
   127  	assert.Equal(resource, value)
   128  	assert.True(ok)
   129  
   130  	pool.Put(value)
   131  	value, ok = pool.GetTimeout(timeout)
   132  	assert.Equal(resource, value)
   133  	assert.True(ok)
   134  
   135  	// GetTimeout should fallback to TryGet for nonpositive timeouts
   136  	value, ok = pool.GetTimeout(0)
   137  	assert.Nil(value)
   138  	assert.False(ok)
   139  
   140  	value, ok = pool.GetTimeout(-1)
   141  	assert.Nil(value)
   142  	assert.False(ok)
   143  }
   144  
   145  func TestCircularPoolGetPreallocated(t *testing.T) {
   146  	assert := assert.New(t)
   147  	pool, err := NewCircularPool(poolSize, poolSize, resourceFunc)
   148  	assert.NotNil(pool)
   149  	assert.Nil(err)
   150  
   151  	// Put on a full pool should not alter its size
   152  	pool.Put(resource)
   153  
   154  	// Get should succeed poolSize times
   155  	for repeat := 0; repeat < poolSize; repeat++ {
   156  		value := pool.Get()
   157  		assert.Equal(resource, value)
   158  	}
   159  
   160  	// the pool should be empty
   161  	value, ok := pool.TryGet()
   162  	assert.Nil(value)
   163  	assert.False(ok)
   164  
   165  	value, ok = pool.GetTimeout(timeout)
   166  	assert.Nil(value)
   167  	assert.False(ok)
   168  }
   169  
   170  func TestCircularPoolTryGetPreallocated(t *testing.T) {
   171  	assert := assert.New(t)
   172  	pool, err := NewCircularPool(poolSize, poolSize, resourceFunc)
   173  	assert.NotNil(pool)
   174  	assert.Nil(err)
   175  
   176  	// Put on a full pool should not alter its size
   177  	pool.Put(resource)
   178  
   179  	// TryGet should succeed poolSize times
   180  	for repeat := 0; repeat < poolSize; repeat++ {
   181  		value, ok := pool.TryGet()
   182  		assert.Equal(resource, value)
   183  		assert.True(ok)
   184  	}
   185  
   186  	// the pool should be empty
   187  	value, ok := pool.TryGet()
   188  	assert.Nil(value)
   189  	assert.False(ok)
   190  
   191  	value, ok = pool.GetTimeout(timeout)
   192  	assert.Nil(value)
   193  	assert.False(ok)
   194  }
   195  
   196  func TestCircularPoolTryGetTimeoutPreallocated(t *testing.T) {
   197  	assert := assert.New(t)
   198  	pool, err := NewCircularPool(poolSize, poolSize, resourceFunc)
   199  	assert.NotNil(pool)
   200  	assert.Nil(err)
   201  
   202  	// Put on a full pool should not alter its size
   203  	pool.Put(resource)
   204  
   205  	// GetTimeout should succeed poolSize times
   206  	for repeat := 0; repeat < poolSize; repeat++ {
   207  		value, ok := pool.GetTimeout(timeout)
   208  		assert.Equal(resource, value)
   209  		assert.True(ok)
   210  	}
   211  
   212  	// the pool should be empty
   213  	value, ok := pool.TryGet()
   214  	assert.Nil(value)
   215  	assert.False(ok)
   216  
   217  	value, ok = pool.GetTimeout(timeout)
   218  	assert.Nil(value)
   219  	assert.False(ok)
   220  }
   221  
   222  func TestCircularPoolTryGetOrNewPreallocated(t *testing.T) {
   223  	assert := assert.New(t)
   224  	pool, err := NewCircularPool(poolSize, poolSize, resourceFunc)
   225  	assert.NotNil(pool)
   226  	assert.Nil(err)
   227  
   228  	// Put on a full pool should not alter its size
   229  	pool.Put(resource)
   230  
   231  	// GetOrNew should drain the pool poolSize times
   232  	for repeat := 0; repeat < poolSize; repeat++ {
   233  		value := pool.GetOrNew()
   234  		assert.Equal(resource, value)
   235  	}
   236  
   237  	// the pool should be empty
   238  	value, ok := pool.TryGet()
   239  	assert.Nil(value)
   240  	assert.False(ok)
   241  
   242  	value, ok = pool.GetTimeout(timeout)
   243  	assert.Nil(value)
   244  	assert.False(ok)
   245  
   246  	// GetOrNew should return a new object, but the pool should be empty afterward
   247  	value = pool.GetOrNew()
   248  	assert.Equal(resource, value)
   249  
   250  	value, ok = pool.TryGet()
   251  	assert.Nil(value)
   252  	assert.False(ok)
   253  
   254  	value, ok = pool.GetTimeout(timeout)
   255  	assert.Nil(value)
   256  	assert.False(ok)
   257  }
   258  
   259  func TestCircularPoolGetCancel(t *testing.T) {
   260  	assert := assert.New(t)
   261  	pool, err := NewCircularPool(poolSize, poolSize, resourceFunc)
   262  	assert.NotNil(pool)
   263  	assert.Nil(err)
   264  
   265  	// Put on a full pool should not alter its size
   266  	pool.Put(resource)
   267  
   268  	done := make(chan struct{})
   269  
   270  	// GetOrNew should drain the pool poolSize times
   271  	for repeat := 0; repeat < poolSize; repeat++ {
   272  		value, ok := pool.GetCancel(done)
   273  		assert.Equal(resource, value)
   274  		assert.True(ok)
   275  	}
   276  
   277  	// the pool should be empty
   278  	value, ok := pool.TryGet()
   279  	assert.Nil(value)
   280  	assert.False(ok)
   281  
   282  	value, ok = pool.GetTimeout(timeout)
   283  	assert.Nil(value)
   284  	assert.False(ok)
   285  
   286  	waitGroup := &sync.WaitGroup{}
   287  	waitGroup.Add(1)
   288  	go func() {
   289  		defer waitGroup.Done()
   290  
   291  		// this should unblock when done is closed
   292  		value, ok := pool.GetCancel(done)
   293  		assert.Nil(value)
   294  		assert.False(ok)
   295  	}()
   296  
   297  	close(done)
   298  	waitGroup.Wait()
   299  }