...

Source file src/go.etcd.io/etcd/server/v3/etcdserver/util_test.go

Documentation: go.etcd.io/etcd/server/v3/etcdserver

     1  // Copyright 2016 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 etcdserver
    16  
    17  import (
    18  	"net/http"
    19  	"testing"
    20  	"time"
    21  
    22  	"go.uber.org/zap"
    23  	"go.uber.org/zap/zaptest"
    24  
    25  	pb "go.etcd.io/etcd/api/v3/etcdserverpb"
    26  	"go.etcd.io/etcd/client/pkg/v3/types"
    27  	"go.etcd.io/etcd/raft/v3/raftpb"
    28  	"go.etcd.io/etcd/server/v3/etcdserver/api/membership"
    29  	"go.etcd.io/etcd/server/v3/etcdserver/api/rafthttp"
    30  	"go.etcd.io/etcd/server/v3/etcdserver/api/snap"
    31  )
    32  
    33  func TestLongestConnected(t *testing.T) {
    34  	umap, err := types.NewURLsMap("mem1=http://10.1:2379,mem2=http://10.2:2379,mem3=http://10.3:2379")
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	clus, err := membership.NewClusterFromURLsMap(zap.NewExample(), "test", umap)
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	memberIDs := clus.MemberIDs()
    43  
    44  	tr := newNopTransporterWithActiveTime(memberIDs)
    45  	transferee, ok := longestConnected(tr, memberIDs)
    46  	if !ok {
    47  		t.Fatalf("unexpected ok %v", ok)
    48  	}
    49  	if memberIDs[0] != transferee {
    50  		t.Fatalf("expected first member %s to be transferee, got %s", memberIDs[0], transferee)
    51  	}
    52  
    53  	// make all members non-active
    54  	amap := make(map[types.ID]time.Time)
    55  	for _, id := range memberIDs {
    56  		amap[id] = time.Time{}
    57  	}
    58  	tr.(*nopTransporterWithActiveTime).reset(amap)
    59  
    60  	_, ok2 := longestConnected(tr, memberIDs)
    61  	if ok2 {
    62  		t.Fatalf("unexpected ok %v", ok)
    63  	}
    64  }
    65  
    66  type nopTransporterWithActiveTime struct {
    67  	activeMap map[types.ID]time.Time
    68  }
    69  
    70  // newNopTransporterWithActiveTime creates nopTransporterWithActiveTime with the first member
    71  // being the most stable (longest active-since time).
    72  func newNopTransporterWithActiveTime(memberIDs []types.ID) rafthttp.Transporter {
    73  	am := make(map[types.ID]time.Time)
    74  	for i, id := range memberIDs {
    75  		am[id] = time.Now().Add(time.Duration(i) * time.Second)
    76  	}
    77  	return &nopTransporterWithActiveTime{activeMap: am}
    78  }
    79  
    80  func (s *nopTransporterWithActiveTime) Start() error                        { return nil }
    81  func (s *nopTransporterWithActiveTime) Handler() http.Handler               { return nil }
    82  func (s *nopTransporterWithActiveTime) Send(m []raftpb.Message)             {}
    83  func (s *nopTransporterWithActiveTime) SendSnapshot(m snap.Message)         {}
    84  func (s *nopTransporterWithActiveTime) AddRemote(id types.ID, us []string)  {}
    85  func (s *nopTransporterWithActiveTime) AddPeer(id types.ID, us []string)    {}
    86  func (s *nopTransporterWithActiveTime) RemovePeer(id types.ID)              {}
    87  func (s *nopTransporterWithActiveTime) RemoveAllPeers()                     {}
    88  func (s *nopTransporterWithActiveTime) UpdatePeer(id types.ID, us []string) {}
    89  func (s *nopTransporterWithActiveTime) ActiveSince(id types.ID) time.Time   { return s.activeMap[id] }
    90  func (s *nopTransporterWithActiveTime) ActivePeers() int                    { return 0 }
    91  func (s *nopTransporterWithActiveTime) Stop()                               {}
    92  func (s *nopTransporterWithActiveTime) Pause()                              {}
    93  func (s *nopTransporterWithActiveTime) Resume()                             {}
    94  func (s *nopTransporterWithActiveTime) reset(am map[types.ID]time.Time)     { s.activeMap = am }
    95  
    96  func TestPanicAlternativeStringer(t *testing.T) {
    97  	p := panicAlternativeStringer{alternative: func() string { return "alternative" }}
    98  
    99  	p.stringer = testStringerFunc(func() string { panic("here") })
   100  	if s := p.String(); s != "alternative" {
   101  		t.Fatalf("expected 'alternative', got %q", s)
   102  	}
   103  
   104  	p.stringer = testStringerFunc(func() string { return "test" })
   105  	if s := p.String(); s != "test" {
   106  		t.Fatalf("expected 'test', got %q", s)
   107  	}
   108  }
   109  
   110  type testStringerFunc func() string
   111  
   112  func (s testStringerFunc) String() string {
   113  	return s()
   114  }
   115  
   116  // TestWarnOfExpensiveReadOnlyTxnRequest verifies WarnOfExpensiveReadOnlyTxnRequest
   117  // never panic no matter what data the txnResponse contains.
   118  func TestWarnOfExpensiveReadOnlyTxnRequest(t *testing.T) {
   119  	testCases := []struct {
   120  		name    string
   121  		txnResp *pb.TxnResponse
   122  	}{
   123  		{
   124  			name: "all readonly responses",
   125  			txnResp: &pb.TxnResponse{
   126  				Responses: []*pb.ResponseOp{
   127  					{
   128  						Response: &pb.ResponseOp_ResponseRange{
   129  							ResponseRange: &pb.RangeResponse{},
   130  						},
   131  					},
   132  					{
   133  						Response: &pb.ResponseOp_ResponseRange{
   134  							ResponseRange: &pb.RangeResponse{},
   135  						},
   136  					},
   137  				},
   138  			},
   139  		},
   140  		{
   141  			name: "all readonly responses with partial nil responses",
   142  			txnResp: &pb.TxnResponse{
   143  				Responses: []*pb.ResponseOp{
   144  					{
   145  						Response: &pb.ResponseOp_ResponseRange{
   146  							ResponseRange: &pb.RangeResponse{},
   147  						},
   148  					},
   149  					{
   150  						Response: &pb.ResponseOp_ResponseRange{
   151  							ResponseRange: nil,
   152  						},
   153  					},
   154  				},
   155  			},
   156  		},
   157  		{
   158  			name: "all readonly responses with all nil responses",
   159  			txnResp: &pb.TxnResponse{
   160  				Responses: []*pb.ResponseOp{
   161  					{
   162  						Response: &pb.ResponseOp_ResponseRange{
   163  							ResponseRange: nil,
   164  						},
   165  					},
   166  					{
   167  						Response: &pb.ResponseOp_ResponseRange{
   168  							ResponseRange: nil,
   169  						},
   170  					},
   171  				},
   172  			},
   173  		},
   174  		{
   175  			name: "partial non readonly responses",
   176  			txnResp: &pb.TxnResponse{
   177  				Responses: []*pb.ResponseOp{
   178  					{
   179  						Response: &pb.ResponseOp_ResponseRange{
   180  							ResponseRange: nil,
   181  						},
   182  					},
   183  					{
   184  						Response: &pb.ResponseOp_ResponsePut{},
   185  					},
   186  					{
   187  						Response: &pb.ResponseOp_ResponseDeleteRange{},
   188  					},
   189  				},
   190  			},
   191  		},
   192  		{
   193  			name: "all non readonly responses",
   194  			txnResp: &pb.TxnResponse{
   195  				Responses: []*pb.ResponseOp{
   196  					{
   197  						Response: &pb.ResponseOp_ResponsePut{},
   198  					},
   199  					{
   200  						Response: &pb.ResponseOp_ResponseDeleteRange{},
   201  					},
   202  				},
   203  			},
   204  		},
   205  	}
   206  
   207  	for _, tc := range testCases {
   208  		tc := tc
   209  		t.Run(tc.name, func(t *testing.T) {
   210  			lg := zaptest.NewLogger(t)
   211  			start := time.Now().Add(-1 * time.Second)
   212  			// WarnOfExpensiveReadOnlyTxnRequest shouldn't panic.
   213  			warnOfExpensiveReadOnlyTxnRequest(lg, 0, start, &pb.TxnRequest{}, tc.txnResp, nil)
   214  		})
   215  	}
   216  }
   217  

View as plain text