Merge pull request #298 from benbjohnson/migration-test

Migration test
This commit is contained in:
Ben Johnson
2013-11-13 10:19:33 -08:00
23 changed files with 252 additions and 0 deletions

2
release_version.go Normal file
View File

@@ -0,0 +1,2 @@
package main
const releaseVersion = "v0.1.2-33-g1a2a9d6"

View File

@@ -32,6 +32,12 @@ import (
// The default version to set when the store is first initialized.
const defaultVersion = 2
var minExpireTime time.Time
func init() {
minExpireTime, _ = time.Parse(time.RFC3339, "2000-01-01T00:00:00Z")
}
type Store interface {
Version() int
CommandFactory() CommandFactory
@@ -384,6 +390,13 @@ func (s *store) internalCreate(nodePath string, value string, unique bool, repla
nodePath = path.Clean(path.Join("/", nodePath))
// Assume expire times that are way in the past are not valid.
// This can occur when the time is serialized to JSON and read back in.
if expireTime.Before(minExpireTime) {
expireTime = Permanent
}
dir, newNodeName := path.Split(nodePath)
// walk through the nodePath, create dirs and get the last directory node

15
tests/fixtures/v1.cluster/README vendored Normal file
View File

@@ -0,0 +1,15 @@
README
The scripts in this directory should be run from the project root:
$ cd $GOPATH/src/github.com/coreos/etcd
$ tests/fixtures/v1/run.1.sh
Scripts with numbers should be run in separate terminal windows (in order):
$ tests/fixtures/v1/run.1.sh
$ tests/fixtures/v1/run.2.sh
$ tests/fixtures/v1/run.3.sh
$ tests/fixtures/v1/run.4.sh
The resulting server state data can be found in tmp/node*.

1
tests/fixtures/v1.cluster/node0/conf vendored Normal file
View File

@@ -0,0 +1 @@
{"commitIndex":15,"peers":[{"name":"node2","connectionString":""}]}

18
tests/fixtures/v1.cluster/node0/info vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "node0",
"raftURL": "http://127.0.0.1:7001",
"etcdURL": "http://127.0.0.1:4001",
"webURL": "",
"raftListenHost": "127.0.0.1:7001",
"etcdListenHost": "127.0.0.1:4001",
"raftTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
},
"etcdTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
}
}

BIN
tests/fixtures/v1.cluster/node0/log vendored Normal file

Binary file not shown.

1
tests/fixtures/v1.cluster/node2/conf vendored Normal file
View File

@@ -0,0 +1 @@
{"commitIndex":15,"peers":[{"name":"node0","connectionString":""}]}

18
tests/fixtures/v1.cluster/node2/info vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "node2",
"raftURL": "http://127.0.0.1:7002",
"etcdURL": "http://127.0.0.1:4002",
"webURL": "",
"raftListenHost": "127.0.0.1:7002",
"etcdListenHost": "127.0.0.1:4002",
"raftTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
},
"etcdTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
}
}

BIN
tests/fixtures/v1.cluster/node2/log vendored Normal file

Binary file not shown.

1
tests/fixtures/v1.cluster/node3/conf vendored Normal file
View File

@@ -0,0 +1 @@
{"commitIndex":15,"peers":[{"name":"node0","connectionString":""},{"name":"node2","connectionString":""}]}

18
tests/fixtures/v1.cluster/node3/info vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "node3",
"raftURL": "http://127.0.0.1:7003",
"etcdURL": "http://127.0.0.1:4003",
"webURL": "",
"raftListenHost": "127.0.0.1:7003",
"etcdListenHost": "127.0.0.1:4003",
"raftTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
},
"etcdTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
}
}

BIN
tests/fixtures/v1.cluster/node3/log vendored Normal file

Binary file not shown.

4
tests/fixtures/v1.cluster/run.1.sh vendored Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
./build
./etcd -d tmp/node0 -n node0

3
tests/fixtures/v1.cluster/run.2.sh vendored Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
./etcd -s 127.0.0.1:7002 -c 127.0.0.1:4002 -C 127.0.0.1:7001 -d tmp/node2 -n node2

3
tests/fixtures/v1.cluster/run.3.sh vendored Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
./etcd -s 127.0.0.1:7003 -c 127.0.0.1:4003 -C 127.0.0.1:7001 -d tmp/node3 -n node3

13
tests/fixtures/v1.cluster/run.4.sh vendored Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello world"
curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello etcd"
curl -L http://127.0.0.1:4001/v1/keys/message -X DELETE
curl -L http://127.0.0.1:4001/v1/keys/message2 -d value="Hola"
curl -L http://127.0.0.1:4001/v1/keys/expiring -d value=bar -d ttl=5
curl -L http://127.0.0.1:4001/v1/keys/foo -d value=one
curl -L http://127.0.0.1:4001/v1/keys/foo -d prevValue=two -d value=three
curl -L http://127.0.0.1:4001/v1/keys/foo -d prevValue=one -d value=two
curl -L http://127.0.0.1:4001/v1/keys/bar -d prevValue= -d value=four
curl -L http://127.0.0.1:4001/v1/keys/bar -d prevValue= -d value=five
curl -X DELETE http://127.0.0.1:7001/remove/node2

13
tests/fixtures/v1.solo/README vendored Normal file
View File

@@ -0,0 +1,13 @@
README
The scripts in this directory should be run from the project root:
$ cd $GOPATH/src/github.com/coreos/etcd
$ tests/fixtures/v1.solo/run.1.sh
Scripts with numbers should be run in separate terminal windows (in order):
$ tests/fixtures/v1/run.1.sh
$ tests/fixtures/v1/run.2.sh
The resulting server state data can be found in tmp/node0.

1
tests/fixtures/v1.solo/node0/conf vendored Normal file
View File

@@ -0,0 +1 @@
{"commitIndex":1,"peers":[]}

18
tests/fixtures/v1.solo/node0/info vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "node0",
"raftURL": "http://127.0.0.1:7001",
"etcdURL": "http://127.0.0.1:4001",
"webURL": "",
"raftListenHost": "127.0.0.1:7001",
"etcdListenHost": "127.0.0.1:4001",
"raftTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
},
"etcdTLS": {
"CertFile": "",
"KeyFile": "",
"CAFile": ""
}
}

BIN
tests/fixtures/v1.solo/node0/log vendored Normal file

Binary file not shown.

4
tests/fixtures/v1.solo/run.1.sh vendored Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
./build
./etcd -d tmp/node0 -n node0

3
tests/fixtures/v1.solo/run.2.sh vendored Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh
curl -L http://127.0.0.1:4001/v1/keys/message -d value="Hello world"

View File

@@ -0,0 +1,103 @@
package test
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
"github.com/coreos/etcd/tests"
"github.com/stretchr/testify/assert"
)
// Ensure that we can start a v2 node from the log of a v1 node.
func TestV1SoloMigration(t *testing.T) {
path, _ := ioutil.TempDir("", "etcd-")
os.MkdirAll(path, 0777)
defer os.RemoveAll(path)
nodepath := filepath.Join(path, "node0")
fixturepath, _ := filepath.Abs("../fixtures/v1.solo/node0")
fmt.Println("DATA_DIR =", nodepath)
// Copy over fixture files.
c := exec.Command("cp", "-rf", fixturepath, nodepath)
if out, err := c.CombinedOutput(); err != nil {
fmt.Println(">>>>>>\n", string(out), "<<<<<<")
panic("Fixture initialization error:" + err.Error())
}
procAttr := new(os.ProcAttr)
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
args := []string{"etcd", fmt.Sprintf("-d=%s", nodepath)}
args = append(args, "-c", "127.0.0.1:4001")
args = append(args, "-s", "127.0.0.1:7001")
process, err := os.StartProcess(EtcdBinPath, args, procAttr)
if err != nil {
t.Fatal("start process failed:" + err.Error())
return
}
defer process.Kill()
time.Sleep(time.Second)
// Ensure deleted message is removed.
resp, err := tests.Get("http://localhost:4001/v2/keys/message")
tests.ReadBody(resp)
assert.Nil(t, err, "")
assert.Equal(t, resp.StatusCode, 200, "")
}
// Ensure that we can start a v2 cluster from the logs of a v1 cluster.
func TestV1ClusterMigration(t *testing.T) {
path, _ := ioutil.TempDir("", "etcd-")
os.RemoveAll(path)
defer os.RemoveAll(path)
nodes := []string{"node0", "node2"}
for i, node := range nodes {
nodepath := filepath.Join(path, node)
fixturepath, _ := filepath.Abs(filepath.Join("../fixtures/v1.cluster/", node))
fmt.Println("FIXPATH =", fixturepath)
fmt.Println("NODEPATH =", nodepath)
os.MkdirAll(filepath.Dir(nodepath), 0777)
// Copy over fixture files.
c := exec.Command("cp", "-rf", fixturepath, nodepath)
if out, err := c.CombinedOutput(); err != nil {
fmt.Println(">>>>>>\n", string(out), "<<<<<<")
panic("Fixture initialization error:" + err.Error())
}
procAttr := new(os.ProcAttr)
procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr}
args := []string{"etcd", fmt.Sprintf("-d=%s", nodepath)}
args = append(args, "-c", fmt.Sprintf("127.0.0.1:%d", 4001 + i))
args = append(args, "-s", fmt.Sprintf("127.0.0.1:%d", 7001 + i))
process, err := os.StartProcess(EtcdBinPath, args, procAttr)
if err != nil {
t.Fatal("start process failed:" + err.Error())
return
}
defer process.Kill()
time.Sleep(time.Second)
}
// Ensure deleted message is removed.
resp, err := tests.Get("http://localhost:4001/v2/keys/message")
body := tests.ReadBody(resp)
assert.Nil(t, err, "")
assert.Equal(t, resp.StatusCode, 400, )
assert.Equal(t, string(body), `{"errorCode":100,"message":"Key Not Found","cause":"/message","index":11}`+"\n")
// Ensure TTL'd message is removed.
resp, err = tests.Get("http://localhost:4001/v2/keys/foo")
body = tests.ReadBody(resp)
assert.Nil(t, err, "")
assert.Equal(t, resp.StatusCode, 200, "")
assert.Equal(t, string(body), `{"action":"get","key":"/foo","value":"one","modifiedIndex":9}`)
}