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 }