github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvclient/kvcoord/transport_test.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package kvcoord 12 13 import ( 14 "context" 15 "fmt" 16 "testing" 17 18 "github.com/cockroachdb/cockroach/pkg/roachpb" 19 "github.com/cockroachdb/cockroach/pkg/testutils" 20 "github.com/cockroachdb/cockroach/pkg/util/caller" 21 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 22 "github.com/cockroachdb/cockroach/pkg/util/log" 23 "github.com/cockroachdb/cockroach/pkg/util/tracing" 24 opentracing "github.com/opentracing/opentracing-go" 25 "google.golang.org/grpc" 26 ) 27 28 func TestTransportMoveToFront(t *testing.T) { 29 defer leaktest.AfterTest(t)() 30 rd1 := roachpb.ReplicaDescriptor{NodeID: 1, StoreID: 1, ReplicaID: 1} 31 rd2 := roachpb.ReplicaDescriptor{NodeID: 2, StoreID: 2, ReplicaID: 2} 32 rd3 := roachpb.ReplicaDescriptor{NodeID: 3, StoreID: 3, ReplicaID: 3} 33 clients := []batchClient{ 34 {replica: rd1}, 35 {replica: rd2}, 36 {replica: rd3}, 37 } 38 gt := grpcTransport{orderedClients: clients} 39 40 verifyOrder := func(replicas []roachpb.ReplicaDescriptor) { 41 file, line, _ := caller.Lookup(1) 42 for i, bc := range gt.orderedClients { 43 if bc.replica != replicas[i] { 44 t.Fatalf("%s:%d: expected order %+v; got mismatch at index %d: %+v", 45 file, line, replicas, i, bc.replica) 46 } 47 } 48 } 49 50 verifyOrder([]roachpb.ReplicaDescriptor{rd1, rd2, rd3}) 51 52 // Move replica 2 to the front. 53 gt.MoveToFront(rd2) 54 verifyOrder([]roachpb.ReplicaDescriptor{rd2, rd1, rd3}) 55 56 // Now replica 3. 57 gt.MoveToFront(rd3) 58 verifyOrder([]roachpb.ReplicaDescriptor{rd3, rd1, rd2}) 59 60 // Advance the client index and move replica 3 back to front. 61 gt.clientIndex++ 62 gt.MoveToFront(rd3) 63 verifyOrder([]roachpb.ReplicaDescriptor{rd3, rd1, rd2}) 64 if gt.clientIndex != 0 { 65 t.Fatalf("expected client index 0; got %d", gt.clientIndex) 66 } 67 68 // Advance the client index again and verify replica 3 can 69 // be moved to front for a second retry. 70 gt.clientIndex++ 71 gt.MoveToFront(rd3) 72 verifyOrder([]roachpb.ReplicaDescriptor{rd3, rd1, rd2}) 73 if gt.clientIndex != 0 { 74 t.Fatalf("expected client index 0; got %d", gt.clientIndex) 75 } 76 77 // Move replica 2 to the front. 78 gt.MoveToFront(rd2) 79 verifyOrder([]roachpb.ReplicaDescriptor{rd2, rd1, rd3}) 80 81 // Advance client index and move rd1 front; should be no change. 82 gt.clientIndex++ 83 gt.MoveToFront(rd1) 84 verifyOrder([]roachpb.ReplicaDescriptor{rd2, rd1, rd3}) 85 86 // Advance client index and and move rd1 to front. Should move 87 // client index back for a retry. 88 gt.clientIndex++ 89 gt.MoveToFront(rd1) 90 verifyOrder([]roachpb.ReplicaDescriptor{rd2, rd1, rd3}) 91 if gt.clientIndex != 1 { 92 t.Fatalf("expected client index 1; got %d", gt.clientIndex) 93 } 94 95 // Advance client index once more; verify second retry. 96 gt.clientIndex++ 97 gt.MoveToFront(rd2) 98 verifyOrder([]roachpb.ReplicaDescriptor{rd1, rd2, rd3}) 99 if gt.clientIndex != 1 { 100 t.Fatalf("expected client index 1; got %d", gt.clientIndex) 101 } 102 } 103 104 // TestSpanImport tests that the gRPC transport ingests trace information that 105 // came from gRPC responses (through the "snowball tracing" mechanism). 106 func TestSpanImport(t *testing.T) { 107 defer leaktest.AfterTest(t)() 108 ctx := context.Background() 109 metrics := makeDistSenderMetrics() 110 gt := grpcTransport{ 111 opts: SendOptions{ 112 metrics: &metrics, 113 }, 114 } 115 server := mockInternalClient{} 116 // Let's spice things up and simulate an error from the server. 117 expectedErr := "my expected error" 118 server.pErr = roachpb.NewErrorf(expectedErr /* nolint:fmtsafe */) 119 120 recCtx, getRec, cancel := tracing.ContextWithRecordingSpan(ctx, "test") 121 defer cancel() 122 123 server.tr = opentracing.SpanFromContext(recCtx).Tracer().(*tracing.Tracer) 124 125 br, err := gt.sendBatch(recCtx, roachpb.NodeID(1), &server, roachpb.BatchRequest{}) 126 if err != nil { 127 t.Fatal(err) 128 } 129 if !testutils.IsPError(br.Error, expectedErr) { 130 t.Fatalf("expected err: %s, got: %q", expectedErr, br.Error) 131 } 132 expectedMsg := "mockInternalClient processing batch" 133 if tracing.FindMsgInRecording(getRec(), expectedMsg) == -1 { 134 t.Fatalf("didn't find expected message in trace: %s", expectedMsg) 135 } 136 } 137 138 // mockInternalClient is an implementation of roachpb.InternalClient. 139 // It simulates aspects of how the Node normally handles tracing in gRPC calls. 140 type mockInternalClient struct { 141 tr *tracing.Tracer 142 pErr *roachpb.Error 143 } 144 145 var _ roachpb.InternalClient = &mockInternalClient{} 146 147 // Batch is part of the roachpb.InternalClient interface. 148 func (m *mockInternalClient) Batch( 149 ctx context.Context, in *roachpb.BatchRequest, opts ...grpc.CallOption, 150 ) (*roachpb.BatchResponse, error) { 151 sp := m.tr.StartRootSpan("mock", nil /* logTags */, tracing.RecordableSpan) 152 defer sp.Finish() 153 tracing.StartRecording(sp, tracing.SnowballRecording) 154 ctx = opentracing.ContextWithSpan(ctx, sp) 155 156 log.Eventf(ctx, "mockInternalClient processing batch") 157 br := &roachpb.BatchResponse{} 158 br.Error = m.pErr 159 if rec := tracing.GetRecording(sp); rec != nil { 160 br.CollectedSpans = append(br.CollectedSpans, rec...) 161 } 162 return br, nil 163 } 164 165 // RangeFeed is part of the roachpb.InternalClient interface. 166 func (m *mockInternalClient) RangeFeed( 167 ctx context.Context, in *roachpb.RangeFeedRequest, opts ...grpc.CallOption, 168 ) (roachpb.Internal_RangeFeedClient, error) { 169 return nil, fmt.Errorf("unsupported RangeFeed call") 170 }