github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/kv/sharedconn/conn_and_client_test.go (about)

     1  // Copyright 2023 PingCAP, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package sharedconn
    15  
    16  import (
    17  	"context"
    18  	"net"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/pingcap/kvproto/pkg/cdcpb"
    24  	"github.com/pingcap/tiflow/pkg/security"
    25  	"github.com/stretchr/testify/require"
    26  	"google.golang.org/grpc"
    27  	"google.golang.org/grpc/codes"
    28  	grpccodes "google.golang.org/grpc/codes"
    29  	"google.golang.org/grpc/keepalive"
    30  	"google.golang.org/grpc/status"
    31  	grpcstatus "google.golang.org/grpc/status"
    32  )
    33  
    34  func TestConnAndClientPool(t *testing.T) {
    35  	service := make(chan *grpc.Server, 1)
    36  	var addr string
    37  
    38  	var wg sync.WaitGroup
    39  	defer wg.Wait()
    40  	wg.Add(1)
    41  	go func() {
    42  		defer wg.Done()
    43  		require.Nil(t, runGrpcService(&srv{}, &addr, service))
    44  	}()
    45  
    46  	svc := <-service
    47  	require.NotNil(t, svc)
    48  	defer svc.GracefulStop()
    49  
    50  	pool := newConnAndClientPool(&security.Credential{}, nil, 2)
    51  	cc1, err := pool.Connect(context.Background(), addr)
    52  	require.Nil(t, err)
    53  	require.NotNil(t, cc1)
    54  	require.Equal(t, 1, len(cc1.array.conns))
    55  	require.Equal(t, 1, cc1.conn.streams)
    56  	require.False(t, cc1.Multiplexing())
    57  
    58  	cc2, err := pool.Connect(context.Background(), addr)
    59  	require.Nil(t, err)
    60  	require.NotNil(t, cc2)
    61  	require.Equal(t, 1, len(cc2.array.conns))
    62  	require.Equal(t, 2, cc2.conn.streams)
    63  	require.False(t, cc2.Multiplexing())
    64  
    65  	cc3, err := pool.Connect(context.Background(), addr)
    66  	require.Nil(t, err)
    67  	require.NotNil(t, cc3)
    68  	require.Equal(t, 2, len(cc3.array.conns))
    69  	require.Equal(t, 1, cc3.conn.streams)
    70  	require.False(t, cc3.Multiplexing())
    71  
    72  	cc1.Release()
    73  	cc1.Release()
    74  	cc2.Release()
    75  	require.Equal(t, 1, len(cc3.array.conns))
    76  	require.Equal(t, 1, cc3.conn.streams)
    77  
    78  	cc3.Release()
    79  	require.Equal(t, 0, len(pool.stores))
    80  }
    81  
    82  func TestConnAndClientPoolForV2(t *testing.T) {
    83  	service := make(chan *grpc.Server, 1)
    84  	var addr string
    85  
    86  	var wg sync.WaitGroup
    87  	defer wg.Wait()
    88  	wg.Add(1)
    89  	go func() {
    90  		defer wg.Done()
    91  		require.Nil(t, runGrpcService(&srv{v2: true}, &addr, service))
    92  	}()
    93  
    94  	svc := <-service
    95  	require.NotNil(t, svc)
    96  	defer svc.GracefulStop()
    97  
    98  	pool := newConnAndClientPool(&security.Credential{}, nil, 2)
    99  	cc1, err := pool.Connect(context.Background(), addr)
   100  	require.Nil(t, err)
   101  	require.NotNil(t, cc1)
   102  	require.True(t, cc1.Multiplexing())
   103  
   104  	cc1.Release()
   105  	require.Equal(t, 0, len(pool.stores))
   106  }
   107  
   108  func TestConnectToUnavailable(t *testing.T) {
   109  	pool := newConnAndClientPool(&security.Credential{}, nil, 1)
   110  
   111  	targets := []string{"127.0.0.1:9999", "2.2.2.2:9999"}
   112  	for _, target := range targets {
   113  		ctx := context.Background()
   114  		conn, err := pool.connect(ctx, target)
   115  		require.NotNil(t, conn)
   116  		require.Nil(t, err)
   117  
   118  		rpc := cdcpb.NewChangeDataClient(conn)
   119  		_, err = rpc.EventFeedV2(ctx)
   120  		require.NotNil(t, err)
   121  
   122  		require.Nil(t, conn.Close())
   123  	}
   124  
   125  	service := make(chan *grpc.Server, 1)
   126  	var addr string
   127  
   128  	var wg sync.WaitGroup
   129  	defer wg.Wait()
   130  	wg.Add(1)
   131  	go func() {
   132  		defer wg.Done()
   133  		require.Nil(t, runGrpcService(&srv{}, &addr, service))
   134  	}()
   135  
   136  	svc := <-service
   137  	require.NotNil(t, svc)
   138  	defer svc.GracefulStop()
   139  
   140  	conn, err := pool.connect(context.Background(), addr)
   141  	require.NotNil(t, conn)
   142  	require.Nil(t, err)
   143  
   144  	rpc := cdcpb.NewChangeDataClient(conn)
   145  	client, err := rpc.EventFeedV2(context.Background())
   146  	require.Nil(t, err)
   147  	_ = client.CloseSend()
   148  
   149  	_, err = client.Recv()
   150  	require.Equal(t, codes.Unimplemented, status.Code(err))
   151  
   152  	require.Nil(t, conn.Close())
   153  }
   154  
   155  func TestCancelStream(t *testing.T) {
   156  	service := make(chan *grpc.Server, 1)
   157  	var addr string
   158  	var wg sync.WaitGroup
   159  	defer wg.Wait()
   160  	wg.Add(1)
   161  	go func() {
   162  		defer wg.Done()
   163  		require.Nil(t, runGrpcService(&srv{}, &addr, service))
   164  	}()
   165  
   166  	svc := <-service
   167  	require.NotNil(t, svc)
   168  	defer svc.GracefulStop()
   169  
   170  	connCtx, connCancel := context.WithCancel(context.Background())
   171  	defer connCancel()
   172  
   173  	pool := newConnAndClientPool(&security.Credential{}, nil, 1)
   174  	conn, err := pool.connect(connCtx, addr)
   175  	require.NotNil(t, conn)
   176  	require.Nil(t, err)
   177  
   178  	rpcCtx, rpcCancel := context.WithCancel(context.Background())
   179  	rpc := cdcpb.NewChangeDataClient(conn)
   180  	client, err := rpc.EventFeed(rpcCtx)
   181  	require.Nil(t, err)
   182  
   183  	rpcCancel()
   184  	_, err = client.Recv()
   185  	require.Equal(t, grpccodes.Canceled, grpcstatus.Code(err))
   186  	require.Nil(t, conn.Close())
   187  }
   188  
   189  func runGrpcService(srv cdcpb.ChangeDataServer, addr *string, service chan<- *grpc.Server) error {
   190  	defer close(service)
   191  	lis, err := net.Listen("tcp", "127.0.0.1:0")
   192  	if err != nil {
   193  		return err
   194  	}
   195  	defer lis.Close()
   196  
   197  	kaep := keepalive.EnforcementPolicy{
   198  		MinTime:             3 * time.Second,
   199  		PermitWithoutStream: true,
   200  	}
   201  	kasp := keepalive.ServerParameters{
   202  		MaxConnectionIdle:     10 * time.Second,
   203  		MaxConnectionAge:      10 * time.Second,
   204  		MaxConnectionAgeGrace: 5 * time.Second,
   205  		Time:                  3 * time.Second,
   206  		Timeout:               1 * time.Second,
   207  	}
   208  	grpcServer := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
   209  	cdcpb.RegisterChangeDataServer(grpcServer, srv)
   210  	*addr = lis.Addr().String()
   211  	service <- grpcServer
   212  	return grpcServer.Serve(lis)
   213  }
   214  
   215  type srv struct {
   216  	v2 bool
   217  }
   218  
   219  func (s *srv) EventFeed(server cdcpb.ChangeData_EventFeedServer) error {
   220  	for {
   221  		if _, err := server.Recv(); err != nil {
   222  			return err
   223  		}
   224  	}
   225  }
   226  
   227  func (s *srv) EventFeedV2(server cdcpb.ChangeData_EventFeedV2Server) error {
   228  	if !s.v2 {
   229  		return grpcstatus.Error(grpccodes.Unimplemented, "srv")
   230  	}
   231  	for {
   232  		if _, err := server.Recv(); err != nil {
   233  			return err
   234  		}
   235  	}
   236  }