Index: src/pkg/co/resourcecache_test.go |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/src/pkg/co/resourcecache_test.go |
@@ -0,0 +1,241 @@ |
+// Copyright 2011 The Go Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style |
+// license that can be found in the LICENSE file. |
+ |
+package co_test |
+ |
+import ( |
+ "co" |
+ "runtime" |
+ "sync" |
+ "sync/atomic" |
+ "testing" |
+) |
+ |
+func TestResourceCache(t *testing.T) { |
+ runtime.LockOSThread() |
+ defer runtime.UnlockOSThread() |
+ rc := co.MakeResourceCache(10, 20, 20, nil, nil) |
+ res := rc.Get() |
+ if res != nil { |
+ t.Fatalf("new cache is not empty") |
+ } |
+ res = 42 |
+ rc.Put(res) |
+ res = rc.Get() |
+ if res == nil || res.(int) != 42 { |
+ t.Fatalf("cache returned invalid resource") |
+ } |
+ res = rc.Get() |
+ if res != nil { |
+ t.Fatalf("cache is not empty") |
+ } |
+ rc.Close() |
+} |
+ |
+func TestResourceCacheLifo(t *testing.T) { |
+ runtime.LockOSThread() |
+ defer runtime.UnlockOSThread() |
+ rc := co.MakeResourceCache(10, 20, 20, nil, nil) |
+ for i := 0; i != 5; i++ { |
+ rc.Put(i) |
+ } |
+ for i := 4; i >= 0; i-- { |
+ if v := rc.Get().(int); v != i { |
+ t.Fatalf("cache is not LIFO: %d/%d", v, i) |
+ } |
+ } |
+ if rc.Get() != nil { |
+ t.Fatalf("cache is not empty") |
+ } |
+ rc.Close() |
+} |
+ |
+func TestResourceCacheGlobal(t *testing.T) { |
+ runtime.LockOSThread() |
+ defer runtime.UnlockOSThread() |
+ rc := co.MakeResourceCache(10, 20, 20, nil, nil) |
+ for i := 0; i != 100; i++ { |
+ rc.Put(i) |
+ } |
+ for i := 39; i >= 30; i-- { |
+ if v := rc.Get().(int); v != i { |
+ t.Fatalf("wrong values are cached: %d/%d", v, i) |
+ } |
+ } |
+ for i := 9; i >= 0; i-- { |
+ if v := rc.Get().(int); v != i { |
+ t.Fatalf("wrong values are cached: %d/%d", v, i) |
+ } |
+ } |
+ for i := 29; i >= 20; i-- { |
+ if v := rc.Get().(int); v != i { |
+ t.Fatalf("wrong values are cached: %d/%d", v, i) |
+ } |
+ } |
+ for i := 19; i >= 10; i-- { |
+ if v := rc.Get().(int); v != i { |
+ t.Fatalf("wrong values are cached: %d/%d", v, i) |
+ } |
+ } |
+ if rc.Get() != nil { |
+ t.Fatalf("cache is not empty") |
+ } |
+ rc.Close() |
+} |
+ |
+func TestResourceCacheCtorDtor(t *testing.T) { |
+ runtime.LockOSThread() |
+ defer runtime.UnlockOSThread() |
+ ctorVal := -1 |
+ ctorValPtr := &ctorVal |
+ ctor := func() (res interface{}) { |
+ res = *ctorValPtr |
+ *ctorValPtr = -1 |
+ return res |
+ } |
+ dtorVal := -1 |
+ dtorValPtr := &dtorVal |
+ dtor := func(res interface{}) { |
+ if res.(int) != *dtorValPtr { |
+ t.Fatalf("wrong value in dtor: %d/%d", res.(int), *dtorValPtr) |
+ } |
+ *dtorValPtr = -1 |
+ } |
+ rc := co.MakeResourceCache(1, 2, 1, ctor, dtor) |
+ ctorVal = 42 |
+ if v := rc.Get().(int); v != 42 { |
+ t.Fatalf("wrong value returned: %d/%d", v, 42) |
+ } |
+ rc.Put(43) |
+ if v := rc.Get().(int); v != 43 { |
+ t.Fatalf("wrong value returned: %d/%d", v, 43) |
+ } |
+ ctorVal = 44 |
+ if v := rc.Get().(int); v != 44 { |
+ t.Fatalf("wrong value returned: %d/%d", v, 44) |
+ } |
+ rc.Put(100) |
+ rc.Put(101) |
+ rc.Put(102) |
+ dtorVal = 103 |
+ rc.Put(103) |
+ if dtorVal != -1 { |
+ t.Fatalf("dtor is not called") |
+ } |
+ rc.Get() |
+ rc.Get() |
+ dtorVal = 101 |
+ rc.Close() |
+ if dtorVal != -1 { |
+ t.Fatalf("dtor is not called in close") |
+ } |
+} |
+ |
+func TestResourceCacheLocalDtor(t *testing.T) { |
+ runtime.LockOSThread() |
+ defer runtime.UnlockOSThread() |
+ dtorVal := -1 |
+ dtorValPtr := &dtorVal |
+ dtor := func(res interface{}) { |
+ if res.(int) != *dtorValPtr { |
+ t.Fatalf("wrong value in dtor: %d/%d", res.(int), *dtorValPtr) |
+ } |
+ *dtorValPtr = -1 |
+ } |
+ rc := co.MakeResourceCache(1, 2, 1, nil, dtor) |
+ rc.Put(42) |
+ dtorVal = 42 |
+ rc.Close() |
+ if dtorVal != -1 { |
+ t.Fatalf("dtor is not called in close") |
+ } |
+} |
+ |
+func TestResourceCacheNil(t *testing.T) { |
+ runtime.LockOSThread() |
+ defer runtime.UnlockOSThread() |
+ ctor := func() interface{} { |
+ return nil |
+ } |
+ rc := co.MakeResourceCache(1, 2, 0, ctor, nil) |
+ if rc.Get() != nil { |
+ t.Fatalf("cache does not return nil") |
+ } |
+ rc.Close() |
+} |
+ |
+func TestResourceCacheInvalidUse(t *testing.T) { |
+ runtime.LockOSThread() |
+ defer runtime.UnlockOSThread() |
+ func() { |
+ defer func() { |
+ if recover() == nil { |
+ t.Fatalf("lowMark=0 does not panic") |
+ } |
+ }() |
+ co.MakeResourceCache(0, 2, 0, nil, nil) |
+ }() |
+ func() { |
+ defer func() { |
+ if recover() == nil { |
+ t.Fatalf("highMark=lowMark does not panic") |
+ } |
+ }() |
+ co.MakeResourceCache(1, 1, 0, nil, nil) |
+ }() |
+ func() { |
+ defer func() { |
+ if recover() == nil { |
+ t.Fatalf("double close does not panic") |
+ } |
+ }() |
+ rc := co.MakeResourceCache(1, 2, 0, nil, nil) |
+ rc.Close() |
+ rc.Close() |
+ }() |
+ func() { |
+ defer func() { |
+ if recover() == nil { |
+ t.Fatalf("Get() on closed cache does not panic") |
+ } |
+ }() |
+ rc := co.MakeResourceCache(1, 2, 0, nil, nil) |
+ rc.Close() |
+ rc.Get() |
+ }() |
+ func() { |
+ defer func() { |
+ if recover() == nil { |
+ t.Fatalf("Put() on closed cache does not panic") |
+ } |
+ }() |
+ rc := co.MakeResourceCache(1, 2, 0, nil, nil) |
+ rc.Close() |
+ rc.Put(0) |
+ }() |
+} |
+ |
+func BenchmarkResourceCache(b *testing.B) { |
+ const CallsPerSched = 1000 |
+ procs := runtime.GOMAXPROCS(-1) |
+ N := int32(b.N / CallsPerSched) |
+ var wg sync.WaitGroup |
+ wg.Add(procs) |
+ rc := co.MakeResourceCache(1, 2, 0, nil, nil) |
+ for p := 0; p < procs; p++ { |
+ go func() { |
+ var res interface{} = 42 |
+ for atomic.AddInt32(&N, -1) >= 0 { |
+ for g := 0; g < CallsPerSched; g++ { |
+ rc.Put(res) |
+ res = rc.Get() |
+ } |
+ runtime.Gosched() |
+ } |
+ wg.Done() |
+ }() |
+ } |
+ wg.Wait() |
+ rc.Close() |
+} |