1
18
19 package pool
20
21 import (
22 "context"
23 "errors"
24 "testing"
25 "time"
26 )
27
28 var lastID, count AtomicInt64
29
30 type TestResource struct {
31 num int64
32 closed bool
33 }
34
35 func (tr *TestResource) Close() {
36 if !tr.closed {
37 count.Add(-1)
38 tr.closed = true
39 }
40 }
41
42 func PoolFactory() (Resource, error) {
43 count.Add(1)
44 return &TestResource{lastID.Add(1), false}, nil
45 }
46
47 func FailFactory() (Resource, error) {
48 return nil, errors.New("Failed")
49 }
50
51 func SlowFailFactory() (Resource, error) {
52 time.Sleep(10 * time.Millisecond)
53 return nil, errors.New("Failed")
54 }
55
56 func TestOpen(t *testing.T) {
57 ctx := context.Background()
58 lastID.Set(0)
59 count.Set(0)
60 p := NewResourcePool(PoolFactory, 6, 6, time.Second, 0)
61 p.SetCapacity(5)
62 var resources [10]Resource
63
64
65 for i := 0; i < 5; i++ {
66 r, err := p.Get(ctx)
67 resources[i] = r
68 if err != nil {
69 t.Errorf("Unexpected error %v", err)
70 }
71 if p.Available() != int64(5-i-1) {
72 t.Errorf("expecting %d, received %d", 5-i-1, p.Available())
73 }
74 if p.WaitCount() != 0 {
75 t.Errorf("expecting 0, received %d", p.WaitCount())
76 }
77 if p.WaitTime() != 0 {
78 t.Errorf("expecting 0, received %d", p.WaitTime())
79 }
80 if lastID.Get() != int64(i+1) {
81 t.Errorf("Expecting %d, received %d", i+1, lastID.Get())
82 }
83 if count.Get() != int64(i+1) {
84 t.Errorf("Expecting %d, received %d", i+1, count.Get())
85 }
86 }
87
88
89 ch := make(chan bool)
90 go func() {
91 for i := 0; i < 5; i++ {
92 r, err := p.Get(ctx)
93 if err != nil {
94 t.Errorf("Get failed: %v", err)
95 }
96 resources[i] = r
97 }
98 for i := 0; i < 5; i++ {
99 p.Put(resources[i])
100 }
101 ch <- true
102 }()
103 for i := 0; i < 5; i++ {
104
105 time.Sleep(10 * time.Millisecond)
106 p.Put(resources[i])
107 }
108 <-ch
109 if p.WaitCount() != 5 {
110 t.Errorf("Expecting 5, received %d", p.WaitCount())
111 }
112 if p.WaitTime() == 0 {
113 t.Errorf("Expecting non-zero")
114 }
115 if lastID.Get() != 5 {
116 t.Errorf("Expecting 5, received %d", lastID.Get())
117 }
118
119
120 r, err := p.Get(ctx)
121 if err != nil {
122 t.Errorf("Unexpected error %v", err)
123 }
124 r.Close()
125
126 p.Put(nil)
127 if count.Get() != 5 {
128 t.Errorf("Expecting 5, received %d", count.Get())
129 }
130 for i := 0; i < 5; i++ {
131 r, err := p.Get(ctx)
132 if err != nil {
133 t.Errorf("Get failed: %v", err)
134 }
135 resources[i] = r
136 }
137 for i := 0; i < 5; i++ {
138 p.Put(resources[i])
139 }
140 if count.Get() != 5 {
141 t.Errorf("Expecting 5, received %d", count.Get())
142 }
143 if lastID.Get() != 6 {
144 t.Errorf("Expecting 6, received %d", lastID.Get())
145 }
146
147
148 p.SetCapacity(3)
149 if count.Get() != 3 {
150 t.Errorf("Expecting 3, received %d", count.Get())
151 }
152 if lastID.Get() != 6 {
153 t.Errorf("Expecting 6, received %d", lastID.Get())
154 }
155 if p.Capacity() != 3 {
156 t.Errorf("Expecting 3, received %d", p.Capacity())
157 }
158 if p.Available() != 3 {
159 t.Errorf("Expecting 3, received %d", p.Available())
160 }
161 p.SetCapacity(6)
162 if p.Capacity() != 6 {
163 t.Errorf("Expecting 6, received %d", p.Capacity())
164 }
165 if p.Available() != 6 {
166 t.Errorf("Expecting 6, received %d", p.Available())
167 }
168 for i := 0; i < 6; i++ {
169 r, err := p.Get(ctx)
170 if err != nil {
171 t.Errorf("Get failed: %v", err)
172 }
173 resources[i] = r
174 }
175 for i := 0; i < 6; i++ {
176 p.Put(resources[i])
177 }
178 if count.Get() != 6 {
179 t.Errorf("Expecting 5, received %d", count.Get())
180 }
181 if lastID.Get() != 9 {
182 t.Errorf("Expecting 9, received %d", lastID.Get())
183 }
184
185
186 p.Close()
187 if p.Capacity() != 0 {
188 t.Errorf("Expecting 0, received %d", p.Capacity())
189 }
190 if p.Available() != 0 {
191 t.Errorf("Expecting 0, received %d", p.Available())
192 }
193 if count.Get() != 0 {
194 t.Errorf("Expecting 0, received %d", count.Get())
195 }
196 }
197
198 func TestPrefill(t *testing.T) {
199 lastID.Set(0)
200 count.Set(0)
201 p := NewResourcePool(PoolFactory, 5, 5, time.Second, 1)
202 defer p.Close()
203 if p.Active() != 5 {
204 t.Errorf("p.Active(): %d, want 5", p.Active())
205 }
206 p = NewResourcePool(FailFactory, 5, 5, time.Second, 1)
207 defer p.Close()
208 if p.Active() != 0 {
209 t.Errorf("p.Active(): %d, want 0", p.Active())
210 }
211 }
212
213 func TestPrefillTimeout(t *testing.T) {
214 lastID.Set(0)
215 count.Set(0)
216 saveTimeout := prefillTimeout
217 prefillTimeout = 1 * time.Millisecond
218 defer func() { prefillTimeout = saveTimeout }()
219
220 start := time.Now()
221 p := NewResourcePool(SlowFailFactory, 5, 5, time.Second, 1)
222 defer p.Close()
223 if elapsed := time.Since(start); elapsed > 20*time.Millisecond {
224 t.Errorf("elapsed: %v, should be around 10ms", elapsed)
225 }
226 if p.Active() != 0 {
227 t.Errorf("p.Active(): %d, want 0", p.Active())
228 }
229 }
230
231 func TestShrinking(t *testing.T) {
232 ctx := context.Background()
233 lastID.Set(0)
234 count.Set(0)
235 p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0)
236 var resources [10]Resource
237
238 for i := 0; i < 4; i++ {
239 r, err := p.Get(ctx)
240 if err != nil {
241 t.Errorf("Get failed: %v", err)
242 }
243 resources[i] = r
244 }
245 done := make(chan bool)
246 go func() {
247 p.SetCapacity(3)
248 done <- true
249 }()
250 expected := `{"Capacity": 3, "Available": 0, "Active": 4, "InUse": 4, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0}`
251 for i := 0; i < 10; i++ {
252 time.Sleep(10 * time.Millisecond)
253 stats := p.StatsJSON()
254 if stats != expected {
255 if i == 9 {
256 t.Errorf(`expecting '%s', received '%s'`, expected, stats)
257 }
258 }
259 }
260
261
262 p.Put(resources[3])
263 <-done
264
265 for i := 0; i < 3; i++ {
266 p.Put(resources[i])
267 }
268 stats := p.StatsJSON()
269 expected = `{"Capacity": 3, "Available": 3, "Active": 3, "InUse": 0, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0}`
270 if stats != expected {
271 t.Errorf(`expecting '%s', received '%s'`, expected, stats)
272 }
273 if count.Get() != 3 {
274 t.Errorf("Expecting 3, received %d", count.Get())
275 }
276
277
278
279 var err error
280 for i := 0; i < 3; i++ {
281 resources[i], err = p.Get(ctx)
282 if err != nil {
283 t.Errorf("Unexpected error %v", err)
284 }
285 }
286
287 go func() {
288 r, err := p.Get(ctx)
289 if err != nil {
290 t.Errorf("Unexpected error %v", err)
291 }
292 p.Put(r)
293 done <- true
294 }()
295
296
297 go func() {
298 p.SetCapacity(2)
299 done <- true
300 }()
301 time.Sleep(10 * time.Millisecond)
302
303
304 for i := 0; i < 3; i++ {
305 p.Put(resources[i])
306 }
307 <-done
308 <-done
309 if p.Capacity() != 2 {
310 t.Errorf("Expecting 2, received %d", p.Capacity())
311 }
312 if p.Available() != 2 {
313 t.Errorf("Expecting 2, received %d", p.Available())
314 }
315 if p.WaitCount() != 1 {
316 t.Errorf("Expecting 1, received %d", p.WaitCount())
317 }
318 if count.Get() != 2 {
319 t.Errorf("Expecting 2, received %d", count.Get())
320 }
321
322
323 p.SetCapacity(3)
324 for i := 0; i < 3; i++ {
325 resources[i], err = p.Get(ctx)
326 if err != nil {
327 t.Errorf("Unexpected error %v", err)
328 }
329 }
330
331 go func() {
332 r, err := p.Get(ctx)
333 if err != nil {
334 t.Errorf("Unexpected error %v", err)
335 }
336 p.Put(r)
337 done <- true
338 }()
339 time.Sleep(10 * time.Millisecond)
340
341
342 go p.SetCapacity(2)
343 time.Sleep(10 * time.Millisecond)
344 go p.SetCapacity(4)
345 time.Sleep(10 * time.Millisecond)
346
347
348 for i := 0; i < 3; i++ {
349 p.Put(resources[i])
350 }
351 <-done
352
353 err = p.SetCapacity(-1)
354 if err == nil {
355 t.Errorf("Expecting error")
356 }
357 err = p.SetCapacity(255555)
358 if err == nil {
359 t.Errorf("Expecting error")
360 }
361
362 if p.Capacity() != 4 {
363 t.Errorf("Expecting 4, received %d", p.Capacity())
364 }
365 if p.Available() != 4 {
366 t.Errorf("Expecting 4, received %d", p.Available())
367 }
368 }
369
370 func TestClosing(t *testing.T) {
371 ctx := context.Background()
372 lastID.Set(0)
373 count.Set(0)
374 p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0)
375 var resources [10]Resource
376 for i := 0; i < 5; i++ {
377 r, err := p.Get(ctx)
378 if err != nil {
379 t.Errorf("Get failed: %v", err)
380 }
381 resources[i] = r
382 }
383 ch := make(chan bool)
384 go func() {
385 p.Close()
386 ch <- true
387 }()
388
389
390 time.Sleep(10 * time.Millisecond)
391 stats := p.StatsJSON()
392 expected := `{"Capacity": 0, "Available": 0, "Active": 5, "InUse": 5, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0}`
393 if stats != expected {
394 t.Errorf(`expecting '%s', received '%s'`, expected, stats)
395 }
396
397
398 for i := 0; i < 5; i++ {
399 p.Put(resources[i])
400 }
401
402
403 <-ch
404
405
406 err := p.SetCapacity(1)
407 if err == nil {
408 t.Errorf("expecting error")
409 }
410
411 stats = p.StatsJSON()
412 expected = `{"Capacity": 0, "Available": 0, "Active": 0, "InUse": 0, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0}`
413 if stats != expected {
414 t.Errorf(`expecting '%s', received '%s'`, expected, stats)
415 }
416 if lastID.Get() != 5 {
417 t.Errorf("Expecting 5, received %d", count.Get())
418 }
419 if count.Get() != 0 {
420 t.Errorf("Expecting 0, received %d", count.Get())
421 }
422 }
423
424 func TestIdleTimeout(t *testing.T) {
425 ctx := context.Background()
426 lastID.Set(0)
427 count.Set(0)
428 p := NewResourcePool(PoolFactory, 1, 1, 10*time.Millisecond, 0)
429 defer p.Close()
430
431 r, err := p.Get(ctx)
432 if err != nil {
433 t.Errorf("Unexpected error %v", err)
434 }
435 if count.Get() != 1 {
436 t.Errorf("Expecting 1, received %d", count.Get())
437 }
438 if p.IdleClosed() != 0 {
439 t.Errorf("Expecting 0, received %d", p.IdleClosed())
440 }
441 p.Put(r)
442 if lastID.Get() != 1 {
443 t.Errorf("Expecting 1, received %d", count.Get())
444 }
445 if count.Get() != 1 {
446 t.Errorf("Expecting 1, received %d", count.Get())
447 }
448 if p.IdleClosed() != 0 {
449 t.Errorf("Expecting 0, received %d", p.IdleClosed())
450 }
451 time.Sleep(15 * time.Millisecond)
452
453 if count.Get() != 1 {
454 t.Errorf("Expecting 1, received %d", count.Get())
455 }
456 if p.IdleClosed() != 1 {
457 t.Errorf("Expecting 1, received %d", p.IdleClosed())
458 }
459 r, err = p.Get(ctx)
460 if err != nil {
461 t.Errorf("Unexpected error %v", err)
462 }
463 if lastID.Get() != 2 {
464 t.Errorf("Expecting 2, received %d", count.Get())
465 }
466 if count.Get() != 1 {
467 t.Errorf("Expecting 1, received %d", count.Get())
468 }
469 if p.IdleClosed() != 1 {
470 t.Errorf("Expecting 1, received %d", p.IdleClosed())
471 }
472
473
474
475 time.Sleep(15 * time.Millisecond)
476 if lastID.Get() != 2 {
477 t.Errorf("Expecting 2, received %d", count.Get())
478 }
479 if count.Get() != 1 {
480 t.Errorf("Expecting 1, received %d", count.Get())
481 }
482 if p.IdleClosed() != 1 {
483 t.Errorf("Expecting 1, received %d", p.IdleClosed())
484 }
485 p.Put(r)
486 r, err = p.Get(ctx)
487 if err != nil {
488 t.Errorf("Unexpected error %v", err)
489 }
490 if lastID.Get() != 2 {
491 t.Errorf("Expecting 2, received %d", count.Get())
492 }
493 if count.Get() != 1 {
494 t.Errorf("Expecting 1, received %d", count.Get())
495 }
496 if p.IdleClosed() != 1 {
497 t.Errorf("Expecting 1, received %d", p.IdleClosed())
498 }
499
500
501
502 p.SetIdleTimeout(1000 * time.Millisecond)
503 p.Put(r)
504
505 time.Sleep(15 * time.Millisecond)
506 if lastID.Get() != 2 {
507 t.Errorf("Expecting 2, received %d", count.Get())
508 }
509 if count.Get() != 1 {
510 t.Errorf("Expecting 1, received %d", count.Get())
511 }
512 if p.IdleClosed() != 1 {
513 t.Errorf("Expecting 1, received %d", p.IdleClosed())
514 }
515
516
517 r, err = p.Get(ctx)
518 if err != nil {
519 t.Errorf("Unexpected error %v", err)
520 }
521 p.Put(r)
522 p.SetIdleTimeout(10 * time.Millisecond)
523 time.Sleep(15 * time.Millisecond)
524 if lastID.Get() != 3 {
525 t.Errorf("Expecting 3, received %d", lastID.Get())
526 }
527 if count.Get() != 1 {
528 t.Errorf("Expecting 1, received %d", count.Get())
529 }
530 if p.IdleClosed() != 2 {
531 t.Errorf("Expecting 2, received %d", p.IdleClosed())
532 }
533 }
534
535 func TestIdleTimeoutCreateFail(t *testing.T) {
536 ctx := context.Background()
537 lastID.Set(0)
538 count.Set(0)
539 p := NewResourcePool(PoolFactory, 1, 1, 10*time.Millisecond, 0)
540 defer p.Close()
541 r, err := p.Get(ctx)
542 if err != nil {
543 t.Fatal(err)
544 }
545
546
547
548 p.factory = FailFactory
549 p.Put(r)
550 time.Sleep(15 * time.Millisecond)
551 if p.Active() != 0 {
552 t.Errorf("p.Active(): %d, want 0", p.Active())
553 }
554 }
555
556 func TestCreateFail(t *testing.T) {
557 ctx := context.Background()
558 lastID.Set(0)
559 count.Set(0)
560 p := NewResourcePool(FailFactory, 5, 5, time.Second, 0)
561 defer p.Close()
562 if _, err := p.Get(ctx); err.Error() != "Failed" {
563 t.Errorf("Expecting Failed, received %v", err)
564 }
565 stats := p.StatsJSON()
566 expected := `{"Capacity": 5, "Available": 5, "Active": 0, "InUse": 0, "MaxCapacity": 5, "WaitCount": 0, "WaitTime": 0, "IdleTimeout": 1000000000, "IdleClosed": 0}`
567 if stats != expected {
568 t.Errorf(`expecting '%s', received '%s'`, expected, stats)
569 }
570 }
571
572 func TestCreateFailOnPut(t *testing.T) {
573 ctx := context.Background()
574 lastID.Set(0)
575 count.Set(0)
576 p := NewResourcePool(PoolFactory, 5, 5, time.Second, 0)
577 defer p.Close()
578 _, err := p.Get(ctx)
579 if err != nil {
580 t.Fatal(err)
581 }
582 p.factory = FailFactory
583 p.Put(nil)
584 if p.Active() != 0 {
585 t.Errorf("p.Active(): %d, want 0", p.Active())
586 }
587 }
588
589 func TestSlowCreateFail(t *testing.T) {
590 ctx := context.Background()
591 lastID.Set(0)
592 count.Set(0)
593 p := NewResourcePool(SlowFailFactory, 2, 2, time.Second, 0)
594 defer p.Close()
595 ch := make(chan bool)
596
597 for i := 0; i < 3; i++ {
598 go func() {
599 p.Get(ctx)
600 ch <- true
601 }()
602 }
603 for i := 0; i < 3; i++ {
604 <-ch
605 }
606 if p.Available() != 2 {
607 t.Errorf("Expecting 2, received %d", p.Available())
608 }
609 }
610
611 func TestTimeout(t *testing.T) {
612 ctx := context.Background()
613 lastID.Set(0)
614 count.Set(0)
615 p := NewResourcePool(PoolFactory, 1, 1, time.Second, 0)
616 defer p.Close()
617 r, err := p.Get(ctx)
618 if err != nil {
619 t.Fatal(err)
620 }
621 newctx, cancel := context.WithTimeout(ctx, 1*time.Millisecond)
622 _, err = p.Get(newctx)
623 cancel()
624 want := "resource pool timed out"
625 if err == nil || err.Error() != want {
626 t.Errorf("got %v, want %s", err, want)
627 }
628 p.Put(r)
629 }
630
631 func TestExpired(t *testing.T) {
632 lastID.Set(0)
633 count.Set(0)
634 p := NewResourcePool(PoolFactory, 1, 1, time.Second, 0)
635 defer p.Close()
636 ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(-1*time.Second))
637 r, err := p.Get(ctx)
638 if err == nil {
639 p.Put(r)
640 }
641 cancel()
642 want := "resource pool timed out"
643 if err == nil || err.Error() != want {
644 t.Errorf("got %v, want %s", err, want)
645 }
646 }
647
View as plain text