diff --git a/e2e/ctl_v3_migrate_test.go b/e2e/ctl_v3_migrate_test.go index 3c6ac15f5def..9d7a0330643f 100644 --- a/e2e/ctl_v3_migrate_test.go +++ b/e2e/ctl_v3_migrate_test.go @@ -52,7 +52,7 @@ func TestCtlV3Migrate(t *testing.T) { for i := range epc.procs { dataDirs[i] = epc.procs[i].cfg.dataDirPath } - if err := epc.Stop(); err != nil { + if err := epc.StopAll(); err != nil { t.Fatalf("error closing etcd processes (%v)", err) } @@ -74,7 +74,7 @@ func TestCtlV3Migrate(t *testing.T) { for i := range epc.procs { epc.procs[i].cfg.keepDataDir = true } - if err := epc.Restart(); err != nil { + if err := epc.RestartAll(); err != nil { t.Fatal(err) } diff --git a/e2e/etcd_release_migrate_test.go b/e2e/etcd_release_migrate_test.go new file mode 100644 index 000000000000..fa79d6346b92 --- /dev/null +++ b/e2e/etcd_release_migrate_test.go @@ -0,0 +1,73 @@ +// Copyright 2016 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "os" + "testing" + "time" + + "github.com/coreos/etcd/pkg/testutil" +) + +// TestReleaseMigrate ensures that changes to master branch does not affect the +// migration from latest etcd releases. +func TestReleaseMigrate(t *testing.T) { + releaseBinaryPath := os.Getenv("RELEASE_BINARY") + if releaseBinaryPath == "" { + t.Skip("skipping release migration tests (release binary not provided)") + } + + defer testutil.AfterTest(t) + + copiedCfg := configNoTLS + copiedCfg.execPath = releaseBinaryPath + epc, err := newEtcdProcessCluster(&copiedCfg) + if err != nil { + t.Fatalf("could not start etcd process cluster (%v)", err) + } + defer func() { + if errC := epc.Close(); errC != nil { + t.Fatalf("error closing etcd processes (%v)", errC) + } + }() + + os.Setenv("ETCDCTL_API", "3") + defer os.Unsetenv("ETCDCTL_API") + cx := ctlCtx{ + t: t, + cfg: configNoTLS, + dialTimeout: 7 * time.Second, + quorum: true, + epc: epc, + } + if err := ctlV3Put(cx, "foo", "bar", ""); err != nil { + cx.t.Fatalf("ctlV3Put error (%v)", err) + } + + for i := range epc.backends() { + if err := epc.Stop(i); err != nil { + t.Fatalf("error closing etcd process (%v)", err) + } + epc.procs[i].cfg.execPath = "../bin/etcd" + epc.procs[i].cfg.keepDataDir = true + if err := epc.Restart(i); err != nil { + t.Fatalf("error restarting etcd process (%v)", err) + } + if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil { + cx.t.Fatalf("ctlV3Get error (%v)", err) + } + } +} diff --git a/e2e/etcd_test.go b/e2e/etcd_test.go index 54d0d0dd7270..a465158bd094 100644 --- a/e2e/etcd_test.go +++ b/e2e/etcd_test.go @@ -42,17 +42,20 @@ const ( var ( configNoTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, proxySize: 0, initialToken: "new", } configAutoTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, isPeerTLS: true, isPeerAutoTLS: true, initialToken: "new", } configTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, proxySize: 0, clientTLS: clientTLS, @@ -60,18 +63,21 @@ var ( initialToken: "new", } configClientTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, proxySize: 0, clientTLS: clientTLS, initialToken: "new", } configClientBoth = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 1, proxySize: 0, clientTLS: clientTLSAndNonTLS, initialToken: "new", } configClientAutoTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 1, proxySize: 0, isClientAutoTLS: true, @@ -79,17 +85,20 @@ var ( initialToken: "new", } configPeerTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, proxySize: 0, isPeerTLS: true, initialToken: "new", } configWithProxy = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, proxySize: 1, initialToken: "new", } configWithProxyTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, proxySize: 1, clientTLS: clientTLS, @@ -97,6 +106,7 @@ var ( initialToken: "new", } configWithProxyPeerTLS = etcdProcessClusterConfig{ + execPath: "../bin/etcd", clusterSize: 3, proxySize: 1, isPeerTLS: true, @@ -122,7 +132,8 @@ type etcdProcess struct { } type etcdProcessConfig struct { - args []string + execPath string + args []string dataDirPath string keepDataDir bool @@ -137,6 +148,7 @@ type etcdProcessConfig struct { } type etcdProcessClusterConfig struct { + execPath string dataDirPath string keepDataDir bool @@ -175,7 +187,7 @@ func newEtcdProcessCluster(cfg *etcdProcessClusterConfig) (*etcdProcessCluster, } func newEtcdProcess(cfg *etcdProcessConfig) (*etcdProcess, error) { - if !fileutil.Exist("../bin/etcd") { + if !fileutil.Exist(cfg.execPath) { return nil, fmt.Errorf("could not find etcd binary") } @@ -185,7 +197,7 @@ func newEtcdProcess(cfg *etcdProcessConfig) (*etcdProcess, error) { } } - child, err := spawnCmd(append([]string{"../bin/etcd"}, cfg.args...)) + child, err := spawnCmd(append([]string{cfg.execPath}, cfg.args...)) if err != nil { return nil, err } @@ -256,6 +268,7 @@ func (cfg *etcdProcessClusterConfig) etcdProcessConfigs() []*etcdProcessConfig { args = append(args, cfg.tlsArgs()...) etcdCfgs[i] = &etcdProcessConfig{ + execPath: cfg.execPath, args: args, dataDirPath: dataDirPath, keepDataDir: cfg.keepDataDir, @@ -281,6 +294,7 @@ func (cfg *etcdProcessClusterConfig) etcdProcessConfigs() []*etcdProcessConfig { } args = append(args, cfg.tlsArgs()...) etcdCfgs[cfg.clusterSize+i] = &etcdProcessConfig{ + execPath: cfg.execPath, args: args, dataDirPath: dataDirPath, keepDataDir: cfg.keepDataDir, @@ -351,7 +365,7 @@ func (epc *etcdProcessCluster) Start() (err error) { return nil } -func (epc *etcdProcessCluster) Restart() error { +func (epc *etcdProcessCluster) RestartAll() error { for i := range epc.procs { proc, err := newEtcdProcess(epc.procs[i].cfg) if err != nil { @@ -363,7 +377,29 @@ func (epc *etcdProcessCluster) Restart() error { return epc.Start() } -func (epc *etcdProcessCluster) Stop() (err error) { +func (epc *etcdProcessCluster) Restart(i int) error { + proc, err := newEtcdProcess(epc.procs[i].cfg) + if err != nil { + epc.Close() + return err + } + epc.procs[i] = proc + + readyStr := "enabled capabilities for version" + if epc.procs[i].cfg.isProxy { + readyStr = "httpproxy: endpoints found" + } + + if _, err = epc.procs[i].proc.Expect(readyStr); err != nil { + epc.Close() + return err + } + close(epc.procs[i].donec) + + return nil +} + +func (epc *etcdProcessCluster) StopAll() (err error) { for _, p := range epc.procs { if p == nil { continue @@ -380,8 +416,22 @@ func (epc *etcdProcessCluster) Stop() (err error) { return err } +func (epc *etcdProcessCluster) Stop(i int) error { + p := epc.procs[i] + if p == nil { + return nil + } + + if err := p.proc.Stop(); err != nil { + return err + } + + <-p.donec + return nil +} + func (epc *etcdProcessCluster) Close() error { - err := epc.Stop() + err := epc.StopAll() for _, p := range epc.procs { os.RemoveAll(p.cfg.dataDirPath) }