mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
e2e: etcdctl test for proxy no-sync
For https://github.com/coreos/etcd/issues/3894.
This commit is contained in:
parent
5bd930c9d2
commit
6491bae27f
@ -145,10 +145,12 @@ type etcdProcessConfig struct {
|
|||||||
args []string
|
args []string
|
||||||
dataDirPath string
|
dataDirPath string
|
||||||
acurl url.URL
|
acurl url.URL
|
||||||
|
isProxy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type etcdProcessClusterConfig struct {
|
type etcdProcessClusterConfig struct {
|
||||||
clusterSize int
|
clusterSize int
|
||||||
|
proxySize int
|
||||||
isClientTLS bool
|
isClientTLS bool
|
||||||
isPeerTLS bool
|
isPeerTLS bool
|
||||||
initialToken string
|
initialToken string
|
||||||
@ -160,7 +162,7 @@ func newEtcdProcessCluster(cfg *etcdProcessClusterConfig) (*etcdProcessCluster,
|
|||||||
etcdCfgs := cfg.etcdProcessConfigs()
|
etcdCfgs := cfg.etcdProcessConfigs()
|
||||||
epc := &etcdProcessCluster{
|
epc := &etcdProcessCluster{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
procs: make([]*etcdProcess, cfg.clusterSize),
|
procs: make([]*etcdProcess, cfg.clusterSize+cfg.proxySize),
|
||||||
}
|
}
|
||||||
|
|
||||||
// launch etcd processes
|
// launch etcd processes
|
||||||
@ -174,11 +176,15 @@ func newEtcdProcessCluster(cfg *etcdProcessClusterConfig) (*etcdProcessCluster,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait for cluster to start
|
// wait for cluster to start
|
||||||
readyC := make(chan error, cfg.clusterSize)
|
readyC := make(chan error, cfg.clusterSize+cfg.proxySize)
|
||||||
readyStr := "set the initial cluster version"
|
readyStr := "set the initial cluster version"
|
||||||
for i := range etcdCfgs {
|
for i := range etcdCfgs {
|
||||||
go func(etcdp *etcdProcess) {
|
go func(etcdp *etcdProcess) {
|
||||||
_, err := etcdp.proc.ExpectRegex(readyStr)
|
rs := readyStr
|
||||||
|
if etcdp.cfg.isProxy {
|
||||||
|
rs = "listening for client requests"
|
||||||
|
}
|
||||||
|
_, err := etcdp.proc.ExpectRegex(rs)
|
||||||
readyC <- err
|
readyC <- err
|
||||||
etcdp.proc.ReadLine()
|
etcdp.proc.ReadLine()
|
||||||
etcdp.proc.Interact() // this blocks(leaks) if another goroutine is reading
|
etcdp.proc.Interact() // this blocks(leaks) if another goroutine is reading
|
||||||
@ -220,7 +226,7 @@ func (cfg *etcdProcessClusterConfig) etcdProcessConfigs() []*etcdProcessConfig {
|
|||||||
peerScheme = "https"
|
peerScheme = "https"
|
||||||
}
|
}
|
||||||
|
|
||||||
etcdCfgs := make([]*etcdProcessConfig, cfg.clusterSize)
|
etcdCfgs := make([]*etcdProcessConfig, cfg.clusterSize+cfg.proxySize)
|
||||||
initialCluster := make([]string, cfg.clusterSize)
|
initialCluster := make([]string, cfg.clusterSize)
|
||||||
for i := 0; i < cfg.clusterSize; i++ {
|
for i := 0; i < cfg.clusterSize; i++ {
|
||||||
port := etcdProcessBasePort + 2*i
|
port := etcdProcessBasePort + 2*i
|
||||||
@ -262,6 +268,24 @@ func (cfg *etcdProcessClusterConfig) etcdProcessConfigs() []*etcdProcessConfig {
|
|||||||
acurl: curl,
|
acurl: curl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i := 0; i < cfg.proxySize; i++ {
|
||||||
|
port := etcdProcessBasePort + 2*cfg.clusterSize + i + 1
|
||||||
|
curl := url.URL{Scheme: clientScheme, Host: fmt.Sprintf("localhost:%d", port)}
|
||||||
|
name := fmt.Sprintf("testname-proxy%d", i)
|
||||||
|
dataDirPath := name + ".etcd"
|
||||||
|
args := []string{
|
||||||
|
"--name", name,
|
||||||
|
"--proxy", "on",
|
||||||
|
"--listen-client-urls", curl.String(),
|
||||||
|
"--data-dir", dataDirPath,
|
||||||
|
}
|
||||||
|
etcdCfgs[cfg.clusterSize+i] = &etcdProcessConfig{
|
||||||
|
args: args,
|
||||||
|
dataDirPath: dataDirPath,
|
||||||
|
acurl: curl,
|
||||||
|
isProxy: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initialClusterArgs := []string{"--initial-cluster", strings.Join(initialCluster, ",")}
|
initialClusterArgs := []string{"--initial-cluster", strings.Join(initialCluster, ",")}
|
||||||
for i := range etcdCfgs {
|
for i := range etcdCfgs {
|
||||||
@ -289,6 +313,15 @@ func (epc *etcdProcessCluster) Close() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// proxies returns only the proxy etcdProcess.
|
||||||
|
func (epc *etcdProcessCluster) proxies() []*etcdProcess {
|
||||||
|
return epc.procs[epc.cfg.clusterSize:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (epc *etcdProcessCluster) backends() []*etcdProcess {
|
||||||
|
return epc.procs[:epc.cfg.clusterSize]
|
||||||
|
}
|
||||||
|
|
||||||
func spawnCmd(args []string) (*gexpect.ExpectSubprocess, error) {
|
func spawnCmd(args []string) (*gexpect.ExpectSubprocess, error) {
|
||||||
// redirect stderr to stdout since gexpect only uses stdout
|
// redirect stderr to stdout since gexpect only uses stdout
|
||||||
cmd := `/bin/sh -c "` + strings.Join(args, " ") + ` 2>&1 "`
|
cmd := `/bin/sh -c "` + strings.Join(args, " ") + ` 2>&1 "`
|
||||||
|
125
e2e/etcdctl_test.go
Normal file
125
e2e/etcdctl_test.go
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// Copyright 2016 CoreOS, Inc.
|
||||||
|
//
|
||||||
|
// 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 (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/etcd/pkg/fileutil"
|
||||||
|
"github.com/coreos/etcd/pkg/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBasicOpsV2CtlWatchWithProxy(t *testing.T) {
|
||||||
|
defer testutil.AfterTest(t)
|
||||||
|
testProcessClusterV2CtlWatch(
|
||||||
|
t,
|
||||||
|
&etcdProcessClusterConfig{
|
||||||
|
clusterSize: 3,
|
||||||
|
proxySize: 1,
|
||||||
|
isClientTLS: false,
|
||||||
|
isPeerTLS: false,
|
||||||
|
initialToken: "new",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBasicOpsV2CtlWatchWithProxyNoSync(t *testing.T) {
|
||||||
|
defer testutil.AfterTest(t)
|
||||||
|
testProcessClusterV2CtlWatch(
|
||||||
|
t,
|
||||||
|
&etcdProcessClusterConfig{
|
||||||
|
clusterSize: 3,
|
||||||
|
proxySize: 1,
|
||||||
|
isClientTLS: false,
|
||||||
|
isPeerTLS: false,
|
||||||
|
initialToken: "new",
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func etcdctlSet(epc *etcdProcessCluster, key, value string, noSync bool) error {
|
||||||
|
endpoint := ""
|
||||||
|
if proxies := epc.proxies(); len(proxies) != 0 {
|
||||||
|
endpoint = proxies[0].cfg.acurl.String()
|
||||||
|
} else if backends := epc.backends(); len(backends) != 0 {
|
||||||
|
endpoint = backends[0].cfg.acurl.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
putArgs := []string{"../bin/etcdctl", "--endpoint", endpoint}
|
||||||
|
if noSync {
|
||||||
|
putArgs = append(putArgs, "--no-sync")
|
||||||
|
}
|
||||||
|
putArgs = append(putArgs, "set", key, value)
|
||||||
|
|
||||||
|
return spawnWithExpect(putArgs, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func etcdctlWatch(epc *etcdProcessCluster, key, value string, noSync bool, done chan struct{}, errChan chan error) {
|
||||||
|
endpoint := ""
|
||||||
|
if proxies := epc.proxies(); len(proxies) != 0 {
|
||||||
|
endpoint = proxies[0].cfg.acurl.String()
|
||||||
|
} else if backends := epc.backends(); len(backends) != 0 {
|
||||||
|
endpoint = backends[0].cfg.acurl.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
watchArgs := []string{"../bin/etcdctl", "--endpoint", endpoint}
|
||||||
|
if noSync {
|
||||||
|
watchArgs = append(watchArgs, "--no-sync")
|
||||||
|
}
|
||||||
|
watchArgs = append(watchArgs, "watch", key)
|
||||||
|
|
||||||
|
if err := spawnWithExpect(watchArgs, value); err != nil {
|
||||||
|
errChan <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
done <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testProcessClusterV2CtlWatch(t *testing.T, cfg *etcdProcessClusterConfig, noSync bool) {
|
||||||
|
if fileutil.Exist("../bin/etcdctl") == false {
|
||||||
|
t.Fatalf("could not find etcdctl binary")
|
||||||
|
}
|
||||||
|
|
||||||
|
epc, errC := newEtcdProcessCluster(cfg)
|
||||||
|
if errC != nil {
|
||||||
|
t.Fatalf("could not start etcd process cluster (%v)", errC)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if errC := epc.Close(); errC != nil {
|
||||||
|
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
key, value := "foo", "bar"
|
||||||
|
done, errChan := make(chan struct{}), make(chan error)
|
||||||
|
|
||||||
|
go etcdctlWatch(epc, key, value, noSync, done, errChan)
|
||||||
|
|
||||||
|
if err := etcdctlSet(epc, key, value, noSync); err != nil {
|
||||||
|
t.Fatalf("failed set (%v)", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
case err := <-errChan:
|
||||||
|
t.Fatalf("failed watch (%v)", err)
|
||||||
|
case <-time.After(2 * time.Second):
|
||||||
|
t.Fatalf("watch timed out!")
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user