github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/execinfrapb/testutils.go (about) 1 // Copyright 2019 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 execinfrapb 12 13 import ( 14 "context" 15 "net" 16 "time" 17 18 "github.com/cockroachdb/cockroach/pkg/base" 19 "github.com/cockroachdb/cockroach/pkg/roachpb" 20 "github.com/cockroachdb/cockroach/pkg/rpc" 21 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 22 "github.com/cockroachdb/cockroach/pkg/util" 23 "github.com/cockroachdb/cockroach/pkg/util/hlc" 24 "github.com/cockroachdb/cockroach/pkg/util/log" 25 "github.com/cockroachdb/cockroach/pkg/util/netutil" 26 "github.com/cockroachdb/cockroach/pkg/util/stop" 27 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 28 "github.com/cockroachdb/cockroach/pkg/util/tracing" 29 "github.com/cockroachdb/cockroach/pkg/util/uuid" 30 "google.golang.org/grpc" 31 ) 32 33 // CallbackMetadataSource is a utility struct that implements the MetadataSource 34 // interface by calling a provided callback. 35 type CallbackMetadataSource struct { 36 DrainMetaCb func(context.Context) []ProducerMetadata 37 } 38 39 // DrainMeta is part of the MetadataSource interface. 40 func (s CallbackMetadataSource) DrainMeta(ctx context.Context) []ProducerMetadata { 41 return s.DrainMetaCb(ctx) 42 } 43 44 func newInsecureRPCContext(stopper *stop.Stopper) *rpc.Context { 45 return rpc.NewContext( 46 log.AmbientContext{Tracer: tracing.NewTracer()}, 47 &base.Config{Insecure: true}, 48 hlc.NewClock(hlc.UnixNano, time.Nanosecond), 49 stopper, 50 cluster.MakeTestingClusterSettings(), 51 ) 52 } 53 54 // StartMockDistSQLServer starts a MockDistSQLServer and returns the address on 55 // which it's listening. 56 func StartMockDistSQLServer( 57 clock *hlc.Clock, stopper *stop.Stopper, nodeID roachpb.NodeID, 58 ) (uuid.UUID, *MockDistSQLServer, net.Addr, error) { 59 rpcContext := newInsecureRPCContext(stopper) 60 rpcContext.NodeID.Set(context.TODO(), nodeID) 61 server := rpc.NewServer(rpcContext) 62 mock := newMockDistSQLServer() 63 RegisterDistSQLServer(server, mock) 64 ln, err := netutil.ListenAndServeGRPC(stopper, server, util.IsolatedTestAddr) 65 if err != nil { 66 return uuid.Nil, nil, nil, err 67 } 68 return rpcContext.ClusterID.Get(), mock, ln.Addr(), nil 69 } 70 71 // MockDistSQLServer implements the DistSQLServer (gRPC) interface and allows 72 // clients to control the inbound streams. 73 type MockDistSQLServer struct { 74 InboundStreams chan InboundStreamNotification 75 RunSyncFlowCalls chan RunSyncFlowCall 76 } 77 78 // InboundStreamNotification is the MockDistSQLServer's way to tell its clients 79 // that a new gRPC call has arrived and thus a stream has arrived. The rpc 80 // handler is blocked until Donec is signaled. 81 type InboundStreamNotification struct { 82 Stream DistSQL_FlowStreamServer 83 Donec chan<- error 84 } 85 86 // RunSyncFlowCall is the MockDistSQLServer's way to tell its clients that a 87 // RunSyncFlowCall has arrived. The rpc handler is blocked until Donec is 88 // signaled. 89 type RunSyncFlowCall struct { 90 Stream DistSQL_RunSyncFlowServer 91 Donec chan<- error 92 } 93 94 // MockDistSQLServer implements the DistSQLServer interface. 95 var _ DistSQLServer = &MockDistSQLServer{} 96 97 func newMockDistSQLServer() *MockDistSQLServer { 98 return &MockDistSQLServer{ 99 InboundStreams: make(chan InboundStreamNotification), 100 RunSyncFlowCalls: make(chan RunSyncFlowCall), 101 } 102 } 103 104 // RunSyncFlow is part of the DistSQLServer interface. 105 func (ds *MockDistSQLServer) RunSyncFlow(stream DistSQL_RunSyncFlowServer) error { 106 donec := make(chan error) 107 ds.RunSyncFlowCalls <- RunSyncFlowCall{Stream: stream, Donec: donec} 108 return <-donec 109 } 110 111 // SetupFlow is part of the DistSQLServer interface. 112 func (ds *MockDistSQLServer) SetupFlow( 113 _ context.Context, req *SetupFlowRequest, 114 ) (*SimpleResponse, error) { 115 return nil, nil 116 } 117 118 // FlowStream is part of the DistSQLServer interface. 119 func (ds *MockDistSQLServer) FlowStream(stream DistSQL_FlowStreamServer) error { 120 donec := make(chan error) 121 ds.InboundStreams <- InboundStreamNotification{Stream: stream, Donec: donec} 122 return <-donec 123 } 124 125 // MockDialer is a mocked implementation of the Outbox's `Dialer` interface. 126 // Used to create a connection with a client stream. 127 type MockDialer struct { 128 // Addr is assumed to be obtained from execinfrapb.StartMockDistSQLServer. 129 Addr net.Addr 130 mu struct { 131 syncutil.Mutex 132 conn *grpc.ClientConn 133 } 134 } 135 136 // Dial establishes a grpc connection once. 137 func (d *MockDialer) Dial( 138 context.Context, roachpb.NodeID, rpc.ConnectionClass, 139 ) (*grpc.ClientConn, error) { 140 d.mu.Lock() 141 defer d.mu.Unlock() 142 if d.mu.conn != nil { 143 return d.mu.conn, nil 144 } 145 var err error 146 d.mu.conn, err = grpc.Dial(d.Addr.String(), grpc.WithInsecure(), grpc.WithBlock()) 147 return d.mu.conn, err 148 } 149 150 // Close must be called after the test is done. 151 func (d *MockDialer) Close() { 152 if err := d.mu.conn.Close(); err != nil { 153 panic(err) 154 } 155 }