mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
Merge pull request #16515 from serathius/test-txn
server: Test txn checking
This commit is contained in:
commit
27633923e4
@ -22,6 +22,8 @@ import (
|
||||
|
||||
"go.uber.org/zap/zaptest"
|
||||
|
||||
"go.etcd.io/etcd/pkg/v3/traceutil"
|
||||
|
||||
"go.etcd.io/etcd/api/v3/authpb"
|
||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||
"go.etcd.io/etcd/server/v3/auth"
|
||||
@ -35,6 +37,242 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCheckTxn(t *testing.T) {
|
||||
|
||||
var futureRev int64 = 1000
|
||||
|
||||
tcs := []struct {
|
||||
name string
|
||||
compactRevision int64
|
||||
setupLease int64
|
||||
setupKey []byte
|
||||
txn *pb.TxnRequest
|
||||
|
||||
expectError string
|
||||
}{
|
||||
{
|
||||
name: "Range with revision 0 should succeed",
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestRange{
|
||||
RequestRange: &pb.RangeRequest{
|
||||
Revision: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Range on future rev should fail",
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestRange{
|
||||
RequestRange: &pb.RangeRequest{
|
||||
Revision: futureRev,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: "mvcc: required revision is a future revision",
|
||||
},
|
||||
{
|
||||
name: "Range on compacted rev should fail",
|
||||
compactRevision: 10,
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestRange{
|
||||
RequestRange: &pb.RangeRequest{
|
||||
Revision: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: "mvcc: required revision has been compacted",
|
||||
},
|
||||
{
|
||||
name: "Invalid range on Failed path should succeed",
|
||||
txn: &pb.TxnRequest{
|
||||
Failure: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestRange{
|
||||
RequestRange: &pb.RangeRequest{
|
||||
Revision: futureRev,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Invalid range subtransaction should fail",
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestTxn{
|
||||
RequestTxn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestRange{
|
||||
RequestRange: &pb.RangeRequest{
|
||||
Revision: futureRev,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: "mvcc: required revision is a future revision",
|
||||
},
|
||||
{
|
||||
name: "Put without lease should succeed",
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestPut{
|
||||
RequestPut: &pb.PutRequest{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Put with non-existing lease should fail",
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestPut{
|
||||
RequestPut: &pb.PutRequest{
|
||||
Lease: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: "lease not found",
|
||||
},
|
||||
{
|
||||
name: "Put with existing lease should succeed",
|
||||
setupLease: 123,
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestPut{
|
||||
RequestPut: &pb.PutRequest{
|
||||
Lease: 123,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Put with ignore value without previous key should fail",
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestPut{
|
||||
RequestPut: &pb.PutRequest{
|
||||
IgnoreValue: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: "etcdserver: key not found",
|
||||
},
|
||||
{
|
||||
name: "Put with ignore lease without previous key should fail",
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestPut{
|
||||
RequestPut: &pb.PutRequest{
|
||||
IgnoreLease: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectError: "etcdserver: key not found",
|
||||
},
|
||||
{
|
||||
name: "Put with ignore value with previous key should succeeded",
|
||||
setupKey: []byte("ignore-value"),
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestPut{
|
||||
RequestPut: &pb.PutRequest{
|
||||
IgnoreValue: true,
|
||||
Key: []byte("ignore-value"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Put with ignore lease with previous key should succeed ",
|
||||
setupKey: []byte("ignore-lease"),
|
||||
txn: &pb.TxnRequest{
|
||||
Success: []*pb.RequestOp{
|
||||
{
|
||||
Request: &pb.RequestOp_RequestPut{
|
||||
RequestPut: &pb.PutRequest{
|
||||
IgnoreLease: true,
|
||||
Key: []byte("ignore-lease"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
defer cancel()
|
||||
|
||||
b, _ := betesting.NewDefaultTmpBackend(t)
|
||||
defer betesting.Close(t, b)
|
||||
lessor := &lease.FakeLessor{LeaseSet: map[lease.LeaseID]struct{}{}}
|
||||
s := mvcc.NewStore(zaptest.NewLogger(t), b, lessor, mvcc.StoreConfig{})
|
||||
defer s.Close()
|
||||
|
||||
if tc.compactRevision != 0 {
|
||||
for i := 0; int64(i) < tc.compactRevision; i++ {
|
||||
s.Put([]byte("a"), []byte("b"), 0)
|
||||
}
|
||||
s.Compact(traceutil.TODO(), tc.compactRevision)
|
||||
}
|
||||
if tc.setupLease != 0 {
|
||||
lessor.Grant(lease.LeaseID(tc.setupLease), 0)
|
||||
}
|
||||
if len(tc.setupKey) != 0 {
|
||||
s.Put(tc.setupKey, []byte("b"), 0)
|
||||
}
|
||||
|
||||
_, _, err := Txn(ctx, zaptest.NewLogger(t), tc.txn, false, s, lessor)
|
||||
gotErr := ""
|
||||
if err != nil {
|
||||
gotErr = err.Error()
|
||||
}
|
||||
if gotErr != tc.expectError {
|
||||
t.Errorf("Error not matching, got %q, expected %q", gotErr, tc.expectError)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadonlyTxnError(t *testing.T) {
|
||||
b, _ := betesting.NewDefaultTmpBackend(t)
|
||||
defer betesting.Close(t, b)
|
||||
|
@ -816,13 +816,18 @@ func (le *lessor) initAndRecover() {
|
||||
|
||||
// FakeLessor is a fake implementation of Lessor interface.
|
||||
// Used for testing only.
|
||||
type FakeLessor struct{}
|
||||
type FakeLessor struct {
|
||||
LeaseSet map[LeaseID]struct{}
|
||||
}
|
||||
|
||||
func (fl *FakeLessor) SetRangeDeleter(dr RangeDeleter) {}
|
||||
|
||||
func (fl *FakeLessor) SetCheckpointer(cp Checkpointer) {}
|
||||
|
||||
func (fl *FakeLessor) Grant(id LeaseID, ttl int64) (*Lease, error) { return nil, nil }
|
||||
func (fl *FakeLessor) Grant(id LeaseID, ttl int64) (*Lease, error) {
|
||||
fl.LeaseSet[id] = struct{}{}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (fl *FakeLessor) Revoke(id LeaseID) error { return nil }
|
||||
|
||||
@ -839,7 +844,12 @@ func (fl *FakeLessor) Demote() {}
|
||||
|
||||
func (fl *FakeLessor) Renew(id LeaseID) (int64, error) { return 10, nil }
|
||||
|
||||
func (fl *FakeLessor) Lookup(id LeaseID) *Lease { return nil }
|
||||
func (fl *FakeLessor) Lookup(id LeaseID) *Lease {
|
||||
if _, ok := fl.LeaseSet[id]; ok {
|
||||
return &Lease{ID: id}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fl *FakeLessor) Leases() []*Lease { return nil }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user