etcdserver: fix nil pointer panic for readonly txn
Backporting https://github.com/etcd-io/etcd/pull/14895 Signed-off-by: Benjamin Wang <wachao@vmware.com>
This commit is contained in:
@ -20,7 +20,9 @@ import (
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zaptest"
|
||||
|
||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||
"go.etcd.io/etcd/client/pkg/v3/types"
|
||||
"go.etcd.io/etcd/raft/v3/raftpb"
|
||||
"go.etcd.io/etcd/server/v3/etcdserver/api/membership"
|
||||
@ -110,3 +112,105 @@ type testStringerFunc func() string
|
||||
func (s testStringerFunc) String() string {
|
||||
return s()
|
||||
}
|
||||
|
||||
// TestWarnOfExpensiveReadOnlyTxnRequest verifies WarnOfExpensiveReadOnlyTxnRequest
|
||||
// never panic no matter what data the txnResponse contains.
|
||||
func TestWarnOfExpensiveReadOnlyTxnRequest(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
txnResp *pb.TxnResponse
|
||||
}{
|
||||
{
|
||||
name: "all readonly responses",
|
||||
txnResp: &pb.TxnResponse{
|
||||
Responses: []*pb.ResponseOp{
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseRange{
|
||||
ResponseRange: &pb.RangeResponse{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseRange{
|
||||
ResponseRange: &pb.RangeResponse{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all readonly responses with partial nil responses",
|
||||
txnResp: &pb.TxnResponse{
|
||||
Responses: []*pb.ResponseOp{
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseRange{
|
||||
ResponseRange: &pb.RangeResponse{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseRange{
|
||||
ResponseRange: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all readonly responses with all nil responses",
|
||||
txnResp: &pb.TxnResponse{
|
||||
Responses: []*pb.ResponseOp{
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseRange{
|
||||
ResponseRange: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseRange{
|
||||
ResponseRange: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "partial non readonly responses",
|
||||
txnResp: &pb.TxnResponse{
|
||||
Responses: []*pb.ResponseOp{
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseRange{
|
||||
ResponseRange: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponsePut{},
|
||||
},
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseDeleteRange{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all non readonly responses",
|
||||
txnResp: &pb.TxnResponse{
|
||||
Responses: []*pb.ResponseOp{
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponsePut{},
|
||||
},
|
||||
{
|
||||
Response: &pb.ResponseOp_ResponseDeleteRange{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
lg := zaptest.NewLogger(t)
|
||||
start := time.Now().Add(-1 * time.Second)
|
||||
// WarnOfExpensiveReadOnlyTxnRequest shouldn't panic.
|
||||
warnOfExpensiveReadOnlyTxnRequest(lg, 0, start, &pb.TxnRequest{}, tc.txnResp, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user