77 lines
1.7 KiB
Go
77 lines
1.7 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"bytes"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRawContentCacheCoalescesConcurrentLoads(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cache := newRawContentCache(8, 8*1024*1024)
|
|
var loads int32
|
|
want := []byte("coalesced")
|
|
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 12; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
got, err, _ := cache.GetOrLoad("shared-id", func() ([]byte, error) {
|
|
atomic.AddInt32(&loads, 1)
|
|
time.Sleep(15 * time.Millisecond)
|
|
return want, nil
|
|
})
|
|
if err != nil {
|
|
t.Errorf("GetOrLoad() error = %v", err)
|
|
return
|
|
}
|
|
if !bytes.Equal(got, want) {
|
|
t.Errorf("GetOrLoad() content mismatch = %q, want %q", got, want)
|
|
}
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
|
|
if got := atomic.LoadInt32(&loads); got != 1 {
|
|
t.Fatalf("loader call count = %d, want 1", got)
|
|
}
|
|
}
|
|
|
|
func TestRawContentCacheEvictionCausesReload(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cache := newRawContentCache(1, 3)
|
|
var loadsA int32
|
|
var loadsB int32
|
|
|
|
if _, err, _ := cache.GetOrLoad("a", func() ([]byte, error) {
|
|
atomic.AddInt32(&loadsA, 1)
|
|
return []byte("aaa"), nil
|
|
}); err != nil {
|
|
t.Fatalf("GetOrLoad(a) error = %v", err)
|
|
}
|
|
if _, err, _ := cache.GetOrLoad("b", func() ([]byte, error) {
|
|
atomic.AddInt32(&loadsB, 1)
|
|
return []byte("bbb"), nil
|
|
}); err != nil {
|
|
t.Fatalf("GetOrLoad(b) error = %v", err)
|
|
}
|
|
if _, err, _ := cache.GetOrLoad("a", func() ([]byte, error) {
|
|
atomic.AddInt32(&loadsA, 1)
|
|
return []byte("aaa"), nil
|
|
}); err != nil {
|
|
t.Fatalf("GetOrLoad(a second) error = %v", err)
|
|
}
|
|
|
|
if got := atomic.LoadInt32(&loadsB); got != 1 {
|
|
t.Fatalf("loadsB = %d, want 1", got)
|
|
}
|
|
if got := atomic.LoadInt32(&loadsA); got != 2 {
|
|
t.Fatalf("loadsA = %d, want 2", got)
|
|
}
|
|
}
|