mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
namespace: check IsWithFromKey if keyLen equal 0. (#12307)
* namespace: check IsWithFromKey if keyLen equal 0. Rename function isWithFromKey/isWithPrefix to IsOptsWithFromKey/IsOptsWithPrefix. fixes: #12282 * integration: add test while WithFromKey/WithPrefix called in opts.
This commit is contained in:
parent
2c66612e0e
commit
11ba1a6109
@ -48,7 +48,7 @@ func (kv *kvPrefix) Put(ctx context.Context, key, val string, opts ...clientv3.O
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (kv *kvPrefix) Get(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) {
|
func (kv *kvPrefix) Get(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 && !(clientv3.IsOptsWithFromKey(opts) || clientv3.IsOptsWithPrefix(opts)) {
|
||||||
return nil, rpctypes.ErrEmptyKey
|
return nil, rpctypes.ErrEmptyKey
|
||||||
}
|
}
|
||||||
r, err := kv.KV.Do(ctx, kv.prefixOp(clientv3.OpGet(key, opts...)))
|
r, err := kv.KV.Do(ctx, kv.prefixOp(clientv3.OpGet(key, opts...)))
|
||||||
@ -61,7 +61,7 @@ func (kv *kvPrefix) Get(ctx context.Context, key string, opts ...clientv3.OpOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (kv *kvPrefix) Delete(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.DeleteResponse, error) {
|
func (kv *kvPrefix) Delete(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.DeleteResponse, error) {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 && !(clientv3.IsOptsWithFromKey(opts) || clientv3.IsOptsWithPrefix(opts)) {
|
||||||
return nil, rpctypes.ErrEmptyKey
|
return nil, rpctypes.ErrEmptyKey
|
||||||
}
|
}
|
||||||
r, err := kv.KV.Do(ctx, kv.prefixOp(clientv3.OpDelete(key, opts...)))
|
r, err := kv.KV.Do(ctx, kv.prefixOp(clientv3.OpDelete(key, opts...)))
|
||||||
|
@ -219,7 +219,7 @@ func (op Op) isWrite() bool {
|
|||||||
// OpGet returns "get" operation based on given key and operation options.
|
// OpGet returns "get" operation based on given key and operation options.
|
||||||
func OpGet(key string, opts ...OpOption) Op {
|
func OpGet(key string, opts ...OpOption) Op {
|
||||||
// WithPrefix and WithFromKey are not supported together
|
// WithPrefix and WithFromKey are not supported together
|
||||||
if isWithPrefix(opts) && isWithFromKey(opts) {
|
if IsOptsWithPrefix(opts) && IsOptsWithFromKey(opts) {
|
||||||
panic("`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one")
|
panic("`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one")
|
||||||
}
|
}
|
||||||
ret := Op{t: tRange, key: []byte(key)}
|
ret := Op{t: tRange, key: []byte(key)}
|
||||||
@ -230,7 +230,7 @@ func OpGet(key string, opts ...OpOption) Op {
|
|||||||
// OpDelete returns "delete" operation based on given key and operation options.
|
// OpDelete returns "delete" operation based on given key and operation options.
|
||||||
func OpDelete(key string, opts ...OpOption) Op {
|
func OpDelete(key string, opts ...OpOption) Op {
|
||||||
// WithPrefix and WithFromKey are not supported together
|
// WithPrefix and WithFromKey are not supported together
|
||||||
if isWithPrefix(opts) && isWithFromKey(opts) {
|
if IsOptsWithPrefix(opts) && IsOptsWithFromKey(opts) {
|
||||||
panic("`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one")
|
panic("`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one")
|
||||||
}
|
}
|
||||||
ret := Op{t: tDeleteRange, key: []byte(key)}
|
ret := Op{t: tDeleteRange, key: []byte(key)}
|
||||||
@ -553,8 +553,8 @@ func toLeaseTimeToLiveRequest(id LeaseID, opts ...LeaseOption) *pb.LeaseTimeToLi
|
|||||||
return &pb.LeaseTimeToLiveRequest{ID: int64(id), Keys: ret.attachedKeys}
|
return &pb.LeaseTimeToLiveRequest{ID: int64(id), Keys: ret.attachedKeys}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isWithPrefix returns true if WithPrefix is being called in the op
|
// IsOptsWithPrefix returns true if WithPrefix option is called in the given opts.
|
||||||
func isWithPrefix(opts []OpOption) bool { return isOpFuncCalled("WithPrefix", opts) }
|
func IsOptsWithPrefix(opts []OpOption) bool { return isOpFuncCalled("WithPrefix", opts) }
|
||||||
|
|
||||||
// isWithFromKey returns true if WithFromKey is being called in the op
|
// IsOptsWithFromKey returns true if WithFromKey option is called in the given opts.
|
||||||
func isWithFromKey(opts []OpOption) bool { return isOpFuncCalled("WithFromKey", opts) }
|
func IsOptsWithFromKey(opts []OpOption) bool { return isOpFuncCalled("WithFromKey", opts) }
|
||||||
|
88
integration/v3_kv_test.go
Normal file
88
integration/v3_kv_test.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"go.etcd.io/etcd/v3/clientv3"
|
||||||
|
"go.etcd.io/etcd/v3/clientv3/namespace"
|
||||||
|
"go.etcd.io/etcd/v3/embed"
|
||||||
|
"go.etcd.io/etcd/v3/etcdserver/api/v3client"
|
||||||
|
"go.etcd.io/etcd/v3/pkg/testutil"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestKVWithEmptyValue ensures that a get/delete with an empty value, and with WithFromKey/WithPrefix function will return an empty error.
|
||||||
|
func TestKVWithEmptyValue(t *testing.T) {
|
||||||
|
defer testutil.AfterTest(t)
|
||||||
|
|
||||||
|
cfg := embed.NewConfig()
|
||||||
|
|
||||||
|
// Use temporary data directory.
|
||||||
|
dir, err := ioutil.TempDir("", "etcd-")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
cfg.Dir = dir
|
||||||
|
|
||||||
|
// Suppress server log to keep output clean.
|
||||||
|
//cfg.Logger = "zap"
|
||||||
|
//cfg.LogLevel = "error"
|
||||||
|
|
||||||
|
etcd, err := embed.StartEtcd(cfg)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer etcd.Close()
|
||||||
|
<-etcd.Server.ReadyNotify()
|
||||||
|
|
||||||
|
client := v3client.New(etcd.Server)
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
_, err = client.Put(context.Background(), "my-namespace/foobar", "data")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = client.Put(context.Background(), "my-namespace/foobar1", "data")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = client.Put(context.Background(), "namespace/foobar1", "data")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range over all keys.
|
||||||
|
resp, err := client.Get(context.Background(), "", clientv3.WithFromKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, kv := range resp.Kvs {
|
||||||
|
t.Log(string(kv.Key), "=", string(kv.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range over all keys in a namespace.
|
||||||
|
client.KV = namespace.NewKV(client.KV, "my-namespace/")
|
||||||
|
resp, err = client.Get(context.Background(), "", clientv3.WithFromKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, kv := range resp.Kvs {
|
||||||
|
t.Log(string(kv.Key), "=", string(kv.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove all keys without WithFromKey/WithPrefix func
|
||||||
|
respDel, err := client.Delete(context.Background(), "")
|
||||||
|
if err == nil {
|
||||||
|
// fatal error duo to without WithFromKey/WithPrefix func called.
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
respDel, err = client.Delete(context.Background(), "", clientv3.WithFromKey())
|
||||||
|
if err != nil {
|
||||||
|
// fatal error duo to with WithFromKey/WithPrefix func called.
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Logf("delete keys:%d", respDel.Deleted)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user