From fbb51cdece179736abc3422849a0724cece2871b Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Sat, 12 May 2018 17:39:11 -0700 Subject: [PATCH 01/12] Add travis.yml This will run automated tests against PR's for the groupcache library. --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..ef6e6763 --- /dev/null +++ b/.travis.yml @@ -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 From 3fbe15d760cbf95787e9da4d16691f243fd13cdf Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Mon, 24 Sep 2018 14:43:12 -0400 Subject: [PATCH 02/12] Fix typo in test name. --- lru/lru_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lru/lru_test.go b/lru/lru_test.go index b7d9d8ac..a14f439e 100644 --- a/lru/lru_test.go +++ b/lru/lru_test.go @@ -40,7 +40,7 @@ var getTests = []struct { {"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}, + {"simple_struct_miss", simpleStruct{1, "two"}, simpleStruct{0, "noway"}, false}, {"complex_struct_hit", complexStruct{1, simpleStruct{2, "three"}}, complexStruct{1, simpleStruct{2, "three"}}, true}, } From d7bca77b06f3e5afbc04db44d04cc0cc7545a084 Mon Sep 17 00:00:00 2001 From: Harald Nordgren Date: Sat, 20 Oct 2018 01:13:27 +0200 Subject: [PATCH 03/12] Bump Travis versions --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index ef6e6763..67492579 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ script: go: - 1.9.x - 1.10.x + - 1.11.x - master cache: From 5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b Mon Sep 17 00:00:00 2001 From: Sean Chen <40845434+two@users.noreply.github.com> Date: Tue, 29 Jan 2019 23:46:38 +0800 Subject: [PATCH 04/12] lru: fix misspelling (#112) --- lru/lru.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lru/lru.go b/lru/lru.go index 532cc45e..eac1c766 100644 --- a/lru/lru.go +++ b/lru/lru.go @@ -25,7 +25,7 @@ type Cache struct { // an item is evicted. Zero means no limit. MaxEntries int - // OnEvicted optionally specificies a callback function to be + // OnEvicted optionally specifies a callback function to be // executed when an entry is purged from the cache. OnEvicted func(key Key, value interface{}) From 869f871628b6baa9cfbc11732cdf6546b17c1298 Mon Sep 17 00:00:00 2001 From: maru <1249107551@qq.com> Date: Mon, 1 Jul 2019 18:44:52 +0800 Subject: [PATCH 05/12] groupcache.go: fix misspelling --- groupcache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groupcache.go b/groupcache.go index 316ca494..8cf714a9 100644 --- a/groupcache.go +++ b/groupcache.go @@ -245,7 +245,7 @@ func (g *Group) load(ctx Context, key string, dest Sink) (value ByteView, destPo // be only one entry for this key. // // Consider the following serialized event ordering for two - // goroutines in which this callback gets called twice for hte + // goroutines in which this callback gets called twice for the // same key: // 1: Get("key") // 2: Get("key") From 404acd9df4cc9859d64fb9eed42e5c026187287a Mon Sep 17 00:00:00 2001 From: Solomon Boulos Date: Wed, 2 Oct 2019 12:53:25 -0700 Subject: [PATCH 06/12] Make it clearer that groupcache is distributed --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 70c29da1..e4337ad3 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ ## Summary -groupcache is a caching and cache-filling library, intended as a -replacement for memcached in many cases. +groupcache is a distributed caching and cache-filling library, intended as a +replacement for a pool of memcached nodes in many cases. For API docs and examples, see http://godoc.org/github.com/golang/groupcache @@ -17,7 +17,8 @@ For API docs and examples, see http://godoc.org/github.com/golang/groupcache * does not require running a separate set of servers, thus massively reducing deployment/configuration pain. groupcache is a client - library as well as a server. It connects to its own peers. + library as well as a server. It connects to its own peers, forming + a distributed cache. * comes with a cache filling mechanism. Whereas memcached just says "Sorry, cache miss", often resulting in a thundering herd of From 4a4ac3fbac33b83bb138f808c8945a2812023fc4 Mon Sep 17 00:00:00 2001 From: CodeLingo Bot Date: Wed, 13 Feb 2019 00:48:11 +0000 Subject: [PATCH 07/12] Fix function comments based on best practices from Effective Go Signed-off-by: CodeLingo Bot --- consistenthash/consistenthash.go | 6 +++--- groupcache_test.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/consistenthash/consistenthash.go b/consistenthash/consistenthash.go index a9c56f07..da139094 100644 --- a/consistenthash/consistenthash.go +++ b/consistenthash/consistenthash.go @@ -44,12 +44,12 @@ func New(replicas int, fn Hash) *Map { return m } -// Returns true if there are no items available. +// IsEmpty returns true if there are no items available. func (m *Map) IsEmpty() bool { return len(m.keys) == 0 } -// Adds some keys to the hash. +// Add adds some keys to the hash. func (m *Map) Add(keys ...string) { for _, key := range keys { for i := 0; i < m.replicas; i++ { @@ -61,7 +61,7 @@ func (m *Map) Add(keys ...string) { sort.Ints(m.keys) } -// Gets the closest item in the hash to the provided key. +// Get gets the closest item in the hash to the provided key. func (m *Map) Get(key string) string { if m.IsEmpty() { return "" diff --git a/groupcache_test.go b/groupcache_test.go index ea05cac4..ffbd0b9b 100644 --- a/groupcache_test.go +++ b/groupcache_test.go @@ -78,7 +78,7 @@ func testSetup() { })) } -// tests that a Getter's Get method is only called once with two +// TestGetDupSuppressString 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) @@ -120,7 +120,7 @@ func TestGetDupSuppressString(t *testing.T) { } } -// tests that a Getter's Get method is only called once with two +// TestGetDupSuppressProto 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) @@ -249,7 +249,7 @@ func (p fakePeers) PickPeer(key string) (peer ProtoGetter, ok bool) { return p[n], p[n] != nil } -// tests that peers (virtual, in-process) are hit, and how much. +// TestPeers tests that peers (virtual, in-process) are hit, and how much. func TestPeers(t *testing.T) { once.Do(testSetup) rand.Seed(123) From 611e8accdfc92c4187d399e95ce826046d4c8d73 Mon Sep 17 00:00:00 2001 From: Aditya Harindar Date: Mon, 28 Oct 2019 02:51:12 +0530 Subject: [PATCH 08/12] format error string as per go style (#127) --- singleflight/singleflight_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/singleflight/singleflight_test.go b/singleflight/singleflight_test.go index 47b4d3dc..f1b6e117 100644 --- a/singleflight/singleflight_test.go +++ b/singleflight/singleflight_test.go @@ -40,7 +40,7 @@ func TestDo(t *testing.T) { func TestDoErr(t *testing.T) { var g Group - someErr := errors.New("Some error") + someErr := errors.New("some error") v, err := g.Do("key", func() (interface{}, error) { return nil, someErr }) From 215e87163ea771ffa998a96c611387313bb5a403 Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Thu, 26 Dec 2019 21:28:52 -0800 Subject: [PATCH 09/12] use std library context.Context (#131) Signed-off-by: Bobby DeSimone --- groupcache.go | 15 ++++++++------- groupcache_test.go | 13 +++++++------ http.go | 15 +++++++++------ http_test.go | 5 +++-- peers.go | 9 +++------ 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/groupcache.go b/groupcache.go index 8cf714a9..9e81087b 100644 --- a/groupcache.go +++ b/groupcache.go @@ -25,6 +25,7 @@ limitations under the License. package groupcache import ( + "context" "errors" "math/rand" "strconv" @@ -44,13 +45,13 @@ type Getter interface { // uniquely describe the loaded data, without an implicit // current time, and without relying on cache expiration // mechanisms. - Get(ctx Context, key string, dest Sink) error + Get(ctx context.Context, key string, dest Sink) error } // A GetterFunc implements Getter with a function. -type GetterFunc func(ctx Context, key string, dest Sink) error +type GetterFunc func(ctx context.Context, key string, dest Sink) error -func (f GetterFunc) Get(ctx Context, key string, dest Sink) error { +func (f GetterFunc) Get(ctx context.Context, key string, dest Sink) error { return f(ctx, key, dest) } @@ -204,7 +205,7 @@ func (g *Group) initPeers() { } } -func (g *Group) Get(ctx Context, key string, dest Sink) error { +func (g *Group) Get(ctx context.Context, key string, dest Sink) error { g.peersOnce.Do(g.initPeers) g.Stats.Gets.Add(1) if dest == nil { @@ -233,7 +234,7 @@ func (g *Group) Get(ctx Context, key string, dest Sink) error { } // load loads key either by invoking the getter locally or by sending it to another machine. -func (g *Group) load(ctx Context, key string, dest Sink) (value ByteView, destPopulated bool, err error) { +func (g *Group) load(ctx context.Context, key string, dest Sink) (value ByteView, destPopulated bool, err error) { g.Stats.Loads.Add(1) viewi, err := g.loadGroup.Do(key, func() (interface{}, error) { // Check the cache again because singleflight can only dedup calls @@ -292,7 +293,7 @@ func (g *Group) load(ctx Context, key string, dest Sink) (value ByteView, destPo return } -func (g *Group) getLocally(ctx Context, key string, dest Sink) (ByteView, error) { +func (g *Group) getLocally(ctx context.Context, key string, dest Sink) (ByteView, error) { err := g.getter.Get(ctx, key, dest) if err != nil { return ByteView{}, err @@ -300,7 +301,7 @@ func (g *Group) getLocally(ctx Context, key string, dest Sink) (ByteView, error) return dest.view() } -func (g *Group) getFromPeer(ctx Context, peer ProtoGetter, key string) (ByteView, error) { +func (g *Group) getFromPeer(ctx context.Context, peer ProtoGetter, key string) (ByteView, error) { req := &pb.GetRequest{ Group: &g.name, Key: &key, diff --git a/groupcache_test.go b/groupcache_test.go index ffbd0b9b..85bcc564 100644 --- a/groupcache_test.go +++ b/groupcache_test.go @@ -19,6 +19,7 @@ limitations under the License. package groupcache import ( + "context" "errors" "fmt" "hash/crc32" @@ -41,7 +42,7 @@ var ( stringc = make(chan string) - dummyCtx Context + dummyCtx = context.TODO() // cacheFills is the number of times stringGroup or // protoGroup's Getter have been called. Read using the @@ -58,7 +59,7 @@ const ( ) func testSetup() { - stringGroup = NewGroup(stringGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error { + stringGroup = NewGroup(stringGroupName, cacheSize, GetterFunc(func(_ context.Context, key string, dest Sink) error { if key == fromChan { key = <-stringc } @@ -66,7 +67,7 @@ func testSetup() { return dest.SetString("ECHO:" + key) })) - protoGroup = NewGroup(protoGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error { + protoGroup = NewGroup(protoGroupName, cacheSize, GetterFunc(func(_ context.Context, key string, dest Sink) error { if key == fromChan { key = <-stringc } @@ -230,7 +231,7 @@ type fakePeer struct { fail bool } -func (p *fakePeer) Get(_ Context, in *pb.GetRequest, out *pb.GetResponse) error { +func (p *fakePeer) Get(_ context.Context, in *pb.GetRequest, out *pb.GetResponse) error { p.hits++ if p.fail { return errors.New("simulated error from peer") @@ -259,7 +260,7 @@ func TestPeers(t *testing.T) { peerList := fakePeers([]ProtoGetter{peer0, peer1, peer2, nil}) const cacheSize = 0 // disabled localHits := 0 - getter := func(_ Context, key string, dest Sink) error { + getter := func(_ context.Context, key string, dest Sink) error { localHits++ return dest.SetString("got:" + key) } @@ -387,7 +388,7 @@ func (g *orderedFlightGroup) Do(key string, fn func() (interface{}, error)) (int func TestNoDedup(t *testing.T) { const testkey = "testkey" const testval = "testval" - g := newGroup("testgroup", 1024, GetterFunc(func(_ Context, key string, dest Sink) error { + g := newGroup("testgroup", 1024, GetterFunc(func(_ context.Context, key string, dest Sink) error { return dest.SetString(testval) }), nil) diff --git a/http.go b/http.go index f37467a7..56c94062 100644 --- a/http.go +++ b/http.go @@ -18,6 +18,7 @@ package groupcache import ( "bytes" + "context" "fmt" "io" "net/http" @@ -38,13 +39,13 @@ const defaultReplicas = 50 type HTTPPool struct { // Context optionally specifies a context for the server to use when it // receives a request. - // If nil, the server uses a nil Context. - Context func(*http.Request) Context + // If nil, the server uses the request's context + Context func(*http.Request) context.Context // Transport optionally specifies an http.RoundTripper for the client // to use when it makes a request. // If nil, the client uses http.DefaultTransport. - Transport func(Context) http.RoundTripper + Transport func(context.Context) http.RoundTripper // this peer's base URL, e.g. "https://example.net:8000" self string @@ -157,9 +158,11 @@ func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Error(w, "no such group: "+groupName, http.StatusNotFound) return } - var ctx Context + var ctx context.Context if p.Context != nil { ctx = p.Context(r) + } else { + ctx = r.Context() } group.Stats.ServerRequests.Add(1) @@ -181,7 +184,7 @@ func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) { } type httpGetter struct { - transport func(Context) http.RoundTripper + transport func(context.Context) http.RoundTripper baseURL string } @@ -189,7 +192,7 @@ var bufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } -func (h *httpGetter) Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error { +func (h *httpGetter) Get(context context.Context, in *pb.GetRequest, out *pb.GetResponse) error { u := fmt.Sprintf( "%v%v/%v", h.baseURL, diff --git a/http_test.go b/http_test.go index b42edd7f..e2c9093f 100644 --- a/http_test.go +++ b/http_test.go @@ -17,6 +17,7 @@ limitations under the License. package groupcache import ( + "context" "errors" "flag" "log" @@ -85,7 +86,7 @@ func TestHTTPPool(t *testing.T) { // 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 { + getter := GetterFunc(func(ctx context.Context, key string, dest Sink) error { return errors.New("parent getter called; something's wrong") }) g := NewGroup("httpPoolTest", 1<<20, getter) @@ -116,7 +117,7 @@ func beChildForTestHTTPPool() { p := NewHTTPPool("http://" + addrs[*peerIndex]) p.Set(addrToURL(addrs)...) - getter := GetterFunc(func(ctx Context, key string, dest Sink) error { + getter := GetterFunc(func(ctx context.Context, key string, dest Sink) error { dest.SetString(strconv.Itoa(*peerIndex) + ":" + key) return nil }) diff --git a/peers.go b/peers.go index 1625ff04..f42e9070 100644 --- a/peers.go +++ b/peers.go @@ -19,17 +19,14 @@ limitations under the License. package groupcache import ( + "context" + pb "github.com/golang/groupcache/groupcachepb" ) -// Context is an opaque value passed through calls to the -// ProtoGetter. It may be nil if your ProtoGetter implementation does -// not require a context. -type Context interface{} - // ProtoGetter is the interface that must be implemented by a peer. type ProtoGetter interface { - Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error + Get(context context.Context, in *pb.GetRequest, out *pb.GetResponse) error } // PeerPicker is the interface that must be implemented to locate From 8c9f03a8e57eb486e42badaed3fb287da51807ba Mon Sep 17 00:00:00 2001 From: Bobby DeSimone Date: Mon, 20 Jan 2020 20:51:36 -0800 Subject: [PATCH 10/12] http: make http client request with context (#132) * http: make request with context - use ctx naming convention - use context.TODO() instead of nil Signed-off-by: Bobby DeSimone --- http.go | 5 +++-- http_test.go | 2 +- peers.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/http.go b/http.go index 56c94062..e0d391a5 100644 --- a/http.go +++ b/http.go @@ -192,7 +192,7 @@ var bufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } -func (h *httpGetter) Get(context context.Context, in *pb.GetRequest, out *pb.GetResponse) error { +func (h *httpGetter) Get(ctx context.Context, in *pb.GetRequest, out *pb.GetResponse) error { u := fmt.Sprintf( "%v%v/%v", h.baseURL, @@ -203,9 +203,10 @@ func (h *httpGetter) Get(context context.Context, in *pb.GetRequest, out *pb.Get if err != nil { return err } + req = req.WithContext(ctx) tr := http.DefaultTransport if h.transport != nil { - tr = h.transport(context) + tr = h.transport(ctx) } res, err := tr.RoundTrip(req) if err != nil { diff --git a/http_test.go b/http_test.go index e2c9093f..132c1173 100644 --- a/http_test.go +++ b/http_test.go @@ -93,7 +93,7 @@ func TestHTTPPool(t *testing.T) { for _, key := range testKeys(nGets) { var value string - if err := g.Get(nil, key, StringSink(&value)); err != nil { + if err := g.Get(context.TODO(), key, StringSink(&value)); err != nil { t.Fatal(err) } if suffix := ":" + key; !strings.HasSuffix(value, suffix) { diff --git a/peers.go b/peers.go index f42e9070..33e1fba8 100644 --- a/peers.go +++ b/peers.go @@ -26,7 +26,7 @@ import ( // ProtoGetter is the interface that must be implemented by a peer. type ProtoGetter interface { - Get(context context.Context, in *pb.GetRequest, out *pb.GetResponse) error + Get(ctx context.Context, in *pb.GetRequest, out *pb.GetResponse) error } // PeerPicker is the interface that must be implemented to locate From 41bb18bfe9da5321badc438f91158cd790a33aa3 Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Wed, 31 Mar 2021 15:47:55 -0700 Subject: [PATCH 11/12] add back Context type as alias to context.Context (#148) Pull request #131 deleted the Context declaration, which broke most usages of this package since users needed to implement the interfaces mentioned in this package by referencing the groupcache.Context type. However, that type was removed from peers.go in the mentioned pull request. Technically, #131 is a breaking change since groupcache.Context was an interface{}, and the PR switched it to be context.Context. Fortunately, it seems that all users are passing a context.Context anyways so that the type safety just checks out. However, most users are still referencing groupcache.Context. --- peers.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/peers.go b/peers.go index 33e1fba8..552c0aee 100644 --- a/peers.go +++ b/peers.go @@ -24,6 +24,9 @@ import ( pb "github.com/golang/groupcache/groupcachepb" ) +// Context is an alias to context.Context for backwards compatibility purposes. +type Context = context.Context + // ProtoGetter is the interface that must be implemented by a peer. type ProtoGetter interface { Get(ctx context.Context, in *pb.GetRequest, out *pb.GetResponse) error From 2c02b8208cf8c02a3e358cb1d9b60950647543fc Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 29 Nov 2024 13:07:26 -0800 Subject: [PATCH 12/12] groupcache: add go.mod, update for Go 1.24 (#175) Add a go.mod file As of Go 1.24 rand.Seed is a no-op. Change TestPeers to use an explicit rand.Rand instead. --- go.mod | 7 +++++++ go.sum | 6 ++++++ groupcache.go | 12 +++++++++++- groupcache_test.go | 2 +- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..e5c26dca --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module github.com/golang/groupcache + +go 1.20 + +require github.com/golang/protobuf v1.5.4 + +require google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..bc2601b8 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/groupcache.go b/groupcache.go index 9e81087b..bc123f1d 100644 --- a/groupcache.go +++ b/groupcache.go @@ -171,6 +171,10 @@ type Group struct { // Stats are statistics on the group. Stats Stats + + // rand is only non-nil when testing, + // to get predictable results in TestPeers. + rand *rand.Rand } // flightGroup is defined as an interface which flightgroup.Group @@ -315,7 +319,13 @@ func (g *Group) getFromPeer(ctx context.Context, peer ProtoGetter, key string) ( // TODO(bradfitz): use res.MinuteQps or something smart to // conditionally populate hotCache. For now just do it some // percentage of the time. - if rand.Intn(10) == 0 { + var pop bool + if g.rand != nil { + pop = g.rand.Intn(10) == 0 + } else { + pop = rand.Intn(10) == 0 + } + if pop { g.populateCache(key, value, &g.hotCache) } return value, nil diff --git a/groupcache_test.go b/groupcache_test.go index 85bcc564..1bfe278c 100644 --- a/groupcache_test.go +++ b/groupcache_test.go @@ -253,7 +253,6 @@ func (p fakePeers) PickPeer(key string) (peer ProtoGetter, ok bool) { // TestPeers 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{} @@ -265,6 +264,7 @@ func TestPeers(t *testing.T) { return dest.SetString("got:" + key) } testGroup := newGroup("TestPeers-group", cacheSize, GetterFunc(getter), peerList) + testGroup.rand = rand.New(rand.NewSource(123)) run := func(name string, n int, wantSummary string) { // Reset counters localHits = 0