mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
156 lines
4.8 KiB
Go
156 lines
4.8 KiB
Go
// 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 common
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
|
clientv3 "go.etcd.io/etcd/client/v3"
|
|
"go.etcd.io/etcd/tests/v3/framework/config"
|
|
"go.etcd.io/etcd/tests/v3/framework/testutils"
|
|
)
|
|
|
|
type txnReq struct {
|
|
compare []string
|
|
ifSuccess []string
|
|
ifFail []string
|
|
results []string
|
|
}
|
|
|
|
func TestTxnSucc(t *testing.T) {
|
|
testRunner.BeforeTest(t)
|
|
reqs := []txnReq{
|
|
{
|
|
compare: []string{`value("key1") != "value2"`, `value("key2") != "value1"`},
|
|
ifSuccess: []string{"get key1", "get key2"},
|
|
results: []string{"SUCCESS", "key1", "value1", "key2", "value2"},
|
|
},
|
|
{
|
|
compare: []string{`version("key1") = "1"`, `version("key2") = "1"`},
|
|
ifSuccess: []string{"get key1", "get key2", `put "key \"with\" space" "value \x23"`},
|
|
ifFail: []string{`put key1 "fail"`, `put key2 "fail"`},
|
|
results: []string{"SUCCESS", "key1", "value1", "key2", "value2", "OK"},
|
|
},
|
|
{
|
|
compare: []string{`version("key \"with\" space") = "1"`},
|
|
ifSuccess: []string{`get "key \"with\" space"`},
|
|
results: []string{"SUCCESS", `key "with" space`, "value \x23"},
|
|
},
|
|
}
|
|
for _, cfg := range clusterTestCases() {
|
|
t.Run(cfg.name, func(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
clus := testRunner.NewCluster(ctx, t, config.WithClusterConfig(cfg.config))
|
|
defer clus.Close()
|
|
cc := testutils.MustClient(clus.Client())
|
|
testutils.ExecuteUntil(ctx, t, func() {
|
|
if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil {
|
|
t.Fatalf("could not create key:%s, value:%s", "key1", "value1")
|
|
}
|
|
if err := cc.Put(ctx, "key2", "value2", config.PutOptions{}); err != nil {
|
|
t.Fatalf("could not create key:%s, value:%s", "key2", "value2")
|
|
}
|
|
for _, req := range reqs {
|
|
resp, err := cc.Txn(ctx, req.compare, req.ifSuccess, req.ifFail, config.TxnOptions{
|
|
Interactive: true,
|
|
})
|
|
if err != nil {
|
|
t.Errorf("Txn returned error: %s", err)
|
|
}
|
|
assert.Equal(t, req.results, getRespValues(resp))
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTxnFail(t *testing.T) {
|
|
testRunner.BeforeTest(t)
|
|
reqs := []txnReq{
|
|
{
|
|
compare: []string{`version("key") < "0"`},
|
|
ifSuccess: []string{`put key "success"`},
|
|
ifFail: []string{`put key "fail"`},
|
|
results: []string{"FAILURE", "OK"},
|
|
},
|
|
{
|
|
compare: []string{`value("key1") != "value1"`},
|
|
ifSuccess: []string{`put key1 "success"`},
|
|
ifFail: []string{`put key1 "fail"`},
|
|
results: []string{"FAILURE", "OK"},
|
|
},
|
|
}
|
|
for _, cfg := range clusterTestCases() {
|
|
t.Run(cfg.name, func(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
clus := testRunner.NewCluster(ctx, t, config.WithClusterConfig(cfg.config))
|
|
defer clus.Close()
|
|
cc := testutils.MustClient(clus.Client())
|
|
testutils.ExecuteUntil(ctx, t, func() {
|
|
if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil {
|
|
t.Fatalf("could not create key:%s, value:%s", "key1", "value1")
|
|
}
|
|
for _, req := range reqs {
|
|
resp, err := cc.Txn(ctx, req.compare, req.ifSuccess, req.ifFail, config.TxnOptions{
|
|
Interactive: true,
|
|
})
|
|
if err != nil {
|
|
t.Errorf("Txn returned error: %s", err)
|
|
}
|
|
assert.Equal(t, req.results, getRespValues(resp))
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func getRespValues(r *clientv3.TxnResponse) []string {
|
|
var ss []string
|
|
if r.Succeeded {
|
|
ss = append(ss, "SUCCESS")
|
|
} else {
|
|
ss = append(ss, "FAILURE")
|
|
}
|
|
for _, resp := range r.Responses {
|
|
switch v := resp.Response.(type) {
|
|
case *pb.ResponseOp_ResponseDeleteRange:
|
|
r := (clientv3.DeleteResponse)(*v.ResponseDeleteRange)
|
|
ss = append(ss, fmt.Sprintf("%d", r.Deleted))
|
|
case *pb.ResponseOp_ResponsePut:
|
|
r := (clientv3.PutResponse)(*v.ResponsePut)
|
|
ss = append(ss, "OK")
|
|
if r.PrevKv != nil {
|
|
ss = append(ss, string(r.PrevKv.Key), string(r.PrevKv.Value))
|
|
}
|
|
case *pb.ResponseOp_ResponseRange:
|
|
r := (clientv3.GetResponse)(*v.ResponseRange)
|
|
for _, kv := range r.Kvs {
|
|
ss = append(ss, string(kv.Key), string(kv.Value))
|
|
}
|
|
default:
|
|
ss = append(ss, fmt.Sprintf("\"Unknown\" : %q\n", fmt.Sprintf("%+v", v)))
|
|
}
|
|
}
|
|
return ss
|
|
}
|