summaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/garyburd
diff options
context:
space:
mode:
Diffstat (limited to 'Godeps/_workspace/src/github.com/garyburd')
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/internal/redistest/testdb.go5
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn.go182
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn_test.go163
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool.go14
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool_test.go96
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/pubsub_test.go22
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply.go37
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply_test.go29
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan.go92
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan_test.go64
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/script_test.go5
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/test_test.go157
-rw-r--r--Godeps/_workspace/src/github.com/garyburd/redigo/redis/zpop_example_test.go2
13 files changed, 681 insertions, 187 deletions
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/internal/redistest/testdb.go b/Godeps/_workspace/src/github.com/garyburd/redigo/internal/redistest/testdb.go
index 5f955c424..3eb4bcd77 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/internal/redistest/testdb.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/internal/redistest/testdb.go
@@ -19,7 +19,7 @@ import (
"errors"
"time"
- "github.com/garyburd/redigo/redis"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
type testConn struct {
@@ -49,15 +49,18 @@ func Dial() (redis.Conn, error) {
_, err = c.Do("SELECT", "9")
if err != nil {
+ c.Close()
return nil, err
}
n, err := redis.Int(c.Do("DBSIZE"))
if err != nil {
+ c.Close()
return nil, err
}
if n != 0 {
+ c.Close()
return nil, errors.New("database #9 is not empty, test can not continue")
}
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn.go
index ac0e971c4..6a3819f1d 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn.go
@@ -21,6 +21,8 @@ import (
"fmt"
"io"
"net"
+ "net/url"
+ "regexp"
"strconv"
"sync"
"time"
@@ -51,56 +53,164 @@ type conn struct {
numScratch [40]byte
}
-// Dial connects to the Redis server at the given network and address.
-func Dial(network, address string) (Conn, error) {
- dialer := xDialer{}
- return dialer.Dial(network, address)
-}
-
// DialTimeout acts like Dial but takes timeouts for establishing the
// connection to the server, writing a command and reading a reply.
+//
+// Deprecated: Use Dial with options instead.
func DialTimeout(network, address string, connectTimeout, readTimeout, writeTimeout time.Duration) (Conn, error) {
- netDialer := net.Dialer{Timeout: connectTimeout}
- dialer := xDialer{
- NetDial: netDialer.Dial,
- ReadTimeout: readTimeout,
- WriteTimeout: writeTimeout,
- }
- return dialer.Dial(network, address)
+ return Dial(network, address,
+ DialConnectTimeout(connectTimeout),
+ DialReadTimeout(readTimeout),
+ DialWriteTimeout(writeTimeout))
+}
+
+// DialOption specifies an option for dialing a Redis server.
+type DialOption struct {
+ f func(*dialOptions)
+}
+
+type dialOptions struct {
+ readTimeout time.Duration
+ writeTimeout time.Duration
+ dial func(network, addr string) (net.Conn, error)
+ db int
+ password string
+}
+
+// DialReadTimeout specifies the timeout for reading a single command reply.
+func DialReadTimeout(d time.Duration) DialOption {
+ return DialOption{func(do *dialOptions) {
+ do.readTimeout = d
+ }}
+}
+
+// DialWriteTimeout specifies the timeout for writing a single command.
+func DialWriteTimeout(d time.Duration) DialOption {
+ return DialOption{func(do *dialOptions) {
+ do.writeTimeout = d
+ }}
}
-// A Dialer specifies options for connecting to a Redis server.
-type xDialer struct {
- // NetDial specifies the dial function for creating TCP connections. If
- // NetDial is nil, then net.Dial is used.
- NetDial func(network, addr string) (net.Conn, error)
+// DialConnectTimeout specifies the timeout for connecting to the Redis server.
+func DialConnectTimeout(d time.Duration) DialOption {
+ return DialOption{func(do *dialOptions) {
+ dialer := net.Dialer{Timeout: d}
+ do.dial = dialer.Dial
+ }}
+}
+
+// DialNetDial specifies a custom dial function for creating TCP
+// connections. If this option is left out, then net.Dial is
+// used. DialNetDial overrides DialConnectTimeout.
+func DialNetDial(dial func(network, addr string) (net.Conn, error)) DialOption {
+ return DialOption{func(do *dialOptions) {
+ do.dial = dial
+ }}
+}
- // ReadTimeout specifies the timeout for reading a single command
- // reply. If ReadTimeout is zero, then no timeout is used.
- ReadTimeout time.Duration
+// DialDatabase specifies the database to select when dialing a connection.
+func DialDatabase(db int) DialOption {
+ return DialOption{func(do *dialOptions) {
+ do.db = db
+ }}
+}
- // WriteTimeout specifies the timeout for writing a single command. If
- // WriteTimeout is zero, then no timeout is used.
- WriteTimeout time.Duration
+// DialPassword specifies the password to use when connecting to
+// the Redis server.
+func DialPassword(password string) DialOption {
+ return DialOption{func(do *dialOptions) {
+ do.password = password
+ }}
}
-// Dial connects to the Redis server at address on the named network.
-func (d *xDialer) Dial(network, address string) (Conn, error) {
- dial := d.NetDial
- if dial == nil {
- dial = net.Dial
+// Dial connects to the Redis server at the given network and
+// address using the specified options.
+func Dial(network, address string, options ...DialOption) (Conn, error) {
+ do := dialOptions{
+ dial: net.Dial,
}
- netConn, err := dial(network, address)
+ for _, option := range options {
+ option.f(&do)
+ }
+
+ netConn, err := do.dial(network, address)
if err != nil {
return nil, err
}
- return &conn{
+ c := &conn{
conn: netConn,
bw: bufio.NewWriter(netConn),
br: bufio.NewReader(netConn),
- readTimeout: d.ReadTimeout,
- writeTimeout: d.WriteTimeout,
- }, nil
+ readTimeout: do.readTimeout,
+ writeTimeout: do.writeTimeout,
+ }
+
+ if do.password != "" {
+ if _, err := c.Do("AUTH", do.password); err != nil {
+ netConn.Close()
+ return nil, err
+ }
+ }
+
+ if do.db != 0 {
+ if _, err := c.Do("SELECT", do.db); err != nil {
+ netConn.Close()
+ return nil, err
+ }
+ }
+
+ return c, nil
+}
+
+var pathDBRegexp = regexp.MustCompile(`/(\d+)\z`)
+
+// DialURL connects to a Redis server at the given URL using the Redis
+// URI scheme. URLs should follow the draft IANA specification for the
+// scheme (https://www.iana.org/assignments/uri-schemes/prov/redis).
+func DialURL(rawurl string, options ...DialOption) (Conn, error) {
+ u, err := url.Parse(rawurl)
+ if err != nil {
+ return nil, err
+ }
+
+ if u.Scheme != "redis" {
+ return nil, fmt.Errorf("invalid redis URL scheme: %s", u.Scheme)
+ }
+
+ // As per the IANA draft spec, the host defaults to localhost and
+ // the port defaults to 6379.
+ host, port, err := net.SplitHostPort(u.Host)
+ if err != nil {
+ // assume port is missing
+ host = u.Host
+ port = "6379"
+ }
+ if host == "" {
+ host = "localhost"
+ }
+ address := net.JoinHostPort(host, port)
+
+ if u.User != nil {
+ password, isSet := u.User.Password()
+ if isSet {
+ options = append(options, DialPassword(password))
+ }
+ }
+
+ match := pathDBRegexp.FindStringSubmatch(u.Path)
+ if len(match) == 2 {
+ db, err := strconv.Atoi(match[1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid database: %s", u.Path[1:])
+ }
+ if db != 0 {
+ options = append(options, DialDatabase(db))
+ }
+ } else if u.Path != "" {
+ return nil, fmt.Errorf("invalid database: %s", u.Path[1:])
+ }
+
+ return Dial("tcp", address, options...)
}
// NewConn returns a new Redigo connection for the given net connection.
@@ -417,7 +527,9 @@ func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
}
if cmd != "" {
- c.writeCommand(cmd, args)
+ if err := c.writeCommand(cmd, args); err != nil {
+ return nil, c.fatal(err)
+ }
}
if err := c.bw.Flush(); err != nil {
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn_test.go
index 800370136..06a2c8fa7 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/conn_test.go
@@ -15,19 +15,37 @@
package redis_test
import (
- "bufio"
"bytes"
+ "io"
"math"
"net"
+ "os"
"reflect"
"strings"
"testing"
"time"
- "github.com/garyburd/redigo/internal/redistest"
- "github.com/garyburd/redigo/redis"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
+type testConn struct {
+ io.Reader
+ io.Writer
+}
+
+func (*testConn) Close() error { return nil }
+func (*testConn) LocalAddr() net.Addr { return nil }
+func (*testConn) RemoteAddr() net.Addr { return nil }
+func (*testConn) SetDeadline(t time.Time) error { return nil }
+func (*testConn) SetReadDeadline(t time.Time) error { return nil }
+func (*testConn) SetWriteDeadline(t time.Time) error { return nil }
+
+func dialTestConn(r io.Reader, w io.Writer) redis.DialOption {
+ return redis.DialNetDial(func(net, addr string) (net.Conn, error) {
+ return &testConn{Reader: r, Writer: w}, nil
+ })
+}
+
var writeTests = []struct {
args []interface{}
expected string
@@ -73,14 +91,13 @@ var writeTests = []struct {
func TestWrite(t *testing.T) {
for _, tt := range writeTests {
var buf bytes.Buffer
- rw := bufio.ReadWriter{Writer: bufio.NewWriter(&buf)}
- c := redis.NewConnBufio(rw)
+ c, _ := redis.Dial("", "", dialTestConn(nil, &buf))
err := c.Send(tt.args[0].(string), tt.args[1:]...)
if err != nil {
t.Errorf("Send(%v) returned error %v", tt.args, err)
continue
}
- rw.Flush()
+ c.Flush()
actual := buf.String()
if actual != tt.expected {
t.Errorf("Send(%v) = %q, want %q", tt.args, actual, tt.expected)
@@ -173,11 +190,7 @@ var readTests = []struct {
func TestRead(t *testing.T) {
for _, tt := range readTests {
- rw := bufio.ReadWriter{
- Reader: bufio.NewReader(strings.NewReader(tt.reply)),
- Writer: bufio.NewWriter(nil), // writer need to support Flush
- }
- c := redis.NewConnBufio(rw)
+ c, _ := redis.Dial("", "", dialTestConn(strings.NewReader(tt.reply), nil))
actual, err := c.Receive()
if tt.expected == errorSentinel {
if err == nil {
@@ -257,7 +270,7 @@ var testCommands = []struct {
}
func TestDoCommands(t *testing.T) {
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
@@ -276,7 +289,7 @@ func TestDoCommands(t *testing.T) {
}
func TestPipelineCommands(t *testing.T) {
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
@@ -302,7 +315,7 @@ func TestPipelineCommands(t *testing.T) {
}
func TestBlankCommmand(t *testing.T) {
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
@@ -329,7 +342,7 @@ func TestBlankCommmand(t *testing.T) {
}
func TestRecvBeforeSend(t *testing.T) {
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
@@ -350,7 +363,7 @@ func TestRecvBeforeSend(t *testing.T) {
}
func TestError(t *testing.T) {
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
@@ -370,7 +383,7 @@ func TestError(t *testing.T) {
}
}
-func TestReadDeadline(t *testing.T) {
+func TestReadTimeout(t *testing.T) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("net.Listen returned %v", err)
@@ -391,7 +404,9 @@ func TestReadDeadline(t *testing.T) {
}
}()
- c1, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
+ // Do
+
+ c1, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
if err != nil {
t.Fatalf("redis.Dial returned %v", err)
}
@@ -405,7 +420,9 @@ func TestReadDeadline(t *testing.T) {
t.Fatalf("c1.Err() = nil, expect error")
}
- c2, err := redis.DialTimeout(l.Addr().Network(), l.Addr().String(), 0, time.Millisecond, 0)
+ // Send/Flush/Receive
+
+ c2, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
if err != nil {
t.Fatalf("redis.Dial returned %v", err)
}
@@ -422,6 +439,95 @@ func TestReadDeadline(t *testing.T) {
}
}
+var dialErrors = []struct {
+ rawurl string
+ expectedError string
+}{
+ {
+ "localhost",
+ "invalid redis URL scheme",
+ },
+ // The error message for invalid hosts is diffferent in different
+ // versions of Go, so just check that there is an error message.
+ {
+ "redis://weird url",
+ "",
+ },
+ {
+ "redis://foo:bar:baz",
+ "",
+ },
+ {
+ "http://www.google.com",
+ "invalid redis URL scheme: http",
+ },
+ {
+ "redis://localhost:6379/abc123",
+ "invalid database: abc123",
+ },
+}
+
+func TestDialURLErrors(t *testing.T) {
+ for _, d := range dialErrors {
+ _, err := redis.DialURL(d.rawurl)
+ if err == nil || !strings.Contains(err.Error(), d.expectedError) {
+ t.Errorf("DialURL did not return expected error (expected %v to contain %s)", err, d.expectedError)
+ }
+ }
+}
+
+func TestDialURLPort(t *testing.T) {
+ checkPort := func(network, address string) (net.Conn, error) {
+ if address != "localhost:6379" {
+ t.Errorf("DialURL did not set port to 6379 by default (got %v)", address)
+ }
+ return nil, nil
+ }
+ _, err := redis.DialURL("redis://localhost", redis.DialNetDial(checkPort))
+ if err != nil {
+ t.Error("dial error:", err)
+ }
+}
+
+func TestDialURLHost(t *testing.T) {
+ checkHost := func(network, address string) (net.Conn, error) {
+ if address != "localhost:6379" {
+ t.Errorf("DialURL did not set host to localhost by default (got %v)", address)
+ }
+ return nil, nil
+ }
+ _, err := redis.DialURL("redis://:6379", redis.DialNetDial(checkHost))
+ if err != nil {
+ t.Error("dial error:", err)
+ }
+}
+
+func TestDialURLPassword(t *testing.T) {
+ var buf bytes.Buffer
+ _, err := redis.DialURL("redis://x:abc123@localhost", dialTestConn(strings.NewReader("+OK\r\n"), &buf))
+ if err != nil {
+ t.Error("dial error:", err)
+ }
+ expected := "*2\r\n$4\r\nAUTH\r\n$6\r\nabc123\r\n"
+ actual := buf.String()
+ if actual != expected {
+ t.Errorf("commands = %q, want %q", actual, expected)
+ }
+}
+
+func TestDialURLDatabase(t *testing.T) {
+ var buf bytes.Buffer
+ _, err := redis.DialURL("redis://localhost/3", dialTestConn(strings.NewReader("+OK\r\n"), &buf))
+ if err != nil {
+ t.Error("dial error:", err)
+ }
+ expected := "*2\r\n$6\r\nSELECT\r\n$1\r\n3\r\n"
+ actual := buf.String()
+ if actual != expected {
+ t.Errorf("commands = %q, want %q", actual, expected)
+ }
+}
+
// Connect to local instance of Redis running on the default port.
func ExampleDial(x int) {
c, err := redis.Dial("tcp", ":6379")
@@ -431,11 +537,20 @@ func ExampleDial(x int) {
defer c.Close()
}
+// Connect to remote instance of Redis using a URL.
+func ExampleDialURL() {
+ c, err := redis.DialURL(os.Getenv("REDIS_URL"))
+ if err != nil {
+ // handle connection error
+ }
+ defer c.Close()
+}
+
// TextExecError tests handling of errors in a transaction. See
// http://redis.io/topics/transactions for information on how Redis handles
// errors in a transaction.
func TestExecError(t *testing.T) {
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
@@ -443,6 +558,7 @@ func TestExecError(t *testing.T) {
// Execute commands that fail before EXEC is called.
+ c.Do("DEL", "k0")
c.Do("ZADD", "k0", 0, 0)
c.Send("MULTI")
c.Send("NOTACOMMAND", "k0", 0, 0)
@@ -455,6 +571,7 @@ func TestExecError(t *testing.T) {
// Execute commands that fail after EXEC is called. The first command
// returns an error.
+ c.Do("DEL", "k1")
c.Do("ZADD", "k1", 0, 0)
c.Send("MULTI")
c.Send("HSET", "k1", 0, 0)
@@ -478,7 +595,7 @@ func TestExecError(t *testing.T) {
}
if _, ok := vs[1].([]byte); !ok {
- t.Fatalf("second result is type %T, expected []byte", vs[2])
+ t.Fatalf("second result is type %T, expected []byte", vs[1])
}
// Execute commands that fail after EXEC is called. The second command
@@ -513,7 +630,7 @@ func TestExecError(t *testing.T) {
func BenchmarkDoEmpty(b *testing.B) {
b.StopTimer()
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
b.Fatal(err)
}
@@ -528,7 +645,7 @@ func BenchmarkDoEmpty(b *testing.B) {
func BenchmarkDoPing(b *testing.B) {
b.StopTimer()
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
b.Fatal(err)
}
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool.go
index 9daf2e33f..c29b35f81 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool.go
@@ -25,7 +25,7 @@ import (
"sync"
"time"
- "github.com/garyburd/redigo/internal"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/internal"
)
var nowFunc = time.Now // for testing
@@ -94,7 +94,10 @@ var (
type Pool struct {
// Dial is an application supplied function for creating and configuring a
- // connection
+ // connection.
+ //
+ // The connection returned from Dial must not be in a special state
+ // (subscribed to pubsub channel, transaction started, ...).
Dial func() (Conn, error)
// TestOnBorrow is an optional application supplied function for checking
@@ -116,7 +119,7 @@ type Pool struct {
// the timeout to a value less than the server's timeout.
IdleTimeout time.Duration
- // If Wait is true and the pool is at the MaxIdle limit, then Get() waits
+ // If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning.
Wait bool
@@ -135,8 +138,9 @@ type idleConn struct {
t time.Time
}
-// NewPool creates a new pool. This function is deprecated. Applications should
-// initialize the Pool fields directly as shown in example.
+// NewPool creates a new pool.
+//
+// Deprecated: Initialize the Pool directory as shown in the example.
func NewPool(newFn func() (Conn, error), maxIdle int) *Pool {
return &Pool{Dial: newFn, MaxIdle: maxIdle}
}
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool_test.go
index 1fe305f16..89e46e08d 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pool_test.go
@@ -22,8 +22,7 @@ import (
"testing"
"time"
- "github.com/garyburd/redigo/internal/redistest"
- "github.com/garyburd/redigo/redis"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
type poolTestConn struct {
@@ -32,10 +31,16 @@ type poolTestConn struct {
redis.Conn
}
-func (c *poolTestConn) Close() error { c.d.open -= 1; return nil }
-func (c *poolTestConn) Err() error { return c.err }
+func (c *poolTestConn) Close() error {
+ c.d.mu.Lock()
+ c.d.open -= 1
+ c.d.mu.Unlock()
+ return c.Conn.Close()
+}
+
+func (c *poolTestConn) Err() error { return c.err }
-func (c *poolTestConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
+func (c *poolTestConn) Do(commandName string, args ...interface{}) (interface{}, error) {
if commandName == "ERR" {
c.err = args[0].(error)
commandName = "PING"
@@ -52,6 +57,7 @@ func (c *poolTestConn) Send(commandName string, args ...interface{}) error {
}
type poolDialer struct {
+ mu sync.Mutex
t *testing.T
dialed int
open int
@@ -60,19 +66,25 @@ type poolDialer struct {
}
func (d *poolDialer) dial() (redis.Conn, error) {
+ d.mu.Lock()
d.dialed += 1
- if d.dialErr != nil {
+ dialErr := d.dialErr
+ d.mu.Unlock()
+ if dialErr != nil {
return nil, d.dialErr
}
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
return nil, err
}
+ d.mu.Lock()
d.open += 1
+ d.mu.Unlock()
return &poolTestConn{d: d, Conn: c}, nil
}
func (d *poolDialer) check(message string, p *redis.Pool, dialed, open int) {
+ d.mu.Lock()
if d.dialed != dialed {
d.t.Errorf("%s: dialed=%d, want %d", message, d.dialed, dialed)
}
@@ -82,6 +94,7 @@ func (d *poolDialer) check(message string, p *redis.Pool, dialed, open int) {
if active := p.ActiveCount(); active != open {
d.t.Errorf("%s: active=%d, want %d", message, active, open)
}
+ d.mu.Unlock()
}
func TestPoolReuse(t *testing.T) {
@@ -111,6 +124,8 @@ func TestPoolMaxIdle(t *testing.T) {
MaxIdle: 2,
Dial: d.dial,
}
+ defer p.Close()
+
for i := 0; i < 10; i++ {
c1 := p.Get()
c1.Do("PING")
@@ -133,6 +148,7 @@ func TestPoolError(t *testing.T) {
MaxIdle: 2,
Dial: d.dial,
}
+ defer p.Close()
c := p.Get()
c.Do("ERR", io.EOF)
@@ -154,6 +170,7 @@ func TestPoolClose(t *testing.T) {
MaxIdle: 2,
Dial: d.dial,
}
+ defer p.Close()
c1 := p.Get()
c1.Do("PING")
@@ -195,6 +212,7 @@ func TestPoolTimeout(t *testing.T) {
IdleTimeout: 300 * time.Second,
Dial: d.dial,
}
+ defer p.Close()
now := time.Now()
redis.SetNowFunc(func() time.Time { return now })
@@ -213,14 +231,14 @@ func TestPoolTimeout(t *testing.T) {
c.Close()
d.check("2", p, 2, 1)
-
- p.Close()
}
func TestPoolConcurrenSendReceive(t *testing.T) {
p := &redis.Pool{
- Dial: redistest.Dial,
+ Dial: redis.DialDefaultServer,
}
+ defer p.Close()
+
c := p.Get()
done := make(chan error, 1)
go func() {
@@ -238,7 +256,6 @@ func TestPoolConcurrenSendReceive(t *testing.T) {
t.Fatalf("Do() returned error %v", err)
}
c.Close()
- p.Close()
}
func TestPoolBorrowCheck(t *testing.T) {
@@ -248,6 +265,7 @@ func TestPoolBorrowCheck(t *testing.T) {
Dial: d.dial,
TestOnBorrow: func(redis.Conn, time.Time) error { return redis.Error("BLAH") },
}
+ defer p.Close()
for i := 0; i < 10; i++ {
c := p.Get()
@@ -255,7 +273,6 @@ func TestPoolBorrowCheck(t *testing.T) {
c.Close()
}
d.check("1", p, 10, 1)
- p.Close()
}
func TestPoolMaxActive(t *testing.T) {
@@ -265,6 +282,8 @@ func TestPoolMaxActive(t *testing.T) {
MaxActive: 2,
Dial: d.dial,
}
+ defer p.Close()
+
c1 := p.Get()
c1.Do("PING")
c2 := p.Get()
@@ -289,7 +308,6 @@ func TestPoolMaxActive(t *testing.T) {
c3.Close()
d.check("4", p, 2, 2)
- p.Close()
}
func TestPoolMonitorCleanup(t *testing.T) {
@@ -299,12 +317,13 @@ func TestPoolMonitorCleanup(t *testing.T) {
MaxActive: 2,
Dial: d.dial,
}
+ defer p.Close()
+
c := p.Get()
c.Send("MONITOR")
c.Close()
d.check("", p, 1, 0)
- p.Close()
}
func TestPoolPubSubCleanup(t *testing.T) {
@@ -314,6 +333,7 @@ func TestPoolPubSubCleanup(t *testing.T) {
MaxActive: 2,
Dial: d.dial,
}
+ defer p.Close()
c := p.Get()
c.Send("SUBSCRIBE", "x")
@@ -334,8 +354,6 @@ func TestPoolPubSubCleanup(t *testing.T) {
t.Errorf("got commands %v, want %v", d.commands, want)
}
d.commands = nil
-
- p.Close()
}
func TestPoolTransactionCleanup(t *testing.T) {
@@ -345,6 +363,7 @@ func TestPoolTransactionCleanup(t *testing.T) {
MaxActive: 2,
Dial: d.dial,
}
+ defer p.Close()
c := p.Get()
c.Do("WATCH", "key")
@@ -406,8 +425,6 @@ func TestPoolTransactionCleanup(t *testing.T) {
t.Errorf("got commands %v, want %v", d.commands, want)
}
d.commands = nil
-
- p.Close()
}
func startGoroutines(p *redis.Pool, cmd string, args ...interface{}) chan error {
@@ -436,6 +453,7 @@ func TestWaitPool(t *testing.T) {
Wait: true,
}
defer p.Close()
+
c := p.Get()
errs := startGoroutines(p, "PING")
d.check("before close", p, 1, 1)
@@ -462,6 +480,8 @@ func TestWaitPoolClose(t *testing.T) {
Dial: d.dial,
Wait: true,
}
+ defer p.Close()
+
c := p.Get()
if _, err := c.Do("PING"); err != nil {
t.Fatal(err)
@@ -497,6 +517,7 @@ func TestWaitPoolCommandError(t *testing.T) {
Wait: true,
}
defer p.Close()
+
c := p.Get()
errs := startGoroutines(p, "ERR", testErr)
d.check("before close", p, 1, 1)
@@ -525,6 +546,7 @@ func TestWaitPoolDialError(t *testing.T) {
Wait: true,
}
defer p.Close()
+
c := p.Get()
errs := startGoroutines(p, "ERR", testErr)
d.check("before close", p, 1, 1)
@@ -565,7 +587,7 @@ func TestWaitPoolDialError(t *testing.T) {
// test ensures that iteration will work correctly if multiple threads are
// iterating simultaneously.
func TestLocking_TestOnBorrowFails_PoolDoesntCrash(t *testing.T) {
- count := 100
+ const count = 100
// First we'll Create a pool where the pilfering of idle connections fails.
d := poolDialer{t: t}
@@ -580,29 +602,17 @@ func TestLocking_TestOnBorrowFails_PoolDoesntCrash(t *testing.T) {
defer p.Close()
// Fill the pool with idle connections.
- b1 := sync.WaitGroup{}
- b1.Add(count)
- b2 := sync.WaitGroup{}
- b2.Add(count)
- for i := 0; i < count; i++ {
- go func() {
- c := p.Get()
- if c.Err() != nil {
- t.Errorf("pool get failed: %v", c.Err())
- }
- b1.Done()
- b1.Wait()
- c.Close()
- b2.Done()
- }()
+ conns := make([]redis.Conn, count)
+ for i := range conns {
+ conns[i] = p.Get()
}
- b2.Wait()
- if d.dialed != count {
- t.Errorf("Expected %d dials, got %d", count, d.dialed)
+ for i := range conns {
+ conns[i].Close()
}
// Spawn a bunch of goroutines to thrash the pool.
- b2.Add(count)
+ var wg sync.WaitGroup
+ wg.Add(count)
for i := 0; i < count; i++ {
go func() {
c := p.Get()
@@ -610,10 +620,10 @@ func TestLocking_TestOnBorrowFails_PoolDoesntCrash(t *testing.T) {
t.Errorf("pool get failed: %v", c.Err())
}
c.Close()
- b2.Done()
+ wg.Done()
}()
}
- b2.Wait()
+ wg.Wait()
if d.dialed != count*2 {
t.Errorf("Expected %d dials, got %d", count*2, d.dialed)
}
@@ -621,7 +631,7 @@ func TestLocking_TestOnBorrowFails_PoolDoesntCrash(t *testing.T) {
func BenchmarkPoolGet(b *testing.B) {
b.StopTimer()
- p := redis.Pool{Dial: redistest.Dial, MaxIdle: 2}
+ p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
c := p.Get()
if err := c.Err(); err != nil {
b.Fatal(err)
@@ -637,7 +647,7 @@ func BenchmarkPoolGet(b *testing.B) {
func BenchmarkPoolGetErr(b *testing.B) {
b.StopTimer()
- p := redis.Pool{Dial: redistest.Dial, MaxIdle: 2}
+ p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
c := p.Get()
if err := c.Err(); err != nil {
b.Fatal(err)
@@ -656,7 +666,7 @@ func BenchmarkPoolGetErr(b *testing.B) {
func BenchmarkPoolGetPing(b *testing.B) {
b.StopTimer()
- p := redis.Pool{Dial: redistest.Dial, MaxIdle: 2}
+ p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
c := p.Get()
if err := c.Err(); err != nil {
b.Fatal(err)
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pubsub_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pubsub_test.go
index 365a58821..05e60763c 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pubsub_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/pubsub_test.go
@@ -16,20 +16,18 @@ package redis_test
import (
"fmt"
- "net"
"reflect"
"sync"
"testing"
- "time"
- "github.com/garyburd/redigo/internal/redistest"
- "github.com/garyburd/redigo/redis"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
func publish(channel, value interface{}) {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
c.Do("PUBLISH", channel, value)
@@ -39,7 +37,8 @@ func publish(channel, value interface{}) {
func ExamplePubSubConn() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
var wg sync.WaitGroup
@@ -111,20 +110,19 @@ func expectPushed(t *testing.T, c redis.PubSubConn, message string, expected int
}
func TestPushed(t *testing.T) {
- pc, err := redistest.Dial()
+ pc, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
defer pc.Close()
- nc, err := net.Dial("tcp", ":6379")
+ sc, err := redis.DialDefaultServer()
if err != nil {
- t.Fatal(err)
+ t.Fatalf("error connection to database, %v", err)
}
- defer nc.Close()
- nc.SetReadDeadline(time.Now().Add(4 * time.Second))
+ defer sc.Close()
- c := redis.PubSubConn{Conn: redis.NewConn(nc, 0, 0)}
+ c := redis.PubSubConn{Conn: sc}
c.Subscribe("c1")
expectPushed(t, c, "Subscribe(c1)", redis.Subscription{Kind: "subscribe", Channel: "c1", Count: 1})
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply.go
index 5af29bf51..57896147f 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply.go
@@ -215,7 +215,9 @@ func Bool(reply interface{}, err error) (bool, error) {
return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply)
}
-// MultiBulk is deprecated. Use Values.
+// MultiBulk is a helper that converts an array command reply to a []interface{}.
+//
+// Deprecated: Use Values instead.
func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) }
// Values is a helper that converts an array command reply to a []interface{}.
@@ -271,13 +273,40 @@ func Strings(reply interface{}, err error) ([]string, error) {
return nil, fmt.Errorf("redigo: unexpected type for Strings, got type %T", reply)
}
+// ByteSlices is a helper that converts an array command reply to a [][]byte.
+// If err is not equal to nil, then ByteSlices returns nil, err. Nil array
+// items are stay nil. ByteSlices returns an error if an array item is not a
+// bulk string or nil.
+func ByteSlices(reply interface{}, err error) ([][]byte, error) {
+ if err != nil {
+ return nil, err
+ }
+ switch reply := reply.(type) {
+ case []interface{}:
+ result := make([][]byte, len(reply))
+ for i := range reply {
+ if reply[i] == nil {
+ continue
+ }
+ p, ok := reply[i].([]byte)
+ if !ok {
+ return nil, fmt.Errorf("redigo: unexpected element type for ByteSlices, got type %T", reply[i])
+ }
+ result[i] = p
+ }
+ return result, nil
+ case nil:
+ return nil, ErrNil
+ case Error:
+ return nil, reply
+ }
+ return nil, fmt.Errorf("redigo: unexpected type for ByteSlices, got type %T", reply)
+}
+
// Ints is a helper that converts an array command reply to a []int. If
// err is not equal to nil, then Ints returns nil, err.
func Ints(reply interface{}, err error) ([]int, error) {
var ints []int
- if reply == nil {
- return ints, ErrNil
- }
values, err := Values(reply, err)
if err != nil {
return ints, err
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply_test.go
index 92744c590..83c0c7b98 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/reply_test.go
@@ -19,8 +19,7 @@ import (
"reflect"
"testing"
- "github.com/garyburd/redigo/internal/redistest"
- "github.com/garyburd/redigo/redis"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
type valueError struct {
@@ -58,6 +57,16 @@ var replyTests = []struct {
ve([]string(nil), redis.ErrNil),
},
{
+ "byteslices([v1, v2])",
+ ve(redis.ByteSlices([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
+ ve([][]byte{[]byte("v1"), []byte("v2")}, nil),
+ },
+ {
+ "byteslices(nil)",
+ ve(redis.ByteSlices(nil, nil)),
+ ve([][]byte(nil), redis.ErrNil),
+ },
+ {
"values([v1, v2])",
ve(redis.Values([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
ve([]interface{}{[]byte("v1"), []byte("v2")}, nil),
@@ -101,15 +110,16 @@ func TestReply(t *testing.T) {
}
}
-// dial wraps DialTestDB() with a more suitable function name for examples.
+// dial wraps DialDefaultServer() with a more suitable function name for examples.
func dial() (redis.Conn, error) {
- return redistest.Dial()
+ return redis.DialDefaultServer()
}
func ExampleBool() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
@@ -123,7 +133,8 @@ func ExampleBool() {
func ExampleInt() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
@@ -140,7 +151,8 @@ func ExampleInt() {
func ExampleInts() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
@@ -154,7 +166,8 @@ func ExampleInts() {
func ExampleString() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan.go
index 8c9cfa18d..962e94bcc 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan.go
@@ -32,11 +32,25 @@ func ensureLen(d reflect.Value, n int) {
}
func cannotConvert(d reflect.Value, s interface{}) error {
- return fmt.Errorf("redigo: Scan cannot convert from %s to %s",
- reflect.TypeOf(s), d.Type())
+ var sname string
+ switch s.(type) {
+ case string:
+ sname = "Redis simple string"
+ case Error:
+ sname = "Redis error"
+ case int64:
+ sname = "Redis integer"
+ case []byte:
+ sname = "Redis bulk string"
+ case []interface{}:
+ sname = "Redis array"
+ default:
+ sname = reflect.TypeOf(s).String()
+ }
+ return fmt.Errorf("cannot convert from %s to %s", sname, d.Type())
}
-func convertAssignBytes(d reflect.Value, s []byte) (err error) {
+func convertAssignBulkString(d reflect.Value, s []byte) (err error) {
switch d.Type().Kind() {
case reflect.Float32, reflect.Float64:
var x float64
@@ -98,7 +112,7 @@ func convertAssignInt(d reflect.Value, s int64) (err error) {
func convertAssignValue(d reflect.Value, s interface{}) (err error) {
switch s := s.(type) {
case []byte:
- err = convertAssignBytes(d, s)
+ err = convertAssignBulkString(d, s)
case int64:
err = convertAssignInt(d, s)
default:
@@ -107,7 +121,7 @@ func convertAssignValue(d reflect.Value, s interface{}) (err error) {
return err
}
-func convertAssignValues(d reflect.Value, s []interface{}) error {
+func convertAssignArray(d reflect.Value, s []interface{}) error {
if d.Type().Kind() != reflect.Slice {
return cannotConvert(d, s)
}
@@ -144,7 +158,7 @@ func convertAssign(d interface{}, s interface{}) (err error) {
if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
err = cannotConvert(d, s)
} else {
- err = convertAssignBytes(d.Elem(), s)
+ err = convertAssignBulkString(d.Elem(), s)
}
}
case int64:
@@ -169,6 +183,13 @@ func convertAssign(d interface{}, s interface{}) (err error) {
err = convertAssignInt(d.Elem(), s)
}
}
+ case string:
+ switch d := d.(type) {
+ case *string:
+ *d = string(s)
+ default:
+ err = cannotConvert(reflect.ValueOf(d), s)
+ }
case []interface{}:
switch d := d.(type) {
case *[]interface{}:
@@ -181,7 +202,7 @@ func convertAssign(d interface{}, s interface{}) (err error) {
if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr {
err = cannotConvert(d, s)
} else {
- err = convertAssignValues(d.Elem(), s)
+ err = convertAssignArray(d.Elem(), s)
}
}
case Error:
@@ -206,12 +227,13 @@ func convertAssign(d interface{}, s interface{}) (err error) {
// following the copied values.
func Scan(src []interface{}, dest ...interface{}) ([]interface{}, error) {
if len(src) < len(dest) {
- return nil, errors.New("redigo: Scan array short")
+ return nil, errors.New("redigo.Scan: array short")
}
var err error
for i, d := range dest {
err = convertAssign(d, src[i])
if err != nil {
+ err = fmt.Errorf("redigo.Scan: cannot assign to dest %d: %v", i, err)
break
}
}
@@ -219,9 +241,9 @@ func Scan(src []interface{}, dest ...interface{}) ([]interface{}, error) {
}
type fieldSpec struct {
- name string
- index []int
- //omitEmpty bool
+ name string
+ index []int
+ omitEmpty bool
}
type structSpec struct {
@@ -237,7 +259,7 @@ func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *st
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
switch {
- case f.PkgPath != "":
+ case f.PkgPath != "" && !f.Anonymous:
// Ignore unexported fields.
case f.Anonymous:
// TODO: Handle pointers. Requires change to decoder and
@@ -258,10 +280,10 @@ func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *st
}
for _, s := range p[1:] {
switch s {
- //case "omitempty":
- // fs.omitempty = true
+ case "omitempty":
+ fs.omitEmpty = true
default:
- panic(errors.New("redigo: unknown field flag " + s + " for type " + t.Name()))
+ panic(fmt.Errorf("redigo: unknown field tag %s for type %s", s, t.Name()))
}
}
}
@@ -321,7 +343,7 @@ func structSpecForType(t reflect.Type) *structSpec {
return ss
}
-var errScanStructValue = errors.New("redigo: ScanStruct value must be non-nil pointer to a struct")
+var errScanStructValue = errors.New("redigo.ScanStruct: value must be non-nil pointer to a struct")
// ScanStruct scans alternating names and values from src to a struct. The
// HGETALL and CONFIG GET commands return replies in this format.
@@ -350,7 +372,7 @@ func ScanStruct(src []interface{}, dest interface{}) error {
ss := structSpecForType(d.Type())
if len(src)%2 != 0 {
- return errors.New("redigo: ScanStruct expects even number of values in values")
+ return errors.New("redigo.ScanStruct: number of values not a multiple of 2")
}
for i := 0; i < len(src); i += 2 {
@@ -360,21 +382,21 @@ func ScanStruct(src []interface{}, dest interface{}) error {
}
name, ok := src[i].([]byte)
if !ok {
- return errors.New("redigo: ScanStruct key not a bulk string value")
+ return fmt.Errorf("redigo.ScanStruct: key %d not a bulk string value", i)
}
fs := ss.fieldSpec(name)
if fs == nil {
continue
}
if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil {
- return err
+ return fmt.Errorf("redigo.ScanStruct: cannot assign field %s: %v", fs.name, err)
}
}
return nil
}
var (
- errScanSliceValue = errors.New("redigo: ScanSlice dest must be non-nil pointer to a struct")
+ errScanSliceValue = errors.New("redigo.ScanSlice: dest must be non-nil pointer to a struct")
)
// ScanSlice scans src to the slice pointed to by dest. The elements the dest
@@ -407,7 +429,7 @@ func ScanSlice(src []interface{}, dest interface{}, fieldNames ...string) error
continue
}
if err := convertAssignValue(d.Index(i), s); err != nil {
- return err
+ return fmt.Errorf("redigo.ScanSlice: cannot assign element %d: %v", i, err)
}
}
return nil
@@ -420,18 +442,18 @@ func ScanSlice(src []interface{}, dest interface{}, fieldNames ...string) error
for i, name := range fieldNames {
fss[i] = ss.m[name]
if fss[i] == nil {
- return errors.New("redigo: ScanSlice bad field name " + name)
+ return fmt.Errorf("redigo.ScanSlice: ScanSlice bad field name %s", name)
}
}
}
if len(fss) == 0 {
- return errors.New("redigo: ScanSlice no struct fields")
+ return errors.New("redigo.ScanSlice: no struct fields")
}
n := len(src) / len(fss)
if n*len(fss) != len(src) {
- return errors.New("redigo: ScanSlice length not a multiple of struct field count")
+ return errors.New("redigo.ScanSlice: length not a multiple of struct field count")
}
ensureLen(d, n)
@@ -449,7 +471,7 @@ func ScanSlice(src []interface{}, dest interface{}, fieldNames ...string) error
continue
}
if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil {
- return err
+ return fmt.Errorf("redigo.ScanSlice: cannot assign element %d to field %s: %v", i*len(fss)+j, fs.name, err)
}
}
}
@@ -507,6 +529,26 @@ func flattenStruct(args Args, v reflect.Value) Args {
ss := structSpecForType(v.Type())
for _, fs := range ss.l {
fv := v.FieldByIndex(fs.index)
+ if fs.omitEmpty {
+ var empty = false
+ switch fv.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ empty = fv.Len() == 0
+ case reflect.Bool:
+ empty = !fv.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ empty = fv.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ empty = fv.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ empty = fv.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ empty = fv.IsNil()
+ }
+ if empty {
+ continue
+ }
+ }
args = append(args, fs.name, fv.Interface())
}
return args
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan_test.go
index b57dd8969..af1f2c2da 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/scan_test.go
@@ -16,10 +16,11 @@ package redis_test
import (
"fmt"
- "github.com/garyburd/redigo/redis"
"math"
"reflect"
"testing"
+
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
var scanConversionTests = []struct {
@@ -46,6 +47,7 @@ var scanConversionTests = []struct {
{[]byte("1"), true},
{int64(1), true},
{[]byte("t"), true},
+ {"hello", "hello"},
{[]byte("hello"), "hello"},
{[]byte("world"), []byte("world")},
{[]interface{}{[]byte("foo")}, []interface{}{[]byte("foo")}},
@@ -100,7 +102,8 @@ func TestScanConversionError(t *testing.T) {
func ExampleScan() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
@@ -115,7 +118,8 @@ func ExampleScan() {
"GET", "album:*->title",
"GET", "album:*->rating"))
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
for len(values) > 0 {
@@ -123,7 +127,8 @@ func ExampleScan() {
rating := -1 // initialize to illegal value to detect nil.
values, err = redis.Scan(values, &title, &rating)
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
if rating == -1 {
fmt.Println(title, "not-rated")
@@ -295,7 +300,8 @@ func TestScanSlice(t *testing.T) {
func ExampleScanSlice() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
@@ -310,7 +316,8 @@ func ExampleScanSlice() {
"GET", "album:*->title",
"GET", "album:*->rating"))
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
var albums []struct {
@@ -318,7 +325,8 @@ func ExampleScanSlice() {
Rating int
}
if err := redis.ScanSlice(values, &albums); err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
fmt.Printf("%v\n", albums)
// Output:
@@ -332,16 +340,17 @@ var argsTests = []struct {
}{
{"struct ptr",
redis.Args{}.AddFlat(&struct {
- I int `redis:"i"`
- U uint `redis:"u"`
- S string `redis:"s"`
- P []byte `redis:"p"`
+ I int `redis:"i"`
+ U uint `redis:"u"`
+ S string `redis:"s"`
+ P []byte `redis:"p"`
+ M map[string]string `redis:"m"`
Bt bool
Bf bool
}{
- -1234, 5678, "hello", []byte("world"), true, false,
+ -1234, 5678, "hello", []byte("world"), map[string]string{"hello": "world"}, true, false,
}),
- redis.Args{"i", int(-1234), "u", uint(5678), "s", "hello", "p", []byte("world"), "Bt", true, "Bf", false},
+ redis.Args{"i", int(-1234), "u", uint(5678), "s", "hello", "p", []byte("world"), "m", map[string]string{"hello": "world"}, "Bt", true, "Bf", false},
},
{"struct",
redis.Args{}.AddFlat(struct{ I int }{123}),
@@ -351,6 +360,20 @@ var argsTests = []struct {
redis.Args{}.Add(1).AddFlat([]string{"a", "b", "c"}).Add(2),
redis.Args{1, "a", "b", "c", 2},
},
+ {"struct omitempty",
+ redis.Args{}.AddFlat(&struct {
+ I int `redis:"i,omitempty"`
+ U uint `redis:"u,omitempty"`
+ S string `redis:"s,omitempty"`
+ P []byte `redis:"p,omitempty"`
+ M map[string]string `redis:"m,omitempty"`
+ Bt bool `redis:"Bt,omitempty"`
+ Bf bool `redis:"Bf,omitempty"`
+ }{
+ 0, 0, "", []byte{}, map[string]string{}, true, false,
+ }),
+ redis.Args{"Bt", true},
+ },
}
func TestArgs(t *testing.T) {
@@ -364,7 +387,8 @@ func TestArgs(t *testing.T) {
func ExampleArgs() {
c, err := dial()
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
defer c.Close()
@@ -379,7 +403,8 @@ func ExampleArgs() {
p1.Body = "Hello"
if _, err := c.Do("HMSET", redis.Args{}.Add("id1").AddFlat(&p1)...); err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
m := map[string]string{
@@ -389,18 +414,21 @@ func ExampleArgs() {
}
if _, err := c.Do("HMSET", redis.Args{}.Add("id2").AddFlat(m)...); err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
for _, id := range []string{"id1", "id2"} {
v, err := redis.Values(c.Do("HGETALL", id))
if err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
if err := redis.ScanStruct(v, &p2); err != nil {
- panic(err)
+ fmt.Println(err)
+ return
}
fmt.Printf("%+v\n", p2)
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/script_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/script_test.go
index c9635bf08..5d414ea59 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/script_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/script_test.go
@@ -20,8 +20,7 @@ import (
"testing"
"time"
- "github.com/garyburd/redigo/internal/redistest"
- "github.com/garyburd/redigo/redis"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
func ExampleScript(c redis.Conn, reply interface{}, err error) {
@@ -35,7 +34,7 @@ func ExampleScript(c redis.Conn, reply interface{}, err error) {
}
func TestScript(t *testing.T) {
- c, err := redistest.Dial()
+ c, err := redis.DialDefaultServer()
if err != nil {
t.Fatalf("error connection to database, %v", err)
}
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/test_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/test_test.go
index b959a11f4..7240fa1f3 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/test_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/test_test.go
@@ -16,7 +16,17 @@ package redis
import (
"bufio"
- "net"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
"time"
)
@@ -24,15 +34,144 @@ func SetNowFunc(f func() time.Time) {
nowFunc = f
}
-type nopCloser struct{ net.Conn }
+var (
+ ErrNegativeInt = errNegativeInt
-func (nopCloser) Close() error { return nil }
+ serverPath = flag.String("redis-server", "redis-server", "Path to redis server binary")
+ serverBasePort = flag.Int("redis-port", 16379, "Beginning of port range for test servers")
+ serverLogName = flag.String("redis-log", "", "Write Redis server logs to `filename`")
+ serverLog = ioutil.Discard
+
+ defaultServerMu sync.Mutex
+ defaultServer *Server
+ defaultServerErr error
+)
-// NewConnBufio is a hook for tests.
-func NewConnBufio(rw bufio.ReadWriter) Conn {
- return &conn{br: rw.Reader, bw: rw.Writer, conn: nopCloser{}}
+type Server struct {
+ name string
+ cmd *exec.Cmd
+ done chan struct{}
}
-var (
- ErrNegativeInt = errNegativeInt
-)
+func NewServer(name string, args ...string) (*Server, error) {
+ s := &Server{
+ name: name,
+ cmd: exec.Command(*serverPath, args...),
+ done: make(chan struct{}),
+ }
+
+ r, err := s.cmd.StdoutPipe()
+ if err != nil {
+ return nil, err
+ }
+
+ err = s.cmd.Start()
+ if err != nil {
+ return nil, err
+ }
+
+ ready := make(chan error, 1)
+ go s.watch(r, ready)
+
+ select {
+ case err = <-ready:
+ case <-time.After(time.Second * 10):
+ err = errors.New("timeout waiting for server to start")
+ }
+
+ if err != nil {
+ s.Stop()
+ return nil, err
+ }
+
+ return s, nil
+}
+
+func (s *Server) watch(r io.Reader, ready chan error) {
+ fmt.Fprintf(serverLog, "%d START %s \n", s.cmd.Process.Pid, s.name)
+ var listening bool
+ var text string
+ scn := bufio.NewScanner(r)
+ for scn.Scan() {
+ text = scn.Text()
+ fmt.Fprintf(serverLog, "%s\n", text)
+ if !listening {
+ if strings.Contains(text, "The server is now ready to accept connections on port") {
+ listening = true
+ ready <- nil
+ }
+ }
+ }
+ if !listening {
+ ready <- fmt.Errorf("server exited: %s", text)
+ }
+ s.cmd.Wait()
+ fmt.Fprintf(serverLog, "%d STOP %s \n", s.cmd.Process.Pid, s.name)
+ close(s.done)
+}
+
+func (s *Server) Stop() {
+ s.cmd.Process.Signal(os.Interrupt)
+ <-s.done
+}
+
+// stopDefaultServer stops the server created by DialDefaultServer.
+func stopDefaultServer() {
+ defaultServerMu.Lock()
+ defer defaultServerMu.Unlock()
+ if defaultServer != nil {
+ defaultServer.Stop()
+ defaultServer = nil
+ }
+}
+
+// startDefaultServer starts the default server if not already running.
+func startDefaultServer() error {
+ defaultServerMu.Lock()
+ defer defaultServerMu.Unlock()
+ if defaultServer != nil || defaultServerErr != nil {
+ return defaultServerErr
+ }
+ defaultServer, defaultServerErr = NewServer(
+ "default",
+ "--port", strconv.Itoa(*serverBasePort),
+ "--save", "",
+ "--appendonly", "no")
+ return defaultServerErr
+}
+
+// DialDefaultServer starts the test server if not already started and dials a
+// connection to the server.
+func DialDefaultServer() (Conn, error) {
+ if err := startDefaultServer(); err != nil {
+ return nil, err
+ }
+ c, err := Dial("tcp", fmt.Sprintf(":%d", *serverBasePort), DialReadTimeout(1*time.Second), DialWriteTimeout(1*time.Second))
+ if err != nil {
+ return nil, err
+ }
+ c.Do("FLUSHDB")
+ return c, nil
+}
+
+func TestMain(m *testing.M) {
+ os.Exit(func() int {
+ flag.Parse()
+
+ var f *os.File
+ if *serverLogName != "" {
+ var err error
+ f, err = os.OpenFile(*serverLogName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error opening redis-log: %v\n", err)
+ return 1
+ }
+ defer f.Close()
+ serverLog = f
+ }
+
+ defer stopDefaultServer()
+
+ return m.Run()
+ }())
+}
diff --git a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/zpop_example_test.go b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/zpop_example_test.go
index 1d86ee6ce..3e4bca418 100644
--- a/Godeps/_workspace/src/github.com/garyburd/redigo/redis/zpop_example_test.go
+++ b/Godeps/_workspace/src/github.com/garyburd/redigo/redis/zpop_example_test.go
@@ -16,7 +16,7 @@ package redis_test
import (
"fmt"
- "github.com/garyburd/redigo/redis"
+ "github.com/mattermost/platform/Godeps/_workspace/src/github.com/garyburd/redigo/redis"
)
// zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands.