mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #13740 from serathius/common-get
Migrate key value Get to common framework
This commit is contained in:
commit
31de503859
@ -18,33 +18,148 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
|
"go.etcd.io/etcd/tests/v3/framework/config"
|
||||||
"go.etcd.io/etcd/tests/v3/framework/testutils"
|
"go.etcd.io/etcd/tests/v3/framework/testutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestKVPut(t *testing.T) {
|
func TestKVPut(t *testing.T) {
|
||||||
testRunner.BeforeTest(t)
|
testRunner.BeforeTest(t)
|
||||||
clus := testRunner.NewCluster(t)
|
tcs := []struct {
|
||||||
defer clus.Close()
|
name string
|
||||||
cc := clus.Client()
|
config config.ClusterConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "NoTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PeerTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 3, PeerTLS: config.ManualTLS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PeerAutoTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 3, PeerTLS: config.AutoTLS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ClientTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 1, ClientTLS: config.ManualTLS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ClientAutoTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 1, ClientTLS: config.AutoTLS},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcs {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
clus := testRunner.NewCluster(t, tc.config)
|
||||||
|
defer clus.Close()
|
||||||
|
cc := clus.Client()
|
||||||
|
|
||||||
testutils.ExecuteWithTimeout(t, 10*time.Second, func() {
|
testutils.ExecuteWithTimeout(t, 10*time.Second, func() {
|
||||||
key, value := "foo", "bar"
|
key, value := "foo", "bar"
|
||||||
|
|
||||||
if err := cc.Put(key, value); err != nil {
|
if err := cc.Put(key, value); err != nil {
|
||||||
t.Fatalf("count not put key %q, err: %s", key, err)
|
t.Fatalf("count not put key %q, err: %s", key, err)
|
||||||
}
|
}
|
||||||
resp, err := cc.Get(key, testutils.WithSerializable())
|
resp, err := cc.Get(key, config.GetOptions{Serializable: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("count not get key %q, err: %s", key, err)
|
t.Fatalf("count not get key %q, err: %s", key, err)
|
||||||
}
|
}
|
||||||
if len(resp.Kvs) != 1 {
|
if len(resp.Kvs) != 1 {
|
||||||
t.Errorf("Unexpected lenth of response, got %d", len(resp.Kvs))
|
t.Errorf("Unexpected lenth of response, got %d", len(resp.Kvs))
|
||||||
}
|
}
|
||||||
if string(resp.Kvs[0].Key) != key {
|
if string(resp.Kvs[0].Key) != key {
|
||||||
t.Errorf("Unexpected key, want %q, got %q", key, resp.Kvs[0].Key)
|
t.Errorf("Unexpected key, want %q, got %q", key, resp.Kvs[0].Key)
|
||||||
}
|
}
|
||||||
if string(resp.Kvs[0].Value) != value {
|
if string(resp.Kvs[0].Value) != value {
|
||||||
t.Errorf("Unexpected value, want %q, got %q", value, resp.Kvs[0].Value)
|
t.Errorf("Unexpected value, want %q, got %q", value, resp.Kvs[0].Value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKVGet(t *testing.T) {
|
||||||
|
testRunner.BeforeTest(t)
|
||||||
|
tcs := []struct {
|
||||||
|
name string
|
||||||
|
config config.ClusterConfig
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "NoTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 1},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PeerTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 3, PeerTLS: config.ManualTLS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PeerAutoTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 3, PeerTLS: config.AutoTLS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ClientTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 1, ClientTLS: config.ManualTLS},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ClientAutoTLS",
|
||||||
|
config: config.ClusterConfig{ClusterSize: 1, ClientTLS: config.AutoTLS},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tcs {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
clus := testRunner.NewCluster(t, tc.config)
|
||||||
|
defer clus.Close()
|
||||||
|
cc := clus.Client()
|
||||||
|
|
||||||
|
testutils.ExecuteWithTimeout(t, 10*time.Second, func() {
|
||||||
|
var (
|
||||||
|
kvs = []string{"a", "b", "c", "c", "c", "foo", "foo/abc", "fop"}
|
||||||
|
wantKvs = []string{"a", "b", "c", "foo", "foo/abc", "fop"}
|
||||||
|
kvsByVersion = []string{"a", "b", "foo", "foo/abc", "fop", "c"}
|
||||||
|
reversedKvs = []string{"fop", "foo/abc", "foo", "c", "b", "a"}
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := range kvs {
|
||||||
|
if err := cc.Put(kvs[i], "bar"); err != nil {
|
||||||
|
t.Fatalf("count not put key %q, err: %s", kvs[i], err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
begin string
|
||||||
|
end string
|
||||||
|
options config.GetOptions
|
||||||
|
|
||||||
|
wkv []string
|
||||||
|
}{
|
||||||
|
{begin: "a", wkv: wantKvs[:1]},
|
||||||
|
{begin: "a", options: config.GetOptions{Serializable: true}, wkv: wantKvs[:1]},
|
||||||
|
{begin: "a", options: config.GetOptions{End: "c"}, wkv: wantKvs[:2]},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true}, wkv: wantKvs},
|
||||||
|
{begin: "", options: config.GetOptions{FromKey: true}, wkv: wantKvs},
|
||||||
|
{begin: "a", options: config.GetOptions{End: "x"}, wkv: wantKvs},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true, Revision: 4}, wkv: kvs[:3]},
|
||||||
|
{begin: "a", options: config.GetOptions{CountOnly: true}, wkv: nil},
|
||||||
|
{begin: "foo", options: config.GetOptions{Prefix: true}, wkv: []string{"foo", "foo/abc"}},
|
||||||
|
{begin: "foo", options: config.GetOptions{FromKey: true}, wkv: []string{"foo", "foo/abc", "fop"}},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true, Limit: 2}, wkv: wantKvs[:2]},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true, Order: clientv3.SortAscend, SortBy: clientv3.SortByModRevision}, wkv: wantKvs},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true, Order: clientv3.SortAscend, SortBy: clientv3.SortByVersion}, wkv: kvsByVersion},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true, Order: clientv3.SortNone, SortBy: clientv3.SortByCreateRevision}, wkv: wantKvs},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true, Order: clientv3.SortDescend, SortBy: clientv3.SortByCreateRevision}, wkv: reversedKvs},
|
||||||
|
{begin: "", options: config.GetOptions{Prefix: true, Order: clientv3.SortDescend, SortBy: clientv3.SortByKey}, wkv: reversedKvs},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
resp, err := cc.Get(tt.begin, tt.options)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("count not get key %q, err: %s", tt.begin, err)
|
||||||
|
}
|
||||||
|
kvs := testutils.KeysFromGetResponse(resp)
|
||||||
|
assert.Equal(t, tt.wkv, kvs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,6 @@ import (
|
|||||||
"go.etcd.io/etcd/tests/v3/framework/e2e"
|
"go.etcd.io/etcd/tests/v3/framework/e2e"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCtlV3PutNoTLS(t *testing.T) { testCtl(t, putTest, withCfg(*e2e.NewConfigNoTLS())) }
|
|
||||||
func TestCtlV3PutClientTLS(t *testing.T) { testCtl(t, putTest, withCfg(*e2e.NewConfigClientTLS())) }
|
|
||||||
func TestCtlV3PutClientAutoTLS(t *testing.T) {
|
|
||||||
testCtl(t, putTest, withCfg(*e2e.NewConfigClientAutoTLS()))
|
|
||||||
}
|
|
||||||
func TestCtlV3PutPeerTLS(t *testing.T) { testCtl(t, putTest, withCfg(*e2e.NewConfigPeerTLS())) }
|
|
||||||
func TestCtlV3PutTimeout(t *testing.T) { testCtl(t, putTest, withDialTimeout(0)) }
|
func TestCtlV3PutTimeout(t *testing.T) { testCtl(t, putTest, withDialTimeout(0)) }
|
||||||
func TestCtlV3PutClientTLSFlagByEnv(t *testing.T) {
|
func TestCtlV3PutClientTLSFlagByEnv(t *testing.T) {
|
||||||
testCtl(t, putTest, withCfg(*e2e.NewConfigClientTLS()), withFlagByEnv())
|
testCtl(t, putTest, withCfg(*e2e.NewConfigClientTLS()), withFlagByEnv())
|
||||||
@ -35,15 +29,7 @@ func TestCtlV3PutClientTLSFlagByEnv(t *testing.T) {
|
|||||||
func TestCtlV3PutIgnoreValue(t *testing.T) { testCtl(t, putTestIgnoreValue) }
|
func TestCtlV3PutIgnoreValue(t *testing.T) { testCtl(t, putTestIgnoreValue) }
|
||||||
func TestCtlV3PutIgnoreLease(t *testing.T) { testCtl(t, putTestIgnoreLease) }
|
func TestCtlV3PutIgnoreLease(t *testing.T) { testCtl(t, putTestIgnoreLease) }
|
||||||
|
|
||||||
func TestCtlV3Get(t *testing.T) { testCtl(t, getTest) }
|
|
||||||
func TestCtlV3GetNoTLS(t *testing.T) { testCtl(t, getTest, withCfg(*e2e.NewConfigNoTLS())) }
|
|
||||||
func TestCtlV3GetClientTLS(t *testing.T) { testCtl(t, getTest, withCfg(*e2e.NewConfigClientTLS())) }
|
|
||||||
func TestCtlV3GetClientAutoTLS(t *testing.T) {
|
|
||||||
testCtl(t, getTest, withCfg(*e2e.NewConfigClientAutoTLS()))
|
|
||||||
}
|
|
||||||
func TestCtlV3GetPeerTLS(t *testing.T) { testCtl(t, getTest, withCfg(*e2e.NewConfigPeerTLS())) }
|
|
||||||
func TestCtlV3GetTimeout(t *testing.T) { testCtl(t, getTest, withDialTimeout(0)) }
|
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 TestCtlV3GetFormat(t *testing.T) { testCtl(t, getFormatTest) }
|
||||||
func TestCtlV3GetRev(t *testing.T) { testCtl(t, getRevTest) }
|
func TestCtlV3GetRev(t *testing.T) { testCtl(t, getRevTest) }
|
||||||
|
29
tests/framework/config/client.go
Normal file
29
tests/framework/config/client.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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 config
|
||||||
|
|
||||||
|
import clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
|
|
||||||
|
type GetOptions struct {
|
||||||
|
Revision int
|
||||||
|
End string
|
||||||
|
CountOnly bool
|
||||||
|
Serializable bool
|
||||||
|
Prefix bool
|
||||||
|
FromKey bool
|
||||||
|
Limit int
|
||||||
|
Order clientv3.SortOrder
|
||||||
|
SortBy clientv3.SortTarget
|
||||||
|
}
|
29
tests/framework/config/cluster.go
Normal file
29
tests/framework/config/cluster.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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 config
|
||||||
|
|
||||||
|
type TLSConfig string
|
||||||
|
|
||||||
|
const (
|
||||||
|
NoTLS TLSConfig = ""
|
||||||
|
AutoTLS TLSConfig = "auto-tls"
|
||||||
|
ManualTLS TLSConfig = "manual-tls"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClusterConfig struct {
|
||||||
|
ClusterSize int
|
||||||
|
PeerTLS TLSConfig
|
||||||
|
ClientTLS TLSConfig
|
||||||
|
}
|
@ -19,9 +19,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"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/e2e"
|
"go.etcd.io/etcd/tests/v3/framework/e2e"
|
||||||
"go.etcd.io/etcd/tests/v3/framework/testutils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type e2eRunner struct{}
|
type e2eRunner struct{}
|
||||||
@ -39,8 +38,37 @@ func (e e2eRunner) BeforeTest(t testing.TB) {
|
|||||||
e2e.BeforeTest(t)
|
e2e.BeforeTest(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e e2eRunner) NewCluster(t testing.TB) Cluster {
|
func (e e2eRunner) NewCluster(t testing.TB, cfg config.ClusterConfig) Cluster {
|
||||||
epc, err := e2e.NewEtcdProcessCluster(t, e2e.ConfigStandalone(*e2e.NewConfigAutoTLS()))
|
e2eConfig := e2e.EtcdProcessClusterConfig{
|
||||||
|
InitialToken: "new",
|
||||||
|
ClusterSize: cfg.ClusterSize,
|
||||||
|
}
|
||||||
|
switch cfg.ClientTLS {
|
||||||
|
case config.NoTLS:
|
||||||
|
e2eConfig.ClientTLS = e2e.ClientNonTLS
|
||||||
|
case config.AutoTLS:
|
||||||
|
e2eConfig.IsClientAutoTLS = true
|
||||||
|
e2eConfig.ClientTLS = e2e.ClientTLS
|
||||||
|
case config.ManualTLS:
|
||||||
|
e2eConfig.IsClientAutoTLS = false
|
||||||
|
e2eConfig.ClientTLS = e2e.ClientTLS
|
||||||
|
default:
|
||||||
|
t.Fatalf("ClientTLS config %q not supported", cfg.ClientTLS)
|
||||||
|
}
|
||||||
|
switch cfg.PeerTLS {
|
||||||
|
case config.NoTLS:
|
||||||
|
e2eConfig.IsPeerTLS = false
|
||||||
|
e2eConfig.IsPeerAutoTLS = false
|
||||||
|
case config.AutoTLS:
|
||||||
|
e2eConfig.IsPeerTLS = true
|
||||||
|
e2eConfig.IsPeerAutoTLS = true
|
||||||
|
case config.ManualTLS:
|
||||||
|
e2eConfig.IsPeerTLS = true
|
||||||
|
e2eConfig.IsPeerAutoTLS = false
|
||||||
|
default:
|
||||||
|
t.Fatalf("PeerTLS config %q not supported", cfg.PeerTLS)
|
||||||
|
}
|
||||||
|
epc, err := e2e.NewEtcdProcessCluster(t, &e2eConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not start etcd integrationCluster: %s", err)
|
t.Fatalf("could not start etcd integrationCluster: %s", err)
|
||||||
}
|
}
|
||||||
@ -58,11 +86,3 @@ func (c *e2eCluster) Client() Client {
|
|||||||
type e2eClient struct {
|
type e2eClient struct {
|
||||||
*e2e.EtcdctlV3
|
*e2e.EtcdctlV3
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c e2eClient) Get(key string, opts ...testutils.GetOption) (*clientv3.GetResponse, error) {
|
|
||||||
o := testutils.GetOptions{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&o)
|
|
||||||
}
|
|
||||||
return c.EtcdctlV3.Get(key, o)
|
|
||||||
}
|
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"go.etcd.io/etcd/tests/v3/framework/testutils"
|
"go.etcd.io/etcd/tests/v3/framework/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EtcdctlV3 struct {
|
type EtcdctlV3 struct {
|
||||||
@ -39,20 +39,69 @@ func (ctl *EtcdctlV3) DowngradeEnable(version string) error {
|
|||||||
return SpawnWithExpect(ctl.cmdArgs("downgrade", "enable", version), "Downgrade enable success")
|
return SpawnWithExpect(ctl.cmdArgs("downgrade", "enable", version), "Downgrade enable success")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *EtcdctlV3) Get(key string, o testutils.GetOptions) (*clientv3.GetResponse, error) {
|
func (ctl *EtcdctlV3) Get(key string, o config.GetOptions) (*clientv3.GetResponse, error) {
|
||||||
args := ctl.cmdArgs()
|
args := ctl.cmdArgs()
|
||||||
if o.Serializable {
|
if o.Serializable {
|
||||||
args = append(args, "--consistency", "s")
|
args = append(args, "--consistency", "s")
|
||||||
}
|
}
|
||||||
cmd, err := SpawnCmd(append(args, "get", key, "-w", "json"), nil)
|
args = append(args, "get", key, "-w", "json")
|
||||||
|
if o.End != "" {
|
||||||
|
args = append(args, o.End)
|
||||||
|
}
|
||||||
|
if o.Revision != 0 {
|
||||||
|
args = append(args, fmt.Sprintf("--rev=%d", o.Revision))
|
||||||
|
}
|
||||||
|
if o.Prefix {
|
||||||
|
args = append(args, "--prefix")
|
||||||
|
}
|
||||||
|
if o.Limit != 0 {
|
||||||
|
args = append(args, fmt.Sprintf("--limit=%d", o.Limit))
|
||||||
|
}
|
||||||
|
if o.FromKey {
|
||||||
|
args = append(args, "--from-key")
|
||||||
|
}
|
||||||
|
if o.CountOnly {
|
||||||
|
args = append(args, "-w", "fields", "--count-only")
|
||||||
|
} else {
|
||||||
|
args = append(args, "-w", "json")
|
||||||
|
}
|
||||||
|
switch o.SortBy {
|
||||||
|
case clientv3.SortByCreateRevision:
|
||||||
|
args = append(args, "--sort-by=CREATE")
|
||||||
|
case clientv3.SortByModRevision:
|
||||||
|
args = append(args, "--sort-by=MODIFY")
|
||||||
|
case clientv3.SortByValue:
|
||||||
|
args = append(args, "--sort-by=VALUE")
|
||||||
|
case clientv3.SortByVersion:
|
||||||
|
args = append(args, "--sort-by=VERSION")
|
||||||
|
case clientv3.SortByKey:
|
||||||
|
// nothing
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("bad sort target %v", o.SortBy)
|
||||||
|
}
|
||||||
|
switch o.Order {
|
||||||
|
case clientv3.SortAscend:
|
||||||
|
args = append(args, "--order=ASCEND")
|
||||||
|
case clientv3.SortDescend:
|
||||||
|
args = append(args, "--order=DESCEND")
|
||||||
|
case clientv3.SortNone:
|
||||||
|
// nothing
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("bad sort order %v", o.Order)
|
||||||
|
}
|
||||||
|
cmd, err := SpawnCmd(args, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var resp clientv3.GetResponse
|
||||||
|
if o.CountOnly {
|
||||||
|
_, err := cmd.Expect("Count")
|
||||||
|
return &resp, err
|
||||||
|
}
|
||||||
line, err := cmd.Expect("kvs")
|
line, err := cmd.Expect("kvs")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var resp clientv3.GetResponse
|
|
||||||
err = json.Unmarshal([]byte(line), &resp)
|
err = json.Unmarshal([]byte(line), &resp)
|
||||||
return &resp, err
|
return &resp, err
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,15 @@ package framework
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.etcd.io/etcd/client/pkg/v3/testutil"
|
"go.etcd.io/etcd/client/pkg/v3/testutil"
|
||||||
|
"go.etcd.io/etcd/client/pkg/v3/transport"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
|
"go.etcd.io/etcd/tests/v3/framework/config"
|
||||||
"go.etcd.io/etcd/tests/v3/framework/integration"
|
"go.etcd.io/etcd/tests/v3/framework/integration"
|
||||||
"go.etcd.io/etcd/tests/v3/framework/testutils"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type integrationRunner struct{}
|
type integrationRunner struct{}
|
||||||
@ -34,13 +37,41 @@ func (e integrationRunner) BeforeTest(t testing.TB) {
|
|||||||
integration.BeforeTest(t)
|
integration.BeforeTest(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e integrationRunner) NewCluster(t testing.TB) Cluster {
|
func (e integrationRunner) NewCluster(t testing.TB, cfg config.ClusterConfig) Cluster {
|
||||||
|
var err error
|
||||||
|
var integrationCfg integration.ClusterConfig
|
||||||
|
integrationCfg.Size = cfg.ClusterSize
|
||||||
|
integrationCfg.ClientTLS, err = tlsInfo(t, cfg.ClientTLS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ClientTLS: %s", err)
|
||||||
|
}
|
||||||
|
integrationCfg.PeerTLS, err = tlsInfo(t, cfg.PeerTLS)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("PeerTLS: %s", err)
|
||||||
|
}
|
||||||
return &integrationCluster{
|
return &integrationCluster{
|
||||||
Cluster: integration.NewCluster(t, &integration.ClusterConfig{Size: 1}),
|
Cluster: integration.NewCluster(t, &integrationCfg),
|
||||||
t: t,
|
t: t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tlsInfo(t testing.TB, cfg config.TLSConfig) (*transport.TLSInfo, error) {
|
||||||
|
switch cfg {
|
||||||
|
case config.NoTLS:
|
||||||
|
return nil, nil
|
||||||
|
case config.AutoTLS:
|
||||||
|
tls, err := transport.SelfCert(zap.NewNop(), t.TempDir(), []string{"localhost"}, 1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to generate cert: %s", err)
|
||||||
|
}
|
||||||
|
return &tls, nil
|
||||||
|
case config.ManualTLS:
|
||||||
|
return &integration.TestTLSInfo, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("config %q not supported", cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type integrationCluster struct {
|
type integrationCluster struct {
|
||||||
*integration.Cluster
|
*integration.Cluster
|
||||||
t testing.TB
|
t testing.TB
|
||||||
@ -63,15 +94,32 @@ type integrationClient struct {
|
|||||||
*clientv3.Client
|
*clientv3.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c integrationClient) Get(key string, opts ...testutils.GetOption) (*clientv3.GetResponse, error) {
|
func (c integrationClient) Get(key string, o config.GetOptions) (*clientv3.GetResponse, error) {
|
||||||
o := testutils.GetOptions{}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&o)
|
|
||||||
}
|
|
||||||
clientOpts := []clientv3.OpOption{}
|
clientOpts := []clientv3.OpOption{}
|
||||||
|
if o.Revision != 0 {
|
||||||
|
clientOpts = append(clientOpts, clientv3.WithRev(int64(o.Revision)))
|
||||||
|
}
|
||||||
|
if o.End != "" {
|
||||||
|
clientOpts = append(clientOpts, clientv3.WithRange(o.End))
|
||||||
|
}
|
||||||
if o.Serializable {
|
if o.Serializable {
|
||||||
clientOpts = append(clientOpts, clientv3.WithSerializable())
|
clientOpts = append(clientOpts, clientv3.WithSerializable())
|
||||||
}
|
}
|
||||||
|
if o.Prefix {
|
||||||
|
clientOpts = append(clientOpts, clientv3.WithPrefix())
|
||||||
|
}
|
||||||
|
if o.Limit != 0 {
|
||||||
|
clientOpts = append(clientOpts, clientv3.WithLimit(int64(o.Limit)))
|
||||||
|
}
|
||||||
|
if o.FromKey {
|
||||||
|
clientOpts = append(clientOpts, clientv3.WithFromKey())
|
||||||
|
}
|
||||||
|
if o.CountOnly {
|
||||||
|
clientOpts = append(clientOpts, clientv3.WithCountOnly())
|
||||||
|
}
|
||||||
|
if o.SortBy != clientv3.SortByKey || o.Order != clientv3.SortNone {
|
||||||
|
clientOpts = append(clientOpts, clientv3.WithSort(o.SortBy, o.Order))
|
||||||
|
}
|
||||||
return c.Client.Get(context.Background(), key, clientOpts...)
|
return c.Client.Get(context.Background(), key, clientOpts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1373,9 +1373,18 @@ func (c *Cluster) ClusterClient() (client *clientv3.Client, err error) {
|
|||||||
endpoints = append(endpoints, m.GrpcURL)
|
endpoints = append(endpoints, m.GrpcURL)
|
||||||
}
|
}
|
||||||
cfg := clientv3.Config{
|
cfg := clientv3.Config{
|
||||||
Endpoints: endpoints,
|
Endpoints: endpoints,
|
||||||
DialTimeout: 5 * time.Second,
|
DialTimeout: 5 * time.Second,
|
||||||
DialOptions: []grpc.DialOption{grpc.WithBlock()},
|
DialOptions: []grpc.DialOption{grpc.WithBlock()},
|
||||||
|
MaxCallSendMsgSize: c.Cfg.ClientMaxCallSendMsgSize,
|
||||||
|
MaxCallRecvMsgSize: c.Cfg.ClientMaxCallRecvMsgSize,
|
||||||
|
}
|
||||||
|
if c.Cfg.ClientTLS != nil {
|
||||||
|
tls, err := c.Cfg.ClientTLS.ClientConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cfg.TLS = tls
|
||||||
}
|
}
|
||||||
c.clusterClient, err = newClientV3(cfg)
|
c.clusterClient, err = newClientV3(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -18,13 +18,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"go.etcd.io/etcd/tests/v3/framework/testutils"
|
"go.etcd.io/etcd/tests/v3/framework/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testRunner interface {
|
type testRunner interface {
|
||||||
TestMain(m *testing.M)
|
TestMain(m *testing.M)
|
||||||
BeforeTest(testing.TB)
|
BeforeTest(testing.TB)
|
||||||
NewCluster(testing.TB) Cluster
|
NewCluster(testing.TB, config.ClusterConfig) Cluster
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cluster interface {
|
type Cluster interface {
|
||||||
@ -34,5 +34,5 @@ type Cluster interface {
|
|||||||
|
|
||||||
type Client interface {
|
type Client interface {
|
||||||
Put(key, value string) error
|
Put(key, value string) error
|
||||||
Get(key string, opts ...testutils.GetOption) (*clientv3.GetResponse, error)
|
Get(key string, opts config.GetOptions) (*clientv3.GetResponse, error)
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,11 @@
|
|||||||
|
|
||||||
package testutils
|
package testutils
|
||||||
|
|
||||||
type GetOptions struct {
|
import clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
Serializable bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetOption func(*GetOptions)
|
func KeysFromGetResponse(resp *clientv3.GetResponse) (kvs []string) {
|
||||||
|
for _, kv := range resp.Kvs {
|
||||||
func WithSerializable() GetOption {
|
kvs = append(kvs, string(kv.Key))
|
||||||
return func(options *GetOptions) {
|
|
||||||
options.Serializable = true
|
|
||||||
}
|
}
|
||||||
|
return kvs
|
||||||
}
|
}
|
@ -21,6 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.etcd.io/etcd/client/pkg/v3/testutil"
|
"go.etcd.io/etcd/client/pkg/v3/testutil"
|
||||||
|
"go.etcd.io/etcd/tests/v3/framework/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type unitRunner struct{}
|
type unitRunner struct{}
|
||||||
@ -38,7 +39,7 @@ func (e unitRunner) TestMain(m *testing.M) {
|
|||||||
func (e unitRunner) BeforeTest(t testing.TB) {
|
func (e unitRunner) BeforeTest(t testing.TB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e unitRunner) NewCluster(t testing.TB) Cluster {
|
func (e unitRunner) NewCluster(t testing.TB, cfg config.ClusterConfig) Cluster {
|
||||||
testutil.SkipTestIfShortMode(t, "Cannot create clusters in --short tests")
|
testutil.SkipTestIfShortMode(t, "Cannot create clusters in --short tests")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -254,180 +254,12 @@ func TestKVRange(t *testing.T) {
|
|||||||
|
|
||||||
wantSet []*mvccpb.KeyValue
|
wantSet []*mvccpb.KeyValue
|
||||||
}{
|
}{
|
||||||
// range first two
|
|
||||||
{
|
|
||||||
"a", "c",
|
|
||||||
0,
|
|
||||||
nil,
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// range first two with serializable
|
|
||||||
{
|
|
||||||
"a", "c",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithSerializable()},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// range all with rev
|
|
||||||
{
|
|
||||||
"a", "x",
|
|
||||||
2,
|
|
||||||
nil,
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// range all with countOnly
|
|
||||||
{
|
|
||||||
"a", "x",
|
|
||||||
2,
|
|
||||||
[]clientv3.OpOption{clientv3.WithCountOnly()},
|
|
||||||
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
// range all with SortByKey, SortAscend
|
|
||||||
{
|
|
||||||
"a", "x",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// range all with SortByKey, missing sorting order (ASCEND by default)
|
|
||||||
{
|
|
||||||
"a", "x",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByKey, clientv3.SortNone)},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// range all with SortByCreateRevision, SortDescend
|
|
||||||
{
|
|
||||||
"a", "x",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortDescend)},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// range all with SortByCreateRevision, missing sorting order (ASCEND by default)
|
|
||||||
{
|
|
||||||
"a", "x",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortNone)},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// range all with SortByModRevision, SortDescend
|
|
||||||
{
|
|
||||||
"a", "x",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByModRevision, clientv3.SortDescend)},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// WithPrefix
|
|
||||||
{
|
|
||||||
"foo", "",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithPrefix()},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// WithFromKey
|
|
||||||
{
|
|
||||||
"fo", "",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithFromKey()},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// fetch entire keyspace using WithFromKey
|
// fetch entire keyspace using WithFromKey
|
||||||
{
|
{
|
||||||
"\x00", "",
|
"\x00", "",
|
||||||
0,
|
0,
|
||||||
[]clientv3.OpOption{clientv3.WithFromKey(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
|
[]clientv3.OpOption{clientv3.WithFromKey(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// fetch entire keyspace using WithPrefix
|
|
||||||
{
|
|
||||||
"", "",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithPrefix(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
|
||||||
{Key: []byte("c"), Value: nil, CreateRevision: 4, ModRevision: 6, Version: 3},
|
|
||||||
{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
|
|
||||||
{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
|
|
||||||
{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// fetch keyspace with empty key using WithFromKey
|
|
||||||
{
|
|
||||||
"", "",
|
|
||||||
0,
|
|
||||||
[]clientv3.OpOption{clientv3.WithFromKey(), clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
|
|
||||||
|
|
||||||
[]*mvccpb.KeyValue{
|
[]*mvccpb.KeyValue{
|
||||||
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
|
||||||
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
{Key: []byte("b"), Value: nil, CreateRevision: 3, ModRevision: 3, Version: 1},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user