add go.mod
This commit is contained in:
18
go.mod
Normal file
18
go.mod
Normal file
@ -0,0 +1,18 @@
|
||||
module github.com/eyedeekay/i2p-tools-1
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/MDrollette/i2p-tools v0.0.0-20171015191648-e7d4585361c2
|
||||
github.com/codegangsta/cli v1.20.0
|
||||
github.com/cretz/bine v0.1.0
|
||||
github.com/garyburd/redigo v1.1.0 // indirect
|
||||
github.com/gomodule/redigo v2.0.0+incompatible // indirect
|
||||
github.com/gorilla/handlers v1.2.1
|
||||
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad // indirect
|
||||
github.com/justinas/alice v0.0.0-20160910103822-1051eaf52fca
|
||||
github.com/throttled/throttled v2.2.4+incompatible
|
||||
golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf // indirect
|
||||
golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9 // indirect
|
||||
gopkg.in/throttled/throttled.v2 v2.0.3 // indirect
|
||||
)
|
59
vendor/gopkg.in/throttled/throttled.v2/deprecated_test.go
generated
vendored
59
vendor/gopkg.in/throttled/throttled.v2/deprecated_test.go
generated
vendored
@ -1,59 +0,0 @@
|
||||
package throttled_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2"
|
||||
"gopkg.in/throttled/throttled.v2/store"
|
||||
)
|
||||
|
||||
// Ensure that the current implementation remains compatible with the
|
||||
// supported but deprecated usage until the next major version.
|
||||
func TestDeprecatedUsage(t *testing.T) {
|
||||
// Declare interfaces to statically check that names haven't changed
|
||||
var st throttled.Store
|
||||
var thr *throttled.Throttler
|
||||
var q throttled.Quota
|
||||
|
||||
st = store.NewMemStore(100)
|
||||
vary := &throttled.VaryBy{Path: true}
|
||||
q = throttled.PerMin(2)
|
||||
thr = throttled.RateLimit(q, vary, st)
|
||||
handler := thr.Throttle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
|
||||
cases := []struct {
|
||||
path string
|
||||
code int
|
||||
headers map[string]string
|
||||
}{
|
||||
{"/foo", 200, map[string]string{"X-Ratelimit-Limit": "2", "X-Ratelimit-Remaining": "1", "X-Ratelimit-Reset": "30"}},
|
||||
{"/foo", 200, map[string]string{"X-Ratelimit-Limit": "2", "X-Ratelimit-Remaining": "0", "X-Ratelimit-Reset": "60"}},
|
||||
{"/foo", 429, map[string]string{"X-Ratelimit-Limit": "2", "X-Ratelimit-Remaining": "0", "X-Ratelimit-Reset": "60", "Retry-After": "30"}},
|
||||
{"/bar", 200, map[string]string{"X-Ratelimit-Limit": "2", "X-Ratelimit-Remaining": "1", "X-Ratelimit-Reset": "30"}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
req, err := http.NewRequest("GET", c.path, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler.ServeHTTP(rr, req)
|
||||
if have, want := rr.Code, c.code; have != want {
|
||||
t.Errorf("Expected request %d at %s to return %d but got %d",
|
||||
i, c.path, want, have)
|
||||
}
|
||||
|
||||
for name, want := range c.headers {
|
||||
if have := rr.HeaderMap.Get(name); have != want {
|
||||
t.Errorf("Expected request %d at %s to have header '%s: %s' but got '%s'",
|
||||
i, c.path, name, want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
103
vendor/gopkg.in/throttled/throttled.v2/example_test.go
generated
vendored
103
vendor/gopkg.in/throttled/throttled.v2/example_test.go
generated
vendored
@ -1,103 +0,0 @@
|
||||
package throttled_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2"
|
||||
"gopkg.in/throttled/throttled.v2/store/memstore"
|
||||
)
|
||||
|
||||
var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("hi there!"))
|
||||
})
|
||||
|
||||
// ExampleHTTPRateLimiter demonstrates the usage of HTTPRateLimiter
|
||||
// for rate-limiting access to an http.Handler to 20 requests per path
|
||||
// per minute with a maximum burst of 5 requests.
|
||||
func ExampleHTTPRateLimiter() {
|
||||
store, err := memstore.New(65536)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Maximum burst of 5 which refills at 20 tokens per minute.
|
||||
quota := throttled.RateQuota{throttled.PerMin(20), 5}
|
||||
|
||||
rateLimiter, err := throttled.NewGCRARateLimiter(store, quota)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
httpRateLimiter := throttled.HTTPRateLimiter{
|
||||
RateLimiter: rateLimiter,
|
||||
VaryBy: &throttled.VaryBy{Path: true},
|
||||
}
|
||||
|
||||
http.ListenAndServe(":8080", httpRateLimiter.RateLimit(myHandler))
|
||||
}
|
||||
|
||||
// Demonstrates direct use of GCRARateLimiter's RateLimit function (and the
|
||||
// more general RateLimiter interface). This should be used anywhere where
|
||||
// granular control over rate limiting is required.
|
||||
func ExampleGCRARateLimiter() {
|
||||
store, err := memstore.New(65536)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Maximum burst of 5 which refills at 1 token per hour.
|
||||
quota := throttled.RateQuota{throttled.PerHour(1), 5}
|
||||
|
||||
rateLimiter, err := throttled.NewGCRARateLimiter(store, quota)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Bucket according to the number i / 10 (so 1 falls into the bucket 0
|
||||
// while 11 falls into the bucket 1). This has the effect of allowing a
|
||||
// burst of 5 plus 1 (a single emission interval) on every ten iterations
|
||||
// of the loop. See the output for better clarity here.
|
||||
//
|
||||
// We also refill the bucket at 1 token per hour, but that has no effect
|
||||
// for the purposes of this example.
|
||||
for i := 0; i < 20; i++ {
|
||||
bucket := fmt.Sprintf("by-order:%v", i/10)
|
||||
|
||||
limited, result, err := rateLimiter.RateLimit(bucket, 1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if limited {
|
||||
fmt.Printf("Iteration %2v; bucket %v: FAILED. Rate limit exceeded.\n",
|
||||
i, bucket)
|
||||
} else {
|
||||
fmt.Printf("Iteration %2v; bucket %v: Operation successful (remaining=%v).\n",
|
||||
i, bucket, result.Remaining)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Iteration 0; bucket by-order:0: Operation successful (remaining=5).
|
||||
// Iteration 1; bucket by-order:0: Operation successful (remaining=4).
|
||||
// Iteration 2; bucket by-order:0: Operation successful (remaining=3).
|
||||
// Iteration 3; bucket by-order:0: Operation successful (remaining=2).
|
||||
// Iteration 4; bucket by-order:0: Operation successful (remaining=1).
|
||||
// Iteration 5; bucket by-order:0: Operation successful (remaining=0).
|
||||
// Iteration 6; bucket by-order:0: FAILED. Rate limit exceeded.
|
||||
// Iteration 7; bucket by-order:0: FAILED. Rate limit exceeded.
|
||||
// Iteration 8; bucket by-order:0: FAILED. Rate limit exceeded.
|
||||
// Iteration 9; bucket by-order:0: FAILED. Rate limit exceeded.
|
||||
// Iteration 10; bucket by-order:1: Operation successful (remaining=5).
|
||||
// Iteration 11; bucket by-order:1: Operation successful (remaining=4).
|
||||
// Iteration 12; bucket by-order:1: Operation successful (remaining=3).
|
||||
// Iteration 13; bucket by-order:1: Operation successful (remaining=2).
|
||||
// Iteration 14; bucket by-order:1: Operation successful (remaining=1).
|
||||
// Iteration 15; bucket by-order:1: Operation successful (remaining=0).
|
||||
// Iteration 16; bucket by-order:1: FAILED. Rate limit exceeded.
|
||||
// Iteration 17; bucket by-order:1: FAILED. Rate limit exceeded.
|
||||
// Iteration 18; bucket by-order:1: FAILED. Rate limit exceeded.
|
||||
// Iteration 19; bucket by-order:1: FAILED. Rate limit exceeded.
|
||||
}
|
99
vendor/gopkg.in/throttled/throttled.v2/http_test.go
generated
vendored
99
vendor/gopkg.in/throttled/throttled.v2/http_test.go
generated
vendored
@ -1,99 +0,0 @@
|
||||
package throttled_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2"
|
||||
)
|
||||
|
||||
type stubLimiter struct {
|
||||
}
|
||||
|
||||
func (sl *stubLimiter) RateLimit(key string, quantity int) (bool, throttled.RateLimitResult, error) {
|
||||
switch key {
|
||||
case "limit":
|
||||
return true, throttled.RateLimitResult{-1, -1, -1, time.Minute}, nil
|
||||
case "error":
|
||||
return false, throttled.RateLimitResult{}, errors.New("stubLimiter error")
|
||||
default:
|
||||
return false, throttled.RateLimitResult{1, 2, time.Minute, -1}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type pathGetter struct{}
|
||||
|
||||
func (*pathGetter) Key(r *http.Request) string {
|
||||
return r.URL.Path
|
||||
}
|
||||
|
||||
type httpTestCase struct {
|
||||
path string
|
||||
code int
|
||||
headers map[string]string
|
||||
}
|
||||
|
||||
func TestHTTPRateLimiter(t *testing.T) {
|
||||
limiter := throttled.HTTPRateLimiter{
|
||||
RateLimiter: &stubLimiter{},
|
||||
VaryBy: &pathGetter{},
|
||||
}
|
||||
|
||||
handler := limiter.RateLimit(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
|
||||
runHTTPTestCases(t, handler, []httpTestCase{
|
||||
{"ok", 200, map[string]string{"X-Ratelimit-Limit": "1", "X-Ratelimit-Remaining": "2", "X-Ratelimit-Reset": "60"}},
|
||||
{"error", 500, map[string]string{}},
|
||||
{"limit", 429, map[string]string{"Retry-After": "60"}},
|
||||
})
|
||||
}
|
||||
|
||||
func TestCustomHTTPRateLimiterHandlers(t *testing.T) {
|
||||
limiter := throttled.HTTPRateLimiter{
|
||||
RateLimiter: &stubLimiter{},
|
||||
VaryBy: &pathGetter{},
|
||||
DeniedHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "custom limit exceeded", 400)
|
||||
}),
|
||||
Error: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
http.Error(w, "custom internal error", 501)
|
||||
},
|
||||
}
|
||||
|
||||
handler := limiter.RateLimit(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
}))
|
||||
|
||||
runHTTPTestCases(t, handler, []httpTestCase{
|
||||
{"limit", 400, map[string]string{}},
|
||||
{"error", 501, map[string]string{}},
|
||||
})
|
||||
}
|
||||
|
||||
func runHTTPTestCases(t *testing.T, h http.Handler, cs []httpTestCase) {
|
||||
for i, c := range cs {
|
||||
req, err := http.NewRequest("GET", c.path, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
h.ServeHTTP(rr, req)
|
||||
if have, want := rr.Code, c.code; have != want {
|
||||
t.Errorf("Expected request %d at %s to return %d but got %d",
|
||||
i, c.path, want, have)
|
||||
}
|
||||
|
||||
for name, want := range c.headers {
|
||||
if have := rr.HeaderMap.Get(name); have != want {
|
||||
t.Errorf("Expected request %d at %s to have header '%s: %s' but got '%s'",
|
||||
i, c.path, name, want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
128
vendor/gopkg.in/throttled/throttled.v2/rate_test.go
generated
vendored
128
vendor/gopkg.in/throttled/throttled.v2/rate_test.go
generated
vendored
@ -1,128 +0,0 @@
|
||||
package throttled_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2"
|
||||
"gopkg.in/throttled/throttled.v2/store/memstore"
|
||||
)
|
||||
|
||||
const deniedStatus = 429
|
||||
|
||||
type testStore struct {
|
||||
store throttled.GCRAStore
|
||||
|
||||
clock time.Time
|
||||
failUpdates bool
|
||||
}
|
||||
|
||||
func (ts *testStore) GetWithTime(key string) (int64, time.Time, error) {
|
||||
v, _, e := ts.store.GetWithTime(key)
|
||||
return v, ts.clock, e
|
||||
}
|
||||
|
||||
func (ts *testStore) SetIfNotExistsWithTTL(key string, value int64, ttl time.Duration) (bool, error) {
|
||||
if ts.failUpdates {
|
||||
return false, nil
|
||||
}
|
||||
return ts.store.SetIfNotExistsWithTTL(key, value, ttl)
|
||||
}
|
||||
|
||||
func (ts *testStore) CompareAndSwapWithTTL(key string, old, new int64, ttl time.Duration) (bool, error) {
|
||||
if ts.failUpdates {
|
||||
return false, nil
|
||||
}
|
||||
return ts.store.CompareAndSwapWithTTL(key, old, new, ttl)
|
||||
}
|
||||
|
||||
func TestRateLimit(t *testing.T) {
|
||||
limit := 5
|
||||
rq := throttled.RateQuota{throttled.PerSec(1), limit - 1}
|
||||
start := time.Unix(0, 0)
|
||||
cases := []struct {
|
||||
now time.Time
|
||||
volume, remaining int
|
||||
reset, retry time.Duration
|
||||
limited bool
|
||||
}{
|
||||
// You can never make a request larger than the maximum
|
||||
0: {start, 6, 5, 0, -1, true},
|
||||
// Rate limit normal requests appropriately
|
||||
1: {start, 1, 4, time.Second, -1, false},
|
||||
2: {start, 1, 3, 2 * time.Second, -1, false},
|
||||
3: {start, 1, 2, 3 * time.Second, -1, false},
|
||||
4: {start, 1, 1, 4 * time.Second, -1, false},
|
||||
5: {start, 1, 0, 5 * time.Second, -1, false},
|
||||
6: {start, 1, 0, 5 * time.Second, time.Second, true},
|
||||
7: {start.Add(3000 * time.Millisecond), 1, 2, 3000 * time.Millisecond, -1, false},
|
||||
8: {start.Add(3100 * time.Millisecond), 1, 1, 3900 * time.Millisecond, -1, false},
|
||||
9: {start.Add(4000 * time.Millisecond), 1, 1, 4000 * time.Millisecond, -1, false},
|
||||
10: {start.Add(8000 * time.Millisecond), 1, 4, 1000 * time.Millisecond, -1, false},
|
||||
11: {start.Add(9500 * time.Millisecond), 1, 4, 1000 * time.Millisecond, -1, false},
|
||||
// Zero-volume request just peeks at the state
|
||||
12: {start.Add(9500 * time.Millisecond), 0, 4, time.Second, -1, false},
|
||||
// High-volume request uses up more of the limit
|
||||
13: {start.Add(9500 * time.Millisecond), 2, 2, 3 * time.Second, -1, false},
|
||||
// Large requests cannot exceed limits
|
||||
14: {start.Add(9500 * time.Millisecond), 5, 2, 3 * time.Second, 3 * time.Second, true},
|
||||
}
|
||||
|
||||
mst, err := memstore.New(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st := testStore{store: mst}
|
||||
|
||||
rl, err := throttled.NewGCRARateLimiter(&st, rq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Start the server
|
||||
for i, c := range cases {
|
||||
st.clock = c.now
|
||||
|
||||
limited, context, err := rl.RateLimit("foo", c.volume)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: %#v", i, err)
|
||||
}
|
||||
|
||||
if limited != c.limited {
|
||||
t.Errorf("%d: expected Limited to be %t but got %t", i, c.limited, limited)
|
||||
}
|
||||
|
||||
if have, want := context.Limit, limit; have != want {
|
||||
t.Errorf("%d: expected Limit to be %d but got %d", i, want, have)
|
||||
}
|
||||
|
||||
if have, want := context.Remaining, c.remaining; have != want {
|
||||
t.Errorf("%d: expected Remaining to be %d but got %d", i, want, have)
|
||||
}
|
||||
|
||||
if have, want := context.ResetAfter, c.reset; have != want {
|
||||
t.Errorf("%d: expected ResetAfter to be %s but got %s", i, want, have)
|
||||
}
|
||||
|
||||
if have, want := context.RetryAfter, c.retry; have != want {
|
||||
t.Errorf("%d: expected RetryAfter to be %d but got %d", i, want, have)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRateLimitUpdateFailures(t *testing.T) {
|
||||
rq := throttled.RateQuota{throttled.PerSec(1), 1}
|
||||
mst, err := memstore.New(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st := testStore{store: mst, failUpdates: true}
|
||||
rl, err := throttled.NewGCRARateLimiter(&st, rq)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, _, err := rl.RateLimit("foo", 1); err == nil {
|
||||
t.Error("Expected limiting to fail when store updates fail")
|
||||
}
|
||||
}
|
40
vendor/gopkg.in/throttled/throttled.v2/store/memstore/memstore_test.go
generated
vendored
40
vendor/gopkg.in/throttled/throttled.v2/store/memstore/memstore_test.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
package memstore_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2/store/memstore"
|
||||
"gopkg.in/throttled/throttled.v2/store/storetest"
|
||||
)
|
||||
|
||||
func TestMemStoreLRU(t *testing.T) {
|
||||
st, err := memstore.New(10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
storetest.TestGCRAStore(t, st)
|
||||
}
|
||||
|
||||
func TestMemStoreUnlimited(t *testing.T) {
|
||||
st, err := memstore.New(10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
storetest.TestGCRAStore(t, st)
|
||||
}
|
||||
|
||||
func BenchmarkMemStoreLRU(b *testing.B) {
|
||||
st, err := memstore.New(10)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
storetest.BenchmarkGCRAStore(b, st)
|
||||
}
|
||||
|
||||
func BenchmarkMemStoreUnlimited(b *testing.B) {
|
||||
st, err := memstore.New(0)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
storetest.BenchmarkGCRAStore(b, st)
|
||||
}
|
85
vendor/gopkg.in/throttled/throttled.v2/store/redigostore/redisstore_test.go
generated
vendored
85
vendor/gopkg.in/throttled/throttled.v2/store/redigostore/redisstore_test.go
generated
vendored
@ -1,85 +0,0 @@
|
||||
package redigostore_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/garyburd/redigo/redis"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2/store/redigostore"
|
||||
"gopkg.in/throttled/throttled.v2/store/storetest"
|
||||
)
|
||||
|
||||
const (
|
||||
redisTestDB = 1
|
||||
redisTestPrefix = "throttled:"
|
||||
)
|
||||
|
||||
func getPool() *redis.Pool {
|
||||
pool := &redis.Pool{
|
||||
MaxIdle: 3,
|
||||
IdleTimeout: 30 * time.Second,
|
||||
Dial: func() (redis.Conn, error) {
|
||||
return redis.Dial("tcp", ":6379")
|
||||
},
|
||||
TestOnBorrow: func(c redis.Conn, t time.Time) error {
|
||||
_, err := c.Do("PING")
|
||||
return err
|
||||
},
|
||||
}
|
||||
return pool
|
||||
}
|
||||
|
||||
func TestRedisStore(t *testing.T) {
|
||||
c, st := setupRedis(t, 0)
|
||||
defer c.Close()
|
||||
defer clearRedis(c)
|
||||
|
||||
clearRedis(c)
|
||||
storetest.TestGCRAStore(t, st)
|
||||
storetest.TestGCRAStoreTTL(t, st)
|
||||
}
|
||||
|
||||
func BenchmarkRedisStore(b *testing.B) {
|
||||
c, st := setupRedis(b, 0)
|
||||
defer c.Close()
|
||||
defer clearRedis(c)
|
||||
|
||||
storetest.BenchmarkGCRAStore(b, st)
|
||||
}
|
||||
|
||||
func clearRedis(c redis.Conn) error {
|
||||
keys, err := redis.Values(c.Do("KEYS", redisTestPrefix+"*"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := redis.Int(c.Do("DEL", keys...)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupRedis(tb testing.TB, ttl time.Duration) (redis.Conn, *redigostore.RedigoStore) {
|
||||
pool := getPool()
|
||||
c := pool.Get()
|
||||
|
||||
if _, err := redis.String(c.Do("PING")); err != nil {
|
||||
c.Close()
|
||||
tb.Skip("redis server not available on localhost port 6379")
|
||||
}
|
||||
|
||||
if _, err := redis.String(c.Do("SELECT", redisTestDB)); err != nil {
|
||||
c.Close()
|
||||
tb.Fatal(err)
|
||||
}
|
||||
|
||||
st, err := redigostore.New(pool, redisTestPrefix, redisTestDB)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
tb.Fatal(err)
|
||||
}
|
||||
|
||||
return c, st
|
||||
}
|
2
vendor/gopkg.in/throttled/throttled.v2/store/storetest/doc.go
generated
vendored
2
vendor/gopkg.in/throttled/throttled.v2/store/storetest/doc.go
generated
vendored
@ -1,2 +0,0 @@
|
||||
// Package storetest provides a helper for testing throttled stores.
|
||||
package storetest // import "gopkg.in/throttled/throttled.v2/store/storetest"
|
176
vendor/gopkg.in/throttled/throttled.v2/store/storetest/storetest.go
generated
vendored
176
vendor/gopkg.in/throttled/throttled.v2/store/storetest/storetest.go
generated
vendored
@ -1,176 +0,0 @@
|
||||
// Package storetest provides a helper for testing throttled stores.
|
||||
package storetest // import "gopkg.in/throttled/throttled.v2/store/storetest"
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2"
|
||||
)
|
||||
|
||||
// TestGCRAStore tests the behavior of a GCRAStore implementation for
|
||||
// compliance with the throttled API. It does not require support
|
||||
// for TTLs.
|
||||
func TestGCRAStore(t *testing.T, st throttled.GCRAStore) {
|
||||
// GetWithTime a missing key
|
||||
if have, _, err := st.GetWithTime("foo"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if have != -1 {
|
||||
t.Errorf("expected GetWithTime to return -1 for a missing key but got %d", have)
|
||||
}
|
||||
|
||||
// SetIfNotExists on a new key
|
||||
want := int64(1)
|
||||
|
||||
if set, err := st.SetIfNotExistsWithTTL("foo", want, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !set {
|
||||
t.Errorf("expected SetIfNotExists on an empty key to succeed")
|
||||
}
|
||||
|
||||
before := time.Now()
|
||||
|
||||
if have, now, err := st.GetWithTime("foo"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if have != want {
|
||||
t.Errorf("expected GetWithTime to return %d but got %d", want, have)
|
||||
} else if now.UnixNano() <= 0 {
|
||||
t.Errorf("expected GetWithTime to return a time representable representable as a positive int64 of nanoseconds since the epoch")
|
||||
} else if now.Before(before) || now.After(time.Now()) {
|
||||
// Note that we make the assumption here that the store is running on
|
||||
// the same machine as this test and thus shares a clock. This can be a
|
||||
// little tricky in the case of Redis, which could be running
|
||||
// elsewhere. The test assumes that it's running either locally on on
|
||||
// Travis (where currently the Redis is available on localhost). If new
|
||||
// test environments are procured, this may need to be revisited.
|
||||
t.Errorf("expected GetWithTime to return a time between the time before the call and the time after the call")
|
||||
}
|
||||
|
||||
// SetIfNotExists on an existing key
|
||||
if set, err := st.SetIfNotExistsWithTTL("foo", 123, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if set {
|
||||
t.Errorf("expected SetIfNotExists on an existing key to fail")
|
||||
}
|
||||
|
||||
if have, _, err := st.GetWithTime("foo"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if have != want {
|
||||
t.Errorf("expected GetWithTime to return %d but got %d", want, have)
|
||||
}
|
||||
|
||||
// SetIfNotExists on a different key
|
||||
if set, err := st.SetIfNotExistsWithTTL("bar", 456, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !set {
|
||||
t.Errorf("expected SetIfNotExists on an empty key to succeed")
|
||||
}
|
||||
|
||||
// Returns the false on a missing key
|
||||
if swapped, err := st.CompareAndSwapWithTTL("baz", 1, 2, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if swapped {
|
||||
t.Errorf("expected CompareAndSwap to fail on a missing key")
|
||||
}
|
||||
|
||||
// Test a successful CAS
|
||||
want = int64(2)
|
||||
|
||||
if swapped, err := st.CompareAndSwapWithTTL("foo", 1, want, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !swapped {
|
||||
t.Errorf("expected CompareAndSwap to succeed")
|
||||
}
|
||||
|
||||
if have, _, err := st.GetWithTime("foo"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if have != want {
|
||||
t.Errorf("expected GetWithTime to return %d but got %d", want, have)
|
||||
}
|
||||
|
||||
// Test an unsuccessful CAS
|
||||
if swapped, err := st.CompareAndSwapWithTTL("foo", 1, 2, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if swapped {
|
||||
t.Errorf("expected CompareAndSwap to fail")
|
||||
}
|
||||
|
||||
if have, _, err := st.GetWithTime("foo"); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if have != want {
|
||||
t.Errorf("expected GetWithTime to return %d but got %d", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGCRAStoreTTL tests the behavior of TTLs in a GCRAStore implementation.
|
||||
func TestGCRAStoreTTL(t *testing.T, st throttled.GCRAStore) {
|
||||
ttl := time.Second
|
||||
want := int64(1)
|
||||
key := "ttl"
|
||||
|
||||
if _, err := st.SetIfNotExistsWithTTL(key, want, ttl); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if have, _, err := st.GetWithTime(key); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if have != want {
|
||||
t.Errorf("expected GetWithTime to return %d, got %d", want, have)
|
||||
}
|
||||
|
||||
// I can't think of a generic way to test expiration without a sleep
|
||||
time.Sleep(ttl + time.Millisecond)
|
||||
|
||||
if have, _, err := st.GetWithTime(key); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if have != -1 {
|
||||
t.Errorf("expected GetWithTime to fail on an expired key but got %d", have)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkGCRAStore runs parallel benchmarks against a GCRAStore implementation.
|
||||
// Aside from being useful for performance testing, this is useful for finding
|
||||
// race conditions with the Go race detector.
|
||||
func BenchmarkGCRAStore(b *testing.B, st throttled.GCRAStore) {
|
||||
seed := int64(42)
|
||||
var attempts, updates int64
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
// We need atomic behavior around the RNG or go detects a race in the test
|
||||
delta := int64(1)
|
||||
seedValue := atomic.AddInt64(&seed, delta) - delta
|
||||
gen := rand.New(rand.NewSource(seedValue))
|
||||
|
||||
for pb.Next() {
|
||||
key := strconv.FormatInt(gen.Int63n(50), 10)
|
||||
|
||||
var v int64
|
||||
var updated bool
|
||||
|
||||
v, _, err := st.GetWithTime(key)
|
||||
if v == -1 {
|
||||
updated, err = st.SetIfNotExistsWithTTL(key, gen.Int63(), 0)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
} else if err != nil {
|
||||
b.Error(err)
|
||||
} else {
|
||||
updated, err = st.CompareAndSwapWithTTL(key, v, gen.Int63(), 0)
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
atomic.AddInt64(&attempts, 1)
|
||||
if updated {
|
||||
atomic.AddInt64(&updates, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
b.Logf("%d/%d update operations succeeed", updates, attempts)
|
||||
}
|
58
vendor/gopkg.in/throttled/throttled.v2/varyby_test.go
generated
vendored
58
vendor/gopkg.in/throttled/throttled.v2/varyby_test.go
generated
vendored
@ -1,58 +0,0 @@
|
||||
package throttled_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/throttled/throttled.v2"
|
||||
)
|
||||
|
||||
func TestVaryBy(t *testing.T) {
|
||||
u, err := url.Parse("http://localhost/test/path?q=s")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ck := &http.Cookie{Name: "ssn", Value: "test"}
|
||||
cases := []struct {
|
||||
vb *throttled.VaryBy
|
||||
r *http.Request
|
||||
k string
|
||||
}{
|
||||
0: {nil, &http.Request{}, ""},
|
||||
1: {&throttled.VaryBy{RemoteAddr: true}, &http.Request{RemoteAddr: "::"}, "::\n"},
|
||||
2: {
|
||||
&throttled.VaryBy{Method: true, Path: true},
|
||||
&http.Request{Method: "POST", URL: u},
|
||||
"post\n/test/path\n",
|
||||
},
|
||||
3: {
|
||||
&throttled.VaryBy{Headers: []string{"Content-length"}},
|
||||
&http.Request{Header: http.Header{"Content-Type": []string{"text/plain"}, "Content-Length": []string{"123"}}},
|
||||
"123\n",
|
||||
},
|
||||
4: {
|
||||
&throttled.VaryBy{Separator: ",", Method: true, Headers: []string{"Content-length"}, Params: []string{"q", "user"}},
|
||||
&http.Request{Method: "GET", Header: http.Header{"Content-Type": []string{"text/plain"}, "Content-Length": []string{"123"}}, Form: url.Values{"q": []string{"s"}, "pwd": []string{"secret"}, "user": []string{"test"}}},
|
||||
"get,123,s,test,",
|
||||
},
|
||||
5: {
|
||||
&throttled.VaryBy{Cookies: []string{"ssn"}},
|
||||
&http.Request{Header: http.Header{"Cookie": []string{ck.String()}}},
|
||||
"test\n",
|
||||
},
|
||||
6: {
|
||||
&throttled.VaryBy{Cookies: []string{"ssn"}, RemoteAddr: true, Custom: func(r *http.Request) string {
|
||||
return "blah"
|
||||
}},
|
||||
&http.Request{Header: http.Header{"Cookie": []string{ck.String()}}},
|
||||
"blah",
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
got := c.vb.Key(c.r)
|
||||
if got != c.k {
|
||||
t.Errorf("%d: expected '%s' (%d), got '%s' (%d)", i, c.k, len(c.k), got, len(got))
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user