Merge pull request #14331 from chaochn47/auth_test_framework_update

common tests framework: cluster client creation could fail with invalid auth
This commit is contained in:
Benjamin Wang 2022-09-30 15:38:47 +08:00 committed by GitHub
commit 7fff4c4241
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 299 additions and 100 deletions

View File

@ -121,6 +121,10 @@ type AuthConfig struct {
Password string `json:"password"` Password string `json:"password"`
} }
func (cfg AuthConfig) Empty() bool {
return cfg.Username == "" && cfg.Password == ""
}
// NewClientConfig creates a Config based on the provided ConfigSpec. // NewClientConfig creates a Config based on the provided ConfigSpec.
func NewClientConfig(confSpec *ConfigSpec, lg *zap.Logger) (*Config, error) { func NewClientConfig(confSpec *ConfigSpec, lg *zap.Logger) (*Config, error) {
tlsCfg, err := newTLSConfig(confSpec.Secure, lg) tlsCfg, err := newTLSConfig(confSpec.Secure, lg)

View File

@ -22,6 +22,7 @@ import (
"time" "time"
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -32,17 +33,18 @@ func TestAlarm(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1, QuotaBackendBytes: int64(13 * os.Getpagesize())}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1, QuotaBackendBytes: int64(13 * os.Getpagesize())})
defer clus.Close() defer clus.Close()
cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
// test small put still works // test small put still works
smallbuf := strings.Repeat("a", 64) smallbuf := strings.Repeat("a", 64)
if err := clus.Client().Put(ctx, "1st_test", smallbuf, config.PutOptions{}); err != nil { if err := cc.Put(ctx, "1st_test", smallbuf, config.PutOptions{}); err != nil {
t.Fatalf("alarmTest: put kv error (%v)", err) t.Fatalf("alarmTest: put kv error (%v)", err)
} }
// write some chunks to fill up the database // write some chunks to fill up the database
buf := strings.Repeat("b", os.Getpagesize()) buf := strings.Repeat("b", os.Getpagesize())
for { for {
if err := clus.Client().Put(ctx, "2nd_test", buf, config.PutOptions{}); err != nil { if err := cc.Put(ctx, "2nd_test", buf, config.PutOptions{}); err != nil {
if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") { if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
t.Fatal(err) t.Fatal(err)
} }
@ -51,20 +53,20 @@ func TestAlarm(t *testing.T) {
} }
// quota alarm should now be on // quota alarm should now be on
alarmResp, err := clus.Client().AlarmList(ctx) alarmResp, err := cc.AlarmList(ctx)
if err != nil { if err != nil {
t.Fatalf("alarmTest: Alarm error (%v)", err) t.Fatalf("alarmTest: Alarm error (%v)", err)
} }
// check that Put is rejected when alarm is on // check that Put is rejected when alarm is on
if err := clus.Client().Put(ctx, "3rd_test", smallbuf, config.PutOptions{}); err != nil { if err := cc.Put(ctx, "3rd_test", smallbuf, config.PutOptions{}); err != nil {
if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") { if !strings.Contains(err.Error(), "etcdserver: mvcc: database space exceeded") {
t.Fatal(err) t.Fatal(err)
} }
} }
// get latest revision to compact // get latest revision to compact
sresp, err := clus.Client().Status(ctx) sresp, err := cc.Status(ctx)
if err != nil { if err != nil {
t.Fatalf("get endpoint status error: %v", err) t.Fatalf("get endpoint status error: %v", err)
} }
@ -77,12 +79,12 @@ func TestAlarm(t *testing.T) {
} }
// make some space // make some space
_, err = clus.Client().Compact(ctx, rvs, config.CompactOption{Physical: true, Timeout: 10 * time.Second}) _, err = cc.Compact(ctx, rvs, config.CompactOption{Physical: true, Timeout: 10 * time.Second})
if err != nil { if err != nil {
t.Fatalf("alarmTest: Compact error (%v)", err) t.Fatalf("alarmTest: Compact error (%v)", err)
} }
if err = clus.Client().Defragment(ctx, config.DefragOption{Timeout: 10 * time.Second}); err != nil { if err = cc.Defragment(ctx, config.DefragOption{Timeout: 10 * time.Second}); err != nil {
t.Fatalf("alarmTest: defrag error (%v)", err) t.Fatalf("alarmTest: defrag error (%v)", err)
} }
@ -92,14 +94,14 @@ func TestAlarm(t *testing.T) {
MemberID: alarm.MemberID, MemberID: alarm.MemberID,
Alarm: alarm.Alarm, Alarm: alarm.Alarm,
} }
_, err = clus.Client().AlarmDisarm(ctx, alarmMember) _, err = cc.AlarmDisarm(ctx, alarmMember)
if err != nil { if err != nil {
t.Fatalf("alarmTest: Alarm error (%v)", err) t.Fatalf("alarmTest: Alarm error (%v)", err)
} }
} }
// put one more key below quota // put one more key below quota
if err := clus.Client().Put(ctx, "4th_test", smallbuf, config.PutOptions{}); err != nil { if err := cc.Put(ctx, "4th_test", smallbuf, config.PutOptions{}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
}) })
@ -115,10 +117,11 @@ func TestAlarmlistOnMemberRestart(t *testing.T) {
SnapshotCount: 5, SnapshotCount: 5,
}) })
defer clus.Close() defer clus.Close()
cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
for i := 0; i < 6; i++ { for i := 0; i < 6; i++ {
if _, err := clus.Client().AlarmList(ctx); err != nil { if _, err := cc.AlarmList(ctx); err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
} }

View File

@ -21,6 +21,8 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -47,14 +49,15 @@ func TestCompact(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3})
defer clus.Close() defer clus.Close()
cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
var kvs = []testutils.KV{{Key: "key", Val: "val1"}, {Key: "key", Val: "val2"}, {Key: "key", Val: "val3"}} var kvs = []testutils.KV{{Key: "key", Val: "val1"}, {Key: "key", Val: "val2"}, {Key: "key", Val: "val3"}}
for i := range kvs { for i := range kvs {
if err := clus.Client().Put(ctx, kvs[i].Key, kvs[i].Val, config.PutOptions{}); err != nil { if err := cc.Put(ctx, kvs[i].Key, kvs[i].Val, config.PutOptions{}); err != nil {
t.Fatalf("compactTest #%d: put kv error (%v)", i, err) t.Fatalf("compactTest #%d: put kv error (%v)", i, err)
} }
} }
get, err := clus.Client().Get(ctx, "key", config.GetOptions{Revision: 3}) get, err := cc.Get(ctx, "key", config.GetOptions{Revision: 3})
if err != nil { if err != nil {
t.Fatalf("compactTest: Get kv by revision error (%v)", err) t.Fatalf("compactTest: Get kv by revision error (%v)", err)
} }
@ -62,12 +65,12 @@ func TestCompact(t *testing.T) {
getkvs := testutils.KeyValuesFromGetResponse(get) getkvs := testutils.KeyValuesFromGetResponse(get)
assert.Equal(t, kvs[1:2], getkvs) assert.Equal(t, kvs[1:2], getkvs)
_, err = clus.Client().Compact(ctx, 4, tc.options) _, err = cc.Compact(ctx, 4, tc.options)
if err != nil { if err != nil {
t.Fatalf("compactTest: Compact error (%v)", err) t.Fatalf("compactTest: Compact error (%v)", err)
} }
get, err = clus.Client().Get(ctx, "key", config.GetOptions{Revision: 3}) get, err = cc.Get(ctx, "key", config.GetOptions{Revision: 3})
if err != nil { if err != nil {
if !strings.Contains(err.Error(), "required revision has been compacted") { if !strings.Contains(err.Error(), "required revision has been compacted") {
t.Fatalf("compactTest: Get compact key error (%v)", err) t.Fatalf("compactTest: Get compact key error (%v)", err)
@ -76,7 +79,7 @@ func TestCompact(t *testing.T) {
t.Fatalf("expected '...has been compacted' error, got <nil>") t.Fatalf("expected '...has been compacted' error, got <nil>")
} }
_, err = clus.Client().Compact(ctx, 2, tc.options) _, err = cc.Compact(ctx, 2, tc.options)
if err != nil { if err != nil {
if !strings.Contains(err.Error(), "required revision has been compacted") { if !strings.Contains(err.Error(), "required revision has been compacted") {
t.Fatal(err) t.Fatal(err)

View File

@ -19,6 +19,8 @@ import (
"testing" "testing"
"time" "time"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -29,20 +31,21 @@ func TestDefragOnline(t *testing.T) {
defer cancel() defer cancel()
options := config.DefragOption{Timeout: 10 * time.Second} options := config.DefragOption{Timeout: 10 * time.Second}
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3})
cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
defer clus.Close() defer clus.Close()
var kvs = []testutils.KV{{Key: "key", Val: "val1"}, {Key: "key", Val: "val2"}, {Key: "key", Val: "val3"}} var kvs = []testutils.KV{{Key: "key", Val: "val1"}, {Key: "key", Val: "val2"}, {Key: "key", Val: "val3"}}
for i := range kvs { for i := range kvs {
if err := clus.Client().Put(ctx, kvs[i].Key, kvs[i].Val, config.PutOptions{}); err != nil { if err := cc.Put(ctx, kvs[i].Key, kvs[i].Val, config.PutOptions{}); err != nil {
t.Fatalf("compactTest #%d: put kv error (%v)", i, err) t.Fatalf("compactTest #%d: put kv error (%v)", i, err)
} }
} }
_, err := clus.Client().Compact(ctx, 4, config.CompactOption{Physical: true, Timeout: 10 * time.Second}) _, err := cc.Compact(ctx, 4, config.CompactOption{Physical: true, Timeout: 10 * time.Second})
if err != nil { if err != nil {
t.Fatalf("defrag_test: compact with revision error (%v)", err) t.Fatalf("defrag_test: compact with revision error (%v)", err)
} }
if err = clus.Client().Defragment(ctx, options); err != nil { if err = cc.Defragment(ctx, options); err != nil {
t.Fatalf("defrag_test: defrag error (%v)", err) t.Fatalf("defrag_test: defrag error (%v)", err)
} }
}) })

View File

@ -19,6 +19,8 @@ import (
"testing" "testing"
"time" "time"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -29,8 +31,9 @@ func TestEndpointStatus(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3})
defer clus.Close() defer clus.Close()
cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
_, err := clus.Client().Status(ctx) _, err := cc.Status(ctx)
if err != nil { if err != nil {
t.Fatalf("get endpoint status error: %v", err) t.Fatalf("get endpoint status error: %v", err)
} }
@ -43,8 +46,9 @@ func TestEndpointHashKV(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3})
defer clus.Close() defer clus.Close()
cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
_, err := clus.Client().HashKV(ctx, 0) _, err := cc.HashKV(ctx, 0)
if err != nil { if err != nil {
t.Fatalf("get endpoint hashkv error: %v", err) t.Fatalf("get endpoint hashkv error: %v", err)
} }
@ -57,8 +61,9 @@ func TestEndpointHealth(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 3})
defer clus.Close() defer clus.Close()
cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
if err := clus.Client().Health(ctx); err != nil { if err := cc.Health(ctx); err != nil {
t.Fatalf("get endpoint health error: %v", err) t.Fatalf("get endpoint health error: %v", err)
} }
}) })

View File

@ -21,6 +21,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -33,7 +34,7 @@ func TestKVPut(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
key, value := "foo", "bar" key, value := "foo", "bar"
@ -67,7 +68,7 @@ func TestKVGet(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
var ( var (
@ -127,7 +128,7 @@ func TestKVDelete(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
kvs := []string{"a", "b", "c", "c/abc", "d"} kvs := []string{"a", "b", "c", "c/abc", "d"}
tests := []struct { tests := []struct {

View File

@ -21,6 +21,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -59,7 +60,7 @@ func TestLeaseGrantTimeToLive(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
ttl := int64(10) ttl := int64(10)
@ -103,7 +104,7 @@ func TestLeaseGrantAndList(t *testing.T) {
t.Logf("Creating cluster...") t.Logf("Creating cluster...")
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
t.Logf("Created cluster and client") t.Logf("Created cluster and client")
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
var createdLeases []clientv3.LeaseID var createdLeases []clientv3.LeaseID
@ -150,7 +151,7 @@ func TestLeaseGrantTimeToLiveExpired(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
leaseResp, err := cc.Grant(ctx, 2) leaseResp, err := cc.Grant(ctx, 2)
@ -187,7 +188,7 @@ func TestLeaseGrantKeepAliveOnce(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
leaseResp, err := cc.Grant(ctx, 2) leaseResp, err := cc.Grant(ctx, 2)
@ -216,7 +217,7 @@ func TestLeaseGrantRevoke(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
leaseResp, err := cc.Grant(ctx, 20) leaseResp, err := cc.Grant(ctx, 20)

View File

@ -35,7 +35,7 @@ func TestMemberList(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
resp, err := cc.MemberList(ctx) resp, err := cc.MemberList(ctx)
@ -109,7 +109,7 @@ func TestMemberAdd(t *testing.T) {
c.DisableStrictReconfigCheck = !quorumTc.strictReconfigCheck c.DisableStrictReconfigCheck = !quorumTc.strictReconfigCheck
clus := testRunner.NewCluster(ctx, t, c) clus := testRunner.NewCluster(ctx, t, c)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
var addResp *clientv3.MemberAddResponse var addResp *clientv3.MemberAddResponse

View File

@ -22,6 +22,7 @@ import (
"go.etcd.io/etcd/api/v3/v3rpc/rpctypes" "go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -34,7 +35,7 @@ func TestRoleAdd_Simple(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
_, err := cc.RoleAdd(ctx, "root") _, err := cc.RoleAdd(ctx, "root")
@ -52,7 +53,7 @@ func TestRoleAdd_Error(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1})
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
_, err := cc.RoleAdd(ctx, "test-role") _, err := cc.RoleAdd(ctx, "test-role")
if err != nil { if err != nil {
@ -75,7 +76,7 @@ func TestRootRole(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1})
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
_, err := cc.RoleAdd(ctx, "root") _, err := cc.RoleAdd(ctx, "root")
if err != nil { if err != nil {
@ -105,7 +106,7 @@ func TestRoleGrantRevokePermission(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1})
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
_, err := cc.RoleAdd(ctx, "role1") _, err := cc.RoleAdd(ctx, "role1")
if err != nil { if err != nil {
@ -140,7 +141,7 @@ func TestRoleDelete(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1}) clus := testRunner.NewCluster(ctx, t, config.ClusterConfig{ClusterSize: 1})
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
_, err := cc.RoleAdd(ctx, "role1") _, err := cc.RoleAdd(ctx, "role1")
if err != nil { if err != nil {

View File

@ -19,6 +19,8 @@ import (
"testing" "testing"
"time" "time"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -32,7 +34,7 @@ func TestStatus(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
rs, err := cc.Status(ctx) rs, err := cc.Status(ctx)

View File

@ -23,6 +23,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
pb "go.etcd.io/etcd/api/v3/etcdserverpb" pb "go.etcd.io/etcd/api/v3/etcdserverpb"
clientv3 "go.etcd.io/etcd/client/v3" clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -60,7 +61,7 @@ func TestTxnSucc(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, cfg.config) clus := testRunner.NewCluster(ctx, t, cfg.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil { if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil {
t.Fatalf("could not create key:%s, value:%s", "key1", "value1") t.Fatalf("could not create key:%s, value:%s", "key1", "value1")
@ -104,7 +105,7 @@ func TestTxnFail(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, cfg.config) clus := testRunner.NewCluster(ctx, t, cfg.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil { if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil {
t.Fatalf("could not create key:%s, value:%s", "key1", "value1") t.Fatalf("could not create key:%s, value:%s", "key1", "value1")

View File

@ -20,6 +20,8 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -68,7 +70,7 @@ func TestUserAdd_Simple(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
resp, err := cc.UserAdd(ctx, nc.username, nc.password, config.UserAddOptions{NoPassword: nc.noPassword}) resp, err := cc.UserAdd(ctx, nc.username, nc.password, config.UserAddOptions{NoPassword: nc.noPassword})
@ -102,7 +104,7 @@ func TestUserAdd_DuplicateUserNotAllowed(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
user := "barb" user := "barb"
@ -131,7 +133,7 @@ func TestUserList(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
// No Users Yet // No Users Yet
@ -172,7 +174,7 @@ func TestUserDelete(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
user := "barb" user := "barb"
@ -224,7 +226,7 @@ func TestUserChangePassword(t *testing.T) {
defer cancel() defer cancel()
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
user := "barb" user := "barb"

View File

@ -6,6 +6,8 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/testutils" "go.etcd.io/etcd/tests/v3/framework/testutils"
) )
@ -20,7 +22,7 @@ func TestWatch(t *testing.T) {
clus := testRunner.NewCluster(ctx, t, tc.config) clus := testRunner.NewCluster(ctx, t, tc.config)
defer clus.Close() defer clus.Close()
cc := clus.Client() cc := framework.MustClient(clus.Client(clientv3.AuthConfig{}))
testutils.ExecuteUntil(ctx, t, func() { testutils.ExecuteUntil(ctx, t, func() {
tests := []struct { tests := []struct {
puts []testutils.KV puts []testutils.KV

View File

@ -32,5 +32,6 @@ type ClusterConfig struct {
ClientTLS TLSConfig ClientTLS TLSConfig
QuotaBackendBytes int64 QuotaBackendBytes int64
DisableStrictReconfigCheck bool DisableStrictReconfigCheck bool
AuthToken string
SnapshotCount int SnapshotCount int
} }

View File

@ -22,8 +22,11 @@ import (
"time" "time"
"go.etcd.io/etcd/client/pkg/v3/testutil" "go.etcd.io/etcd/client/pkg/v3/testutil"
clientv3 "go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/tests/v3/framework/config" "go.etcd.io/etcd/tests/v3/framework/config"
"go.etcd.io/etcd/tests/v3/framework/e2e" "go.etcd.io/etcd/tests/v3/framework/e2e"
"go.etcd.io/etcd/tests/v3/framework/integration"
"google.golang.org/grpc"
) )
type e2eRunner struct{} type e2eRunner struct{}
@ -47,6 +50,7 @@ func (e e2eRunner) NewCluster(ctx context.Context, t testing.TB, cfg config.Clus
ClusterSize: cfg.ClusterSize, ClusterSize: cfg.ClusterSize,
QuotaBackendBytes: cfg.QuotaBackendBytes, QuotaBackendBytes: cfg.QuotaBackendBytes,
DisableStrictReconfigCheck: cfg.DisableStrictReconfigCheck, DisableStrictReconfigCheck: cfg.DisableStrictReconfigCheck,
AuthTokenOpts: cfg.AuthToken,
SnapshotCount: cfg.SnapshotCount, SnapshotCount: cfg.SnapshotCount,
} }
switch cfg.ClientTLS { switch cfg.ClientTLS {
@ -78,15 +82,31 @@ func (e e2eRunner) NewCluster(ctx context.Context, t testing.TB, cfg config.Clus
if err != nil { if err != nil {
t.Fatalf("could not start etcd integrationCluster: %s", err) t.Fatalf("could not start etcd integrationCluster: %s", err)
} }
return &e2eCluster{*epc} return &e2eCluster{t, *epc}
} }
type e2eCluster struct { type e2eCluster struct {
t testing.TB
e2e.EtcdProcessCluster e2e.EtcdProcessCluster
} }
func (c *e2eCluster) Client() Client { func (c *e2eCluster) Client(cfg clientv3.AuthConfig) (Client, error) {
return e2eClient{e2e.NewEtcdctl(c.Cfg, c.EndpointsV3())} etcdctl := e2e.NewEtcdctl(c.Cfg, c.EndpointsV3())
if !cfg.Empty() {
// use integration test client to validate if permissions are authorized
_, err := integration.NewClient(c.t, clientv3.Config{
Endpoints: c.EndpointsV3(),
DialTimeout: 5 * time.Second,
DialOptions: []grpc.DialOption{grpc.WithBlock()},
Username: cfg.Username,
Password: cfg.Password,
})
if err != nil {
return nil, err
}
etcdctl = etcdctl.WithAuth(cfg.Username, cfg.Password)
}
return e2eClient{etcdctl}, nil
} }
func (c *e2eCluster) Members() (ms []Member) { func (c *e2eCluster) Members() (ms []Member) {
@ -107,7 +127,7 @@ func (c *e2eCluster) WaitLeader(t testing.TB) int {
// WaitMembersForLeader waits until given members agree on the same leader, // WaitMembersForLeader waits until given members agree on the same leader,
// and returns its 'index' in the 'membs' list // and returns its 'index' in the 'membs' list
func (c *e2eCluster) WaitMembersForLeader(ctx context.Context, t testing.TB, membs []Member) int { func (c *e2eCluster) WaitMembersForLeader(ctx context.Context, t testing.TB, membs []Member) int {
cc := c.Client() cc := MustClient(c.Client(clientv3.AuthConfig{}))
// ensure leader is up via linearizable get // ensure leader is up via linearizable get
for { for {

View File

@ -31,6 +31,8 @@ import (
type EtcdctlV3 struct { type EtcdctlV3 struct {
cfg *EtcdProcessClusterConfig cfg *EtcdProcessClusterConfig
endpoints []string endpoints []string
userName string
password string
} }
func NewEtcdctl(cfg *EtcdProcessClusterConfig, endpoints []string) *EtcdctlV3 { func NewEtcdctl(cfg *EtcdProcessClusterConfig, endpoints []string) *EtcdctlV3 {
@ -40,6 +42,12 @@ func NewEtcdctl(cfg *EtcdProcessClusterConfig, endpoints []string) *EtcdctlV3 {
} }
} }
func (ctl *EtcdctlV3) WithAuth(userName, password string) *EtcdctlV3 {
ctl.userName = userName
ctl.password = password
return ctl
}
func (ctl *EtcdctlV3) DowngradeEnable(ctx context.Context, version string) error { func (ctl *EtcdctlV3) DowngradeEnable(ctx context.Context, version string) error {
_, err := SpawnWithExpectLines(ctx, ctl.cmdArgs("downgrade", "enable", version), nil, "Downgrade enable success") _, err := SpawnWithExpectLines(ctx, ctl.cmdArgs("downgrade", "enable", version), nil, "Downgrade enable success")
return err return err
@ -234,6 +242,7 @@ func AddTxnResponse(resp *clientv3.TxnResponse, jsonData string) {
} }
} }
} }
func (ctl *EtcdctlV3) MemberList(ctx context.Context) (*clientv3.MemberListResponse, error) { func (ctl *EtcdctlV3) MemberList(ctx context.Context) (*clientv3.MemberListResponse, error) {
var resp clientv3.MemberListResponse var resp clientv3.MemberListResponse
err := ctl.spawnJsonCmd(ctx, &resp, "member", "list") err := ctl.spawnJsonCmd(ctx, &resp, "member", "list")
@ -283,6 +292,9 @@ func (ctl *EtcdctlV3) flags() map[string]string {
} }
} }
fmap["endpoints"] = strings.Join(ctl.endpoints, ",") fmap["endpoints"] = strings.Join(ctl.endpoints, ",")
if ctl.userName != "" && ctl.password != "" {
fmap["user"] = ctl.userName + ":" + ctl.password
}
return fmap return fmap
} }
@ -453,6 +465,24 @@ func (ctl *EtcdctlV3) AlarmDisarm(ctx context.Context, _ *clientv3.AlarmMember)
return &resp, err return &resp, err
} }
func (ctl *EtcdctlV3) AuthEnable(ctx context.Context) (*clientv3.AuthEnableResponse, error) {
var resp clientv3.AuthEnableResponse
err := ctl.spawnJsonCmd(ctx, &resp, "auth", "enable")
return &resp, err
}
func (ctl *EtcdctlV3) AuthDisable(ctx context.Context) (*clientv3.AuthDisableResponse, error) {
var resp clientv3.AuthDisableResponse
err := ctl.spawnJsonCmd(ctx, &resp, "auth", "disable")
return &resp, err
}
func (ctl *EtcdctlV3) AuthStatus(ctx context.Context) (*clientv3.AuthStatusResponse, error) {
var resp clientv3.AuthStatusResponse
err := ctl.spawnJsonCmd(ctx, &resp, "auth", "status")
return &resp, err
}
func (ctl *EtcdctlV3) UserAdd(ctx context.Context, name, password string, opts config.UserAddOptions) (*clientv3.AuthUserAddResponse, error) { func (ctl *EtcdctlV3) UserAdd(ctx context.Context, name, password string, opts config.UserAddOptions) (*clientv3.AuthUserAddResponse, error) {
args := ctl.cmdArgs() args := ctl.cmdArgs()
args = append(args, "user", "add") args = append(args, "user", "add")
@ -492,6 +522,12 @@ func (ctl *EtcdctlV3) UserAdd(ctx context.Context, name, password string, opts c
return &resp, err return &resp, err
} }
func (ctl *EtcdctlV3) UserGet(ctx context.Context, name string) (*clientv3.AuthUserGetResponse, error) {
var resp clientv3.AuthUserGetResponse
err := ctl.spawnJsonCmd(ctx, &resp, "user", "get", name)
return &resp, err
}
func (ctl *EtcdctlV3) UserList(ctx context.Context) (*clientv3.AuthUserListResponse, error) { func (ctl *EtcdctlV3) UserList(ctx context.Context) (*clientv3.AuthUserListResponse, error) {
var resp clientv3.AuthUserListResponse var resp clientv3.AuthUserListResponse
err := ctl.spawnJsonCmd(ctx, &resp, "user", "list") err := ctl.spawnJsonCmd(ctx, &resp, "user", "list")
@ -521,6 +557,18 @@ func (ctl *EtcdctlV3) UserChangePass(ctx context.Context, user, newPass string)
return err return err
} }
func (ctl *EtcdctlV3) UserGrantRole(ctx context.Context, user string, role string) (*clientv3.AuthUserGrantRoleResponse, error) {
var resp clientv3.AuthUserGrantRoleResponse
err := ctl.spawnJsonCmd(ctx, &resp, "user", "grant-role", user, role)
return &resp, err
}
func (ctl *EtcdctlV3) UserRevokeRole(ctx context.Context, user string, role string) (*clientv3.AuthUserRevokeRoleResponse, error) {
var resp clientv3.AuthUserRevokeRoleResponse
err := ctl.spawnJsonCmd(ctx, &resp, "user", "revoke-role", user, role)
return &resp, err
}
func (ctl *EtcdctlV3) RoleAdd(ctx context.Context, name string) (*clientv3.AuthRoleAddResponse, error) { func (ctl *EtcdctlV3) RoleAdd(ctx context.Context, name string) (*clientv3.AuthRoleAddResponse, error) {
var resp clientv3.AuthRoleAddResponse var resp clientv3.AuthRoleAddResponse
err := ctl.spawnJsonCmd(ctx, &resp, "role", "add", name) err := ctl.spawnJsonCmd(ctx, &resp, "role", "add", name)

View File

@ -48,6 +48,7 @@ func (e integrationRunner) NewCluster(ctx context.Context, t testing.TB, cfg con
Size: cfg.ClusterSize, Size: cfg.ClusterSize,
QuotaBackendBytes: cfg.QuotaBackendBytes, QuotaBackendBytes: cfg.QuotaBackendBytes,
DisableStrictReconfigCheck: cfg.DisableStrictReconfigCheck, DisableStrictReconfigCheck: cfg.DisableStrictReconfigCheck,
AuthToken: cfg.AuthToken,
SnapshotCount: uint64(cfg.SnapshotCount), SnapshotCount: uint64(cfg.SnapshotCount),
} }
integrationCfg.ClientTLS, err = tlsInfo(t, cfg.ClientTLS) integrationCfg.ClientTLS, err = tlsInfo(t, cfg.ClientTLS)
@ -117,12 +118,19 @@ func (c *integrationCluster) Close() error {
return nil return nil
} }
func (c *integrationCluster) Client() Client { func (c *integrationCluster) Client(cfg clientv3.AuthConfig) (Client, error) {
cc, err := c.ClusterClient() option := func(_ *clientv3.Config) {}
if err != nil { if !cfg.Empty() {
c.t.Fatal(err) option = func(clientCfg *clientv3.Config) {
clientCfg.Username = cfg.Username
clientCfg.Password = cfg.Password
} }
return integrationClient{Client: cc} }
cc, err := c.ClusterClient(c.t, option)
if err != nil {
return nil, err
}
return integrationClient{Client: cc}, nil
} }
type integrationClient struct { type integrationClient struct {
@ -261,17 +269,85 @@ func (c integrationClient) TimeToLive(ctx context.Context, id clientv3.LeaseID,
return c.Client.TimeToLive(ctx, id, leaseOpts...) return c.Client.TimeToLive(ctx, id, leaseOpts...)
} }
func (c integrationClient) Leases(ctx context.Context) (*clientv3.LeaseLeasesResponse, error) {
return c.Client.Leases(ctx)
}
func (c integrationClient) KeepAliveOnce(ctx context.Context, id clientv3.LeaseID) (*clientv3.LeaseKeepAliveResponse, error) {
return c.Client.KeepAliveOnce(ctx, id)
}
func (c integrationClient) Revoke(ctx context.Context, id clientv3.LeaseID) (*clientv3.LeaseRevokeResponse, error) {
return c.Client.Revoke(ctx, id)
}
func (c integrationClient) AuthEnable(ctx context.Context) (*clientv3.AuthEnableResponse, error) {
return c.Client.AuthEnable(ctx)
}
func (c integrationClient) AuthDisable(ctx context.Context) (*clientv3.AuthDisableResponse, error) {
return c.Client.AuthDisable(ctx)
}
func (c integrationClient) AuthStatus(ctx context.Context) (*clientv3.AuthStatusResponse, error) {
return c.Client.AuthStatus(ctx)
}
func (c integrationClient) UserAdd(ctx context.Context, name, password string, opts config.UserAddOptions) (*clientv3.AuthUserAddResponse, error) { func (c integrationClient) UserAdd(ctx context.Context, name, password string, opts config.UserAddOptions) (*clientv3.AuthUserAddResponse, error) {
return c.Client.UserAddWithOptions(ctx, name, password, &clientv3.UserAddOptions{ return c.Client.UserAddWithOptions(ctx, name, password, &clientv3.UserAddOptions{
NoPassword: opts.NoPassword, NoPassword: opts.NoPassword,
}) })
} }
func (c integrationClient) UserGet(ctx context.Context, name string) (*clientv3.AuthUserGetResponse, error) {
return c.Client.UserGet(ctx, name)
}
func (c integrationClient) UserList(ctx context.Context) (*clientv3.AuthUserListResponse, error) {
return c.Client.UserList(ctx)
}
func (c integrationClient) UserDelete(ctx context.Context, name string) (*clientv3.AuthUserDeleteResponse, error) {
return c.Client.UserDelete(ctx, name)
}
func (c integrationClient) UserChangePass(ctx context.Context, user, newPass string) error { func (c integrationClient) UserChangePass(ctx context.Context, user, newPass string) error {
_, err := c.Client.UserChangePassword(ctx, user, newPass) _, err := c.Client.UserChangePassword(ctx, user, newPass)
return err return err
} }
func (c integrationClient) UserGrantRole(ctx context.Context, user string, role string) (*clientv3.AuthUserGrantRoleResponse, error) {
return c.Client.UserGrantRole(ctx, user, role)
}
func (c integrationClient) UserRevokeRole(ctx context.Context, user string, role string) (*clientv3.AuthUserRevokeRoleResponse, error) {
return c.Client.UserRevokeRole(ctx, user, role)
}
func (c integrationClient) RoleAdd(ctx context.Context, name string) (*clientv3.AuthRoleAddResponse, error) {
return c.Client.RoleAdd(ctx, name)
}
func (c integrationClient) RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType clientv3.PermissionType) (*clientv3.AuthRoleGrantPermissionResponse, error) {
return c.Client.RoleGrantPermission(ctx, name, key, rangeEnd, permType)
}
func (c integrationClient) RoleGet(ctx context.Context, role string) (*clientv3.AuthRoleGetResponse, error) {
return c.Client.RoleGet(ctx, role)
}
func (c integrationClient) RoleList(ctx context.Context) (*clientv3.AuthRoleListResponse, error) {
return c.Client.RoleList(ctx)
}
func (c integrationClient) RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*clientv3.AuthRoleRevokePermissionResponse, error) {
return c.Client.RoleRevokePermission(ctx, role, key, rangeEnd)
}
func (c integrationClient) RoleDelete(ctx context.Context, role string) (*clientv3.AuthRoleDeleteResponse, error) {
return c.Client.RoleDelete(ctx, role)
}
func (c integrationClient) Txn(ctx context.Context, compares, ifSucess, ifFail []string, o config.TxnOptions) (*clientv3.TxnResponse, error) { func (c integrationClient) Txn(ctx context.Context, compares, ifSucess, ifFail []string, o config.TxnOptions) (*clientv3.TxnResponse, error) {
txn := c.Client.Txn(ctx) txn := c.Client.Txn(ctx)
var cmps []clientv3.Cmp var cmps []clientv3.Cmp

View File

@ -180,7 +180,6 @@ type Cluster struct {
LastMemberNum int LastMemberNum int
mu sync.Mutex mu sync.Mutex
clusterClient *clientv3.Client
} }
func SchemeFromTLSInfo(tls *transport.TLSInfo) string { func SchemeFromTLSInfo(tls *transport.TLSInfo) string {
@ -441,7 +440,7 @@ func (c *Cluster) waitMembersForLeader(ctx context.Context, t testing.TB, membs
for _, m := range membs { for _, m := range membs {
possibleLead[uint64(m.Server.MemberId())] = true possibleLead[uint64(m.Server.MemberId())] = true
} }
cc, err := c.ClusterClient() cc, err := c.ClusterClient(t)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1378,13 +1377,6 @@ func (c *Cluster) Terminate(t testutil.TB) {
if t != nil { if t != nil {
t.Logf("========= Cluster termination started =====================") t.Logf("========= Cluster termination started =====================")
} }
c.mu.Lock()
if c.clusterClient != nil {
if err := c.clusterClient.Close(); err != nil {
t.Error(err)
}
}
c.mu.Unlock()
for _, m := range c.Members { for _, m := range c.Members {
if m.Client != nil { if m.Client != nil {
m.Client.Close() m.Client.Close()
@ -1420,14 +1412,27 @@ func (c *Cluster) Endpoints() []string {
return endpoints return endpoints
} }
func (c *Cluster) ClusterClient() (client *clientv3.Client, err error) { func (c *Cluster) ClusterClient(t testing.TB, opts ...func(*clientv3.Config)) (client *clientv3.Client, err error) {
if c.clusterClient == nil { cfg, err := c.newClientCfg()
var endpoints []string if err != nil {
for _, m := range c.Members { return nil, err
endpoints = append(endpoints, m.GrpcURL)
} }
cfg := clientv3.Config{ for _, opt := range opts {
Endpoints: endpoints, opt(cfg)
}
client, err = newClientV3(*cfg)
if err != nil {
return nil, err
}
t.Cleanup(func() {
client.Close()
})
return client, nil
}
func (c *Cluster) newClientCfg() (*clientv3.Config, error) {
cfg := &clientv3.Config{
Endpoints: c.Endpoints(),
DialTimeout: 5 * time.Second, DialTimeout: 5 * time.Second,
DialOptions: []grpc.DialOption{grpc.WithBlock()}, DialOptions: []grpc.DialOption{grpc.WithBlock()},
MaxCallSendMsgSize: c.Cfg.ClientMaxCallSendMsgSize, MaxCallSendMsgSize: c.Cfg.ClientMaxCallSendMsgSize,
@ -1440,12 +1445,7 @@ func (c *Cluster) ClusterClient() (client *clientv3.Client, err error) {
} }
cfg.TLS = tls cfg.TLS = tls
} }
c.clusterClient, err = newClientV3(cfg) return cfg, nil
if err != nil {
return nil, err
}
}
return c.clusterClient, nil
} }
// NewClientV3 creates a new grpc client connection to the member // NewClientV3 creates a new grpc client connection to the member

View File

@ -30,7 +30,7 @@ type testRunner interface {
type Cluster interface { type Cluster interface {
Members() []Member Members() []Member
Client() Client Client(cfg clientv3.AuthConfig) (Client, error)
WaitLeader(t testing.TB) int WaitLeader(t testing.TB) int
Close() error Close() error
} }
@ -57,18 +57,23 @@ type Client interface {
Leases(context context.Context) (*clientv3.LeaseLeasesResponse, error) Leases(context context.Context) (*clientv3.LeaseLeasesResponse, error)
KeepAliveOnce(context context.Context, id clientv3.LeaseID) (*clientv3.LeaseKeepAliveResponse, error) KeepAliveOnce(context context.Context, id clientv3.LeaseID) (*clientv3.LeaseKeepAliveResponse, error)
Revoke(context context.Context, id clientv3.LeaseID) (*clientv3.LeaseRevokeResponse, error) Revoke(context context.Context, id clientv3.LeaseID) (*clientv3.LeaseRevokeResponse, error)
AuthEnable(context context.Context) (*clientv3.AuthEnableResponse, error)
AuthDisable(context context.Context) (*clientv3.AuthDisableResponse, error)
AuthStatus(context context.Context) (*clientv3.AuthStatusResponse, error)
UserAdd(context context.Context, name, password string, opts config.UserAddOptions) (*clientv3.AuthUserAddResponse, error) UserAdd(context context.Context, name, password string, opts config.UserAddOptions) (*clientv3.AuthUserAddResponse, error)
UserGet(context context.Context, name string) (*clientv3.AuthUserGetResponse, error)
UserList(context context.Context) (*clientv3.AuthUserListResponse, error) UserList(context context.Context) (*clientv3.AuthUserListResponse, error)
UserDelete(context context.Context, name string) (*clientv3.AuthUserDeleteResponse, error) UserDelete(context context.Context, name string) (*clientv3.AuthUserDeleteResponse, error)
UserChangePass(context context.Context, user, newPass string) error UserChangePass(context context.Context, user, newPass string) error
UserGrantRole(context context.Context, user string, role string) (*clientv3.AuthUserGrantRoleResponse, error)
UserRevokeRole(context context.Context, user string, role string) (*clientv3.AuthUserRevokeRoleResponse, error)
RoleAdd(context context.Context, name string) (*clientv3.AuthRoleAddResponse, error) RoleAdd(context context.Context, name string) (*clientv3.AuthRoleAddResponse, error)
RoleGrantPermission(context context.Context, name string, key, rangeEnd string, permType clientv3.PermissionType) (*clientv3.AuthRoleGrantPermissionResponse, error) RoleGrantPermission(context context.Context, name string, key, rangeEnd string, permType clientv3.PermissionType) (*clientv3.AuthRoleGrantPermissionResponse, error)
RoleGet(context context.Context, role string) (*clientv3.AuthRoleGetResponse, error) RoleGet(context context.Context, role string) (*clientv3.AuthRoleGetResponse, error)
RoleList(context context.Context) (*clientv3.AuthRoleListResponse, error) RoleList(context context.Context) (*clientv3.AuthRoleListResponse, error)
RoleRevokePermission(context context.Context, role string, key, rangeEnd string) (*clientv3.AuthRoleRevokePermissionResponse, error) RoleRevokePermission(context context.Context, role string, key, rangeEnd string) (*clientv3.AuthRoleRevokePermissionResponse, error)
RoleDelete(context context.Context, role string) (*clientv3.AuthRoleDeleteResponse, error) RoleDelete(context context.Context, role string) (*clientv3.AuthRoleDeleteResponse, error)
Txn(context context.Context, compares, ifSucess, ifFail []string, o config.TxnOptions) (*clientv3.TxnResponse, error) Txn(context context.Context, compares, ifSucess, ifFail []string, o config.TxnOptions) (*clientv3.TxnResponse, error)
MemberList(context context.Context) (*clientv3.MemberListResponse, error) MemberList(context context.Context) (*clientv3.MemberListResponse, error)

22
tests/framework/util.go Normal file
View File

@ -0,0 +1,22 @@
// Copyright 2022 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 framework
func MustClient(c Client, err error) Client {
if err != nil {
panic(err)
}
return c
}

View File

@ -77,7 +77,7 @@ func TestCompactionHash(t *testing.T) {
clus := integration2.NewCluster(t, &integration2.ClusterConfig{Size: 1}) clus := integration2.NewCluster(t, &integration2.ClusterConfig{Size: 1})
defer clus.Terminate(t) defer clus.Terminate(t)
cc, err := clus.ClusterClient() cc, err := clus.ClusterClient(t)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@ -34,7 +34,7 @@ func TestPeriodicCheck(t *testing.T) {
clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3})
defer clus.Terminate(t) defer clus.Terminate(t)
cc, err := clus.ClusterClient() cc, err := clus.ClusterClient(t)
require.NoError(t, err) require.NoError(t, err)
ctx := context.Background() ctx := context.Background()
@ -70,7 +70,7 @@ func TestPeriodicCheckDetectsCorruption(t *testing.T) {
clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3})
defer clus.Terminate(t) defer clus.Terminate(t)
cc, err := clus.ClusterClient() cc, err := clus.ClusterClient(t)
require.NoError(t, err) require.NoError(t, err)
ctx := context.Background() ctx := context.Background()
@ -106,7 +106,7 @@ func TestCompactHashCheck(t *testing.T) {
clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3})
defer clus.Terminate(t) defer clus.Terminate(t)
cc, err := clus.ClusterClient() cc, err := clus.ClusterClient(t)
require.NoError(t, err) require.NoError(t, err)
ctx := context.Background() ctx := context.Background()
@ -143,7 +143,7 @@ func TestCompactHashCheckDetectCorruption(t *testing.T) {
clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3}) clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3})
defer clus.Terminate(t) defer clus.Terminate(t)
cc, err := clus.ClusterClient() cc, err := clus.ClusterClient(t)
require.NoError(t, err) require.NoError(t, err)
ctx := context.Background() ctx := context.Background()

View File

@ -34,11 +34,10 @@ func TestCompactionHash(t *testing.T) {
clus := integration2.NewCluster(t, &integration2.ClusterConfig{Size: 1}) clus := integration2.NewCluster(t, &integration2.ClusterConfig{Size: 1})
defer clus.Terminate(t) defer clus.Terminate(t)
cc, err := clus.ClusterClient() cc, err := clus.ClusterClient(t)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
client := &http.Client{ client := &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {

View File

@ -523,11 +523,11 @@ func testLeaseStress(t *testing.T, stresser func(context.Context, pb.LeaseClient
errc := make(chan error) errc := make(chan error)
if useClusterClient { if useClusterClient {
for i := 0; i < 300; i++ { clusterClient, err := clus.ClusterClient(t)
clusterClient, err := clus.ClusterClient()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
for i := 0; i < 300; i++ {
go func(i int) { errc <- stresser(ctx, integration.ToGRPC(clusterClient).Lease) }(i) go func(i int) { errc <- stresser(ctx, integration.ToGRPC(clusterClient).Lease) }(i)
} }
} else { } else {