github.com/lfch/etcd-io/tests/v3@v3.0.0-20221004140520-eac99acd3e9d/common/txn_test.go (about) 1 // Copyright 2022 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package common 16 17 import ( 18 "context" 19 "fmt" 20 "testing" 21 "time" 22 23 pb "github.com/lfch/etcd-io/api/v3/etcdserverpb" 24 clientv3 "github.com/lfch/etcd-io/client/v3" 25 "github.com/lfch/etcd-io/tests/v3/framework" 26 "github.com/lfch/etcd-io/tests/v3/framework/config" 27 "github.com/lfch/etcd-io/tests/v3/framework/testutils" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 type txnReq struct { 32 compare []string 33 ifSucess []string 34 ifFail []string 35 results []string 36 } 37 38 func TestTxnSucc(t *testing.T) { 39 testRunner.BeforeTest(t) 40 reqs := []txnReq{ 41 { 42 compare: []string{`value("key1") != "value2"`, `value("key2") != "value1"`}, 43 ifSucess: []string{"get key1", "get key2"}, 44 results: []string{"SUCCESS", "key1", "value1", "key2", "value2"}, 45 }, 46 { 47 compare: []string{`version("key1") = "1"`, `version("key2") = "1"`}, 48 ifSucess: []string{"get key1", "get key2", `put "key \"with\" space" "value \x23"`}, 49 ifFail: []string{`put key1 "fail"`, `put key2 "fail"`}, 50 results: []string{"SUCCESS", "key1", "value1", "key2", "value2", "OK"}, 51 }, 52 { 53 compare: []string{`version("key \"with\" space") = "1"`}, 54 ifSucess: []string{`get "key \"with\" space"`}, 55 results: []string{"SUCCESS", `key "with" space`, "value \x23"}, 56 }, 57 } 58 for _, cfg := range clusterTestCases { 59 t.Run(cfg.name, func(t *testing.T) { 60 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 61 defer cancel() 62 clus := testRunner.NewCluster(ctx, t, cfg.config) 63 defer clus.Close() 64 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 65 testutils.ExecuteUntil(ctx, t, func() { 66 if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil { 67 t.Fatalf("could not create key:%s, value:%s", "key1", "value1") 68 } 69 if err := cc.Put(ctx, "key2", "value2", config.PutOptions{}); err != nil { 70 t.Fatalf("could not create key:%s, value:%s", "key2", "value2") 71 } 72 for _, req := range reqs { 73 resp, err := cc.Txn(ctx, req.compare, req.ifSucess, req.ifFail, config.TxnOptions{ 74 Interactive: true, 75 }) 76 if err != nil { 77 t.Errorf("Txn returned error: %s", err) 78 } 79 assert.Equal(t, req.results, getRespValues(resp)) 80 } 81 }) 82 }) 83 } 84 } 85 86 func TestTxnFail(t *testing.T) { 87 testRunner.BeforeTest(t) 88 reqs := []txnReq{ 89 { 90 compare: []string{`version("key") < "0"`}, 91 ifSucess: []string{`put key "success"`}, 92 ifFail: []string{`put key "fail"`}, 93 results: []string{"FAILURE", "OK"}, 94 }, 95 { 96 compare: []string{`value("key1") != "value1"`}, 97 ifSucess: []string{`put key1 "success"`}, 98 ifFail: []string{`put key1 "fail"`}, 99 results: []string{"FAILURE", "OK"}, 100 }, 101 } 102 for _, cfg := range clusterTestCases { 103 t.Run(cfg.name, func(t *testing.T) { 104 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 105 defer cancel() 106 clus := testRunner.NewCluster(ctx, t, cfg.config) 107 defer clus.Close() 108 cc := framework.MustClient(clus.Client(clientv3.AuthConfig{})) 109 testutils.ExecuteUntil(ctx, t, func() { 110 if err := cc.Put(ctx, "key1", "value1", config.PutOptions{}); err != nil { 111 t.Fatalf("could not create key:%s, value:%s", "key1", "value1") 112 } 113 for _, req := range reqs { 114 resp, err := cc.Txn(ctx, req.compare, req.ifSucess, req.ifFail, config.TxnOptions{ 115 Interactive: true, 116 }) 117 if err != nil { 118 t.Errorf("Txn returned error: %s", err) 119 } 120 assert.Equal(t, req.results, getRespValues(resp)) 121 } 122 }) 123 }) 124 } 125 } 126 127 func getRespValues(r *clientv3.TxnResponse) []string { 128 var ss []string 129 if r.Succeeded { 130 ss = append(ss, "SUCCESS") 131 } else { 132 ss = append(ss, "FAILURE") 133 } 134 for _, resp := range r.Responses { 135 switch v := resp.Response.(type) { 136 case *pb.ResponseOp_ResponseDeleteRange: 137 r := (clientv3.DeleteResponse)(*v.ResponseDeleteRange) 138 ss = append(ss, fmt.Sprintf("%d", r.Deleted)) 139 case *pb.ResponseOp_ResponsePut: 140 r := (clientv3.PutResponse)(*v.ResponsePut) 141 ss = append(ss, "OK") 142 if r.PrevKv != nil { 143 ss = append(ss, string(r.PrevKv.Key), string(r.PrevKv.Value)) 144 } 145 case *pb.ResponseOp_ResponseRange: 146 r := (clientv3.GetResponse)(*v.ResponseRange) 147 for _, kv := range r.Kvs { 148 ss = append(ss, string(kv.Key), string(kv.Value)) 149 } 150 default: 151 ss = append(ss, fmt.Sprintf("\"Unknown\" : %q\n", fmt.Sprintf("%+v", v))) 152 } 153 } 154 return ss 155 }