Update go dependencies
This commit is contained in:
parent
15ffb51394
commit
bb4d483837
1621 changed files with 86368 additions and 284392 deletions
18
vendor/github.com/golang/groupcache/.travis.yml
generated
vendored
Normal file
18
vendor/github.com/golang/groupcache/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
language: go
|
||||
go_import_path: github.com/golang/groupcache
|
||||
|
||||
os: linux
|
||||
dist: trusty
|
||||
sudo: false
|
||||
|
||||
script:
|
||||
- go test ./...
|
||||
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- master
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $GOPATH/pkg
|
||||
147
vendor/github.com/golang/groupcache/byteview_test.go
generated
vendored
147
vendor/github.com/golang/groupcache/byteview_test.go
generated
vendored
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
Copyright 2012 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package groupcache
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestByteView(t *testing.T) {
|
||||
for _, s := range []string{"", "x", "yy"} {
|
||||
for _, v := range []ByteView{of([]byte(s)), of(s)} {
|
||||
name := fmt.Sprintf("string %q, view %+v", s, v)
|
||||
if v.Len() != len(s) {
|
||||
t.Errorf("%s: Len = %d; want %d", name, v.Len(), len(s))
|
||||
}
|
||||
if v.String() != s {
|
||||
t.Errorf("%s: String = %q; want %q", name, v.String(), s)
|
||||
}
|
||||
var longDest [3]byte
|
||||
if n := v.Copy(longDest[:]); n != len(s) {
|
||||
t.Errorf("%s: long Copy = %d; want %d", name, n, len(s))
|
||||
}
|
||||
var shortDest [1]byte
|
||||
if n := v.Copy(shortDest[:]); n != min(len(s), 1) {
|
||||
t.Errorf("%s: short Copy = %d; want %d", name, n, min(len(s), 1))
|
||||
}
|
||||
if got, err := ioutil.ReadAll(v.Reader()); err != nil || string(got) != s {
|
||||
t.Errorf("%s: Reader = %q, %v; want %q", name, got, err, s)
|
||||
}
|
||||
if got, err := ioutil.ReadAll(io.NewSectionReader(v, 0, int64(len(s)))); err != nil || string(got) != s {
|
||||
t.Errorf("%s: SectionReader of ReaderAt = %q, %v; want %q", name, got, err, s)
|
||||
}
|
||||
var dest bytes.Buffer
|
||||
if _, err := v.WriteTo(&dest); err != nil || !bytes.Equal(dest.Bytes(), []byte(s)) {
|
||||
t.Errorf("%s: WriteTo = %q, %v; want %q", name, dest.Bytes(), err, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// of returns a byte view of the []byte or string in x.
|
||||
func of(x interface{}) ByteView {
|
||||
if bytes, ok := x.([]byte); ok {
|
||||
return ByteView{b: bytes}
|
||||
}
|
||||
return ByteView{s: x.(string)}
|
||||
}
|
||||
|
||||
func TestByteViewEqual(t *testing.T) {
|
||||
tests := []struct {
|
||||
a interface{} // string or []byte
|
||||
b interface{} // string or []byte
|
||||
want bool
|
||||
}{
|
||||
{"x", "x", true},
|
||||
{"x", "y", false},
|
||||
{"x", "yy", false},
|
||||
{[]byte("x"), []byte("x"), true},
|
||||
{[]byte("x"), []byte("y"), false},
|
||||
{[]byte("x"), []byte("yy"), false},
|
||||
{[]byte("x"), "x", true},
|
||||
{[]byte("x"), "y", false},
|
||||
{[]byte("x"), "yy", false},
|
||||
{"x", []byte("x"), true},
|
||||
{"x", []byte("y"), false},
|
||||
{"x", []byte("yy"), false},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
va := of(tt.a)
|
||||
if bytes, ok := tt.b.([]byte); ok {
|
||||
if got := va.EqualBytes(bytes); got != tt.want {
|
||||
t.Errorf("%d. EqualBytes = %v; want %v", i, got, tt.want)
|
||||
}
|
||||
} else {
|
||||
if got := va.EqualString(tt.b.(string)); got != tt.want {
|
||||
t.Errorf("%d. EqualString = %v; want %v", i, got, tt.want)
|
||||
}
|
||||
}
|
||||
if got := va.Equal(of(tt.b)); got != tt.want {
|
||||
t.Errorf("%d. Equal = %v; want %v", i, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteViewSlice(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
from int
|
||||
to interface{} // nil to mean the end (SliceFrom); else int
|
||||
want string
|
||||
}{
|
||||
{
|
||||
in: "abc",
|
||||
from: 1,
|
||||
to: 2,
|
||||
want: "b",
|
||||
},
|
||||
{
|
||||
in: "abc",
|
||||
from: 1,
|
||||
want: "bc",
|
||||
},
|
||||
{
|
||||
in: "abc",
|
||||
to: 2,
|
||||
want: "ab",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
for _, v := range []ByteView{of([]byte(tt.in)), of(tt.in)} {
|
||||
name := fmt.Sprintf("test %d, view %+v", i, v)
|
||||
if tt.to != nil {
|
||||
v = v.Slice(tt.from, tt.to.(int))
|
||||
} else {
|
||||
v = v.SliceFrom(tt.from)
|
||||
}
|
||||
if v.String() != tt.want {
|
||||
t.Errorf("%s: got %q; want %q", name, v.String(), tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
456
vendor/github.com/golang/groupcache/groupcache_test.go
generated
vendored
456
vendor/github.com/golang/groupcache/groupcache_test.go
generated
vendored
|
|
@ -1,456 +0,0 @@
|
|||
/*
|
||||
Copyright 2012 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Tests for groupcache.
|
||||
|
||||
package groupcache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
||||
pb "github.com/golang/groupcache/groupcachepb"
|
||||
testpb "github.com/golang/groupcache/testpb"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
stringGroup, protoGroup Getter
|
||||
|
||||
stringc = make(chan string)
|
||||
|
||||
dummyCtx Context
|
||||
|
||||
// cacheFills is the number of times stringGroup or
|
||||
// protoGroup's Getter have been called. Read using the
|
||||
// cacheFills function.
|
||||
cacheFills AtomicInt
|
||||
)
|
||||
|
||||
const (
|
||||
stringGroupName = "string-group"
|
||||
protoGroupName = "proto-group"
|
||||
testMessageType = "google3/net/groupcache/go/test_proto.TestMessage"
|
||||
fromChan = "from-chan"
|
||||
cacheSize = 1 << 20
|
||||
)
|
||||
|
||||
func testSetup() {
|
||||
stringGroup = NewGroup(stringGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error {
|
||||
if key == fromChan {
|
||||
key = <-stringc
|
||||
}
|
||||
cacheFills.Add(1)
|
||||
return dest.SetString("ECHO:" + key)
|
||||
}))
|
||||
|
||||
protoGroup = NewGroup(protoGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error {
|
||||
if key == fromChan {
|
||||
key = <-stringc
|
||||
}
|
||||
cacheFills.Add(1)
|
||||
return dest.SetProto(&testpb.TestMessage{
|
||||
Name: proto.String("ECHO:" + key),
|
||||
City: proto.String("SOME-CITY"),
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
// tests that a Getter's Get method is only called once with two
|
||||
// outstanding callers. This is the string variant.
|
||||
func TestGetDupSuppressString(t *testing.T) {
|
||||
once.Do(testSetup)
|
||||
// Start two getters. The first should block (waiting reading
|
||||
// from stringc) and the second should latch on to the first
|
||||
// one.
|
||||
resc := make(chan string, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
go func() {
|
||||
var s string
|
||||
if err := stringGroup.Get(dummyCtx, fromChan, StringSink(&s)); err != nil {
|
||||
resc <- "ERROR:" + err.Error()
|
||||
return
|
||||
}
|
||||
resc <- s
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait a bit so both goroutines get merged together via
|
||||
// singleflight.
|
||||
// TODO(bradfitz): decide whether there are any non-offensive
|
||||
// debug/test hooks that could be added to singleflight to
|
||||
// make a sleep here unnecessary.
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
|
||||
// Unblock the first getter, which should unblock the second
|
||||
// as well.
|
||||
stringc <- "foo"
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case v := <-resc:
|
||||
if v != "ECHO:foo" {
|
||||
t.Errorf("got %q; want %q", v, "ECHO:foo")
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Errorf("timeout waiting on getter #%d of 2", i+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tests that a Getter's Get method is only called once with two
|
||||
// outstanding callers. This is the proto variant.
|
||||
func TestGetDupSuppressProto(t *testing.T) {
|
||||
once.Do(testSetup)
|
||||
// Start two getters. The first should block (waiting reading
|
||||
// from stringc) and the second should latch on to the first
|
||||
// one.
|
||||
resc := make(chan *testpb.TestMessage, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
go func() {
|
||||
tm := new(testpb.TestMessage)
|
||||
if err := protoGroup.Get(dummyCtx, fromChan, ProtoSink(tm)); err != nil {
|
||||
tm.Name = proto.String("ERROR:" + err.Error())
|
||||
}
|
||||
resc <- tm
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait a bit so both goroutines get merged together via
|
||||
// singleflight.
|
||||
// TODO(bradfitz): decide whether there are any non-offensive
|
||||
// debug/test hooks that could be added to singleflight to
|
||||
// make a sleep here unnecessary.
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
|
||||
// Unblock the first getter, which should unblock the second
|
||||
// as well.
|
||||
stringc <- "Fluffy"
|
||||
want := &testpb.TestMessage{
|
||||
Name: proto.String("ECHO:Fluffy"),
|
||||
City: proto.String("SOME-CITY"),
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case v := <-resc:
|
||||
if !reflect.DeepEqual(v, want) {
|
||||
t.Errorf(" Got: %v\nWant: %v", proto.CompactTextString(v), proto.CompactTextString(want))
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Errorf("timeout waiting on getter #%d of 2", i+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func countFills(f func()) int64 {
|
||||
fills0 := cacheFills.Get()
|
||||
f()
|
||||
return cacheFills.Get() - fills0
|
||||
}
|
||||
|
||||
func TestCaching(t *testing.T) {
|
||||
once.Do(testSetup)
|
||||
fills := countFills(func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
var s string
|
||||
if err := stringGroup.Get(dummyCtx, "TestCaching-key", StringSink(&s)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
if fills != 1 {
|
||||
t.Errorf("expected 1 cache fill; got %d", fills)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCacheEviction(t *testing.T) {
|
||||
once.Do(testSetup)
|
||||
testKey := "TestCacheEviction-key"
|
||||
getTestKey := func() {
|
||||
var res string
|
||||
for i := 0; i < 10; i++ {
|
||||
if err := stringGroup.Get(dummyCtx, testKey, StringSink(&res)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
fills := countFills(getTestKey)
|
||||
if fills != 1 {
|
||||
t.Fatalf("expected 1 cache fill; got %d", fills)
|
||||
}
|
||||
|
||||
g := stringGroup.(*Group)
|
||||
evict0 := g.mainCache.nevict
|
||||
|
||||
// Trash the cache with other keys.
|
||||
var bytesFlooded int64
|
||||
// cacheSize/len(testKey) is approximate
|
||||
for bytesFlooded < cacheSize+1024 {
|
||||
var res string
|
||||
key := fmt.Sprintf("dummy-key-%d", bytesFlooded)
|
||||
stringGroup.Get(dummyCtx, key, StringSink(&res))
|
||||
bytesFlooded += int64(len(key) + len(res))
|
||||
}
|
||||
evicts := g.mainCache.nevict - evict0
|
||||
if evicts <= 0 {
|
||||
t.Errorf("evicts = %v; want more than 0", evicts)
|
||||
}
|
||||
|
||||
// Test that the key is gone.
|
||||
fills = countFills(getTestKey)
|
||||
if fills != 1 {
|
||||
t.Fatalf("expected 1 cache fill after cache trashing; got %d", fills)
|
||||
}
|
||||
}
|
||||
|
||||
type fakePeer struct {
|
||||
hits int
|
||||
fail bool
|
||||
}
|
||||
|
||||
func (p *fakePeer) Get(_ Context, in *pb.GetRequest, out *pb.GetResponse) error {
|
||||
p.hits++
|
||||
if p.fail {
|
||||
return errors.New("simulated error from peer")
|
||||
}
|
||||
out.Value = []byte("got:" + in.GetKey())
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakePeers []ProtoGetter
|
||||
|
||||
func (p fakePeers) PickPeer(key string) (peer ProtoGetter, ok bool) {
|
||||
if len(p) == 0 {
|
||||
return
|
||||
}
|
||||
n := crc32.Checksum([]byte(key), crc32.IEEETable) % uint32(len(p))
|
||||
return p[n], p[n] != nil
|
||||
}
|
||||
|
||||
// tests that peers (virtual, in-process) are hit, and how much.
|
||||
func TestPeers(t *testing.T) {
|
||||
once.Do(testSetup)
|
||||
rand.Seed(123)
|
||||
peer0 := &fakePeer{}
|
||||
peer1 := &fakePeer{}
|
||||
peer2 := &fakePeer{}
|
||||
peerList := fakePeers([]ProtoGetter{peer0, peer1, peer2, nil})
|
||||
const cacheSize = 0 // disabled
|
||||
localHits := 0
|
||||
getter := func(_ Context, key string, dest Sink) error {
|
||||
localHits++
|
||||
return dest.SetString("got:" + key)
|
||||
}
|
||||
testGroup := newGroup("TestPeers-group", cacheSize, GetterFunc(getter), peerList)
|
||||
run := func(name string, n int, wantSummary string) {
|
||||
// Reset counters
|
||||
localHits = 0
|
||||
for _, p := range []*fakePeer{peer0, peer1, peer2} {
|
||||
p.hits = 0
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
key := fmt.Sprintf("key-%d", i)
|
||||
want := "got:" + key
|
||||
var got string
|
||||
err := testGroup.Get(dummyCtx, key, StringSink(&got))
|
||||
if err != nil {
|
||||
t.Errorf("%s: error on key %q: %v", name, key, err)
|
||||
continue
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("%s: for key %q, got %q; want %q", name, key, got, want)
|
||||
}
|
||||
}
|
||||
summary := func() string {
|
||||
return fmt.Sprintf("localHits = %d, peers = %d %d %d", localHits, peer0.hits, peer1.hits, peer2.hits)
|
||||
}
|
||||
if got := summary(); got != wantSummary {
|
||||
t.Errorf("%s: got %q; want %q", name, got, wantSummary)
|
||||
}
|
||||
}
|
||||
resetCacheSize := func(maxBytes int64) {
|
||||
g := testGroup
|
||||
g.cacheBytes = maxBytes
|
||||
g.mainCache = cache{}
|
||||
g.hotCache = cache{}
|
||||
}
|
||||
|
||||
// Base case; peers all up, with no problems.
|
||||
resetCacheSize(1 << 20)
|
||||
run("base", 200, "localHits = 49, peers = 51 49 51")
|
||||
|
||||
// Verify cache was hit. All localHits are gone, and some of
|
||||
// the peer hits (the ones randomly selected to be maybe hot)
|
||||
run("cached_base", 200, "localHits = 0, peers = 49 47 48")
|
||||
resetCacheSize(0)
|
||||
|
||||
// With one of the peers being down.
|
||||
// TODO(bradfitz): on a peer number being unavailable, the
|
||||
// consistent hashing should maybe keep trying others to
|
||||
// spread the load out. Currently it fails back to local
|
||||
// execution if the first consistent-hash slot is unavailable.
|
||||
peerList[0] = nil
|
||||
run("one_peer_down", 200, "localHits = 100, peers = 0 49 51")
|
||||
|
||||
// Failing peer
|
||||
peerList[0] = peer0
|
||||
peer0.fail = true
|
||||
run("peer0_failing", 200, "localHits = 100, peers = 51 49 51")
|
||||
}
|
||||
|
||||
func TestTruncatingByteSliceTarget(t *testing.T) {
|
||||
var buf [100]byte
|
||||
s := buf[:]
|
||||
if err := stringGroup.Get(dummyCtx, "short", TruncatingByteSliceSink(&s)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want := "ECHO:short"; string(s) != want {
|
||||
t.Errorf("short key got %q; want %q", s, want)
|
||||
}
|
||||
|
||||
s = buf[:6]
|
||||
if err := stringGroup.Get(dummyCtx, "truncated", TruncatingByteSliceSink(&s)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want := "ECHO:t"; string(s) != want {
|
||||
t.Errorf("truncated key got %q; want %q", s, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocatingByteSliceTarget(t *testing.T) {
|
||||
var dst []byte
|
||||
sink := AllocatingByteSliceSink(&dst)
|
||||
|
||||
inBytes := []byte("some bytes")
|
||||
sink.SetBytes(inBytes)
|
||||
if want := "some bytes"; string(dst) != want {
|
||||
t.Errorf("SetBytes resulted in %q; want %q", dst, want)
|
||||
}
|
||||
v, err := sink.view()
|
||||
if err != nil {
|
||||
t.Fatalf("view after SetBytes failed: %v", err)
|
||||
}
|
||||
if &inBytes[0] == &dst[0] {
|
||||
t.Error("inBytes and dst share memory")
|
||||
}
|
||||
if &inBytes[0] == &v.b[0] {
|
||||
t.Error("inBytes and view share memory")
|
||||
}
|
||||
if &dst[0] == &v.b[0] {
|
||||
t.Error("dst and view share memory")
|
||||
}
|
||||
}
|
||||
|
||||
// orderedFlightGroup allows the caller to force the schedule of when
|
||||
// orig.Do will be called. This is useful to serialize calls such
|
||||
// that singleflight cannot dedup them.
|
||||
type orderedFlightGroup struct {
|
||||
mu sync.Mutex
|
||||
stage1 chan bool
|
||||
stage2 chan bool
|
||||
orig flightGroup
|
||||
}
|
||||
|
||||
func (g *orderedFlightGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
|
||||
<-g.stage1
|
||||
<-g.stage2
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
return g.orig.Do(key, fn)
|
||||
}
|
||||
|
||||
// TestNoDedup tests invariants on the cache size when singleflight is
|
||||
// unable to dedup calls.
|
||||
func TestNoDedup(t *testing.T) {
|
||||
const testkey = "testkey"
|
||||
const testval = "testval"
|
||||
g := newGroup("testgroup", 1024, GetterFunc(func(_ Context, key string, dest Sink) error {
|
||||
return dest.SetString(testval)
|
||||
}), nil)
|
||||
|
||||
orderedGroup := &orderedFlightGroup{
|
||||
stage1: make(chan bool),
|
||||
stage2: make(chan bool),
|
||||
orig: g.loadGroup,
|
||||
}
|
||||
// Replace loadGroup with our wrapper so we can control when
|
||||
// loadGroup.Do is entered for each concurrent request.
|
||||
g.loadGroup = orderedGroup
|
||||
|
||||
// Issue two idential requests concurrently. Since the cache is
|
||||
// empty, it will miss. Both will enter load(), but we will only
|
||||
// allow one at a time to enter singleflight.Do, so the callback
|
||||
// function will be called twice.
|
||||
resc := make(chan string, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
go func() {
|
||||
var s string
|
||||
if err := g.Get(dummyCtx, testkey, StringSink(&s)); err != nil {
|
||||
resc <- "ERROR:" + err.Error()
|
||||
return
|
||||
}
|
||||
resc <- s
|
||||
}()
|
||||
}
|
||||
|
||||
// Ensure both goroutines have entered the Do routine. This implies
|
||||
// both concurrent requests have checked the cache, found it empty,
|
||||
// and called load().
|
||||
orderedGroup.stage1 <- true
|
||||
orderedGroup.stage1 <- true
|
||||
orderedGroup.stage2 <- true
|
||||
orderedGroup.stage2 <- true
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
if s := <-resc; s != testval {
|
||||
t.Errorf("result is %s want %s", s, testval)
|
||||
}
|
||||
}
|
||||
|
||||
const wantItems = 1
|
||||
if g.mainCache.items() != wantItems {
|
||||
t.Errorf("mainCache has %d items, want %d", g.mainCache.items(), wantItems)
|
||||
}
|
||||
|
||||
// If the singleflight callback doesn't double-check the cache again
|
||||
// upon entry, we would increment nbytes twice but the entry would
|
||||
// only be in the cache once.
|
||||
const wantBytes = int64(len(testkey) + len(testval))
|
||||
if g.mainCache.nbytes != wantBytes {
|
||||
t.Errorf("cache has %d bytes, want %d", g.mainCache.nbytes, wantBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupStatsAlignment(t *testing.T) {
|
||||
var g Group
|
||||
off := unsafe.Offsetof(g.Stats)
|
||||
if off%8 != 0 {
|
||||
t.Fatal("Stats structure is not 8-byte aligned.")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bradfitz): port the Google-internal full integration test into here,
|
||||
// using HTTP requests instead of our RPC system.
|
||||
166
vendor/github.com/golang/groupcache/http_test.go
generated
vendored
166
vendor/github.com/golang/groupcache/http_test.go
generated
vendored
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
Copyright 2013 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package groupcache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
peerAddrs = flag.String("test_peer_addrs", "", "Comma-separated list of peer addresses; used by TestHTTPPool")
|
||||
peerIndex = flag.Int("test_peer_index", -1, "Index of which peer this child is; used by TestHTTPPool")
|
||||
peerChild = flag.Bool("test_peer_child", false, "True if running as a child process; used by TestHTTPPool")
|
||||
)
|
||||
|
||||
func TestHTTPPool(t *testing.T) {
|
||||
if *peerChild {
|
||||
beChildForTestHTTPPool()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
const (
|
||||
nChild = 4
|
||||
nGets = 100
|
||||
)
|
||||
|
||||
var childAddr []string
|
||||
for i := 0; i < nChild; i++ {
|
||||
childAddr = append(childAddr, pickFreeAddr(t))
|
||||
}
|
||||
|
||||
var cmds []*exec.Cmd
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < nChild; i++ {
|
||||
cmd := exec.Command(os.Args[0],
|
||||
"--test.run=TestHTTPPool",
|
||||
"--test_peer_child",
|
||||
"--test_peer_addrs="+strings.Join(childAddr, ","),
|
||||
"--test_peer_index="+strconv.Itoa(i),
|
||||
)
|
||||
cmds = append(cmds, cmd)
|
||||
wg.Add(1)
|
||||
if err := cmd.Start(); err != nil {
|
||||
t.Fatal("failed to start child process: ", err)
|
||||
}
|
||||
go awaitAddrReady(t, childAddr[i], &wg)
|
||||
}
|
||||
defer func() {
|
||||
for i := 0; i < nChild; i++ {
|
||||
if cmds[i].Process != nil {
|
||||
cmds[i].Process.Kill()
|
||||
}
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
// Use a dummy self address so that we don't handle gets in-process.
|
||||
p := NewHTTPPool("should-be-ignored")
|
||||
p.Set(addrToURL(childAddr)...)
|
||||
|
||||
// Dummy getter function. Gets should go to children only.
|
||||
// The only time this process will handle a get is when the
|
||||
// children can't be contacted for some reason.
|
||||
getter := GetterFunc(func(ctx Context, key string, dest Sink) error {
|
||||
return errors.New("parent getter called; something's wrong")
|
||||
})
|
||||
g := NewGroup("httpPoolTest", 1<<20, getter)
|
||||
|
||||
for _, key := range testKeys(nGets) {
|
||||
var value string
|
||||
if err := g.Get(nil, key, StringSink(&value)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if suffix := ":" + key; !strings.HasSuffix(value, suffix) {
|
||||
t.Errorf("Get(%q) = %q, want value ending in %q", key, value, suffix)
|
||||
}
|
||||
t.Logf("Get key=%q, value=%q (peer:key)", key, value)
|
||||
}
|
||||
}
|
||||
|
||||
func testKeys(n int) (keys []string) {
|
||||
keys = make([]string, n)
|
||||
for i := range keys {
|
||||
keys[i] = strconv.Itoa(i)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func beChildForTestHTTPPool() {
|
||||
addrs := strings.Split(*peerAddrs, ",")
|
||||
|
||||
p := NewHTTPPool("http://" + addrs[*peerIndex])
|
||||
p.Set(addrToURL(addrs)...)
|
||||
|
||||
getter := GetterFunc(func(ctx Context, key string, dest Sink) error {
|
||||
dest.SetString(strconv.Itoa(*peerIndex) + ":" + key)
|
||||
return nil
|
||||
})
|
||||
NewGroup("httpPoolTest", 1<<20, getter)
|
||||
|
||||
log.Fatal(http.ListenAndServe(addrs[*peerIndex], p))
|
||||
}
|
||||
|
||||
// This is racy. Another process could swoop in and steal the port between the
|
||||
// call to this function and the next listen call. Should be okay though.
|
||||
// The proper way would be to pass the l.File() as ExtraFiles to the child
|
||||
// process, and then close your copy once the child starts.
|
||||
func pickFreeAddr(t *testing.T) string {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
return l.Addr().String()
|
||||
}
|
||||
|
||||
func addrToURL(addr []string) []string {
|
||||
url := make([]string, len(addr))
|
||||
for i := range addr {
|
||||
url[i] = "http://" + addr[i]
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
func awaitAddrReady(t *testing.T, addr string, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
const max = 1 * time.Second
|
||||
tries := 0
|
||||
for {
|
||||
tries++
|
||||
c, err := net.Dial("tcp", addr)
|
||||
if err == nil {
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
delay := time.Duration(tries) * 25 * time.Millisecond
|
||||
if delay > max {
|
||||
delay = max
|
||||
}
|
||||
time.Sleep(delay)
|
||||
}
|
||||
}
|
||||
97
vendor/github.com/golang/groupcache/lru/lru_test.go
generated
vendored
97
vendor/github.com/golang/groupcache/lru/lru_test.go
generated
vendored
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
Copyright 2013 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type simpleStruct struct {
|
||||
int
|
||||
string
|
||||
}
|
||||
|
||||
type complexStruct struct {
|
||||
int
|
||||
simpleStruct
|
||||
}
|
||||
|
||||
var getTests = []struct {
|
||||
name string
|
||||
keyToAdd interface{}
|
||||
keyToGet interface{}
|
||||
expectedOk bool
|
||||
}{
|
||||
{"string_hit", "myKey", "myKey", true},
|
||||
{"string_miss", "myKey", "nonsense", false},
|
||||
{"simple_struct_hit", simpleStruct{1, "two"}, simpleStruct{1, "two"}, true},
|
||||
{"simeple_struct_miss", simpleStruct{1, "two"}, simpleStruct{0, "noway"}, false},
|
||||
{"complex_struct_hit", complexStruct{1, simpleStruct{2, "three"}},
|
||||
complexStruct{1, simpleStruct{2, "three"}}, true},
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
for _, tt := range getTests {
|
||||
lru := New(0)
|
||||
lru.Add(tt.keyToAdd, 1234)
|
||||
val, ok := lru.Get(tt.keyToGet)
|
||||
if ok != tt.expectedOk {
|
||||
t.Fatalf("%s: cache hit = %v; want %v", tt.name, ok, !ok)
|
||||
} else if ok && val != 1234 {
|
||||
t.Fatalf("%s expected get to return 1234 but got %v", tt.name, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemove(t *testing.T) {
|
||||
lru := New(0)
|
||||
lru.Add("myKey", 1234)
|
||||
if val, ok := lru.Get("myKey"); !ok {
|
||||
t.Fatal("TestRemove returned no match")
|
||||
} else if val != 1234 {
|
||||
t.Fatalf("TestRemove failed. Expected %d, got %v", 1234, val)
|
||||
}
|
||||
|
||||
lru.Remove("myKey")
|
||||
if _, ok := lru.Get("myKey"); ok {
|
||||
t.Fatal("TestRemove returned a removed entry")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvict(t *testing.T) {
|
||||
evictedKeys := make([]Key, 0)
|
||||
onEvictedFun := func(key Key, value interface{}) {
|
||||
evictedKeys = append(evictedKeys, key)
|
||||
}
|
||||
|
||||
lru := New(20)
|
||||
lru.OnEvicted = onEvictedFun
|
||||
for i := 0; i < 22; i++ {
|
||||
lru.Add(fmt.Sprintf("myKey%d", i), 1234)
|
||||
}
|
||||
|
||||
if len(evictedKeys) != 2 {
|
||||
t.Fatalf("got %d evicted keys; want 2", len(evictedKeys))
|
||||
}
|
||||
if evictedKeys[0] != Key("myKey0") {
|
||||
t.Fatalf("got %v in first evicted key; want %s", evictedKeys[0], "myKey0")
|
||||
}
|
||||
if evictedKeys[1] != Key("myKey1") {
|
||||
t.Fatalf("got %v in second evicted key; want %s", evictedKeys[1], "myKey1")
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/golang/groupcache/sinks.go
generated
vendored
2
vendor/github.com/golang/groupcache/sinks.go
generated
vendored
|
|
@ -159,7 +159,7 @@ func ProtoSink(m proto.Message) Sink {
|
|||
}
|
||||
|
||||
type protoSink struct {
|
||||
dst proto.Message // authorative value
|
||||
dst proto.Message // authoritative value
|
||||
typ string
|
||||
|
||||
v ByteView // encoded
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue