sync: resync vendor folder

This commit is contained in:
Kubernetes Publisher 2017-06-13 20:39:14 +00:00
parent 5990d225d9
commit 83b4b27326
3 changed files with 148 additions and 74 deletions

120
Godeps/Godeps.json generated
View File

@ -8,14 +8,17 @@
"Deps": [
{
"ImportPath": "cloud.google.com/go/compute/metadata",
"Comment": "v0.1.0-115-g3b1ae45",
"Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821"
},
{
"ImportPath": "cloud.google.com/go/internal",
"Comment": "v0.1.0-115-g3b1ae45",
"Rev": "3b1ae45394a234c385be014e9a488f2bb6eef821"
},
{
"ImportPath": "github.com/PuerkitoBio/purell",
"Comment": "v1.0.0",
"Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4"
},
{
@ -44,14 +47,17 @@
},
{
"ImportPath": "github.com/coreos/pkg/health",
"Comment": "v2-8-gfa29b1d",
"Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8"
},
{
"ImportPath": "github.com/coreos/pkg/httputil",
"Comment": "v2-8-gfa29b1d",
"Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8"
},
{
"ImportPath": "github.com/coreos/pkg/timeutil",
"Comment": "v2-8-gfa29b1d",
"Rev": "fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8"
},
{
@ -60,10 +66,12 @@
},
{
"ImportPath": "github.com/docker/distribution/digest",
"Comment": "v2.4.0-rc.1-38-gcd27f17",
"Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51"
},
{
"ImportPath": "github.com/docker/distribution/reference",
"Comment": "v2.4.0-rc.1-38-gcd27f17",
"Rev": "cd27f179f2c10c5d300e6d09025b538c475b0d51"
},
{
@ -76,14 +84,17 @@
},
{
"ImportPath": "github.com/emicklei/go-restful",
"Comment": "2.2.0-4-gff4f55a",
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
},
{
"ImportPath": "github.com/emicklei/go-restful-swagger12",
"Comment": "1.0.1",
"Rev": "dcef7f55730566d41eae5db10e7d6981829720f6"
},
{
"ImportPath": "github.com/emicklei/go-restful/log",
"Comment": "2.2.0-4-gff4f55a",
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
},
{
@ -116,10 +127,12 @@
},
{
"ImportPath": "github.com/gogo/protobuf/proto",
"Comment": "v0.4-3-gc0656ed",
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
},
{
"ImportPath": "github.com/gogo/protobuf/sortkeys",
"Comment": "v0.4-3-gc0656ed",
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
},
{
@ -152,6 +165,7 @@
},
{
"ImportPath": "github.com/imdario/mergo",
"Comment": "0.1.3-8-g6633656",
"Rev": "6633656539c1639d9d78127b7d47c622b5d7b6dc"
},
{
@ -184,6 +198,7 @@
},
{
"ImportPath": "github.com/stretchr/testify/assert",
"Comment": "v1.0-88-ge3a8ff8",
"Rev": "e3a8ff8ce36581f87a15341206f205b1da467059"
},
{
@ -284,6 +299,7 @@
},
{
"ImportPath": "gopkg.in/inf.v0",
"Comment": "v0.9.0",
"Rev": "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
},
{
@ -292,211 +308,211 @@
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/announced",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apimachinery/registered",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1alpha1",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/unstructured",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/openapi",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/rand",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"Rev": "cff8db64dd5b6fb0166dc2cf36e39c7ff4fe48c8"
}
]
}

View File

@ -7,9 +7,14 @@ import (
"os"
)
var defaultGetCh = func() (byte, error) {
type FdReader interface {
io.Reader
Fd() uintptr
}
var defaultGetCh = func(r io.Reader) (byte, error) {
buf := make([]byte, 1)
if n, err := os.Stdin.Read(buf); n == 0 || err != nil {
if n, err := r.Read(buf); n == 0 || err != nil {
if err != nil {
return 0, err
}
@ -28,9 +33,10 @@ var (
)
// getPasswd returns the input read from terminal.
// If prompt is not empty, it will be output as a prompt to the user
// If masked is true, typing will be matched by asterisks on the screen.
// Otherwise, typing will echo nothing.
func getPasswd(masked bool) ([]byte, error) {
func getPasswd(prompt string, masked bool, r FdReader, w io.Writer) ([]byte, error) {
var err error
var pass, bs, mask []byte
if masked {
@ -38,26 +44,33 @@ func getPasswd(masked bool) ([]byte, error) {
mask = []byte("*")
}
if isTerminal(os.Stdin.Fd()) {
if oldState, err := makeRaw(os.Stdin.Fd()); err != nil {
if isTerminal(r.Fd()) {
if oldState, err := makeRaw(r.Fd()); err != nil {
return pass, err
} else {
defer restore(os.Stdin.Fd(), oldState)
defer func() {
restore(r.Fd(), oldState)
fmt.Fprintln(w)
}()
}
}
if prompt != "" {
fmt.Fprint(w, prompt)
}
// Track total bytes read, not just bytes in the password. This ensures any
// errors that might flood the console with nil or -1 bytes infinitely are
// capped.
var counter int
for counter = 0; counter <= maxLength; counter++ {
if v, e := getch(); e != nil {
if v, e := getch(r); e != nil {
err = e
break
} else if v == 127 || v == 8 {
if l := len(pass); l > 0 {
pass = pass[:l-1]
fmt.Print(string(bs))
fmt.Fprint(w, string(bs))
}
} else if v == 13 || v == 10 {
break
@ -66,7 +79,7 @@ func getPasswd(masked bool) ([]byte, error) {
break
} else if v != 0 {
pass = append(pass, v)
fmt.Print(string(mask))
fmt.Fprint(w, string(mask))
}
}
@ -74,18 +87,24 @@ func getPasswd(masked bool) ([]byte, error) {
err = ErrMaxLengthExceeded
}
fmt.Println()
return pass, err
}
// GetPasswd returns the password read from the terminal without echoing input.
// The returned byte array does not include end-of-line characters.
func GetPasswd() ([]byte, error) {
return getPasswd(false)
return getPasswd("", false, os.Stdin, os.Stdout)
}
// GetPasswdMasked returns the password read from the terminal, echoing asterisks.
// The returned byte array does not include end-of-line characters.
func GetPasswdMasked() ([]byte, error) {
return getPasswd(true)
return getPasswd("", true, os.Stdin, os.Stdout)
}
// GetPasswdPrompt prompts the user and returns the password read from the terminal.
// If mask is true, then asterisks are echoed.
// The returned byte array does not include end-of-line characters.
func GetPasswdPrompt(prompt string, mask bool, r FdReader, w io.Writer) ([]byte, error) {
return getPasswd(prompt, mask, r, w)
}

View File

@ -2,7 +2,7 @@
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
// The ratelimit package provides an efficient token bucket implementation
// Package ratelimit provides an efficient token bucket implementation
// that can be used to limit the rate of arbitrary things.
// See http://en.wikipedia.org/wiki/Token_bucket.
package ratelimit
@ -21,6 +21,7 @@ type Bucket struct {
capacity int64
quantum int64
fillInterval time.Duration
clock Clock
// The mutex guards the fields following it.
mu sync.Mutex
@ -33,12 +34,37 @@ type Bucket struct {
availTick int64
}
// Clock is used to inject testable fakes.
type Clock interface {
Now() time.Time
Sleep(d time.Duration)
}
// realClock implements Clock in terms of standard time functions.
type realClock struct{}
// Now is identical to time.Now.
func (realClock) Now() time.Time {
return time.Now()
}
// Sleep is identical to time.Sleep.
func (realClock) Sleep(d time.Duration) {
time.Sleep(d)
}
// NewBucket returns a new token bucket that fills at the
// rate of one token every fillInterval, up to the given
// maximum capacity. Both arguments must be
// positive. The bucket is initially full.
func NewBucket(fillInterval time.Duration, capacity int64) *Bucket {
return NewBucketWithQuantum(fillInterval, capacity, 1)
return NewBucketWithClock(fillInterval, capacity, realClock{})
}
// NewBucketWithClock is identical to NewBucket but injects a testable clock
// interface.
func NewBucketWithClock(fillInterval time.Duration, capacity int64, clock Clock) *Bucket {
return NewBucketWithQuantumAndClock(fillInterval, capacity, 1, clock)
}
// rateMargin specifes the allowed variance of actual
@ -51,12 +77,18 @@ const rateMargin = 0.01
// at high rates, the actual rate may be up to 1% different from the
// specified rate.
func NewBucketWithRate(rate float64, capacity int64) *Bucket {
return NewBucketWithRateAndClock(rate, capacity, realClock{})
}
// NewBucketWithRateAndClock is identical to NewBucketWithRate but injects a
// testable clock interface.
func NewBucketWithRateAndClock(rate float64, capacity int64, clock Clock) *Bucket {
for quantum := int64(1); quantum < 1<<50; quantum = nextQuantum(quantum) {
fillInterval := time.Duration(1e9 * float64(quantum) / rate)
if fillInterval <= 0 {
continue
}
tb := NewBucketWithQuantum(fillInterval, capacity, quantum)
tb := NewBucketWithQuantumAndClock(fillInterval, capacity, quantum, clock)
if diff := math.Abs(tb.Rate() - rate); diff/rate <= rateMargin {
return tb
}
@ -79,6 +111,12 @@ func nextQuantum(q int64) int64 {
// the specification of the quantum size - quantum tokens
// are added every fillInterval.
func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *Bucket {
return NewBucketWithQuantumAndClock(fillInterval, capacity, quantum, realClock{})
}
// NewBucketWithQuantumAndClock is identical to NewBucketWithQuantum but injects
// a testable clock interface.
func NewBucketWithQuantumAndClock(fillInterval time.Duration, capacity, quantum int64, clock Clock) *Bucket {
if fillInterval <= 0 {
panic("token bucket fill interval is not > 0")
}
@ -89,7 +127,8 @@ func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *
panic("token bucket quantum is not > 0")
}
return &Bucket{
startTime: time.Now(),
clock: clock,
startTime: clock.Now(),
capacity: capacity,
quantum: quantum,
avail: capacity,
@ -101,7 +140,7 @@ func NewBucketWithQuantum(fillInterval time.Duration, capacity, quantum int64) *
// available.
func (tb *Bucket) Wait(count int64) {
if d := tb.Take(count); d > 0 {
time.Sleep(d)
tb.clock.Sleep(d)
}
}
@ -113,7 +152,7 @@ func (tb *Bucket) Wait(count int64) {
func (tb *Bucket) WaitMaxDuration(count int64, maxWait time.Duration) bool {
d, ok := tb.TakeMaxDuration(count, maxWait)
if d > 0 {
time.Sleep(d)
tb.clock.Sleep(d)
}
return ok
}
@ -127,7 +166,7 @@ const infinityDuration time.Duration = 0x7fffffffffffffff
// Note that if the request is irrevocable - there is no way to return
// tokens to the bucket once this method commits us to taking them.
func (tb *Bucket) Take(count int64) time.Duration {
d, _ := tb.take(time.Now(), count, infinityDuration)
d, _ := tb.take(tb.clock.Now(), count, infinityDuration)
return d
}
@ -141,14 +180,14 @@ func (tb *Bucket) Take(count int64) time.Duration {
// wait until the tokens are actually available, and reports
// true.
func (tb *Bucket) TakeMaxDuration(count int64, maxWait time.Duration) (time.Duration, bool) {
return tb.take(time.Now(), count, maxWait)
return tb.take(tb.clock.Now(), count, maxWait)
}
// TakeAvailable takes up to count immediately available tokens from the
// bucket. It returns the number of tokens removed, or zero if there are
// no available tokens. It does not block.
func (tb *Bucket) TakeAvailable(count int64) int64 {
return tb.takeAvailable(time.Now(), count)
return tb.takeAvailable(tb.clock.Now(), count)
}
// takeAvailable is the internal version of TakeAvailable - it takes the
@ -178,7 +217,7 @@ func (tb *Bucket) takeAvailable(now time.Time, count int64) int64 {
// tokens could have changed in the meantime. This method is intended
// primarily for metrics reporting and debugging.
func (tb *Bucket) Available() int64 {
return tb.available(time.Now())
return tb.available(tb.clock.Now())
}
// available is the internal version of available - it takes the current time as