mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 17:57:51 +00:00
Add vendor folder to git
This commit is contained in:
parent
66cf5eaafb
commit
183585f56f
6916 changed files with 2629581 additions and 1 deletions
473
vendor/github.com/coreos/etcd/e2e/ctl_v2_test.go
generated
vendored
Normal file
473
vendor/github.com/coreos/etcd/e2e/ctl_v2_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
// 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 (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/fileutil"
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestCtlV2Set(t *testing.T) { testCtlV2Set(t, &configNoTLS, false) }
|
||||
func TestCtlV2SetQuorum(t *testing.T) { testCtlV2Set(t, &configNoTLS, true) }
|
||||
func TestCtlV2SetClientTLS(t *testing.T) { testCtlV2Set(t, &configClientTLS, false) }
|
||||
func TestCtlV2SetPeerTLS(t *testing.T) { testCtlV2Set(t, &configPeerTLS, false) }
|
||||
func TestCtlV2SetTLS(t *testing.T) { testCtlV2Set(t, &configTLS, false) }
|
||||
func testCtlV2Set(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, cfg, quorum)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
if err := etcdctlSet(epc, key, value); err != nil {
|
||||
t.Fatalf("failed set (%v)", err)
|
||||
}
|
||||
|
||||
if err := etcdctlGet(epc, key, value, quorum); err != nil {
|
||||
t.Fatalf("failed get (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2Mk(t *testing.T) { testCtlV2Mk(t, &configNoTLS, false) }
|
||||
func TestCtlV2MkQuorum(t *testing.T) { testCtlV2Mk(t, &configNoTLS, true) }
|
||||
func TestCtlV2MkTLS(t *testing.T) { testCtlV2Mk(t, &configTLS, false) }
|
||||
func testCtlV2Mk(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, cfg, quorum)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
if err := etcdctlMk(epc, key, value, true); err != nil {
|
||||
t.Fatalf("failed mk (%v)", err)
|
||||
}
|
||||
if err := etcdctlMk(epc, key, value, false); err != nil {
|
||||
t.Fatalf("failed mk (%v)", err)
|
||||
}
|
||||
|
||||
if err := etcdctlGet(epc, key, value, quorum); err != nil {
|
||||
t.Fatalf("failed get (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2Rm(t *testing.T) { testCtlV2Rm(t, &configNoTLS) }
|
||||
func TestCtlV2RmTLS(t *testing.T) { testCtlV2Rm(t, &configTLS) }
|
||||
func testCtlV2Rm(t *testing.T, cfg *etcdProcessClusterConfig) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, cfg, true)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
if err := etcdctlSet(epc, key, value); err != nil {
|
||||
t.Fatalf("failed set (%v)", err)
|
||||
}
|
||||
|
||||
if err := etcdctlRm(epc, key, value, true); err != nil {
|
||||
t.Fatalf("failed rm (%v)", err)
|
||||
}
|
||||
if err := etcdctlRm(epc, key, value, false); err != nil {
|
||||
t.Fatalf("failed rm (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2Ls(t *testing.T) { testCtlV2Ls(t, &configNoTLS, false) }
|
||||
func TestCtlV2LsQuorum(t *testing.T) { testCtlV2Ls(t, &configNoTLS, true) }
|
||||
func TestCtlV2LsTLS(t *testing.T) { testCtlV2Ls(t, &configTLS, false) }
|
||||
func testCtlV2Ls(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, cfg, quorum)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
|
||||
key, value := "foo", "bar"
|
||||
|
||||
if err := etcdctlSet(epc, key, value); err != nil {
|
||||
t.Fatalf("failed set (%v)", err)
|
||||
}
|
||||
|
||||
if err := etcdctlLs(epc, key, quorum); err != nil {
|
||||
t.Fatalf("failed ls (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2Watch(t *testing.T) { testCtlV2Watch(t, &configNoTLS, false) }
|
||||
func TestCtlV2WatchTLS(t *testing.T) { testCtlV2Watch(t, &configTLS, false) }
|
||||
func TestCtlV2WatchWithProxy(t *testing.T) { testCtlV2Watch(t, &configWithProxy, false) }
|
||||
func TestCtlV2WatchWithProxyNoSync(t *testing.T) { testCtlV2Watch(t, &configWithProxy, true) }
|
||||
func testCtlV2Watch(t *testing.T, cfg *etcdProcessClusterConfig, noSync bool) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, cfg, true)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
|
||||
key, value := "foo", "bar"
|
||||
errc := etcdctlWatch(epc, key, value, noSync)
|
||||
if err := etcdctlSet(epc, key, value); err != nil {
|
||||
t.Fatalf("failed set (%v)", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-errc:
|
||||
if err != nil {
|
||||
t.Fatalf("failed watch (%v)", err)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatalf("watch timed out")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2GetRoleUser(t *testing.T) { testCtlV2GetRoleUser(t, &configNoTLS) }
|
||||
func TestCtlV2GetRoleUserWithProxy(t *testing.T) { testCtlV2GetRoleUser(t, &configWithProxy) }
|
||||
func testCtlV2GetRoleUser(t *testing.T, cfg *etcdProcessClusterConfig) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, cfg, true)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := etcdctlRoleAdd(epc, "foo"); err != nil {
|
||||
t.Fatalf("failed to add role (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserAdd(epc, "username", "password"); err != nil {
|
||||
t.Fatalf("failed to add user (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserGrant(epc, "username", "foo"); err != nil {
|
||||
t.Fatalf("failed to grant role (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserGet(epc, "username"); err != nil {
|
||||
t.Fatalf("failed to get user (%v)", err)
|
||||
}
|
||||
|
||||
// ensure double grant gives an error; was crashing in 2.3.1
|
||||
regrantArgs := etcdctlPrefixArgs(epc)
|
||||
regrantArgs = append(regrantArgs, "user", "grant", "--roles", "foo", "username")
|
||||
if err := spawnWithExpect(regrantArgs, "duplicate"); err != nil {
|
||||
t.Fatalf("missing duplicate error on double grant role (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2UserListUsername(t *testing.T) { testCtlV2UserList(t, "username") }
|
||||
func TestCtlV2UserListRoot(t *testing.T) { testCtlV2UserList(t, "root") }
|
||||
func testCtlV2UserList(t *testing.T, username string) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, &configWithProxy, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := etcdctlUserAdd(epc, username, "password"); err != nil {
|
||||
t.Fatalf("failed to add user (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserList(epc, username); err != nil {
|
||||
t.Fatalf("failed to list users (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2RoleList(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, &configWithProxy, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := etcdctlRoleAdd(epc, "foo"); err != nil {
|
||||
t.Fatalf("failed to add role (%v)", err)
|
||||
}
|
||||
if err := etcdctlRoleList(epc, "foo"); err != nil {
|
||||
t.Fatalf("failed to list roles (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2Backup(t *testing.T) { // For https://github.com/coreos/etcd/issues/5360
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
backupDir, err := ioutil.TempDir("", "testbackup0.etcd")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(backupDir)
|
||||
|
||||
epc1 := setupEtcdctlTest(t, &configNoTLS, false)
|
||||
if err := etcdctlSet(epc1, "foo1", "bar"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := etcdctlBackup(epc1, epc1.procs[0].cfg.dataDirPath, backupDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := epc1.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
|
||||
// restart from the backup directory
|
||||
cfg2 := configNoTLS
|
||||
cfg2.dataDirPath = backupDir
|
||||
cfg2.keepDataDir = true
|
||||
cfg2.forceNewCluster = true
|
||||
epc2 := setupEtcdctlTest(t, &cfg2, false)
|
||||
|
||||
// check if backup went through correctly
|
||||
if err := etcdctlGet(epc2, "foo1", "bar", false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// check if it can serve client requests
|
||||
if err := etcdctlSet(epc2, "foo2", "bar"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := etcdctlGet(epc2, "foo2", "bar", false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := epc2.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2AuthWithCommonName(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
copiedCfg := configClientTLS
|
||||
copiedCfg.clientCertAuthEnabled = true
|
||||
|
||||
epc := setupEtcdctlTest(t, &copiedCfg, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := etcdctlRoleAdd(epc, "testrole"); err != nil {
|
||||
t.Fatalf("failed to add role (%v)", err)
|
||||
}
|
||||
if err := etcdctlRoleGrant(epc, "testrole", "--rw", "--path=/foo"); err != nil {
|
||||
t.Fatalf("failed to grant role (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserAdd(epc, "root", "123"); err != nil {
|
||||
t.Fatalf("failed to add user (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserAdd(epc, "Autogenerated CA", "123"); err != nil {
|
||||
t.Fatalf("failed to add user (%v)", err)
|
||||
}
|
||||
if err := etcdctlUserGrant(epc, "Autogenerated CA", "testrole"); err != nil {
|
||||
t.Fatalf("failed to grant role (%v)", err)
|
||||
}
|
||||
if err := etcdctlAuthEnable(epc); err != nil {
|
||||
t.Fatalf("failed to enable auth (%v)", err)
|
||||
}
|
||||
if err := etcdctlSet(epc, "foo", "bar"); err != nil {
|
||||
t.Fatalf("failed to write (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV2ClusterHealth(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
epc := setupEtcdctlTest(t, &configNoTLS, true)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// has quorum
|
||||
if err := etcdctlClusterHealth(epc, "cluster is healthy"); err != nil {
|
||||
t.Fatalf("cluster-health expected to be healthy (%v)", err)
|
||||
}
|
||||
|
||||
// cut quorum
|
||||
epc.procs[0].Stop()
|
||||
epc.procs[1].Stop()
|
||||
if err := etcdctlClusterHealth(epc, "cluster is unhealthy"); err != nil {
|
||||
t.Fatalf("cluster-health expected to be unhealthy (%v)", err)
|
||||
}
|
||||
epc.procs[0], epc.procs[1] = nil, nil
|
||||
}
|
||||
|
||||
func etcdctlPrefixArgs(clus *etcdProcessCluster) []string {
|
||||
endpoints := ""
|
||||
if proxies := clus.proxies(); len(proxies) != 0 {
|
||||
endpoints = proxies[0].cfg.acurl
|
||||
} else if processes := clus.processes(); len(processes) != 0 {
|
||||
es := []string{}
|
||||
for _, b := range processes {
|
||||
es = append(es, b.cfg.acurl)
|
||||
}
|
||||
endpoints = strings.Join(es, ",")
|
||||
}
|
||||
cmdArgs := []string{ctlBinPath, "--endpoints", endpoints}
|
||||
if clus.cfg.clientTLS == clientTLS {
|
||||
cmdArgs = append(cmdArgs, "--ca-file", caPath, "--cert-file", certPath, "--key-file", privateKeyPath)
|
||||
}
|
||||
return cmdArgs
|
||||
}
|
||||
|
||||
func etcdctlClusterHealth(clus *etcdProcessCluster, val string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "cluster-health")
|
||||
return spawnWithExpect(cmdArgs, val)
|
||||
}
|
||||
|
||||
func etcdctlSet(clus *etcdProcessCluster, key, value string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "set", key, value)
|
||||
return spawnWithExpect(cmdArgs, value)
|
||||
}
|
||||
|
||||
func etcdctlMk(clus *etcdProcessCluster, key, value string, first bool) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "mk", key, value)
|
||||
if first {
|
||||
return spawnWithExpect(cmdArgs, value)
|
||||
}
|
||||
return spawnWithExpect(cmdArgs, "Error: 105: Key already exists")
|
||||
}
|
||||
|
||||
func etcdctlGet(clus *etcdProcessCluster, key, value string, quorum bool) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "get", key)
|
||||
if quorum {
|
||||
cmdArgs = append(cmdArgs, "--quorum")
|
||||
}
|
||||
return spawnWithExpect(cmdArgs, value)
|
||||
}
|
||||
|
||||
func etcdctlRm(clus *etcdProcessCluster, key, value string, first bool) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "rm", key)
|
||||
if first {
|
||||
return spawnWithExpect(cmdArgs, "PrevNode.Value: "+value)
|
||||
}
|
||||
return spawnWithExpect(cmdArgs, "Error: 100: Key not found")
|
||||
}
|
||||
|
||||
func etcdctlLs(clus *etcdProcessCluster, key string, quorum bool) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "ls")
|
||||
if quorum {
|
||||
cmdArgs = append(cmdArgs, "--quorum")
|
||||
}
|
||||
return spawnWithExpect(cmdArgs, key)
|
||||
}
|
||||
|
||||
func etcdctlWatch(clus *etcdProcessCluster, key, value string, noSync bool) <-chan error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "watch", "--after-index=1", key)
|
||||
if noSync {
|
||||
cmdArgs = append(cmdArgs, "--no-sync")
|
||||
}
|
||||
errc := make(chan error, 1)
|
||||
go func() {
|
||||
errc <- spawnWithExpect(cmdArgs, value)
|
||||
}()
|
||||
return errc
|
||||
}
|
||||
|
||||
func etcdctlRoleAdd(clus *etcdProcessCluster, role string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "role", "add", role)
|
||||
return spawnWithExpect(cmdArgs, role)
|
||||
}
|
||||
|
||||
func etcdctlRoleGrant(clus *etcdProcessCluster, role string, perms ...string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "role", "grant")
|
||||
cmdArgs = append(cmdArgs, perms...)
|
||||
cmdArgs = append(cmdArgs, role)
|
||||
return spawnWithExpect(cmdArgs, role)
|
||||
}
|
||||
|
||||
func etcdctlRoleList(clus *etcdProcessCluster, expectedRole string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "role", "list")
|
||||
return spawnWithExpect(cmdArgs, expectedRole)
|
||||
}
|
||||
|
||||
func etcdctlUserAdd(clus *etcdProcessCluster, user, pass string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "user", "add", user+":"+pass)
|
||||
return spawnWithExpect(cmdArgs, "User "+user+" created")
|
||||
}
|
||||
|
||||
func etcdctlUserGrant(clus *etcdProcessCluster, user, role string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "user", "grant", "--roles", role, user)
|
||||
return spawnWithExpect(cmdArgs, "User "+user+" updated")
|
||||
}
|
||||
|
||||
func etcdctlUserGet(clus *etcdProcessCluster, user string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "user", "get", user)
|
||||
return spawnWithExpect(cmdArgs, "User: "+user)
|
||||
}
|
||||
|
||||
func etcdctlUserList(clus *etcdProcessCluster, expectedUser string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "user", "list")
|
||||
return spawnWithExpect(cmdArgs, expectedUser)
|
||||
}
|
||||
|
||||
func etcdctlAuthEnable(clus *etcdProcessCluster) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "auth", "enable")
|
||||
return spawnWithExpect(cmdArgs, "Authentication Enabled")
|
||||
}
|
||||
|
||||
func etcdctlBackup(clus *etcdProcessCluster, dataDir, backupDir string) error {
|
||||
cmdArgs := append(etcdctlPrefixArgs(clus), "backup", "--data-dir", dataDir, "--backup-dir", backupDir)
|
||||
return spawnWithExpects(cmdArgs)
|
||||
}
|
||||
|
||||
func mustEtcdctl(t *testing.T) {
|
||||
if !fileutil.Exist(binDir + "/etcdctl") {
|
||||
t.Fatalf("could not find etcdctl binary")
|
||||
}
|
||||
}
|
||||
|
||||
func setupEtcdctlTest(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) *etcdProcessCluster {
|
||||
mustEtcdctl(t)
|
||||
if !quorum {
|
||||
cfg = configStandalone(*cfg)
|
||||
}
|
||||
epc, err := newEtcdProcessCluster(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("could not start etcd process cluster (%v)", err)
|
||||
}
|
||||
return epc
|
||||
}
|
||||
100
vendor/github.com/coreos/etcd/e2e/ctl_v3_alarm_test.go
generated
vendored
Normal file
100
vendor/github.com/coreos/etcd/e2e/ctl_v3_alarm_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// 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"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestCtlV3Alarm(t *testing.T) {
|
||||
// The boltdb minimum working set is six pages.
|
||||
testCtl(t, alarmTest, withQuota(int64(13*os.Getpagesize())))
|
||||
}
|
||||
|
||||
func alarmTest(cx ctlCtx) {
|
||||
// test small put still works
|
||||
smallbuf := strings.Repeat("a", 64)
|
||||
if err := ctlV3Put(cx, "1st_test", smallbuf, ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// write some chunks to fill up the database
|
||||
buf := strings.Repeat("b", int(os.Getpagesize()))
|
||||
for {
|
||||
if err := ctlV3Put(cx, "2nd_test", buf, ""); err != nil {
|
||||
if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// quota alarm should now be on
|
||||
if err := ctlV3Alarm(cx, "list", "alarm:NOSPACE"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// check that Put is rejected when alarm is on
|
||||
if err := ctlV3Put(cx, "3rd_test", smallbuf, ""); err != nil {
|
||||
if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
eps := cx.epc.grpcEndpoints()
|
||||
|
||||
// get latest revision to compact
|
||||
cli, err := clientv3.New(clientv3.Config{
|
||||
Endpoints: eps,
|
||||
DialTimeout: 3 * time.Second,
|
||||
})
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
defer cli.Close()
|
||||
sresp, err := cli.Status(context.TODO(), eps[0])
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// make some space
|
||||
if err := ctlV3Compact(cx, sresp.Header.Revision, true); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err := ctlV3Defrag(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// turn off alarm
|
||||
if err := ctlV3Alarm(cx, "disarm", "alarm:NOSPACE"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// put one more key below quota
|
||||
if err := ctlV3Put(cx, "4th_test", smallbuf, ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Alarm(cx ctlCtx, cmd string, as ...string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "alarm", cmd)
|
||||
return spawnWithExpects(cmdArgs, as...)
|
||||
}
|
||||
545
vendor/github.com/coreos/etcd/e2e/ctl_v3_auth_test.go
generated
vendored
Normal file
545
vendor/github.com/coreos/etcd/e2e/ctl_v3_auth_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,545 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
)
|
||||
|
||||
func TestCtlV3AuthEnable(t *testing.T) { testCtl(t, authEnableTest) }
|
||||
func TestCtlV3AuthDisable(t *testing.T) { testCtl(t, authDisableTest) }
|
||||
func TestCtlV3AuthWriteKey(t *testing.T) { testCtl(t, authCredWriteKeyTest) }
|
||||
func TestCtlV3AuthRoleUpdate(t *testing.T) { testCtl(t, authRoleUpdateTest) }
|
||||
func TestCtlV3AuthUserDeleteDuringOps(t *testing.T) { testCtl(t, authUserDeleteDuringOpsTest) }
|
||||
func TestCtlV3AuthRoleRevokeDuringOps(t *testing.T) { testCtl(t, authRoleRevokeDuringOpsTest) }
|
||||
func TestCtlV3AuthTxn(t *testing.T) { testCtl(t, authTestTxn) }
|
||||
func TestCtlV3AuthPerfixPerm(t *testing.T) { testCtl(t, authTestPrefixPerm) }
|
||||
func TestCtlV3AuthMemberAdd(t *testing.T) { testCtl(t, authTestMemberAdd) }
|
||||
func TestCtlV3AuthMemberRemove(t *testing.T) {
|
||||
testCtl(t, authTestMemberRemove, withQuorum(), withNoStrictReconfig())
|
||||
}
|
||||
func TestCtlV3AuthMemberUpdate(t *testing.T) { testCtl(t, authTestMemberUpdate) }
|
||||
|
||||
func authEnableTest(cx ctlCtx) {
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authEnable(cx ctlCtx) error {
|
||||
// create root user with root role
|
||||
if err := ctlV3User(cx, []string{"add", "root", "--interactive=false"}, "User root created", []string{"root"}); err != nil {
|
||||
return fmt.Errorf("failed to create root user %v", err)
|
||||
}
|
||||
if err := ctlV3User(cx, []string{"grant-role", "root", "root"}, "Role root is granted to user root", nil); err != nil {
|
||||
return fmt.Errorf("failed to grant root user root role %v", err)
|
||||
}
|
||||
if err := ctlV3AuthEnable(cx); err != nil {
|
||||
return fmt.Errorf("authEnableTest ctlV3AuthEnable error (%v)", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ctlV3AuthEnable(cx ctlCtx) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "auth", "enable")
|
||||
return spawnWithExpect(cmdArgs, "Authentication Enabled")
|
||||
}
|
||||
|
||||
func authDisableTest(cx ctlCtx) {
|
||||
// a key that isn't granted to test-user
|
||||
if err := ctlV3Put(cx, "hoo", "a", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
// test-user doesn't have the permission, it must fail
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3AuthDisable(cx); err != nil {
|
||||
cx.t.Fatalf("authDisableTest ctlV3AuthDisable error (%v)", err)
|
||||
}
|
||||
|
||||
// now auth fails unconditionally, note that failed RPC is Authenticate(), not Put()
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3PutFailAuthDisabled(cx, "hoo", "bar"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// now the key can be accessed
|
||||
cx.user, cx.pass = "", ""
|
||||
if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put succeeded
|
||||
if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3AuthDisable(cx ctlCtx) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "auth", "disable")
|
||||
return spawnWithExpect(cmdArgs, "Authentication Disabled")
|
||||
}
|
||||
|
||||
func authCredWriteKeyTest(cx ctlCtx) {
|
||||
// baseline key to check for failed puts
|
||||
if err := ctlV3Put(cx, "foo", "a", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
// confirm root role can access to all keys
|
||||
if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try invalid user
|
||||
cx.user, cx.pass = "a", "b"
|
||||
if err := ctlV3PutFailAuth(cx, "foo", "bar"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put failed
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try good user
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Put(cx, "foo", "bar2", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put succeeded
|
||||
if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try bad password
|
||||
cx.user, cx.pass = "test-user", "badpass"
|
||||
if err := ctlV3PutFailAuth(cx, "foo", "baz"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put failed
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authRoleUpdateTest(cx ctlCtx) {
|
||||
if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
// try put to not granted key
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// grant a new key
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try a newly granted key
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put succeeded
|
||||
if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// revoke the newly granted key
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3RoleRevokePermission(cx, "test-role", "hoo", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try put to the revoked key
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3PutFailPerm(cx, "hoo", "bar"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// confirm a key still granted can be accessed
|
||||
if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authUserDeleteDuringOpsTest(cx ctlCtx) {
|
||||
if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
// create a key
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put succeeded
|
||||
if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// delete the user
|
||||
cx.user, cx.pass = "root", "root"
|
||||
err := ctlV3User(cx, []string{"delete", "test-user"}, "User test-user deleted", []string{})
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// check the user is deleted
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3PutFailAuth(cx, "foo", "baz"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authRoleRevokeDuringOpsTest(cx ctlCtx) {
|
||||
if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
// create a key
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put succeeded
|
||||
if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a new role
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3Role(cx, []string{"add", "test-role2"}, "Role test-role2 created"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// grant a new key to the new role
|
||||
if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", "", false}); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// grant the new role to the user
|
||||
if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role2"}, "Role test-role2 is granted to user test-user", nil); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try a newly granted key
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put succeeded
|
||||
if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// revoke a role from the user
|
||||
cx.user, cx.pass = "root", "root"
|
||||
err := ctlV3User(cx, []string{"revoke-role", "test-user", "test-role"}, "Role test-role is revoked from user test-user", []string{})
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// check the role is revoked and permission is lost from the user
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3PutFailPerm(cx, "foo", "baz"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try a key that can be accessed from the remaining role
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Put(cx, "hoo", "bar2", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
// confirm put succeeded
|
||||
if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar2"}}...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3PutFailAuth(cx ctlCtx, key, val string) error {
|
||||
return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "authentication failed")
|
||||
}
|
||||
|
||||
func ctlV3PutFailPerm(cx ctlCtx, key, val string) error {
|
||||
return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "permission denied")
|
||||
}
|
||||
|
||||
func ctlV3PutFailAuthDisabled(cx ctlCtx, key, val string) error {
|
||||
return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "authentication is not enabled")
|
||||
}
|
||||
|
||||
func authSetupTestUser(cx ctlCtx) {
|
||||
if err := ctlV3User(cx, []string{"add", "test-user", "--interactive=false"}, "User test-user created", []string{"pass"}); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role"), "Role test-role created"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role"}, "Role test-role is granted to user test-user", nil); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
cmd := append(cx.PrefixArgs(), "role", "grant-permission", "test-role", "readwrite", "foo")
|
||||
if err := spawnWithExpect(cmd, "Role test-role updated"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authTestTxn(cx ctlCtx) {
|
||||
// keys with 1 suffix aren't granted to test-user
|
||||
// keys with 2 suffix are granted to test-user
|
||||
|
||||
keys := []string{"c1", "s1", "f1"}
|
||||
grantedKeys := []string{"c2", "s2", "f2"}
|
||||
for _, key := range keys {
|
||||
if err := ctlV3Put(cx, key, "v", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, key := range grantedKeys {
|
||||
if err := ctlV3Put(cx, key, "v", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
// grant keys to test-user
|
||||
cx.user, cx.pass = "root", "root"
|
||||
for _, key := range grantedKeys {
|
||||
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, key, "", false}); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// now test txn
|
||||
cx.interactive = true
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
|
||||
rqs := txnRequests{
|
||||
compare: []string{`version("c2") = "1"`},
|
||||
ifSucess: []string{"get s2"},
|
||||
ifFail: []string{"get f2"},
|
||||
results: []string{"SUCCESS", "s2", "v"},
|
||||
}
|
||||
if err := ctlV3Txn(cx, rqs); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// a key of compare case isn't granted
|
||||
rqs = txnRequests{
|
||||
compare: []string{`version("c1") = "1"`},
|
||||
ifSucess: []string{"get s2"},
|
||||
ifFail: []string{"get f2"},
|
||||
results: []string{"Error: etcdserver: permission denied"},
|
||||
}
|
||||
if err := ctlV3Txn(cx, rqs); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// a key of success case isn't granted
|
||||
rqs = txnRequests{
|
||||
compare: []string{`version("c2") = "1"`},
|
||||
ifSucess: []string{"get s1"},
|
||||
ifFail: []string{"get f2"},
|
||||
results: []string{"Error: etcdserver: permission denied"},
|
||||
}
|
||||
if err := ctlV3Txn(cx, rqs); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// a key of failure case isn't granted
|
||||
rqs = txnRequests{
|
||||
compare: []string{`version("c2") = "1"`},
|
||||
ifSucess: []string{"get s2"},
|
||||
ifFail: []string{"get f1"},
|
||||
results: []string{"Error: etcdserver: permission denied"},
|
||||
}
|
||||
if err := ctlV3Txn(cx, rqs); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authTestPrefixPerm(cx ctlCtx) {
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
prefix := "/prefix/" // directory like prefix
|
||||
// grant keys to test-user
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, prefix, "", true}); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// try a prefix granted permission
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
for i := 0; i < 10; i++ {
|
||||
key := fmt.Sprintf("%s%d", prefix, i)
|
||||
if err := ctlV3Put(cx, key, "val", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := ctlV3PutFailPerm(cx, clientv3.GetPrefixRangeEnd(prefix), "baz"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authTestMemberAdd(cx ctlCtx) {
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)
|
||||
// ordinal user cannot add a new member
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3MemberAdd(cx, peerURL); err == nil {
|
||||
cx.t.Fatalf("ordinal user must not be allowed to add a member")
|
||||
}
|
||||
|
||||
// root can add a new member
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3MemberAdd(cx, peerURL); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authTestMemberRemove(cx ctlCtx) {
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
n1 := cx.cfg.clusterSize
|
||||
if n1 < 2 {
|
||||
cx.t.Fatalf("%d-node is too small to test 'member remove'", n1)
|
||||
}
|
||||
resp, err := getMemberList(cx)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if n1 != len(resp.Members) {
|
||||
cx.t.Fatalf("expected %d, got %d", n1, len(resp.Members))
|
||||
}
|
||||
|
||||
var (
|
||||
memIDToRemove = fmt.Sprintf("%x", resp.Header.MemberId)
|
||||
clusterID = fmt.Sprintf("%x", resp.Header.ClusterId)
|
||||
)
|
||||
|
||||
// ordinal user cannot remove a member
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err = ctlV3MemberRemove(cx, memIDToRemove, clusterID); err == nil {
|
||||
cx.t.Fatalf("ordinal user must not be allowed to remove a member")
|
||||
}
|
||||
|
||||
// root can remove a member
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err = ctlV3MemberRemove(cx, memIDToRemove, clusterID); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func authTestMemberUpdate(cx ctlCtx) {
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
mr, err := getMemberList(cx)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// ordinal user cannot update a member
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)
|
||||
memberID := fmt.Sprintf("%x", mr.Members[0].ID)
|
||||
if err = ctlV3MemberUpdate(cx, memberID, peerURL); err == nil {
|
||||
cx.t.Fatalf("ordinal user must not be allowed to update a member")
|
||||
}
|
||||
|
||||
// root can update a member
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err = ctlV3MemberUpdate(cx, memberID, peerURL); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
75
vendor/github.com/coreos/etcd/e2e/ctl_v3_compact_test.go
generated
vendored
Normal file
75
vendor/github.com/coreos/etcd/e2e/ctl_v3_compact_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// 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 (
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCtlV3Compact(t *testing.T) { testCtl(t, compactTest) }
|
||||
func TestCtlV3CompactPhysical(t *testing.T) { testCtl(t, compactTest, withCompactPhysical()) }
|
||||
|
||||
func compactTest(cx ctlCtx) {
|
||||
compactPhysical := cx.compactPhysical
|
||||
if err := ctlV3Compact(cx, 2, compactPhysical); err != nil {
|
||||
if !strings.Contains(err.Error(), "required revision is a future revision") {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
cx.t.Fatalf("expected '...future revision' error, got <nil>")
|
||||
}
|
||||
|
||||
var kvs = []kv{{"key", "val1"}, {"key", "val2"}, {"key", "val3"}}
|
||||
for i := range kvs {
|
||||
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
|
||||
cx.t.Fatalf("compactTest #%d: ctlV3Put error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := ctlV3Get(cx, []string{"key", "--rev", "3"}, kvs[1:2]...); err != nil {
|
||||
cx.t.Errorf("compactTest: ctlV3Get error (%v)", err)
|
||||
}
|
||||
|
||||
if err := ctlV3Compact(cx, 4, compactPhysical); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ctlV3Get(cx, []string{"key", "--rev", "3"}, kvs[1:2]...); err != nil {
|
||||
if !strings.Contains(err.Error(), "required revision has been compacted") {
|
||||
cx.t.Errorf("compactTest: ctlV3Get error (%v)", err)
|
||||
}
|
||||
} else {
|
||||
cx.t.Fatalf("expected '...has been compacted' error, got <nil>")
|
||||
}
|
||||
|
||||
if err := ctlV3Compact(cx, 2, compactPhysical); err != nil {
|
||||
if !strings.Contains(err.Error(), "required revision has been compacted") {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
cx.t.Fatalf("expected '...has been compacted' error, got <nil>")
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Compact(cx ctlCtx, rev int64, physical bool) error {
|
||||
rs := strconv.FormatInt(rev, 10)
|
||||
cmdArgs := append(cx.PrefixArgs(), "compact", rs)
|
||||
if physical {
|
||||
cmdArgs = append(cmdArgs, "--physical")
|
||||
}
|
||||
return spawnWithExpect(cmdArgs, "compacted revision "+rs)
|
||||
}
|
||||
73
vendor/github.com/coreos/etcd/e2e/ctl_v3_defrag_test.go
generated
vendored
Normal file
73
vendor/github.com/coreos/etcd/e2e/ctl_v3_defrag_test.go
generated
vendored
Normal file
|
|
@ -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 "testing"
|
||||
|
||||
func TestCtlV3Defrag(t *testing.T) { testCtl(t, defragTest) }
|
||||
func TestCtlV3DefragWithAuth(t *testing.T) { testCtl(t, defragTestWithAuth) }
|
||||
|
||||
func maintenanceInitKeys(cx ctlCtx) {
|
||||
var kvs = []kv{{"key", "val1"}, {"key", "val2"}, {"key", "val3"}}
|
||||
for i := range kvs {
|
||||
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func defragTest(cx ctlCtx) {
|
||||
maintenanceInitKeys(cx)
|
||||
|
||||
if err := ctlV3Compact(cx, 4, cx.compactPhysical); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := ctlV3Defrag(cx); err != nil {
|
||||
cx.t.Fatalf("defragTest ctlV3Defrag error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func defragTestWithAuth(cx ctlCtx) {
|
||||
maintenanceInitKeys(cx)
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
// ordinal user cannot defrag
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3Defrag(cx); err == nil {
|
||||
cx.t.Fatal("ordinal user should not be able to issue a defrag request")
|
||||
}
|
||||
|
||||
// root can defrag
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3Defrag(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Defrag(cx ctlCtx) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "defrag")
|
||||
lines := make([]string, cx.epc.cfg.clusterSize)
|
||||
for i := range lines {
|
||||
lines[i] = "Finished defragmenting etcd member"
|
||||
}
|
||||
return spawnWithExpects(cmdArgs, lines...)
|
||||
}
|
||||
113
vendor/github.com/coreos/etcd/e2e/ctl_v3_elect_test.go
generated
vendored
Normal file
113
vendor/github.com/coreos/etcd/e2e/ctl_v3_elect_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// 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"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/expect"
|
||||
)
|
||||
|
||||
func TestCtlV3Elect(t *testing.T) { testCtl(t, testElect) }
|
||||
|
||||
func testElect(cx ctlCtx) {
|
||||
name := "a"
|
||||
|
||||
holder, ch, err := ctlV3Elect(cx, name, "p1")
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
l1 := ""
|
||||
select {
|
||||
case <-time.After(2 * time.Second):
|
||||
cx.t.Fatalf("timed out electing")
|
||||
case l1 = <-ch:
|
||||
if !strings.HasPrefix(l1, name) {
|
||||
cx.t.Errorf("got %q, expected %q prefix", l1, name)
|
||||
}
|
||||
}
|
||||
|
||||
// blocked process that won't win the election
|
||||
blocked, ch, err := ctlV3Elect(cx, name, "p2")
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
case <-ch:
|
||||
cx.t.Fatalf("should block")
|
||||
}
|
||||
|
||||
// overlap with a blocker that will win the election
|
||||
blockAcquire, ch, err := ctlV3Elect(cx, name, "p2")
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
defer blockAcquire.Stop()
|
||||
select {
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
case <-ch:
|
||||
cx.t.Fatalf("should block")
|
||||
}
|
||||
|
||||
// kill blocked process with clean shutdown
|
||||
if err = blocked.Signal(os.Interrupt); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err = blocked.Close(); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// kill the holder with clean shutdown
|
||||
if err = holder.Signal(os.Interrupt); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err = holder.Close(); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// blockAcquire should win the election
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
cx.t.Fatalf("timed out from waiting to holding")
|
||||
case l2 := <-ch:
|
||||
if l1 == l2 || !strings.HasPrefix(l2, name) {
|
||||
cx.t.Fatalf("expected different elect name, got l1=%q, l2=%q", l1, l2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ctlV3Elect creates a elect process with a channel listening for when it wins the election.
|
||||
func ctlV3Elect(cx ctlCtx, name, proposal string) (*expect.ExpectProcess, <-chan string, error) {
|
||||
cmdArgs := append(cx.PrefixArgs(), "elect", name, proposal)
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
outc := make(chan string, 1)
|
||||
if err != nil {
|
||||
close(outc)
|
||||
return proc, outc, err
|
||||
}
|
||||
go func() {
|
||||
s, xerr := proc.ExpectFunc(func(string) bool { return true })
|
||||
if xerr != nil {
|
||||
cx.t.Errorf("expect failed (%v)", xerr)
|
||||
}
|
||||
outc <- s
|
||||
}()
|
||||
return proc, outc, err
|
||||
}
|
||||
86
vendor/github.com/coreos/etcd/e2e/ctl_v3_endpoint_test.go
generated
vendored
Normal file
86
vendor/github.com/coreos/etcd/e2e/ctl_v3_endpoint_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// 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 (
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCtlV3EndpointHealth(t *testing.T) { testCtl(t, endpointHealthTest, withQuorum()) }
|
||||
func TestCtlV3EndpointStatus(t *testing.T) { testCtl(t, endpointStatusTest, withQuorum()) }
|
||||
func TestCtlV3EndpointHealthWithAuth(t *testing.T) {
|
||||
testCtl(t, endpointHealthTestWithAuth, withQuorum())
|
||||
}
|
||||
|
||||
func endpointHealthTest(cx ctlCtx) {
|
||||
if err := ctlV3EndpointHealth(cx); err != nil {
|
||||
cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3EndpointHealth(cx ctlCtx) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "endpoint", "health")
|
||||
lines := make([]string, cx.epc.cfg.clusterSize)
|
||||
for i := range lines {
|
||||
lines[i] = "is healthy"
|
||||
}
|
||||
return spawnWithExpects(cmdArgs, lines...)
|
||||
}
|
||||
|
||||
func endpointStatusTest(cx ctlCtx) {
|
||||
if err := ctlV3EndpointStatus(cx); err != nil {
|
||||
cx.t.Fatalf("endpointStatusTest ctlV3EndpointStatus error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3EndpointStatus(cx ctlCtx) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "endpoint", "status")
|
||||
var eps []string
|
||||
for _, ep := range cx.epc.endpoints() {
|
||||
u, _ := url.Parse(ep)
|
||||
eps = append(eps, u.Host)
|
||||
}
|
||||
return spawnWithExpects(cmdArgs, eps...)
|
||||
}
|
||||
|
||||
func endpointHealthTestWithAuth(cx ctlCtx) {
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
if err := ctlV3EndpointHealth(cx); err != nil {
|
||||
cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
|
||||
}
|
||||
|
||||
// health checking with an ordinal user "succeeds" since permission denial goes through consensus
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3EndpointHealth(cx); err != nil {
|
||||
cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
|
||||
}
|
||||
|
||||
// succeed if permissions granted for ordinary user
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "health", "", false}); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3EndpointHealth(cx); err != nil {
|
||||
cx.t.Fatalf("endpointStatusTest ctlV3EndpointHealth error (%v)", err)
|
||||
}
|
||||
}
|
||||
259
vendor/github.com/coreos/etcd/e2e/ctl_v3_kv_test.go
generated
vendored
Normal file
259
vendor/github.com/coreos/etcd/e2e/ctl_v3_kv_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCtlV3Put(t *testing.T) { testCtl(t, putTest) }
|
||||
func TestCtlV3PutNoTLS(t *testing.T) { testCtl(t, putTest, withCfg(configNoTLS)) }
|
||||
func TestCtlV3PutClientTLS(t *testing.T) { testCtl(t, putTest, withCfg(configClientTLS)) }
|
||||
func TestCtlV3PutClientAutoTLS(t *testing.T) { testCtl(t, putTest, withCfg(configClientAutoTLS)) }
|
||||
func TestCtlV3PutPeerTLS(t *testing.T) { testCtl(t, putTest, withCfg(configPeerTLS)) }
|
||||
func TestCtlV3PutTimeout(t *testing.T) { testCtl(t, putTest, withDialTimeout(0)) }
|
||||
func TestCtlV3PutClientTLSFlagByEnv(t *testing.T) {
|
||||
testCtl(t, putTest, withCfg(configClientTLS), withFlagByEnv())
|
||||
}
|
||||
|
||||
func TestCtlV3Get(t *testing.T) { testCtl(t, getTest) }
|
||||
func TestCtlV3GetNoTLS(t *testing.T) { testCtl(t, getTest, withCfg(configNoTLS)) }
|
||||
func TestCtlV3GetClientTLS(t *testing.T) { testCtl(t, getTest, withCfg(configClientTLS)) }
|
||||
func TestCtlV3GetClientAutoTLS(t *testing.T) { testCtl(t, getTest, withCfg(configClientAutoTLS)) }
|
||||
func TestCtlV3GetPeerTLS(t *testing.T) { testCtl(t, getTest, withCfg(configPeerTLS)) }
|
||||
func TestCtlV3GetTimeout(t *testing.T) { testCtl(t, getTest, withDialTimeout(0)) }
|
||||
func TestCtlV3GetQuorum(t *testing.T) { testCtl(t, getTest, withQuorum()) }
|
||||
|
||||
func TestCtlV3GetFormat(t *testing.T) { testCtl(t, getFormatTest) }
|
||||
func TestCtlV3GetRev(t *testing.T) { testCtl(t, getRevTest) }
|
||||
func TestCtlV3GetKeysOnly(t *testing.T) { testCtl(t, getKeysOnlyTest) }
|
||||
|
||||
func TestCtlV3Del(t *testing.T) { testCtl(t, delTest) }
|
||||
func TestCtlV3DelNoTLS(t *testing.T) { testCtl(t, delTest, withCfg(configNoTLS)) }
|
||||
func TestCtlV3DelClientTLS(t *testing.T) { testCtl(t, delTest, withCfg(configClientTLS)) }
|
||||
func TestCtlV3DelPeerTLS(t *testing.T) { testCtl(t, delTest, withCfg(configPeerTLS)) }
|
||||
func TestCtlV3DelTimeout(t *testing.T) { testCtl(t, delTest, withDialTimeout(0)) }
|
||||
|
||||
func putTest(cx ctlCtx) {
|
||||
key, value := "foo", "bar"
|
||||
|
||||
if err := ctlV3Put(cx, key, value, ""); err != nil {
|
||||
if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
|
||||
cx.t.Fatalf("putTest ctlV3Put error (%v)", err)
|
||||
}
|
||||
}
|
||||
if err := ctlV3Get(cx, []string{key}, kv{key, value}); err != nil {
|
||||
if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
|
||||
cx.t.Fatalf("putTest ctlV3Get error (%v)", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getTest(cx ctlCtx) {
|
||||
var (
|
||||
kvs = []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}
|
||||
revkvs = []kv{{"key3", "val3"}, {"key2", "val2"}, {"key1", "val1"}}
|
||||
)
|
||||
for i := range kvs {
|
||||
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
|
||||
cx.t.Fatalf("getTest #%d: ctlV3Put error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
args []string
|
||||
|
||||
wkv []kv
|
||||
}{
|
||||
{[]string{"key1"}, []kv{{"key1", "val1"}}},
|
||||
{[]string{"", "--prefix"}, kvs},
|
||||
{[]string{"", "--from-key"}, kvs},
|
||||
{[]string{"key", "--prefix"}, kvs},
|
||||
{[]string{"key", "--prefix", "--limit=2"}, kvs[:2]},
|
||||
{[]string{"key", "--prefix", "--order=ASCEND", "--sort-by=MODIFY"}, kvs},
|
||||
{[]string{"key", "--prefix", "--order=ASCEND", "--sort-by=VERSION"}, kvs},
|
||||
{[]string{"key", "--prefix", "--sort-by=CREATE"}, kvs}, // ASCEND by default
|
||||
{[]string{"key", "--prefix", "--order=DESCEND", "--sort-by=CREATE"}, revkvs},
|
||||
{[]string{"key", "--prefix", "--order=DESCEND", "--sort-by=KEY"}, revkvs},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
if err := ctlV3Get(cx, tt.args, tt.wkv...); err != nil {
|
||||
if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
|
||||
cx.t.Errorf("getTest #%d: ctlV3Get error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getFormatTest(cx ctlCtx) {
|
||||
if err := ctlV3Put(cx, "abc", "123", ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
format string
|
||||
valueOnly bool
|
||||
|
||||
wstr string
|
||||
}{
|
||||
{"simple", false, "abc"},
|
||||
{"simple", true, "123"},
|
||||
{"json", false, `"kvs":[{"key":"YWJj"`},
|
||||
{"protobuf", false, "\x17\b\x93\xe7\xf6\x93\xd4ņ\xe14\x10\xed"},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
cmdArgs := append(cx.PrefixArgs(), "get")
|
||||
cmdArgs = append(cmdArgs, "--write-out="+tt.format)
|
||||
if tt.valueOnly {
|
||||
cmdArgs = append(cmdArgs, "--print-value-only")
|
||||
}
|
||||
cmdArgs = append(cmdArgs, "abc")
|
||||
if err := spawnWithExpect(cmdArgs, tt.wstr); err != nil {
|
||||
cx.t.Errorf("#%d: error (%v), wanted %v", i, err, tt.wstr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getRevTest(cx ctlCtx) {
|
||||
var (
|
||||
kvs = []kv{{"key", "val1"}, {"key", "val2"}, {"key", "val3"}}
|
||||
)
|
||||
for i := range kvs {
|
||||
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
|
||||
cx.t.Fatalf("getRevTest #%d: ctlV3Put error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
args []string
|
||||
|
||||
wkv []kv
|
||||
}{
|
||||
{[]string{"key", "--rev", "2"}, kvs[:1]},
|
||||
{[]string{"key", "--rev", "3"}, kvs[1:2]},
|
||||
{[]string{"key", "--rev", "4"}, kvs[2:]},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
if err := ctlV3Get(cx, tt.args, tt.wkv...); err != nil {
|
||||
cx.t.Errorf("getTest #%d: ctlV3Get error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getKeysOnlyTest(cx ctlCtx) {
|
||||
var (
|
||||
kvs = []kv{{"key1", "val1"}}
|
||||
)
|
||||
for i := range kvs {
|
||||
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
|
||||
cx.t.Fatalf("getKeysOnlyTest #%d: ctlV3Put error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
cmdArgs := append(cx.PrefixArgs(), "get")
|
||||
cmdArgs = append(cmdArgs, []string{"--prefix", "--keys-only", "key"}...)
|
||||
|
||||
err := spawnWithExpects(cmdArgs, []string{"key1", ""}...)
|
||||
if err != nil {
|
||||
cx.t.Fatalf("getKeysOnlyTest : error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func delTest(cx ctlCtx) {
|
||||
tests := []struct {
|
||||
puts []kv
|
||||
args []string
|
||||
|
||||
deletedNum int
|
||||
}{
|
||||
{ // delete all keys
|
||||
[]kv{{"foo1", "bar"}, {"foo2", "bar"}, {"foo3", "bar"}},
|
||||
[]string{"", "--prefix"},
|
||||
3,
|
||||
},
|
||||
{ // delete all keys
|
||||
[]kv{{"foo1", "bar"}, {"foo2", "bar"}, {"foo3", "bar"}},
|
||||
[]string{"", "--from-key"},
|
||||
3,
|
||||
},
|
||||
{
|
||||
[]kv{{"this", "value"}},
|
||||
[]string{"that"},
|
||||
0,
|
||||
},
|
||||
{
|
||||
[]kv{{"sample", "value"}},
|
||||
[]string{"sample"},
|
||||
1,
|
||||
},
|
||||
{
|
||||
[]kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
|
||||
[]string{"key", "--prefix"},
|
||||
3,
|
||||
},
|
||||
{
|
||||
[]kv{{"zoo1", "bar"}, {"zoo2", "bar2"}, {"zoo3", "bar3"}},
|
||||
[]string{"zoo1", "--from-key"},
|
||||
3,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
for j := range tt.puts {
|
||||
if err := ctlV3Put(cx, tt.puts[j].key, tt.puts[j].val, ""); err != nil {
|
||||
cx.t.Fatalf("delTest #%d-%d: ctlV3Put error (%v)", i, j, err)
|
||||
}
|
||||
}
|
||||
if err := ctlV3Del(cx, tt.args, tt.deletedNum); err != nil {
|
||||
if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
|
||||
cx.t.Fatalf("delTest #%d: ctlV3Del error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Put(cx ctlCtx, key, value, leaseID string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "put", key, value)
|
||||
if leaseID != "" {
|
||||
cmdArgs = append(cmdArgs, "--lease", leaseID)
|
||||
}
|
||||
return spawnWithExpect(cmdArgs, "OK")
|
||||
}
|
||||
|
||||
type kv struct {
|
||||
key, val string
|
||||
}
|
||||
|
||||
func ctlV3Get(cx ctlCtx, args []string, kvs ...kv) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "get")
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
if !cx.quorum {
|
||||
cmdArgs = append(cmdArgs, "--consistency", "s")
|
||||
}
|
||||
var lines []string
|
||||
for _, elem := range kvs {
|
||||
lines = append(lines, elem.key, elem.val)
|
||||
}
|
||||
return spawnWithExpects(cmdArgs, lines...)
|
||||
}
|
||||
|
||||
func ctlV3Del(cx ctlCtx, args []string, num int) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "del")
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
return spawnWithExpects(cmdArgs, fmt.Sprintf("%d", num))
|
||||
}
|
||||
128
vendor/github.com/coreos/etcd/e2e/ctl_v3_lease_test.go
generated
vendored
Normal file
128
vendor/github.com/coreos/etcd/e2e/ctl_v3_lease_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCtlV3LeaseGrantTimeToLive(t *testing.T) { testCtl(t, leaseTestGrantTimeToLive) }
|
||||
func TestCtlV3LeaseKeepAlive(t *testing.T) { testCtl(t, leaseTestKeepAlive) }
|
||||
func TestCtlV3LeaseRevoke(t *testing.T) { testCtl(t, leaseTestRevoke) }
|
||||
|
||||
func leaseTestGrantTimeToLive(cx ctlCtx) {
|
||||
id, err := ctlV3LeaseGrant(cx, 10)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cmdArgs := append(cx.PrefixArgs(), "lease", "timetolive", id, "--keys")
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
line, err := proc.Expect(" granted with TTL(")
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err = proc.Close(); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(line, ", attached keys") {
|
||||
cx.t.Fatalf("expected 'attached keys', got %q", line)
|
||||
}
|
||||
if !strings.Contains(line, id) {
|
||||
cx.t.Fatalf("expected leaseID %q, got %q", id, line)
|
||||
}
|
||||
}
|
||||
|
||||
func leaseTestKeepAlive(cx ctlCtx) {
|
||||
// put with TTL 10 seconds and keep-alive
|
||||
leaseID, err := ctlV3LeaseGrant(cx, 10)
|
||||
if err != nil {
|
||||
cx.t.Fatalf("leaseTestKeepAlive: ctlV3LeaseGrant error (%v)", err)
|
||||
}
|
||||
if err := ctlV3Put(cx, "key", "val", leaseID); err != nil {
|
||||
cx.t.Fatalf("leaseTestKeepAlive: ctlV3Put error (%v)", err)
|
||||
}
|
||||
if err := ctlV3LeaseKeepAlive(cx, leaseID); err != nil {
|
||||
cx.t.Fatalf("leaseTestKeepAlive: ctlV3LeaseKeepAlive error (%v)", err)
|
||||
}
|
||||
if err := ctlV3Get(cx, []string{"key"}, kv{"key", "val"}); err != nil {
|
||||
cx.t.Fatalf("leaseTestKeepAlive: ctlV3Get error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func leaseTestRevoke(cx ctlCtx) {
|
||||
// put with TTL 10 seconds and revoke
|
||||
leaseID, err := ctlV3LeaseGrant(cx, 10)
|
||||
if err != nil {
|
||||
cx.t.Fatalf("leaseTestRevoke: ctlV3LeaseGrant error (%v)", err)
|
||||
}
|
||||
if err := ctlV3Put(cx, "key", "val", leaseID); err != nil {
|
||||
cx.t.Fatalf("leaseTestRevoke: ctlV3Put error (%v)", err)
|
||||
}
|
||||
if err := ctlV3LeaseRevoke(cx, leaseID); err != nil {
|
||||
cx.t.Fatalf("leaseTestRevoke: ctlV3LeaseRevok error (%v)", err)
|
||||
}
|
||||
if err := ctlV3Get(cx, []string{"key"}); err != nil { // expect no output
|
||||
cx.t.Fatalf("leaseTestRevoke: ctlV3Get error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3LeaseGrant(cx ctlCtx, ttl int) (string, error) {
|
||||
cmdArgs := append(cx.PrefixArgs(), "lease", "grant", strconv.Itoa(ttl))
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
line, err := proc.Expect(" granted with TTL(")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = proc.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// parse 'line LEASE_ID granted with TTL(5s)' to get lease ID
|
||||
hs := strings.Split(line, " ")
|
||||
if len(hs) < 2 {
|
||||
return "", fmt.Errorf("lease grant failed with %q", line)
|
||||
}
|
||||
return hs[1], nil
|
||||
}
|
||||
|
||||
func ctlV3LeaseKeepAlive(cx ctlCtx, leaseID string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "lease", "keep-alive", leaseID)
|
||||
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = proc.Expect(fmt.Sprintf("lease %s keepalived with TTL(", leaseID)); err != nil {
|
||||
return err
|
||||
}
|
||||
return proc.Stop()
|
||||
}
|
||||
|
||||
func ctlV3LeaseRevoke(cx ctlCtx, leaseID string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "lease", "revoke", leaseID)
|
||||
return spawnWithExpect(cmdArgs, fmt.Sprintf("lease %s revoked", leaseID))
|
||||
}
|
||||
113
vendor/github.com/coreos/etcd/e2e/ctl_v3_lock_test.go
generated
vendored
Normal file
113
vendor/github.com/coreos/etcd/e2e/ctl_v3_lock_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// 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"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/expect"
|
||||
)
|
||||
|
||||
func TestCtlV3Lock(t *testing.T) { testCtl(t, testLock) }
|
||||
|
||||
func testLock(cx ctlCtx) {
|
||||
name := "a"
|
||||
|
||||
holder, ch, err := ctlV3Lock(cx, name)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
l1 := ""
|
||||
select {
|
||||
case <-time.After(2 * time.Second):
|
||||
cx.t.Fatalf("timed out locking")
|
||||
case l1 = <-ch:
|
||||
if !strings.HasPrefix(l1, name) {
|
||||
cx.t.Errorf("got %q, expected %q prefix", l1, name)
|
||||
}
|
||||
}
|
||||
|
||||
// blocked process that won't acquire the lock
|
||||
blocked, ch, err := ctlV3Lock(cx, name)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
case <-ch:
|
||||
cx.t.Fatalf("should block")
|
||||
}
|
||||
|
||||
// overlap with a blocker that will acquire the lock
|
||||
blockAcquire, ch, err := ctlV3Lock(cx, name)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
defer blockAcquire.Stop()
|
||||
select {
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
case <-ch:
|
||||
cx.t.Fatalf("should block")
|
||||
}
|
||||
|
||||
// kill blocked process with clean shutdown
|
||||
if err = blocked.Signal(os.Interrupt); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err = blocked.Close(); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// kill the holder with clean shutdown
|
||||
if err = holder.Signal(os.Interrupt); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if err = holder.Close(); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
// blockAcquire should acquire the lock
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
cx.t.Fatalf("timed out from waiting to holding")
|
||||
case l2 := <-ch:
|
||||
if l1 == l2 || !strings.HasPrefix(l2, name) {
|
||||
cx.t.Fatalf("expected different lock name, got l1=%q, l2=%q", l1, l2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ctlV3Lock creates a lock process with a channel listening for when it acquires the lock.
|
||||
func ctlV3Lock(cx ctlCtx, name string) (*expect.ExpectProcess, <-chan string, error) {
|
||||
cmdArgs := append(cx.PrefixArgs(), "lock", name)
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
outc := make(chan string, 1)
|
||||
if err != nil {
|
||||
close(outc)
|
||||
return proc, outc, err
|
||||
}
|
||||
go func() {
|
||||
s, xerr := proc.ExpectFunc(func(string) bool { return true })
|
||||
if xerr != nil {
|
||||
cx.t.Errorf("expect failed (%v)", xerr)
|
||||
}
|
||||
outc <- s
|
||||
}()
|
||||
return proc, outc, err
|
||||
}
|
||||
108
vendor/github.com/coreos/etcd/e2e/ctl_v3_make_mirror_test.go
generated
vendored
Normal file
108
vendor/github.com/coreos/etcd/e2e/ctl_v3_make_mirror_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCtlV3MakeMirror(t *testing.T) { testCtl(t, makeMirrorTest) }
|
||||
func TestCtlV3MakeMirrorModifyDestPrefix(t *testing.T) { testCtl(t, makeMirrorModifyDestPrefixTest) }
|
||||
func TestCtlV3MakeMirrorNoDestPrefix(t *testing.T) { testCtl(t, makeMirrorNoDestPrefixTest) }
|
||||
|
||||
func makeMirrorTest(cx ctlCtx) {
|
||||
var (
|
||||
flags = []string{}
|
||||
kvs = []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}
|
||||
prefix = "key"
|
||||
)
|
||||
testMirrorCommand(cx, flags, kvs, kvs, prefix, prefix)
|
||||
}
|
||||
|
||||
func makeMirrorModifyDestPrefixTest(cx ctlCtx) {
|
||||
var (
|
||||
flags = []string{"--prefix", "o_", "--dest-prefix", "d_"}
|
||||
kvs = []kv{{"o_key1", "val1"}, {"o_key2", "val2"}, {"o_key3", "val3"}}
|
||||
kvs2 = []kv{{"d_key1", "val1"}, {"d_key2", "val2"}, {"d_key3", "val3"}}
|
||||
srcprefix = "o_"
|
||||
destprefix = "d_"
|
||||
)
|
||||
testMirrorCommand(cx, flags, kvs, kvs2, srcprefix, destprefix)
|
||||
}
|
||||
|
||||
func makeMirrorNoDestPrefixTest(cx ctlCtx) {
|
||||
var (
|
||||
flags = []string{"--prefix", "o_", "--no-dest-prefix"}
|
||||
kvs = []kv{{"o_key1", "val1"}, {"o_key2", "val2"}, {"o_key3", "val3"}}
|
||||
kvs2 = []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}
|
||||
srcprefix = "o_"
|
||||
destprefix = "key"
|
||||
)
|
||||
|
||||
testMirrorCommand(cx, flags, kvs, kvs2, srcprefix, destprefix)
|
||||
}
|
||||
|
||||
func testMirrorCommand(cx ctlCtx, flags []string, sourcekvs, destkvs []kv, srcprefix, destprefix string) {
|
||||
// set up another cluster to mirror with
|
||||
mirrorcfg := configAutoTLS
|
||||
mirrorcfg.clusterSize = 1
|
||||
mirrorcfg.basePort = 10000
|
||||
mirrorctx := ctlCtx{
|
||||
t: cx.t,
|
||||
cfg: mirrorcfg,
|
||||
dialTimeout: 7 * time.Second,
|
||||
}
|
||||
|
||||
mirrorepc, err := newEtcdProcessCluster(&mirrorctx.cfg)
|
||||
if err != nil {
|
||||
cx.t.Fatalf("could not start etcd process cluster (%v)", err)
|
||||
}
|
||||
mirrorctx.epc = mirrorepc
|
||||
|
||||
defer func() {
|
||||
if err = mirrorctx.epc.Close(); err != nil {
|
||||
cx.t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
cmdArgs := append(cx.PrefixArgs(), "make-mirror")
|
||||
cmdArgs = append(cmdArgs, flags...)
|
||||
cmdArgs = append(cmdArgs, fmt.Sprintf("localhost:%d", mirrorcfg.basePort))
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
err = proc.Stop()
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
for i := range sourcekvs {
|
||||
if err = ctlV3Put(cx, sourcekvs[i].key, sourcekvs[i].val, ""); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err = ctlV3Get(cx, []string{srcprefix, "--prefix"}, sourcekvs...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = ctlV3Watch(mirrorctx, []string{destprefix, "--rev", "1", "--prefix"}, destkvs...); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
127
vendor/github.com/coreos/etcd/e2e/ctl_v3_member_test.go
generated
vendored
Normal file
127
vendor/github.com/coreos/etcd/e2e/ctl_v3_member_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// 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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||
)
|
||||
|
||||
func TestCtlV3MemberList(t *testing.T) { testCtl(t, memberListTest) }
|
||||
func TestCtlV3MemberRemove(t *testing.T) {
|
||||
testCtl(t, memberRemoveTest, withQuorum(), withNoStrictReconfig())
|
||||
}
|
||||
func TestCtlV3MemberAdd(t *testing.T) { testCtl(t, memberAddTest) }
|
||||
func TestCtlV3MemberUpdate(t *testing.T) { testCtl(t, memberUpdateTest) }
|
||||
|
||||
func memberListTest(cx ctlCtx) {
|
||||
if err := ctlV3MemberList(cx); err != nil {
|
||||
cx.t.Fatalf("memberListTest ctlV3MemberList error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3MemberList(cx ctlCtx) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "member", "list")
|
||||
lines := make([]string, cx.cfg.clusterSize)
|
||||
for i := range lines {
|
||||
lines[i] = "started"
|
||||
}
|
||||
return spawnWithExpects(cmdArgs, lines...)
|
||||
}
|
||||
|
||||
func getMemberList(cx ctlCtx) (etcdserverpb.MemberListResponse, error) {
|
||||
cmdArgs := append(cx.PrefixArgs(), "--write-out", "json", "member", "list")
|
||||
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return etcdserverpb.MemberListResponse{}, err
|
||||
}
|
||||
var txt string
|
||||
txt, err = proc.Expect("members")
|
||||
if err != nil {
|
||||
return etcdserverpb.MemberListResponse{}, err
|
||||
}
|
||||
if err = proc.Close(); err != nil {
|
||||
return etcdserverpb.MemberListResponse{}, err
|
||||
}
|
||||
|
||||
resp := etcdserverpb.MemberListResponse{}
|
||||
dec := json.NewDecoder(strings.NewReader(txt))
|
||||
if err := dec.Decode(&resp); err == io.EOF {
|
||||
return etcdserverpb.MemberListResponse{}, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func memberRemoveTest(cx ctlCtx) {
|
||||
n1 := cx.cfg.clusterSize
|
||||
if n1 < 2 {
|
||||
cx.t.Fatalf("%d-node is too small to test 'member remove'", n1)
|
||||
}
|
||||
resp, err := getMemberList(cx)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
if n1 != len(resp.Members) {
|
||||
cx.t.Fatalf("expected %d, got %d", n1, len(resp.Members))
|
||||
}
|
||||
|
||||
var (
|
||||
memIDToRemove = fmt.Sprintf("%x", resp.Header.MemberId)
|
||||
cluserID = fmt.Sprintf("%x", resp.Header.ClusterId)
|
||||
)
|
||||
if err = ctlV3MemberRemove(cx, memIDToRemove, cluserID); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3MemberRemove(cx ctlCtx, memberID, clusterID string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "member", "remove", memberID)
|
||||
return spawnWithExpect(cmdArgs, fmt.Sprintf("%s removed from cluster %s", memberID, clusterID))
|
||||
}
|
||||
|
||||
func memberAddTest(cx ctlCtx) {
|
||||
if err := ctlV3MemberAdd(cx, fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3MemberAdd(cx ctlCtx, peerURL string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "member", "add", "newmember", fmt.Sprintf("--peer-urls=%s", peerURL))
|
||||
return spawnWithExpect(cmdArgs, " added to cluster ")
|
||||
}
|
||||
|
||||
func memberUpdateTest(cx ctlCtx) {
|
||||
mr, err := getMemberList(cx)
|
||||
if err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+11)
|
||||
memberID := fmt.Sprintf("%x", mr.Members[0].ID)
|
||||
if err = ctlV3MemberUpdate(cx, memberID, peerURL); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3MemberUpdate(cx ctlCtx, memberID, peerURL string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "member", "update", memberID, fmt.Sprintf("--peer-urls=%s", peerURL))
|
||||
return spawnWithExpect(cmdArgs, " updated in cluster ")
|
||||
}
|
||||
100
vendor/github.com/coreos/etcd/e2e/ctl_v3_migrate_test.go
generated
vendored
Normal file
100
vendor/github.com/coreos/etcd/e2e/ctl_v3_migrate_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestCtlV3Migrate(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, &configNoTLS, false)
|
||||
defer func() {
|
||||
if errC := epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
|
||||
keys := make([]string, 3)
|
||||
vals := make([]string, 3)
|
||||
for i := range keys {
|
||||
keys[i] = fmt.Sprintf("foo_%d", i)
|
||||
vals[i] = fmt.Sprintf("bar_%d", i)
|
||||
}
|
||||
for i := range keys {
|
||||
if err := etcdctlSet(epc, keys[i], vals[i]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
dataDir := epc.procs[0].cfg.dataDirPath
|
||||
if err := epc.StopAll(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
|
||||
os.Setenv("ETCDCTL_API", "3")
|
||||
defer os.Unsetenv("ETCDCTL_API")
|
||||
cx := ctlCtx{
|
||||
t: t,
|
||||
cfg: configNoTLS,
|
||||
dialTimeout: 7 * time.Second,
|
||||
epc: epc,
|
||||
}
|
||||
if err := ctlV3Migrate(cx, dataDir, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
epc.procs[0].cfg.keepDataDir = true
|
||||
if err := epc.RestartAll(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// to ensure revision increment is continuous from migrated v2 data
|
||||
if err := ctlV3Put(cx, "test", "value", ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cli, err := clientv3.New(clientv3.Config{
|
||||
Endpoints: epc.grpcEndpoints(),
|
||||
DialTimeout: 3 * time.Second,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer cli.Close()
|
||||
resp, err := cli.Get(context.TODO(), "test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(resp.Kvs) != 1 {
|
||||
t.Fatalf("len(resp.Kvs) expected 1, got %+v", resp.Kvs)
|
||||
}
|
||||
if resp.Kvs[0].CreateRevision != 7 {
|
||||
t.Fatalf("resp.Kvs[0].CreateRevision expected 7, got %d", resp.Kvs[0].CreateRevision)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Migrate(cx ctlCtx, dataDir, walDir string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "migrate", "--data-dir", dataDir, "--wal-dir", walDir)
|
||||
return spawnWithExpects(cmdArgs, "finished transforming keys")
|
||||
}
|
||||
165
vendor/github.com/coreos/etcd/e2e/ctl_v3_role_test.go
generated
vendored
Normal file
165
vendor/github.com/coreos/etcd/e2e/ctl_v3_role_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCtlV3RoleAdd(t *testing.T) { testCtl(t, roleAddTest) }
|
||||
func TestCtlV3RoleAddNoTLS(t *testing.T) { testCtl(t, roleAddTest, withCfg(configNoTLS)) }
|
||||
func TestCtlV3RoleAddClientTLS(t *testing.T) { testCtl(t, roleAddTest, withCfg(configClientTLS)) }
|
||||
func TestCtlV3RoleAddPeerTLS(t *testing.T) { testCtl(t, roleAddTest, withCfg(configPeerTLS)) }
|
||||
func TestCtlV3RoleAddTimeout(t *testing.T) { testCtl(t, roleAddTest, withDialTimeout(0)) }
|
||||
|
||||
func TestCtlV3RoleGrant(t *testing.T) { testCtl(t, roleGrantTest) }
|
||||
|
||||
func roleAddTest(cx ctlCtx) {
|
||||
cmdSet := []struct {
|
||||
args []string
|
||||
expectedStr string
|
||||
}{
|
||||
// Add a role.
|
||||
{
|
||||
args: []string{"add", "root"},
|
||||
expectedStr: "Role root created",
|
||||
},
|
||||
// Try adding the same role.
|
||||
{
|
||||
args: []string{"add", "root"},
|
||||
expectedStr: "role name already exists",
|
||||
},
|
||||
}
|
||||
|
||||
for i, cmd := range cmdSet {
|
||||
if err := ctlV3Role(cx, cmd.args, cmd.expectedStr); err != nil {
|
||||
if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
|
||||
cx.t.Fatalf("roleAddTest #%d: ctlV3Role error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func roleGrantTest(cx ctlCtx) {
|
||||
cmdSet := []struct {
|
||||
args []string
|
||||
expectedStr string
|
||||
}{
|
||||
// Add a role.
|
||||
{
|
||||
args: []string{"add", "root"},
|
||||
expectedStr: "Role root created",
|
||||
},
|
||||
// Grant read permission to the role.
|
||||
{
|
||||
args: []string{"grant", "root", "read", "foo"},
|
||||
expectedStr: "Role root updated",
|
||||
},
|
||||
// Grant write permission to the role.
|
||||
{
|
||||
args: []string{"grant", "root", "write", "foo"},
|
||||
expectedStr: "Role root updated",
|
||||
},
|
||||
// Grant rw permission to the role.
|
||||
{
|
||||
args: []string{"grant", "root", "readwrite", "foo"},
|
||||
expectedStr: "Role root updated",
|
||||
},
|
||||
// Try granting invalid permission to the role.
|
||||
{
|
||||
args: []string{"grant", "root", "123", "foo"},
|
||||
expectedStr: "invalid permission type",
|
||||
},
|
||||
}
|
||||
|
||||
for i, cmd := range cmdSet {
|
||||
if err := ctlV3Role(cx, cmd.args, cmd.expectedStr); err != nil {
|
||||
cx.t.Fatalf("roleGrantTest #%d: ctlV3Role error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Role(cx ctlCtx, args []string, expStr string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "role")
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
|
||||
return spawnWithExpect(cmdArgs, expStr)
|
||||
}
|
||||
|
||||
func ctlV3RoleGrantPermission(cx ctlCtx, rolename string, perm grantingPerm) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "role", "grant-permission")
|
||||
if perm.prefix {
|
||||
cmdArgs = append(cmdArgs, "--prefix")
|
||||
}
|
||||
cmdArgs = append(cmdArgs, rolename)
|
||||
cmdArgs = append(cmdArgs, grantingPermToArgs(perm)...)
|
||||
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expStr := fmt.Sprintf("Role %s updated", rolename)
|
||||
_, err = proc.Expect(expStr)
|
||||
return err
|
||||
}
|
||||
|
||||
func ctlV3RoleRevokePermission(cx ctlCtx, rolename string, key, rangeEnd string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "role", "revoke-permission")
|
||||
cmdArgs = append(cmdArgs, rolename)
|
||||
cmdArgs = append(cmdArgs, key)
|
||||
if len(rangeEnd) != 0 {
|
||||
cmdArgs = append(cmdArgs, rangeEnd)
|
||||
}
|
||||
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expStr := fmt.Sprintf("Permission of key %s is revoked from role %s", key, rolename)
|
||||
_, err = proc.Expect(expStr)
|
||||
return err
|
||||
}
|
||||
|
||||
type grantingPerm struct {
|
||||
read bool
|
||||
write bool
|
||||
key string
|
||||
rangeEnd string
|
||||
prefix bool
|
||||
}
|
||||
|
||||
func grantingPermToArgs(perm grantingPerm) []string {
|
||||
permstr := ""
|
||||
|
||||
if perm.read {
|
||||
permstr += "read"
|
||||
}
|
||||
|
||||
if perm.write {
|
||||
permstr += "write"
|
||||
}
|
||||
|
||||
if len(permstr) == 0 {
|
||||
panic("invalid granting permission")
|
||||
}
|
||||
|
||||
if len(perm.rangeEnd) == 0 {
|
||||
return []string{permstr, perm.key}
|
||||
}
|
||||
return []string{permstr, perm.key, perm.rangeEnd}
|
||||
}
|
||||
286
vendor/github.com/coreos/etcd/e2e/ctl_v3_snapshot_test.go
generated
vendored
Normal file
286
vendor/github.com/coreos/etcd/e2e/ctl_v3_snapshot_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
// 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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/expect"
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestCtlV3Snapshot(t *testing.T) { testCtl(t, snapshotTest) }
|
||||
|
||||
func snapshotTest(cx ctlCtx) {
|
||||
maintenanceInitKeys(cx)
|
||||
|
||||
leaseID, err := ctlV3LeaseGrant(cx, 100)
|
||||
if err != nil {
|
||||
cx.t.Fatalf("snapshot: ctlV3LeaseGrant error (%v)", err)
|
||||
}
|
||||
if err = ctlV3Put(cx, "withlease", "withlease", leaseID); err != nil {
|
||||
cx.t.Fatalf("snapshot: ctlV3Put error (%v)", err)
|
||||
}
|
||||
|
||||
fpath := "test.snapshot"
|
||||
defer os.RemoveAll(fpath)
|
||||
|
||||
if err = ctlV3SnapshotSave(cx, fpath); err != nil {
|
||||
cx.t.Fatalf("snapshotTest ctlV3SnapshotSave error (%v)", err)
|
||||
}
|
||||
|
||||
st, err := getSnapshotStatus(cx, fpath)
|
||||
if err != nil {
|
||||
cx.t.Fatalf("snapshotTest getSnapshotStatus error (%v)", err)
|
||||
}
|
||||
if st.Revision != 5 {
|
||||
cx.t.Fatalf("expected 4, got %d", st.Revision)
|
||||
}
|
||||
if st.TotalKey < 4 {
|
||||
cx.t.Fatalf("expected at least 4, got %d", st.TotalKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV3SnapshotCorrupt(t *testing.T) { testCtl(t, snapshotCorruptTest) }
|
||||
|
||||
func snapshotCorruptTest(cx ctlCtx) {
|
||||
fpath := "test.snapshot"
|
||||
defer os.RemoveAll(fpath)
|
||||
|
||||
if err := ctlV3SnapshotSave(cx, fpath); err != nil {
|
||||
cx.t.Fatalf("snapshotTest ctlV3SnapshotSave error (%v)", err)
|
||||
}
|
||||
|
||||
// corrupt file
|
||||
f, oerr := os.OpenFile(fpath, os.O_WRONLY, 0)
|
||||
if oerr != nil {
|
||||
cx.t.Fatal(oerr)
|
||||
}
|
||||
if _, err := f.Write(make([]byte, 512)); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
defer os.RemoveAll("snap.etcd")
|
||||
serr := spawnWithExpect(
|
||||
append(cx.PrefixArgs(), "snapshot", "restore",
|
||||
"--data-dir", "snap.etcd",
|
||||
fpath),
|
||||
"expected sha256")
|
||||
|
||||
if serr != nil {
|
||||
cx.t.Fatal(serr)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3SnapshotSave(cx ctlCtx, fpath string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "snapshot", "save", fpath)
|
||||
return spawnWithExpect(cmdArgs, fmt.Sprintf("Snapshot saved at %s", fpath))
|
||||
}
|
||||
|
||||
type snapshotStatus struct {
|
||||
Hash uint32 `json:"hash"`
|
||||
Revision int64 `json:"revision"`
|
||||
TotalKey int `json:"totalKey"`
|
||||
TotalSize int64 `json:"totalSize"`
|
||||
}
|
||||
|
||||
func getSnapshotStatus(cx ctlCtx, fpath string) (snapshotStatus, error) {
|
||||
cmdArgs := append(cx.PrefixArgs(), "--write-out", "json", "snapshot", "status", fpath)
|
||||
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return snapshotStatus{}, err
|
||||
}
|
||||
var txt string
|
||||
txt, err = proc.Expect("totalKey")
|
||||
if err != nil {
|
||||
return snapshotStatus{}, err
|
||||
}
|
||||
if err = proc.Close(); err != nil {
|
||||
return snapshotStatus{}, err
|
||||
}
|
||||
|
||||
resp := snapshotStatus{}
|
||||
dec := json.NewDecoder(strings.NewReader(txt))
|
||||
if err := dec.Decode(&resp); err == io.EOF {
|
||||
return snapshotStatus{}, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// TestIssue6361 ensures new member that starts with snapshot correctly
|
||||
// syncs up with other members and serve correct data.
|
||||
func TestIssue6361(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
mustEtcdctl(t)
|
||||
os.Setenv("ETCDCTL_API", "3")
|
||||
defer os.Unsetenv("ETCDCTL_API")
|
||||
|
||||
epc, err := newEtcdProcessCluster(&etcdProcessClusterConfig{
|
||||
clusterSize: 1,
|
||||
initialToken: "new",
|
||||
keepDataDir: true,
|
||||
})
|
||||
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)
|
||||
}
|
||||
}()
|
||||
|
||||
dialTimeout := 7 * time.Second
|
||||
prefixArgs := []string{ctlBinPath, "--endpoints", strings.Join(epc.grpcEndpoints(), ","), "--dial-timeout", dialTimeout.String()}
|
||||
|
||||
// write some keys
|
||||
kvs := []kv{{"foo1", "val1"}, {"foo2", "val2"}, {"foo3", "val3"}}
|
||||
for i := range kvs {
|
||||
if err = spawnWithExpect(append(prefixArgs, "put", kvs[i].key, kvs[i].val), "OK"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
fpath := filepath.Join(os.TempDir(), "test.snapshot")
|
||||
defer os.RemoveAll(fpath)
|
||||
|
||||
// etcdctl save snapshot
|
||||
if err = spawnWithExpect(append(prefixArgs, "snapshot", "save", fpath), fmt.Sprintf("Snapshot saved at %s", fpath)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = epc.processes()[0].Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
newDataDir := filepath.Join(os.TempDir(), "test.data")
|
||||
defer os.RemoveAll(newDataDir)
|
||||
|
||||
// etcdctl restore the snapshot
|
||||
err = spawnWithExpect([]string{ctlBinPath, "snapshot", "restore", fpath, "--name", epc.procs[0].cfg.name, "--initial-cluster", epc.procs[0].cfg.initialCluster, "--initial-cluster-token", epc.procs[0].cfg.initialToken, "--initial-advertise-peer-urls", epc.procs[0].cfg.purl.String(), "--data-dir", newDataDir}, "membership: added member")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// start the etcd member using the restored snapshot
|
||||
epc.procs[0].cfg.dataDirPath = newDataDir
|
||||
for i := range epc.procs[0].cfg.args {
|
||||
if epc.procs[0].cfg.args[i] == "--data-dir" {
|
||||
epc.procs[0].cfg.args[i+1] = newDataDir
|
||||
}
|
||||
}
|
||||
if err = epc.processes()[0].Restart(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// ensure the restored member has the correct data
|
||||
for i := range kvs {
|
||||
if err = spawnWithExpect(append(prefixArgs, "get", kvs[i].key), kvs[i].val); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// add a new member into the cluster
|
||||
clientURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+30)
|
||||
peerURL := fmt.Sprintf("http://localhost:%d", etcdProcessBasePort+31)
|
||||
err = spawnWithExpect(append(prefixArgs, "member", "add", "newmember", fmt.Sprintf("--peer-urls=%s", peerURL)), " added to cluster ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var newDataDir2 string
|
||||
newDataDir2, err = ioutil.TempDir("", "newdata2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(newDataDir2)
|
||||
|
||||
name2 := "infra2"
|
||||
initialCluster2 := epc.procs[0].cfg.initialCluster + fmt.Sprintf(",%s=%s", name2, peerURL)
|
||||
|
||||
// start the new member
|
||||
var nepc *expect.ExpectProcess
|
||||
nepc, err = spawnCmd([]string{epc.procs[0].cfg.execPath, "--name", name2,
|
||||
"--listen-client-urls", clientURL, "--advertise-client-urls", clientURL,
|
||||
"--listen-peer-urls", peerURL, "--initial-advertise-peer-urls", peerURL,
|
||||
"--initial-cluster", initialCluster2, "--initial-cluster-state", "existing", "--data-dir", newDataDir2})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = nepc.Expect("enabled capabilities for version"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
prefixArgs = []string{ctlBinPath, "--endpoints", clientURL, "--dial-timeout", dialTimeout.String()}
|
||||
|
||||
// ensure added member has data from incoming snapshot
|
||||
for i := range kvs {
|
||||
if err = spawnWithExpect(append(prefixArgs, "get", kvs[i].key), kvs[i].val); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = nepc.Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCtlV3SnapshotWithAuth(t *testing.T) { testCtl(t, snapshotTestWithAuth) }
|
||||
|
||||
func snapshotTestWithAuth(cx ctlCtx) {
|
||||
maintenanceInitKeys(cx)
|
||||
|
||||
if err := authEnable(cx); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
|
||||
cx.user, cx.pass = "root", "root"
|
||||
authSetupTestUser(cx)
|
||||
|
||||
fpath := "test.snapshot"
|
||||
defer os.RemoveAll(fpath)
|
||||
|
||||
// ordinal user cannot save a snapshot
|
||||
cx.user, cx.pass = "test-user", "pass"
|
||||
if err := ctlV3SnapshotSave(cx, fpath); err == nil {
|
||||
cx.t.Fatal("ordinal user should not be able to save a snapshot")
|
||||
}
|
||||
|
||||
// root can save a snapshot
|
||||
cx.user, cx.pass = "root", "root"
|
||||
if err := ctlV3SnapshotSave(cx, fpath); err != nil {
|
||||
cx.t.Fatalf("snapshotTest ctlV3SnapshotSave error (%v)", err)
|
||||
}
|
||||
|
||||
st, err := getSnapshotStatus(cx, fpath)
|
||||
if err != nil {
|
||||
cx.t.Fatalf("snapshotTest getSnapshotStatus error (%v)", err)
|
||||
}
|
||||
if st.Revision != 4 {
|
||||
cx.t.Fatalf("expected 4, got %d", st.Revision)
|
||||
}
|
||||
if st.TotalKey < 3 {
|
||||
cx.t.Fatalf("expected at least 3, got %d", st.TotalKey)
|
||||
}
|
||||
}
|
||||
216
vendor/github.com/coreos/etcd/e2e/ctl_v3_test.go
generated
vendored
Normal file
216
vendor/github.com/coreos/etcd/e2e/ctl_v3_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/flags"
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
"github.com/coreos/etcd/version"
|
||||
)
|
||||
|
||||
func TestCtlV3Version(t *testing.T) { testCtl(t, versionTest) }
|
||||
|
||||
func versionTest(cx ctlCtx) {
|
||||
if err := ctlV3Version(cx); err != nil {
|
||||
cx.t.Fatalf("versionTest ctlV3Version error (%v)", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Version(cx ctlCtx) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "version")
|
||||
return spawnWithExpect(cmdArgs, version.Version)
|
||||
}
|
||||
|
||||
// TestCtlV3DialWithHTTPScheme ensures that client handles endpoints with HTTPS scheme.
|
||||
func TestCtlV3DialWithHTTPScheme(t *testing.T) {
|
||||
testCtl(t, dialWithSchemeTest, withCfg(configClientTLS))
|
||||
}
|
||||
|
||||
func dialWithSchemeTest(cx ctlCtx) {
|
||||
cmdArgs := append(cx.prefixArgs(cx.epc.endpoints()), "put", "foo", "bar")
|
||||
if err := spawnWithExpect(cmdArgs, "OK"); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type ctlCtx struct {
|
||||
t *testing.T
|
||||
cfg etcdProcessClusterConfig
|
||||
quotaBackendBytes int64
|
||||
noStrictReconfig bool
|
||||
|
||||
epc *etcdProcessCluster
|
||||
|
||||
envMap map[string]struct{}
|
||||
|
||||
dialTimeout time.Duration
|
||||
|
||||
quorum bool // if true, set up 3-node cluster and linearizable read
|
||||
interactive bool
|
||||
|
||||
user string
|
||||
pass string
|
||||
|
||||
// for compaction
|
||||
compactPhysical bool
|
||||
}
|
||||
|
||||
type ctlOption func(*ctlCtx)
|
||||
|
||||
func (cx *ctlCtx) applyOpts(opts []ctlOption) {
|
||||
for _, opt := range opts {
|
||||
opt(cx)
|
||||
}
|
||||
}
|
||||
|
||||
func withCfg(cfg etcdProcessClusterConfig) ctlOption {
|
||||
return func(cx *ctlCtx) { cx.cfg = cfg }
|
||||
}
|
||||
|
||||
func withDialTimeout(timeout time.Duration) ctlOption {
|
||||
return func(cx *ctlCtx) { cx.dialTimeout = timeout }
|
||||
}
|
||||
|
||||
func withQuorum() ctlOption {
|
||||
return func(cx *ctlCtx) { cx.quorum = true }
|
||||
}
|
||||
|
||||
func withInteractive() ctlOption {
|
||||
return func(cx *ctlCtx) { cx.interactive = true }
|
||||
}
|
||||
|
||||
func withQuota(b int64) ctlOption {
|
||||
return func(cx *ctlCtx) { cx.quotaBackendBytes = b }
|
||||
}
|
||||
|
||||
func withCompactPhysical() ctlOption {
|
||||
return func(cx *ctlCtx) { cx.compactPhysical = true }
|
||||
}
|
||||
|
||||
func withNoStrictReconfig() ctlOption {
|
||||
return func(cx *ctlCtx) { cx.noStrictReconfig = true }
|
||||
}
|
||||
|
||||
func withFlagByEnv() ctlOption {
|
||||
return func(cx *ctlCtx) { cx.envMap = make(map[string]struct{}) }
|
||||
}
|
||||
|
||||
func testCtl(t *testing.T, testFunc func(ctlCtx), opts ...ctlOption) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
ret := ctlCtx{
|
||||
t: t,
|
||||
cfg: configAutoTLS,
|
||||
dialTimeout: 7 * time.Second,
|
||||
}
|
||||
ret.applyOpts(opts)
|
||||
|
||||
os.Setenv("ETCDCTL_API", "3")
|
||||
mustEtcdctl(t)
|
||||
if !ret.quorum {
|
||||
ret.cfg = *configStandalone(ret.cfg)
|
||||
}
|
||||
if ret.quotaBackendBytes > 0 {
|
||||
ret.cfg.quotaBackendBytes = ret.quotaBackendBytes
|
||||
}
|
||||
ret.cfg.noStrictReconfig = ret.noStrictReconfig
|
||||
|
||||
epc, err := newEtcdProcessCluster(&ret.cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("could not start etcd process cluster (%v)", err)
|
||||
}
|
||||
ret.epc = epc
|
||||
|
||||
defer func() {
|
||||
os.Unsetenv("ETCDCTL_API")
|
||||
if ret.envMap != nil {
|
||||
for k := range ret.envMap {
|
||||
os.Unsetenv(k)
|
||||
}
|
||||
}
|
||||
if errC := ret.epc.Close(); errC != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", errC)
|
||||
}
|
||||
}()
|
||||
|
||||
donec := make(chan struct{})
|
||||
go func() {
|
||||
defer close(donec)
|
||||
testFunc(ret)
|
||||
}()
|
||||
|
||||
timeout := 2*ret.dialTimeout + time.Second
|
||||
if ret.dialTimeout == 0 {
|
||||
timeout = 30 * time.Second
|
||||
}
|
||||
select {
|
||||
case <-time.After(timeout):
|
||||
testutil.FatalStack(t, fmt.Sprintf("test timed out after %v", timeout))
|
||||
case <-donec:
|
||||
}
|
||||
}
|
||||
|
||||
func (cx *ctlCtx) prefixArgs(eps []string) []string {
|
||||
if len(cx.epc.proxies()) > 0 { // TODO: add proxy check as in v2
|
||||
panic("v3 proxy not implemented")
|
||||
}
|
||||
|
||||
fmap := make(map[string]string)
|
||||
fmap["endpoints"] = strings.Join(eps, ",")
|
||||
fmap["dial-timeout"] = cx.dialTimeout.String()
|
||||
if cx.epc.cfg.clientTLS == clientTLS {
|
||||
if cx.epc.cfg.isClientAutoTLS {
|
||||
fmap["insecure-transport"] = "false"
|
||||
fmap["insecure-skip-tls-verify"] = "true"
|
||||
} else {
|
||||
fmap["cacert"] = caPath
|
||||
fmap["cert"] = certPath
|
||||
fmap["key"] = privateKeyPath
|
||||
}
|
||||
}
|
||||
if cx.user != "" {
|
||||
fmap["user"] = cx.user + ":" + cx.pass
|
||||
}
|
||||
|
||||
useEnv := cx.envMap != nil
|
||||
|
||||
cmdArgs := []string{ctlBinPath}
|
||||
for k, v := range fmap {
|
||||
if useEnv {
|
||||
ek := flags.FlagToEnv("ETCDCTL", k)
|
||||
os.Setenv(ek, v)
|
||||
cx.envMap[ek] = struct{}{}
|
||||
} else {
|
||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--%s=%s", k, v))
|
||||
}
|
||||
}
|
||||
return cmdArgs
|
||||
}
|
||||
|
||||
// PrefixArgs prefixes etcdctl command.
|
||||
// Make sure to unset environment variables after tests.
|
||||
func (cx *ctlCtx) PrefixArgs() []string {
|
||||
return cx.prefixArgs(cx.epc.grpcEndpoints())
|
||||
}
|
||||
|
||||
func isGRPCTimedout(err error) bool {
|
||||
return strings.Contains(err.Error(), "grpc: timed out trying to connect")
|
||||
}
|
||||
155
vendor/github.com/coreos/etcd/e2e/ctl_v3_txn_test.go
generated
vendored
Normal file
155
vendor/github.com/coreos/etcd/e2e/ctl_v3_txn_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// 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 "testing"
|
||||
|
||||
func TestCtlV3TxnInteractiveSuccess(t *testing.T) {
|
||||
testCtl(t, txnTestSuccess, withInteractive())
|
||||
}
|
||||
func TestCtlV3TxnInteractiveSuccessNoTLS(t *testing.T) {
|
||||
testCtl(t, txnTestSuccess, withInteractive(), withCfg(configNoTLS))
|
||||
}
|
||||
func TestCtlV3TxnInteractiveSuccessClientTLS(t *testing.T) {
|
||||
testCtl(t, txnTestSuccess, withInteractive(), withCfg(configClientTLS))
|
||||
}
|
||||
func TestCtlV3TxnInteractiveSuccessPeerTLS(t *testing.T) {
|
||||
testCtl(t, txnTestSuccess, withInteractive(), withCfg(configPeerTLS))
|
||||
}
|
||||
func TestCtlV3TxnInteractiveFail(t *testing.T) {
|
||||
testCtl(t, txnTestFail, withInteractive())
|
||||
}
|
||||
|
||||
func txnTestSuccess(cx ctlCtx) {
|
||||
if err := ctlV3Put(cx, "key1", "value1", ""); err != nil {
|
||||
cx.t.Fatalf("txnTestSuccess ctlV3Put error (%v)", err)
|
||||
}
|
||||
if err := ctlV3Put(cx, "key2", "value2", ""); err != nil {
|
||||
cx.t.Fatalf("txnTestSuccess ctlV3Put error (%v)", err)
|
||||
}
|
||||
rqs := []txnRequests{
|
||||
{
|
||||
compare: []string{`value("key1") != "value2"`, `value("key2") != "value1"`},
|
||||
ifSucess: []string{"get key1", "get key2"},
|
||||
results: []string{"SUCCESS", "key1", "value1", "key2", "value2"},
|
||||
},
|
||||
{
|
||||
compare: []string{`version("key1") = "1"`, `version("key2") = "1"`},
|
||||
ifSucess: []string{"get key1", "get key2", `put "key \"with\" space" "value \x23"`},
|
||||
ifFail: []string{`put key1 "fail"`, `put key2 "fail"`},
|
||||
results: []string{"SUCCESS", "key1", "value1", "key2", "value2"},
|
||||
},
|
||||
{
|
||||
compare: []string{`version("key \"with\" space") = "1"`},
|
||||
ifSucess: []string{`get "key \"with\" space"`},
|
||||
results: []string{"SUCCESS", `key "with" space`, "value \x23"},
|
||||
},
|
||||
}
|
||||
for _, rq := range rqs {
|
||||
if err := ctlV3Txn(cx, rq); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func txnTestFail(cx ctlCtx) {
|
||||
if err := ctlV3Put(cx, "key1", "value1", ""); err != nil {
|
||||
cx.t.Fatalf("txnTestSuccess ctlV3Put error (%v)", err)
|
||||
}
|
||||
rqs := []txnRequests{
|
||||
{
|
||||
compare: []string{`version("key") < "0"`},
|
||||
ifSucess: []string{`put key "success"`},
|
||||
ifFail: []string{`put key "fail"`},
|
||||
results: []string{"FAILURE", "OK"},
|
||||
},
|
||||
{
|
||||
compare: []string{`value("key1") != "value1"`},
|
||||
ifSucess: []string{`put key1 "success"`},
|
||||
ifFail: []string{`put key1 "fail"`},
|
||||
results: []string{"FAILURE", "OK"},
|
||||
},
|
||||
}
|
||||
for _, rq := range rqs {
|
||||
if err := ctlV3Txn(cx, rq); err != nil {
|
||||
cx.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type txnRequests struct {
|
||||
compare []string
|
||||
ifSucess []string
|
||||
ifFail []string
|
||||
results []string
|
||||
}
|
||||
|
||||
func ctlV3Txn(cx ctlCtx, rqs txnRequests) error {
|
||||
// TODO: support non-interactive mode
|
||||
cmdArgs := append(cx.PrefixArgs(), "txn")
|
||||
if cx.interactive {
|
||||
cmdArgs = append(cmdArgs, "--interactive")
|
||||
}
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = proc.Expect("compares:")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, req := range rqs.compare {
|
||||
if err = proc.Send(req + "\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = proc.Send("\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = proc.Expect("success requests (get, put, delete):")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, req := range rqs.ifSucess {
|
||||
if err = proc.Send(req + "\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = proc.Send("\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = proc.Expect("failure requests (get, put, delete):")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, req := range rqs.ifFail {
|
||||
if err = proc.Send(req + "\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = proc.Send("\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, line := range rqs.results {
|
||||
_, err = proc.Expect(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return proc.Close()
|
||||
}
|
||||
139
vendor/github.com/coreos/etcd/e2e/ctl_v3_user_test.go
generated
vendored
Normal file
139
vendor/github.com/coreos/etcd/e2e/ctl_v3_user_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
// 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 "testing"
|
||||
|
||||
func TestCtlV3UserAdd(t *testing.T) { testCtl(t, userAddTest) }
|
||||
func TestCtlV3UserAddNoTLS(t *testing.T) { testCtl(t, userAddTest, withCfg(configNoTLS)) }
|
||||
func TestCtlV3UserAddClientTLS(t *testing.T) { testCtl(t, userAddTest, withCfg(configClientTLS)) }
|
||||
func TestCtlV3UserAddPeerTLS(t *testing.T) { testCtl(t, userAddTest, withCfg(configPeerTLS)) }
|
||||
func TestCtlV3UserAddTimeout(t *testing.T) { testCtl(t, userAddTest, withDialTimeout(0)) }
|
||||
|
||||
func TestCtlV3UserDelete(t *testing.T) { testCtl(t, userDelTest) }
|
||||
func TestCtlV3UserPasswd(t *testing.T) { testCtl(t, userPasswdTest) }
|
||||
|
||||
type userCmdDesc struct {
|
||||
args []string
|
||||
expectedStr string
|
||||
stdIn []string
|
||||
}
|
||||
|
||||
func userAddTest(cx ctlCtx) {
|
||||
cmdSet := []userCmdDesc{
|
||||
// Adds a user name.
|
||||
{
|
||||
args: []string{"add", "username", "--interactive=false"},
|
||||
expectedStr: "User username created",
|
||||
stdIn: []string{"password"},
|
||||
},
|
||||
// Adds a user name using the usertest:password syntax.
|
||||
{
|
||||
args: []string{"add", "usertest:password"},
|
||||
expectedStr: "User usertest created",
|
||||
stdIn: []string{},
|
||||
},
|
||||
// Tries to add a user with empty username.
|
||||
{
|
||||
args: []string{"add", ":password"},
|
||||
expectedStr: "empty user name is not allowed.",
|
||||
stdIn: []string{},
|
||||
},
|
||||
// Tries to add a user name that already exists.
|
||||
{
|
||||
args: []string{"add", "username", "--interactive=false"},
|
||||
expectedStr: "user name already exists",
|
||||
stdIn: []string{"password"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, cmd := range cmdSet {
|
||||
if err := ctlV3User(cx, cmd.args, cmd.expectedStr, cmd.stdIn); err != nil {
|
||||
if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
|
||||
cx.t.Fatalf("userAddTest #%d: ctlV3User error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func userDelTest(cx ctlCtx) {
|
||||
cmdSet := []userCmdDesc{
|
||||
// Adds a user name.
|
||||
{
|
||||
args: []string{"add", "username", "--interactive=false"},
|
||||
expectedStr: "User username created",
|
||||
stdIn: []string{"password"},
|
||||
},
|
||||
// Deletes the user name just added.
|
||||
{
|
||||
args: []string{"delete", "username"},
|
||||
expectedStr: "User username deleted",
|
||||
},
|
||||
// Deletes a user name that is not present.
|
||||
{
|
||||
args: []string{"delete", "username"},
|
||||
expectedStr: "user name not found",
|
||||
},
|
||||
}
|
||||
|
||||
for i, cmd := range cmdSet {
|
||||
if err := ctlV3User(cx, cmd.args, cmd.expectedStr, cmd.stdIn); err != nil {
|
||||
cx.t.Fatalf("userDelTest #%d: ctlV3User error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func userPasswdTest(cx ctlCtx) {
|
||||
cmdSet := []userCmdDesc{
|
||||
// Adds a user name.
|
||||
{
|
||||
args: []string{"add", "username", "--interactive=false"},
|
||||
expectedStr: "User username created",
|
||||
stdIn: []string{"password"},
|
||||
},
|
||||
// Changes the password.
|
||||
{
|
||||
args: []string{"passwd", "username", "--interactive=false"},
|
||||
expectedStr: "Password updated",
|
||||
stdIn: []string{"password1"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, cmd := range cmdSet {
|
||||
if err := ctlV3User(cx, cmd.args, cmd.expectedStr, cmd.stdIn); err != nil {
|
||||
cx.t.Fatalf("userPasswdTest #%d: ctlV3User error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3User(cx ctlCtx, args []string, expStr string, stdIn []string) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "user")
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send 'stdIn' strings as input.
|
||||
for _, s := range stdIn {
|
||||
if err = proc.Send(s + "\r"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = proc.Expect(expStr)
|
||||
return err
|
||||
}
|
||||
118
vendor/github.com/coreos/etcd/e2e/ctl_v3_watch_test.go
generated
vendored
Normal file
118
vendor/github.com/coreos/etcd/e2e/ctl_v3_watch_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// 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 (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCtlV3Watch(t *testing.T) { testCtl(t, watchTest) }
|
||||
func TestCtlV3WatchNoTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configNoTLS)) }
|
||||
func TestCtlV3WatchClientTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configClientTLS)) }
|
||||
func TestCtlV3WatchPeerTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configPeerTLS)) }
|
||||
func TestCtlV3WatchTimeout(t *testing.T) { testCtl(t, watchTest, withDialTimeout(0)) }
|
||||
|
||||
func TestCtlV3WatchInteractive(t *testing.T) {
|
||||
testCtl(t, watchTest, withInteractive())
|
||||
}
|
||||
func TestCtlV3WatchInteractiveNoTLS(t *testing.T) {
|
||||
testCtl(t, watchTest, withInteractive(), withCfg(configNoTLS))
|
||||
}
|
||||
func TestCtlV3WatchInteractiveClientTLS(t *testing.T) {
|
||||
testCtl(t, watchTest, withInteractive(), withCfg(configClientTLS))
|
||||
}
|
||||
func TestCtlV3WatchInteractivePeerTLS(t *testing.T) {
|
||||
testCtl(t, watchTest, withInteractive(), withCfg(configPeerTLS))
|
||||
}
|
||||
|
||||
func watchTest(cx ctlCtx) {
|
||||
tests := []struct {
|
||||
puts []kv
|
||||
args []string
|
||||
|
||||
wkv []kv
|
||||
}{
|
||||
{ // watch 1 key
|
||||
[]kv{{"sample", "value"}},
|
||||
[]string{"sample", "--rev", "1"},
|
||||
[]kv{{"sample", "value"}},
|
||||
},
|
||||
{ // watch 3 keys by prefix
|
||||
[]kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
|
||||
[]string{"key", "--rev", "1", "--prefix"},
|
||||
[]kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}},
|
||||
},
|
||||
{ // watch by revision
|
||||
[]kv{{"etcd", "revision_1"}, {"etcd", "revision_2"}, {"etcd", "revision_3"}},
|
||||
[]string{"etcd", "--rev", "2"},
|
||||
[]kv{{"etcd", "revision_2"}, {"etcd", "revision_3"}},
|
||||
},
|
||||
{ // watch 3 keys by range
|
||||
[]kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}},
|
||||
[]string{"key", "key3", "--rev", "1"},
|
||||
[]kv{{"key1", "val1"}, {"key2", "val2"}},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
donec := make(chan struct{})
|
||||
go func(i int, puts []kv) {
|
||||
for j := range puts {
|
||||
if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil {
|
||||
cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err)
|
||||
}
|
||||
}
|
||||
close(donec)
|
||||
}(i, tt.puts)
|
||||
if err := ctlV3Watch(cx, tt.args, tt.wkv...); err != nil {
|
||||
if cx.dialTimeout > 0 && !isGRPCTimedout(err) {
|
||||
cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
<-donec
|
||||
}
|
||||
}
|
||||
|
||||
func ctlV3Watch(cx ctlCtx, args []string, kvs ...kv) error {
|
||||
cmdArgs := append(cx.PrefixArgs(), "watch")
|
||||
if cx.interactive {
|
||||
cmdArgs = append(cmdArgs, "--interactive")
|
||||
} else {
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
}
|
||||
|
||||
proc, err := spawnCmd(cmdArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cx.interactive {
|
||||
wl := strings.Join(append([]string{"watch"}, args...), " ") + "\r"
|
||||
if err = proc.Send(wl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, elem := range kvs {
|
||||
if _, err = proc.Expect(elem.key); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = proc.Expect(elem.val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return proc.Stop()
|
||||
}
|
||||
24
vendor/github.com/coreos/etcd/e2e/doc.go
generated
vendored
Normal file
24
vendor/github.com/coreos/etcd/e2e/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// 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 implements tests built upon etcd binaries, and focus on
|
||||
end-to-end testing.
|
||||
|
||||
Features/goals of the end-to-end tests:
|
||||
1. test command-line parsing and arguments.
|
||||
2. test user-facing command-line API.
|
||||
3. launch full processes and check for expected outputs.
|
||||
*/
|
||||
package e2e
|
||||
34
vendor/github.com/coreos/etcd/e2e/etcd_config_test.go
generated
vendored
Normal file
34
vendor/github.com/coreos/etcd/e2e/etcd_config_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// 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 (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const exampleConfigFile = "../etcd.conf.yml.sample"
|
||||
|
||||
func TestEtcdExampleConfig(t *testing.T) {
|
||||
proc, err := spawnCmd([]string{binDir + "/etcd", "--config-file", exampleConfigFile})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = waitReadyExpectProc(proc, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = proc.Stop(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
170
vendor/github.com/coreos/etcd/e2e/etcd_release_upgrade_test.go
generated
vendored
Normal file
170
vendor/github.com/coreos/etcd/e2e/etcd_release_upgrade_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/pkg/fileutil"
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
// TestReleaseUpgrade ensures that changes to master branch does not affect
|
||||
// upgrade from latest etcd releases.
|
||||
func TestReleaseUpgrade(t *testing.T) {
|
||||
lastReleaseBinary := binDir + "/etcd-last-release"
|
||||
if !fileutil.Exist(lastReleaseBinary) {
|
||||
t.Skipf("%q does not exist", lastReleaseBinary)
|
||||
}
|
||||
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
copiedCfg := configNoTLS
|
||||
copiedCfg.execPath = lastReleaseBinary
|
||||
copiedCfg.snapCount = 3
|
||||
copiedCfg.baseScheme = "unix" // to avoid port conflict
|
||||
|
||||
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)
|
||||
}
|
||||
}()
|
||||
// 3.0 boots as 2.3 then negotiates up to 3.0
|
||||
// so there's a window at boot time where it doesn't have V3rpcCapability enabled
|
||||
// poll /version until etcdcluster is >2.3.x before making v3 requests
|
||||
for i := 0; i < 7; i++ {
|
||||
if err = cURLGet(epc, cURLReq{endpoint: "/version", expected: `"etcdcluster":"3.0`}); err != nil {
|
||||
t.Logf("#%d: v3 is not ready yet (%v)", i, err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("cannot pull version (%v)", err)
|
||||
}
|
||||
|
||||
os.Setenv("ETCDCTL_API", "3")
|
||||
defer os.Unsetenv("ETCDCTL_API")
|
||||
cx := ctlCtx{
|
||||
t: t,
|
||||
cfg: configNoTLS,
|
||||
dialTimeout: 7 * time.Second,
|
||||
quorum: true,
|
||||
epc: epc,
|
||||
}
|
||||
var kvs []kv
|
||||
for i := 0; i < 5; i++ {
|
||||
kvs = append(kvs, kv{key: fmt.Sprintf("foo%d", i), val: "bar"})
|
||||
}
|
||||
for i := range kvs {
|
||||
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
|
||||
cx.t.Fatalf("#%d: ctlV3Put error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range epc.procs {
|
||||
if err := epc.procs[i].Stop(); err != nil {
|
||||
t.Fatalf("#%d: error closing etcd process (%v)", i, err)
|
||||
}
|
||||
epc.procs[i].cfg.execPath = binDir + "/etcd"
|
||||
epc.procs[i].cfg.keepDataDir = true
|
||||
|
||||
if err := epc.procs[i].Restart(); err != nil {
|
||||
t.Fatalf("error restarting etcd process (%v)", err)
|
||||
}
|
||||
|
||||
for j := range kvs {
|
||||
if err := ctlV3Get(cx, []string{kvs[j].key}, []kv{kvs[j]}...); err != nil {
|
||||
cx.t.Fatalf("#%d-%d: ctlV3Get error (%v)", i, j, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseUpgradeWithRestart(t *testing.T) {
|
||||
lastReleaseBinary := binDir + "/etcd-last-release"
|
||||
if !fileutil.Exist(lastReleaseBinary) {
|
||||
t.Skipf("%q does not exist", lastReleaseBinary)
|
||||
}
|
||||
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
copiedCfg := configNoTLS
|
||||
copiedCfg.execPath = lastReleaseBinary
|
||||
copiedCfg.snapCount = 10
|
||||
copiedCfg.baseScheme = "unix"
|
||||
|
||||
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,
|
||||
}
|
||||
var kvs []kv
|
||||
for i := 0; i < 50; i++ {
|
||||
kvs = append(kvs, kv{key: fmt.Sprintf("foo%d", i), val: "bar"})
|
||||
}
|
||||
for i := range kvs {
|
||||
if err := ctlV3Put(cx, kvs[i].key, kvs[i].val, ""); err != nil {
|
||||
cx.t.Fatalf("#%d: ctlV3Put error (%v)", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range epc.procs {
|
||||
if err := epc.procs[i].Stop(); err != nil {
|
||||
t.Fatalf("#%d: error closing etcd process (%v)", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(epc.procs))
|
||||
for i := range epc.procs {
|
||||
go func(i int) {
|
||||
epc.procs[i].cfg.execPath = binDir + "/etcd"
|
||||
epc.procs[i].cfg.keepDataDir = true
|
||||
if err := epc.procs[i].Restart(); err != nil {
|
||||
t.Fatalf("error restarting etcd process (%v)", err)
|
||||
}
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if err := ctlV3Get(cx, []string{kvs[0].key}, []kv{kvs[0]}...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
555
vendor/github.com/coreos/etcd/e2e/etcd_test.go
generated
vendored
Normal file
555
vendor/github.com/coreos/etcd/e2e/etcd_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/etcd/etcdserver"
|
||||
"github.com/coreos/etcd/pkg/expect"
|
||||
"github.com/coreos/etcd/pkg/fileutil"
|
||||
)
|
||||
|
||||
const etcdProcessBasePort = 20000
|
||||
|
||||
var (
|
||||
binPath string
|
||||
ctlBinPath string
|
||||
certPath string
|
||||
privateKeyPath string
|
||||
caPath string
|
||||
)
|
||||
|
||||
type clientConnType int
|
||||
|
||||
const (
|
||||
clientNonTLS clientConnType = iota
|
||||
clientTLS
|
||||
clientTLSAndNonTLS
|
||||
)
|
||||
|
||||
var (
|
||||
configNoTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
proxySize: 0,
|
||||
initialToken: "new",
|
||||
}
|
||||
configAutoTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
isPeerTLS: true,
|
||||
isPeerAutoTLS: true,
|
||||
initialToken: "new",
|
||||
}
|
||||
configTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
proxySize: 0,
|
||||
clientTLS: clientTLS,
|
||||
isPeerTLS: true,
|
||||
initialToken: "new",
|
||||
}
|
||||
configClientTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
proxySize: 0,
|
||||
clientTLS: clientTLS,
|
||||
initialToken: "new",
|
||||
}
|
||||
configClientBoth = etcdProcessClusterConfig{
|
||||
clusterSize: 1,
|
||||
proxySize: 0,
|
||||
clientTLS: clientTLSAndNonTLS,
|
||||
initialToken: "new",
|
||||
}
|
||||
configClientAutoTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 1,
|
||||
proxySize: 0,
|
||||
isClientAutoTLS: true,
|
||||
clientTLS: clientTLS,
|
||||
initialToken: "new",
|
||||
}
|
||||
configPeerTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
proxySize: 0,
|
||||
isPeerTLS: true,
|
||||
initialToken: "new",
|
||||
}
|
||||
configWithProxy = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
proxySize: 1,
|
||||
initialToken: "new",
|
||||
}
|
||||
configWithProxyTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
proxySize: 1,
|
||||
clientTLS: clientTLS,
|
||||
isPeerTLS: true,
|
||||
initialToken: "new",
|
||||
}
|
||||
configWithProxyPeerTLS = etcdProcessClusterConfig{
|
||||
clusterSize: 3,
|
||||
proxySize: 1,
|
||||
isPeerTLS: true,
|
||||
initialToken: "new",
|
||||
}
|
||||
)
|
||||
|
||||
func configStandalone(cfg etcdProcessClusterConfig) *etcdProcessClusterConfig {
|
||||
ret := cfg
|
||||
ret.clusterSize = 1
|
||||
return &ret
|
||||
}
|
||||
|
||||
type etcdProcessCluster struct {
|
||||
cfg *etcdProcessClusterConfig
|
||||
procs []*etcdProcess
|
||||
}
|
||||
|
||||
type etcdProcess struct {
|
||||
cfg *etcdProcessConfig
|
||||
proc *expect.ExpectProcess
|
||||
donec chan struct{} // closed when Interact() terminates
|
||||
}
|
||||
|
||||
type etcdProcessConfig struct {
|
||||
execPath string
|
||||
args []string
|
||||
|
||||
dataDirPath string
|
||||
keepDataDir bool
|
||||
|
||||
name string
|
||||
|
||||
purl url.URL
|
||||
|
||||
acurl string
|
||||
// additional url for tls connection when the etcd process
|
||||
// serves both http and https
|
||||
acurltls string
|
||||
acurlHost string
|
||||
|
||||
initialToken string
|
||||
initialCluster string
|
||||
|
||||
isProxy bool
|
||||
}
|
||||
|
||||
type etcdProcessClusterConfig struct {
|
||||
execPath string
|
||||
dataDirPath string
|
||||
keepDataDir bool
|
||||
|
||||
clusterSize int
|
||||
|
||||
baseScheme string
|
||||
basePort int
|
||||
|
||||
proxySize int
|
||||
|
||||
snapCount int // default is 10000
|
||||
|
||||
clientTLS clientConnType
|
||||
clientCertAuthEnabled bool
|
||||
isPeerTLS bool
|
||||
isPeerAutoTLS bool
|
||||
isClientAutoTLS bool
|
||||
forceNewCluster bool
|
||||
initialToken string
|
||||
quotaBackendBytes int64
|
||||
noStrictReconfig bool
|
||||
}
|
||||
|
||||
// newEtcdProcessCluster launches a new cluster from etcd processes, returning
|
||||
// a new etcdProcessCluster once all nodes are ready to accept client requests.
|
||||
func newEtcdProcessCluster(cfg *etcdProcessClusterConfig) (*etcdProcessCluster, error) {
|
||||
etcdCfgs := cfg.etcdProcessConfigs()
|
||||
epc := &etcdProcessCluster{
|
||||
cfg: cfg,
|
||||
procs: make([]*etcdProcess, cfg.clusterSize+cfg.proxySize),
|
||||
}
|
||||
|
||||
// launch etcd processes
|
||||
for i := range etcdCfgs {
|
||||
proc, err := newEtcdProcess(etcdCfgs[i])
|
||||
if err != nil {
|
||||
epc.Close()
|
||||
return nil, err
|
||||
}
|
||||
epc.procs[i] = proc
|
||||
}
|
||||
|
||||
return epc, epc.Start()
|
||||
}
|
||||
|
||||
func newEtcdProcess(cfg *etcdProcessConfig) (*etcdProcess, error) {
|
||||
if !fileutil.Exist(cfg.execPath) {
|
||||
return nil, fmt.Errorf("could not find etcd binary")
|
||||
}
|
||||
|
||||
if !cfg.keepDataDir {
|
||||
if err := os.RemoveAll(cfg.dataDirPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
child, err := spawnCmd(append([]string{cfg.execPath}, cfg.args...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &etcdProcess{cfg: cfg, proc: child, donec: make(chan struct{})}, nil
|
||||
}
|
||||
|
||||
func (cfg *etcdProcessClusterConfig) etcdProcessConfigs() []*etcdProcessConfig {
|
||||
binPath = binDir + "/etcd"
|
||||
ctlBinPath = binDir + "/etcdctl"
|
||||
certPath = certDir + "/server.crt"
|
||||
privateKeyPath = certDir + "/server.key.insecure"
|
||||
caPath = certDir + "/ca.crt"
|
||||
|
||||
if cfg.basePort == 0 {
|
||||
cfg.basePort = etcdProcessBasePort
|
||||
}
|
||||
|
||||
if cfg.execPath == "" {
|
||||
cfg.execPath = binPath
|
||||
}
|
||||
if cfg.snapCount == 0 {
|
||||
cfg.snapCount = etcdserver.DefaultSnapCount
|
||||
}
|
||||
|
||||
clientScheme := "http"
|
||||
if cfg.clientTLS == clientTLS {
|
||||
clientScheme = "https"
|
||||
}
|
||||
peerScheme := cfg.baseScheme
|
||||
if peerScheme == "" {
|
||||
peerScheme = "http"
|
||||
}
|
||||
if cfg.isPeerTLS {
|
||||
peerScheme += "s"
|
||||
}
|
||||
|
||||
etcdCfgs := make([]*etcdProcessConfig, cfg.clusterSize+cfg.proxySize)
|
||||
initialCluster := make([]string, cfg.clusterSize)
|
||||
for i := 0; i < cfg.clusterSize; i++ {
|
||||
var curls []string
|
||||
var curl, curltls string
|
||||
port := cfg.basePort + 2*i
|
||||
curlHost := fmt.Sprintf("localhost:%d", port)
|
||||
|
||||
switch cfg.clientTLS {
|
||||
case clientNonTLS, clientTLS:
|
||||
curl = (&url.URL{Scheme: clientScheme, Host: curlHost}).String()
|
||||
curls = []string{curl}
|
||||
case clientTLSAndNonTLS:
|
||||
curl = (&url.URL{Scheme: "http", Host: curlHost}).String()
|
||||
curltls = (&url.URL{Scheme: "https", Host: curlHost}).String()
|
||||
curls = []string{curl, curltls}
|
||||
}
|
||||
|
||||
purl := url.URL{Scheme: peerScheme, Host: fmt.Sprintf("localhost:%d", port+1)}
|
||||
name := fmt.Sprintf("testname%d", i)
|
||||
dataDirPath := cfg.dataDirPath
|
||||
if cfg.dataDirPath == "" {
|
||||
var derr error
|
||||
dataDirPath, derr = ioutil.TempDir("", name+".etcd")
|
||||
if derr != nil {
|
||||
panic("could not get tempdir for datadir")
|
||||
}
|
||||
}
|
||||
initialCluster[i] = fmt.Sprintf("%s=%s", name, purl.String())
|
||||
|
||||
args := []string{
|
||||
"--name", name,
|
||||
"--listen-client-urls", strings.Join(curls, ","),
|
||||
"--advertise-client-urls", strings.Join(curls, ","),
|
||||
"--listen-peer-urls", purl.String(),
|
||||
"--initial-advertise-peer-urls", purl.String(),
|
||||
"--initial-cluster-token", cfg.initialToken,
|
||||
"--data-dir", dataDirPath,
|
||||
"--snapshot-count", fmt.Sprintf("%d", cfg.snapCount),
|
||||
}
|
||||
if cfg.forceNewCluster {
|
||||
args = append(args, "--force-new-cluster")
|
||||
}
|
||||
if cfg.quotaBackendBytes > 0 {
|
||||
args = append(args,
|
||||
"--quota-backend-bytes", fmt.Sprintf("%d", cfg.quotaBackendBytes),
|
||||
)
|
||||
}
|
||||
if cfg.noStrictReconfig {
|
||||
args = append(args, "--strict-reconfig-check=false")
|
||||
}
|
||||
|
||||
args = append(args, cfg.tlsArgs()...)
|
||||
etcdCfgs[i] = &etcdProcessConfig{
|
||||
execPath: cfg.execPath,
|
||||
args: args,
|
||||
dataDirPath: dataDirPath,
|
||||
keepDataDir: cfg.keepDataDir,
|
||||
name: name,
|
||||
purl: purl,
|
||||
acurl: curl,
|
||||
acurltls: curltls,
|
||||
acurlHost: curlHost,
|
||||
initialToken: cfg.initialToken,
|
||||
}
|
||||
}
|
||||
for i := 0; i < cfg.proxySize; i++ {
|
||||
port := cfg.basePort + 2*cfg.clusterSize + i + 1
|
||||
curlHost := fmt.Sprintf("localhost:%d", port)
|
||||
curl := url.URL{Scheme: clientScheme, Host: curlHost}
|
||||
name := fmt.Sprintf("testname-proxy%d", i)
|
||||
dataDirPath, derr := ioutil.TempDir("", name+".etcd")
|
||||
if derr != nil {
|
||||
panic("could not get tempdir for datadir")
|
||||
}
|
||||
args := []string{
|
||||
"--name", name,
|
||||
"--proxy", "on",
|
||||
"--listen-client-urls", curl.String(),
|
||||
"--data-dir", dataDirPath,
|
||||
}
|
||||
args = append(args, cfg.tlsArgs()...)
|
||||
etcdCfgs[cfg.clusterSize+i] = &etcdProcessConfig{
|
||||
execPath: cfg.execPath,
|
||||
args: args,
|
||||
dataDirPath: dataDirPath,
|
||||
keepDataDir: cfg.keepDataDir,
|
||||
name: name,
|
||||
acurl: curl.String(),
|
||||
acurlHost: curlHost,
|
||||
isProxy: true,
|
||||
}
|
||||
}
|
||||
|
||||
initialClusterArgs := []string{"--initial-cluster", strings.Join(initialCluster, ",")}
|
||||
for i := range etcdCfgs {
|
||||
etcdCfgs[i].initialCluster = strings.Join(initialCluster, ",")
|
||||
etcdCfgs[i].args = append(etcdCfgs[i].args, initialClusterArgs...)
|
||||
}
|
||||
|
||||
return etcdCfgs
|
||||
}
|
||||
|
||||
func (cfg *etcdProcessClusterConfig) tlsArgs() (args []string) {
|
||||
if cfg.clientTLS != clientNonTLS {
|
||||
if cfg.isClientAutoTLS {
|
||||
args = append(args, "--auto-tls=true")
|
||||
} else {
|
||||
tlsClientArgs := []string{
|
||||
"--cert-file", certPath,
|
||||
"--key-file", privateKeyPath,
|
||||
"--ca-file", caPath,
|
||||
}
|
||||
args = append(args, tlsClientArgs...)
|
||||
|
||||
if cfg.clientCertAuthEnabled {
|
||||
args = append(args, "--client-cert-auth")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.isPeerTLS {
|
||||
if cfg.isPeerAutoTLS {
|
||||
args = append(args, "--peer-auto-tls=true")
|
||||
} else {
|
||||
tlsPeerArgs := []string{
|
||||
"--peer-cert-file", certPath,
|
||||
"--peer-key-file", privateKeyPath,
|
||||
"--peer-ca-file", caPath,
|
||||
}
|
||||
args = append(args, tlsPeerArgs...)
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func (epc *etcdProcessCluster) Start() (err error) {
|
||||
readyC := make(chan error, epc.cfg.clusterSize+epc.cfg.proxySize)
|
||||
for i := range epc.procs {
|
||||
go func(n int) { readyC <- epc.procs[n].waitReady() }(i)
|
||||
}
|
||||
for range epc.procs {
|
||||
if err := <-readyC; err != nil {
|
||||
epc.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (epc *etcdProcessCluster) RestartAll() error {
|
||||
for i := range epc.procs {
|
||||
proc, err := newEtcdProcess(epc.procs[i].cfg)
|
||||
if err != nil {
|
||||
epc.Close()
|
||||
return err
|
||||
}
|
||||
epc.procs[i] = proc
|
||||
}
|
||||
return epc.Start()
|
||||
}
|
||||
|
||||
func (epc *etcdProcessCluster) StopAll() (err error) {
|
||||
for _, p := range epc.procs {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
if curErr := p.Stop(); curErr != nil {
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%v; %v", err, curErr)
|
||||
} else {
|
||||
err = curErr
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (epc *etcdProcessCluster) Close() error {
|
||||
err := epc.StopAll()
|
||||
for _, p := range epc.procs {
|
||||
// p is nil when newEtcdProcess fails in the middle
|
||||
// Close still gets called to clean up test data
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
os.RemoveAll(p.cfg.dataDirPath)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (ep *etcdProcess) Restart() error {
|
||||
newEp, err := newEtcdProcess(ep.cfg)
|
||||
if err != nil {
|
||||
ep.Stop()
|
||||
return err
|
||||
}
|
||||
*ep = *newEp
|
||||
if err = ep.waitReady(); err != nil {
|
||||
ep.Stop()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *etcdProcess) Stop() error {
|
||||
if ep == nil {
|
||||
return nil
|
||||
}
|
||||
if err := ep.proc.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
<-ep.donec
|
||||
|
||||
if ep.cfg.purl.Scheme == "unix" || ep.cfg.purl.Scheme == "unixs" {
|
||||
os.RemoveAll(ep.cfg.purl.Host)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *etcdProcess) waitReady() error {
|
||||
defer close(ep.donec)
|
||||
return waitReadyExpectProc(ep.proc, ep.cfg.isProxy)
|
||||
}
|
||||
|
||||
func waitReadyExpectProc(exproc *expect.ExpectProcess, isProxy bool) error {
|
||||
readyStrs := []string{"enabled capabilities for version", "published"}
|
||||
if isProxy {
|
||||
readyStrs = []string{"httpproxy: endpoints found"}
|
||||
}
|
||||
c := 0
|
||||
matchSet := func(l string) bool {
|
||||
for _, s := range readyStrs {
|
||||
if strings.Contains(l, s) {
|
||||
c++
|
||||
break
|
||||
}
|
||||
}
|
||||
return c == len(readyStrs)
|
||||
}
|
||||
_, err := exproc.ExpectFunc(matchSet)
|
||||
return err
|
||||
}
|
||||
|
||||
func spawnCmd(args []string) (*expect.ExpectProcess, error) {
|
||||
return expect.NewExpect(args[0], args[1:]...)
|
||||
}
|
||||
|
||||
func spawnWithExpect(args []string, expected string) error {
|
||||
return spawnWithExpects(args, []string{expected}...)
|
||||
}
|
||||
|
||||
func spawnWithExpects(args []string, xs ...string) error {
|
||||
proc, err := spawnCmd(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// process until either stdout or stderr contains
|
||||
// the expected string
|
||||
var (
|
||||
lines []string
|
||||
lineFunc = func(txt string) bool { return true }
|
||||
)
|
||||
for _, txt := range xs {
|
||||
for {
|
||||
l, err := proc.ExpectFunc(lineFunc)
|
||||
if err != nil {
|
||||
proc.Close()
|
||||
return fmt.Errorf("%v (expected %q, got %q)", err, txt, lines)
|
||||
}
|
||||
lines = append(lines, l)
|
||||
if strings.Contains(l, txt) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
perr := proc.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(xs) == 0 && proc.LineCount() != 0 { // expect no output
|
||||
return fmt.Errorf("unexpected output (got lines %q, line count %d)", lines, proc.LineCount())
|
||||
}
|
||||
return perr
|
||||
}
|
||||
|
||||
// proxies returns only the proxy etcdProcess.
|
||||
func (epc *etcdProcessCluster) proxies() []*etcdProcess {
|
||||
return epc.procs[epc.cfg.clusterSize:]
|
||||
}
|
||||
|
||||
func (epc *etcdProcessCluster) processes() []*etcdProcess {
|
||||
return epc.procs[:epc.cfg.clusterSize]
|
||||
}
|
||||
|
||||
func (epc *etcdProcessCluster) endpoints() []string {
|
||||
eps := make([]string, epc.cfg.clusterSize)
|
||||
for i, ep := range epc.processes() {
|
||||
eps[i] = ep.cfg.acurl
|
||||
}
|
||||
return eps
|
||||
}
|
||||
|
||||
func (epc *etcdProcessCluster) grpcEndpoints() []string {
|
||||
eps := make([]string, epc.cfg.clusterSize)
|
||||
for i, ep := range epc.processes() {
|
||||
eps[i] = ep.cfg.acurlHost
|
||||
}
|
||||
return eps
|
||||
}
|
||||
60
vendor/github.com/coreos/etcd/e2e/gateway_test.go
generated
vendored
Normal file
60
vendor/github.com/coreos/etcd/e2e/gateway_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// 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"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/expect"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultGatewayEndpoint = "127.0.0.1:23790"
|
||||
)
|
||||
|
||||
func TestGateway(t *testing.T) {
|
||||
ec, err := newEtcdProcessCluster(&configNoTLS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer ec.StopAll()
|
||||
|
||||
eps := strings.Join(ec.grpcEndpoints(), ",")
|
||||
|
||||
p := startGateway(t, eps)
|
||||
defer p.Stop()
|
||||
|
||||
os.Setenv("ETCDCTL_API", "3")
|
||||
defer os.Unsetenv("ETCDCTL_API")
|
||||
|
||||
err = spawnWithExpect([]string{ctlBinPath, "--endpoints=" + defaultGatewayEndpoint, "put", "foo", "bar"}, "OK\r\n")
|
||||
if err != nil {
|
||||
t.Errorf("failed to finish put request through gateway: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func startGateway(t *testing.T, endpoints string) *expect.ExpectProcess {
|
||||
p, err := expect.NewExpect(binPath, "gateway", "--endpoints="+endpoints, "start")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = p.Expect("tcpproxy: ready to proxy client requests to")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
32
vendor/github.com/coreos/etcd/e2e/main_test.go
generated
vendored
Normal file
32
vendor/github.com/coreos/etcd/e2e/main_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
var binDir string
|
||||
var certDir string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Setenv("ETCD_UNSUPPORTED_ARCH", runtime.GOARCH)
|
||||
os.Unsetenv("ETCDCTL_API")
|
||||
|
||||
flag.StringVar(&binDir, "bin-dir", "../bin", "The directory for store etcd and etcdctl binaries.")
|
||||
flag.StringVar(&certDir, "cert-dir", "../integration/fixtures", "The directory for store certificate files.")
|
||||
flag.Parse()
|
||||
|
||||
v := m.Run()
|
||||
if v == 0 && testutil.CheckLeakedGoroutine() {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(v)
|
||||
}
|
||||
180
vendor/github.com/coreos/etcd/e2e/v2_curl_test.go
generated
vendored
Normal file
180
vendor/github.com/coreos/etcd/e2e/v2_curl_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
// 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 (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestV2CurlNoTLS(t *testing.T) { testCurlPutGet(t, &configNoTLS) }
|
||||
func TestV2CurlAutoTLS(t *testing.T) { testCurlPutGet(t, &configAutoTLS) }
|
||||
func TestV2CurlAllTLS(t *testing.T) { testCurlPutGet(t, &configTLS) }
|
||||
func TestV2CurlPeerTLS(t *testing.T) { testCurlPutGet(t, &configPeerTLS) }
|
||||
func TestV2CurlClientTLS(t *testing.T) { testCurlPutGet(t, &configClientTLS) }
|
||||
func TestV2CurlProxyNoTLS(t *testing.T) { testCurlPutGet(t, &configWithProxy) }
|
||||
func TestV2CurlProxyTLS(t *testing.T) { testCurlPutGet(t, &configWithProxyTLS) }
|
||||
func TestV2CurlProxyPeerTLS(t *testing.T) { testCurlPutGet(t, &configWithProxyPeerTLS) }
|
||||
func TestV2CurlClientBoth(t *testing.T) { testCurlPutGet(t, &configClientBoth) }
|
||||
func testCurlPutGet(t *testing.T, cfg *etcdProcessClusterConfig) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
// test doesn't use quorum gets, so ensure there are no followers to avoid
|
||||
// stale reads that will break the test
|
||||
cfg = configStandalone(*cfg)
|
||||
|
||||
epc, err := newEtcdProcessCluster(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("could not start etcd process cluster (%v)", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var (
|
||||
expectPut = `{"action":"set","node":{"key":"/foo","value":"bar","`
|
||||
expectGet = `{"action":"get","node":{"key":"/foo","value":"bar","`
|
||||
)
|
||||
if err := cURLPut(epc, cURLReq{endpoint: "/v2/keys/foo", value: "bar", expected: expectPut}); err != nil {
|
||||
t.Fatalf("failed put with curl (%v)", err)
|
||||
}
|
||||
if err := cURLGet(epc, cURLReq{endpoint: "/v2/keys/foo", expected: expectGet}); err != nil {
|
||||
t.Fatalf("failed get with curl (%v)", err)
|
||||
}
|
||||
if cfg.clientTLS == clientTLSAndNonTLS {
|
||||
if err := cURLGet(epc, cURLReq{endpoint: "/v2/keys/foo", expected: expectGet, isTLS: true}); err != nil {
|
||||
t.Fatalf("failed get with curl (%v)", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestV2CurlIssue5182(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc := setupEtcdctlTest(t, &configNoTLS, false)
|
||||
defer func() {
|
||||
if err := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", err)
|
||||
}
|
||||
}()
|
||||
|
||||
expectPut := `{"action":"set","node":{"key":"/foo","value":"bar","`
|
||||
if err := cURLPut(epc, cURLReq{endpoint: "/v2/keys/foo", value: "bar", expected: expectPut}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectUserAdd := `{"user":"foo","roles":null}`
|
||||
if err := cURLPut(epc, cURLReq{endpoint: "/v2/auth/users/foo", value: `{"user":"foo", "password":"pass"}`, expected: expectUserAdd}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectRoleAdd := `{"role":"foo","permissions":{"kv":{"read":["/foo/*"],"write":null}}`
|
||||
if err := cURLPut(epc, cURLReq{endpoint: "/v2/auth/roles/foo", value: `{"role":"foo", "permissions": {"kv": {"read": ["/foo/*"]}}}`, expected: expectRoleAdd}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectUserUpdate := `{"user":"foo","roles":["foo"]}`
|
||||
if err := cURLPut(epc, cURLReq{endpoint: "/v2/auth/users/foo", value: `{"user": "foo", "grant": ["foo"]}`, expected: expectUserUpdate}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := etcdctlUserAdd(epc, "root", "a"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := etcdctlAuthEnable(epc); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cURLGet(epc, cURLReq{endpoint: "/v2/keys/foo/", username: "root", password: "a", expected: "bar"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cURLGet(epc, cURLReq{endpoint: "/v2/keys/foo/", username: "foo", password: "pass", expected: "bar"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := cURLGet(epc, cURLReq{endpoint: "/v2/keys/foo/", username: "foo", password: "", expected: "bar"}); err != nil {
|
||||
if !strings.Contains(err.Error(), `The request requires user authentication`) {
|
||||
t.Fatalf("expected 'The request requires user authentication' error, got %v", err)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("expected 'The request requires user authentication' error")
|
||||
}
|
||||
}
|
||||
|
||||
type cURLReq struct {
|
||||
username string
|
||||
password string
|
||||
|
||||
isTLS bool
|
||||
timeout int
|
||||
|
||||
endpoint string
|
||||
|
||||
value string
|
||||
expected string
|
||||
}
|
||||
|
||||
// cURLPrefixArgs builds the beginning of a curl command for a given key
|
||||
// addressed to a random URL in the given cluster.
|
||||
func cURLPrefixArgs(clus *etcdProcessCluster, method string, req cURLReq) []string {
|
||||
var (
|
||||
cmdArgs = []string{"curl"}
|
||||
acurl = clus.procs[rand.Intn(clus.cfg.clusterSize)].cfg.acurl
|
||||
)
|
||||
if req.isTLS {
|
||||
if clus.cfg.clientTLS != clientTLSAndNonTLS {
|
||||
panic("should not use cURLPrefixArgsUseTLS when serving only TLS or non-TLS")
|
||||
}
|
||||
cmdArgs = append(cmdArgs, "--cacert", caPath, "--cert", certPath, "--key", privateKeyPath)
|
||||
acurl = clus.procs[rand.Intn(clus.cfg.clusterSize)].cfg.acurltls
|
||||
} else if clus.cfg.clientTLS == clientTLS {
|
||||
cmdArgs = append(cmdArgs, "--cacert", caPath, "--cert", certPath, "--key", privateKeyPath)
|
||||
}
|
||||
ep := acurl + req.endpoint
|
||||
|
||||
if req.username != "" || req.password != "" {
|
||||
cmdArgs = append(cmdArgs, "-L", "-u", fmt.Sprintf("%s:%s", req.username, req.password), ep)
|
||||
} else {
|
||||
cmdArgs = append(cmdArgs, "-L", ep)
|
||||
}
|
||||
if req.timeout != 0 {
|
||||
cmdArgs = append(cmdArgs, "-m", fmt.Sprintf("%d", req.timeout))
|
||||
}
|
||||
|
||||
switch method {
|
||||
case "POST", "PUT":
|
||||
dt := req.value
|
||||
if !strings.HasPrefix(dt, "{") { // for non-JSON value
|
||||
dt = "value=" + dt
|
||||
}
|
||||
cmdArgs = append(cmdArgs, "-X", method, "-d", dt)
|
||||
}
|
||||
return cmdArgs
|
||||
}
|
||||
|
||||
func cURLPost(clus *etcdProcessCluster, req cURLReq) error {
|
||||
return spawnWithExpect(cURLPrefixArgs(clus, "POST", req), req.expected)
|
||||
}
|
||||
|
||||
func cURLPut(clus *etcdProcessCluster, req cURLReq) error {
|
||||
return spawnWithExpect(cURLPrefixArgs(clus, "PUT", req), req.expected)
|
||||
}
|
||||
|
||||
func cURLGet(clus *etcdProcessCluster, req cURLReq) error {
|
||||
return spawnWithExpect(cURLPrefixArgs(clus, "GET", req), req.expected)
|
||||
}
|
||||
113
vendor/github.com/coreos/etcd/e2e/v3_curl_test.go
generated
vendored
Normal file
113
vendor/github.com/coreos/etcd/e2e/v3_curl_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// 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 (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||
"github.com/coreos/etcd/pkg/testutil"
|
||||
)
|
||||
|
||||
func TestV3CurlPutGetNoTLS(t *testing.T) { testCurlPutGetGRPCGateway(t, &configNoTLS) }
|
||||
func TestV3CurlPutGetAutoTLS(t *testing.T) { testCurlPutGetGRPCGateway(t, &configAutoTLS) }
|
||||
func TestV3CurlPutGetAllTLS(t *testing.T) { testCurlPutGetGRPCGateway(t, &configTLS) }
|
||||
func TestV3CurlPutGetPeerTLS(t *testing.T) { testCurlPutGetGRPCGateway(t, &configPeerTLS) }
|
||||
func TestV3CurlPutGetClientTLS(t *testing.T) { testCurlPutGetGRPCGateway(t, &configClientTLS) }
|
||||
func testCurlPutGetGRPCGateway(t *testing.T, cfg *etcdProcessClusterConfig) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc, err := newEtcdProcessCluster(cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("could not start etcd process cluster (%v)", err)
|
||||
}
|
||||
defer func() {
|
||||
if cerr := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
var (
|
||||
key = []byte("foo")
|
||||
value = []byte("bar") // this will be automatically base64-encoded by Go
|
||||
|
||||
expectPut = `"revision":"`
|
||||
expectGet = `"value":"`
|
||||
)
|
||||
putData, err := json.Marshal(&pb.PutRequest{
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rangeData, err := json.Marshal(&pb.RangeRequest{
|
||||
Key: key,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := cURLPost(epc, cURLReq{endpoint: "/v3alpha/kv/put", value: string(putData), expected: expectPut}); err != nil {
|
||||
t.Fatalf("failed put with curl (%v)", err)
|
||||
}
|
||||
if err := cURLPost(epc, cURLReq{endpoint: "/v3alpha/kv/range", value: string(rangeData), expected: expectGet}); err != nil {
|
||||
t.Fatalf("failed get with curl (%v)", err)
|
||||
}
|
||||
|
||||
if cfg.clientTLS == clientTLSAndNonTLS {
|
||||
if err := cURLPost(epc, cURLReq{endpoint: "/v3alpha/kv/range", value: string(rangeData), expected: expectGet, isTLS: true}); err != nil {
|
||||
t.Fatalf("failed get with curl (%v)", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestV3CurlWatch(t *testing.T) {
|
||||
defer testutil.AfterTest(t)
|
||||
|
||||
epc, err := newEtcdProcessCluster(&configNoTLS)
|
||||
if err != nil {
|
||||
t.Fatalf("could not start etcd process cluster (%v)", err)
|
||||
}
|
||||
defer func() {
|
||||
if cerr := epc.Close(); err != nil {
|
||||
t.Fatalf("error closing etcd processes (%v)", cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
// store "bar" into "foo"
|
||||
putreq, err := json.Marshal(&pb.PutRequest{Key: []byte("foo"), Value: []byte("bar")})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = cURLPost(epc, cURLReq{endpoint: "/v3alpha/kv/put", value: string(putreq), expected: "revision"}); err != nil {
|
||||
t.Fatalf("failed put with curl (%v)", err)
|
||||
}
|
||||
// watch for first update to "foo"
|
||||
wcr := &pb.WatchCreateRequest{Key: []byte("foo"), StartRevision: 1}
|
||||
wreq, err := json.Marshal(wcr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// marshaling the grpc to json gives:
|
||||
// "{"RequestUnion":{"CreateRequest":{"key":"Zm9v","start_revision":1}}}"
|
||||
// but the gprc-gateway expects a different format..
|
||||
wstr := `{"create_request" : ` + string(wreq) + "}"
|
||||
// expects "bar", timeout after 2 seconds since stream waits forever
|
||||
if err = cURLPost(epc, cURLReq{endpoint: "/v3alpha/watch", value: wstr, expected: `"YmFy"`, timeout: 2}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue