forked from mirror/redis
Add sentinel tests.
This commit is contained in:
parent
1b515b695a
commit
e4b55ec4ee
|
@ -0,0 +1,173 @@
|
|||
package redis_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"gopkg.in/redis.v2"
|
||||
)
|
||||
|
||||
func startRedis(port string) (*exec.Cmd, error) {
|
||||
cmd := exec.Command("redis-server", "--port", port)
|
||||
if false {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func startRedisSlave(port, slave string) (*exec.Cmd, error) {
|
||||
cmd := exec.Command("redis-server", "--port", port, "--slaveof", "127.0.0.1", slave)
|
||||
if false {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func startRedisSentinel(port, masterName, masterPort string) (*exec.Cmd, error) {
|
||||
dir, err := ioutil.TempDir("", "sentinel")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sentinelConfFilepath := filepath.Join(dir, "sentinel.conf")
|
||||
tpl, err := template.New("sentinel.conf").Parse(sentinelConf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := struct {
|
||||
Port string
|
||||
MasterName string
|
||||
MasterPort string
|
||||
}{
|
||||
Port: port,
|
||||
MasterName: masterName,
|
||||
MasterPort: masterPort,
|
||||
}
|
||||
if err := writeTemplateToFile(sentinelConfFilepath, tpl, data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command("redis-server", sentinelConfFilepath, "--sentinel")
|
||||
if false {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func writeTemplateToFile(path string, t *template.Template, data interface{}) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
return t.Execute(f, data)
|
||||
}
|
||||
|
||||
func TestSentinel(t *testing.T) {
|
||||
masterName := "mymaster"
|
||||
masterPort := "8123"
|
||||
slavePort := "8124"
|
||||
sentinelPort := "26379"
|
||||
|
||||
_, err := startRedis(masterPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
master := redis.NewTCPClient(&redis.Options{
|
||||
Addr: ":" + masterPort,
|
||||
})
|
||||
if err := master.Ping().Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer master.Shutdown()
|
||||
|
||||
_, err = startRedisSlave(slavePort, masterPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
slave := redis.NewTCPClient(&redis.Options{
|
||||
Addr: ":" + slavePort,
|
||||
})
|
||||
if err := slave.Ping().Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer slave.Shutdown()
|
||||
|
||||
_, err = startRedisSentinel(sentinelPort, masterName, masterPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
sentinel := redis.NewTCPClient(&redis.Options{
|
||||
Addr: ":" + sentinelPort,
|
||||
})
|
||||
if err := sentinel.Ping().Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer sentinel.Shutdown()
|
||||
|
||||
client := redis.NewFailoverClient(&redis.FailoverOptions{
|
||||
MasterName: masterName,
|
||||
SentinelAddrs: []string{":" + sentinelPort},
|
||||
})
|
||||
|
||||
if err := client.Set("foo", "master").Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
val, err := master.Get("foo").Result()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if val != "master" {
|
||||
t.Fatalf(`got %q, expected "master"`, val)
|
||||
}
|
||||
|
||||
// Kill master.
|
||||
master.Shutdown()
|
||||
|
||||
// Wait for Redis sentinel to elect new master.
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Check that client picked up new master.
|
||||
val, err = client.Get("foo").Result()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if val != "master" {
|
||||
t.Fatalf(`got %q, expected "master"`, val)
|
||||
}
|
||||
}
|
||||
|
||||
var sentinelConf = `
|
||||
port {{ .Port }}
|
||||
|
||||
sentinel monitor {{ .MasterName }} 127.0.0.1 {{ .MasterPort }} 1
|
||||
sentinel down-after-milliseconds {{ .MasterName }} 200
|
||||
sentinel failover-timeout {{ .MasterName }} 400
|
||||
sentinel parallel-syncs {{ .MasterName }} 1
|
||||
`
|
Loading…
Reference in New Issue