github.com/matrixorigin/matrixone@v1.2.0/pkg/queryservice/query_service_test.go (about)

     1  // Copyright 2021 - 2023 Matrix Origin
     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 queryservice
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"math"
    21  	"os"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/lni/goutils/leaktest"
    26  	"github.com/matrixorigin/matrixone/pkg/clusterservice"
    27  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    28  	"github.com/matrixorigin/matrixone/pkg/common/morpc"
    29  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    30  	"github.com/matrixorigin/matrixone/pkg/defines"
    31  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    32  	"github.com/matrixorigin/matrixone/pkg/pb/lock"
    33  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    34  	pb "github.com/matrixorigin/matrixone/pkg/pb/query"
    35  	"github.com/matrixorigin/matrixone/pkg/pb/statsinfo"
    36  	"github.com/matrixorigin/matrixone/pkg/pb/status"
    37  	"github.com/matrixorigin/matrixone/pkg/queryservice/client"
    38  	"github.com/matrixorigin/matrixone/pkg/util/toml"
    39  	"github.com/stretchr/testify/assert"
    40  )
    41  
    42  func testCreateQueryService(t *testing.T) QueryService {
    43  	runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime())
    44  	cluster := clusterservice.NewMOCluster(
    45  		nil,
    46  		0,
    47  		clusterservice.WithDisableRefresh(),
    48  		clusterservice.WithServices([]metadata.CNService{{}}, nil))
    49  	runtime.ProcessLevelRuntime().SetGlobalVariables(runtime.ClusterService, cluster)
    50  	address := fmt.Sprintf("unix:///tmp/%d.sock", time.Now().Nanosecond())
    51  	err := os.RemoveAll(address[7:])
    52  	assert.NoError(t, err)
    53  	qs, err := NewQueryService("s1", address, morpc.Config{})
    54  	assert.NoError(t, err)
    55  	return qs
    56  }
    57  
    58  func TestNewQueryService(t *testing.T) {
    59  	qs := testCreateQueryService(t)
    60  	assert.NotNil(t, qs)
    61  }
    62  
    63  func TestQueryService(t *testing.T) {
    64  	cn := metadata.CNService{
    65  		ServiceID: "s1",
    66  	}
    67  
    68  	t.Run("sys tenant", func(t *testing.T) {
    69  		runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
    70  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    71  			defer cancel()
    72  			req := cli.NewRequest(pb.CmdMethod_ShowProcessList)
    73  			req.ShowProcessListRequest = &pb.ShowProcessListRequest{
    74  				Tenant:    "sys",
    75  				SysTenant: true,
    76  			}
    77  			resp, err := cli.SendMessage(ctx, addr, req)
    78  			assert.NoError(t, err)
    79  			defer cli.Release(resp)
    80  			assert.NotNil(t, resp.ShowProcessListResponse)
    81  			assert.Equal(t, 3, len(resp.ShowProcessListResponse.Sessions))
    82  		})
    83  	})
    84  
    85  	t.Run("common tenant", func(t *testing.T) {
    86  		runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
    87  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    88  			defer cancel()
    89  			req := cli.NewRequest(pb.CmdMethod_ShowProcessList)
    90  			req.ShowProcessListRequest = &pb.ShowProcessListRequest{
    91  				Tenant:    "t1",
    92  				SysTenant: false,
    93  			}
    94  			resp, err := cli.SendMessage(ctx, addr, req)
    95  			assert.NoError(t, err)
    96  			defer cli.Release(resp)
    97  			assert.NotNil(t, resp.ShowProcessListResponse)
    98  			assert.Equal(t, 1, len(resp.ShowProcessListResponse.Sessions))
    99  		})
   100  	})
   101  
   102  	t.Run("bad request", func(t *testing.T) {
   103  		runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   104  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   105  			defer cancel()
   106  			req := cli.NewRequest(pb.CmdMethod_ShowProcessList)
   107  			_, err := cli.SendMessage(ctx, addr, req)
   108  			assert.Error(t, err)
   109  			assert.Equal(t, "internal error: bad request", err.Error())
   110  		})
   111  	})
   112  
   113  	t.Run("unsupported cmd", func(t *testing.T) {
   114  		runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   115  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   116  			defer cancel()
   117  			req := cli.NewRequest(pb.CmdMethod(math.MaxInt32))
   118  			_, err := cli.SendMessage(ctx, addr, req)
   119  			assert.Error(t, err)
   120  			assert.Equal(t, "not supported: 2147483647 not support in current version", err.Error())
   121  		})
   122  	})
   123  }
   124  
   125  func TestQueryServiceKillConn(t *testing.T) {
   126  	cn := metadata.CNService{ServiceID: "s1"}
   127  	runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   128  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   129  		defer cancel()
   130  		req := cli.NewRequest(pb.CmdMethod_KillConn)
   131  		req.KillConnRequest = &pb.KillConnRequest{
   132  			AccountID: 10,
   133  			Version:   10,
   134  		}
   135  		resp, err := cli.SendMessage(ctx, addr, req)
   136  		assert.NoError(t, err)
   137  		defer cli.Release(resp)
   138  		assert.NotNil(t, resp.KillConnResponse)
   139  		assert.Equal(t, true, resp.KillConnResponse.Success)
   140  	})
   141  }
   142  
   143  func runTestWithQueryService(t *testing.T, cn metadata.CNService, fs fileservice.FileService, fn func(cli client.QueryClient, addr string)) {
   144  	defer leaktest.AfterTest(t)()
   145  	runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime())
   146  	runtime.ProcessLevelRuntime().SetGlobalVariables(runtime.MOProtocolVersion, defines.MORPCLatestVersion)
   147  	address := fmt.Sprintf("unix:///tmp/cn-%d-%s.sock",
   148  		time.Now().Nanosecond(), cn.ServiceID)
   149  
   150  	if err := os.RemoveAll(address[7:]); err != nil {
   151  		panic(err)
   152  	}
   153  	cluster := clusterservice.NewMOCluster(
   154  		nil,
   155  		0,
   156  		clusterservice.WithDisableRefresh(),
   157  		clusterservice.WithServices([]metadata.CNService{{
   158  			ServiceID:    cn.ServiceID,
   159  			QueryAddress: address,
   160  		}}, nil))
   161  	runtime.ProcessLevelRuntime().SetGlobalVariables(runtime.ClusterService, cluster)
   162  
   163  	sm := NewSessionManager()
   164  	sm.AddSession(&mockSession{id: "s1", tenant: "t1"})
   165  	sm.AddSession(&mockSession{id: "s2", tenant: "t2"})
   166  	sm.AddSession(&mockSession{id: "s3", tenant: "t3"})
   167  
   168  	qs, err := NewQueryService(cn.ServiceID, address, morpc.Config{})
   169  	assert.NoError(t, err)
   170  
   171  	qt, err := client.NewQueryClient(cn.ServiceID, morpc.Config{})
   172  	assert.NoError(t, err)
   173  
   174  	qs.AddHandleFunc(pb.CmdMethod_ShowProcessList, func(ctx context.Context, req *pb.Request, resp *pb.Response) error {
   175  		if req.ShowProcessListRequest == nil {
   176  			return moerr.NewInternalError(ctx, "bad request")
   177  		}
   178  		var ss []Session
   179  		if req.ShowProcessListRequest.SysTenant {
   180  			ss = sm.GetAllSessions()
   181  		} else {
   182  			ss = sm.GetSessionsByTenant(req.ShowProcessListRequest.Tenant)
   183  		}
   184  		sessions := make([]*status.Session, 0, len(ss))
   185  		for _, ses := range ss {
   186  			sessions = append(sessions, ses.StatusSession())
   187  		}
   188  		resp.ShowProcessListResponse = &pb.ShowProcessListResponse{
   189  			Sessions: sessions,
   190  		}
   191  		return nil
   192  	}, false)
   193  	qs.AddHandleFunc(pb.CmdMethod_KillConn, func(ctx context.Context, request *pb.Request, response *pb.Response) error {
   194  		response.KillConnResponse = &pb.KillConnResponse{Success: true}
   195  		return nil
   196  	}, false)
   197  	qs.AddHandleFunc(pb.CmdMethod_AlterAccount, func(ctx context.Context, request *pb.Request, response *pb.Response) error {
   198  		response.AlterAccountResponse = &pb.AlterAccountResponse{AlterSuccess: true}
   199  		return nil
   200  	}, false)
   201  	qs.AddHandleFunc(pb.CmdMethod_TraceSpan, func(ctx context.Context, request *pb.Request, resp *pb.Response) error {
   202  		resp.TraceSpanResponse = &pb.TraceSpanResponse{
   203  			Resp: "echo",
   204  		}
   205  		return nil
   206  	}, false)
   207  	qs.AddHandleFunc(pb.CmdMethod_GetCacheInfo, func(ctx context.Context, request *pb.Request, resp *pb.Response) error {
   208  		ci := &pb.CacheInfo{
   209  			NodeType:  cn.ServiceID,
   210  			NodeId:    "uuid",
   211  			CacheType: "memory",
   212  		}
   213  		resp.GetCacheInfoResponse = &pb.GetCacheInfoResponse{
   214  			CacheInfoList: []*pb.CacheInfo{ci},
   215  		}
   216  		return nil
   217  	}, false)
   218  	qs.AddHandleFunc(pb.CmdMethod_GetTxnInfo, func(ctx context.Context, request *pb.Request, resp *pb.Response) error {
   219  		ti := &pb.TxnInfo{
   220  			CreateAt:  time.Now(),
   221  			Meta:      nil,
   222  			UserTxn:   true,
   223  			WaitLocks: nil,
   224  		}
   225  		resp.GetTxnInfoResponse = &pb.GetTxnInfoResponse{
   226  			CnId:        "uuid",
   227  			TxnInfoList: []*pb.TxnInfo{ti},
   228  		}
   229  		return nil
   230  	}, false)
   231  	qs.AddHandleFunc(pb.CmdMethod_GetLockInfo, func(ctx context.Context, request *pb.Request, resp *pb.Response) error {
   232  		li := &pb.LockInfo{
   233  			TableId:     100,
   234  			Keys:        nil,
   235  			LockMode:    lock.LockMode_Shared,
   236  			IsRangeLock: true,
   237  			Holders:     nil,
   238  			Waiters:     nil,
   239  		}
   240  		resp.GetLockInfoResponse = &pb.GetLockInfoResponse{
   241  			CnId:         "uuid1",
   242  			LockInfoList: []*pb.LockInfo{li},
   243  		}
   244  		return nil
   245  	}, false)
   246  
   247  	qs.AddHandleFunc(pb.CmdMethod_GetCacheData,
   248  		func(ctx context.Context, req *pb.Request, resp *pb.Response) error {
   249  			wr := &pb.WrappedResponse{
   250  				Response: resp,
   251  			}
   252  			err := fileservice.HandleRemoteRead(ctx, fs, req, wr)
   253  			if err != nil {
   254  				return err
   255  			}
   256  			qs.SetReleaseFunc(resp, wr.ReleaseFunc)
   257  			return nil
   258  		},
   259  		false,
   260  	)
   261  
   262  	qs.AddHandleFunc(pb.CmdMethod_GetStatsInfo,
   263  		func(ctx context.Context, req *pb.Request, resp *pb.Response) error {
   264  			resp.GetStatsInfoResponse = &pb.GetStatsInfoResponse{
   265  				StatsInfo: &statsinfo.StatsInfo{
   266  					TableCnt: 100,
   267  				},
   268  			}
   269  			return nil
   270  		},
   271  		false,
   272  	)
   273  
   274  	err = qs.Start()
   275  	assert.NoError(t, err)
   276  
   277  	fn(qt, address)
   278  
   279  	err = qs.Close()
   280  	assert.NoError(t, err)
   281  	err = qt.Close()
   282  	assert.NoError(t, err)
   283  }
   284  
   285  func TestQueryServiceAlterAccount(t *testing.T) {
   286  	cn := metadata.CNService{ServiceID: "s1"}
   287  	runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   288  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   289  		defer cancel()
   290  		req := cli.NewRequest(pb.CmdMethod_AlterAccount)
   291  		req.AlterAccountRequest = &pb.AlterAccountRequest{
   292  			TenantId: 10,
   293  			Status:   "restricted",
   294  		}
   295  		resp, err := cli.SendMessage(ctx, addr, req)
   296  		assert.NoError(t, err)
   297  		defer cli.Release(resp)
   298  		assert.NotNil(t, resp.AlterAccountResponse)
   299  		assert.Equal(t, true, resp.AlterAccountResponse.AlterSuccess)
   300  	})
   301  }
   302  
   303  func TestQueryServiceTraceSpan(t *testing.T) {
   304  	cn := metadata.CNService{ServiceID: "s1"}
   305  	runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   306  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   307  		defer cancel()
   308  		req := cli.NewRequest(pb.CmdMethod_TraceSpan)
   309  		req.TraceSpanRequest = &pb.TraceSpanRequest{
   310  			Cmd:   "cmd",
   311  			Spans: "spans",
   312  		}
   313  		resp, err := cli.SendMessage(ctx, addr, req)
   314  		assert.NoError(t, err)
   315  		defer cli.Release(resp)
   316  		assert.NotNil(t, resp.TraceSpanResponse)
   317  		assert.Equal(t, "echo", resp.TraceSpanResponse.Resp)
   318  	})
   319  }
   320  
   321  func TestRequestMultipleCn(t *testing.T) {
   322  	type args struct {
   323  		ctx                   context.Context
   324  		nodes                 []string
   325  		qs                    QueryService
   326  		genRequest            func() *pb.Request
   327  		handleValidResponse   func(string, *pb.Response)
   328  		handleInvalidResponse func(string)
   329  	}
   330  
   331  	cn := metadata.CNService{ServiceID: "test_request_multi_cn"}
   332  	runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   333  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   334  		defer cancel()
   335  
   336  		//////
   337  
   338  		tests := []struct {
   339  			name    string
   340  			args    args
   341  			wantErr assert.ErrorAssertionFunc
   342  		}{
   343  			{
   344  				name: "genRequest is nil",
   345  				args: args{
   346  					ctx:                   context.Background(),
   347  					nodes:                 []string{},
   348  					qs:                    nil,
   349  					genRequest:            nil,
   350  					handleValidResponse:   nil,
   351  					handleInvalidResponse: nil,
   352  				},
   353  				wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
   354  					assert.NotNil(t, err)
   355  					return true
   356  				},
   357  			},
   358  			{
   359  				name: "handleValidResponse is nil",
   360  				args: args{
   361  					ctx:                   context.Background(),
   362  					nodes:                 []string{},
   363  					qs:                    nil,
   364  					genRequest:            func() *pb.Request { return nil },
   365  					handleValidResponse:   nil,
   366  					handleInvalidResponse: nil,
   367  				},
   368  				wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
   369  					assert.NotNil(t, err)
   370  					return true
   371  				},
   372  			},
   373  			{
   374  				name: "get cache info",
   375  				args: args{
   376  					ctx:   context.Background(),
   377  					nodes: []string{},
   378  					qs:    nil,
   379  					genRequest: func() *pb.Request {
   380  						req := cli.NewRequest(pb.CmdMethod_GetCacheInfo)
   381  						req.GetCacheInfoRequest = &pb.GetCacheInfoRequest{}
   382  						return req
   383  					},
   384  					handleValidResponse: func(nodeAddr string, rsp *pb.Response) {
   385  						if rsp != nil && rsp.GetCacheInfoResponse != nil {
   386  							assert.GreaterOrEqual(t, len(rsp.GetCacheInfoResponse.GetCacheInfoList()), 1)
   387  						}
   388  					},
   389  					handleInvalidResponse: nil,
   390  				},
   391  				wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
   392  					assert.Nil(t, err)
   393  					return true
   394  				},
   395  			},
   396  			{
   397  				name: "get txn info",
   398  				args: args{
   399  					ctx:   context.Background(),
   400  					nodes: []string{},
   401  					qs:    nil,
   402  					genRequest: func() *pb.Request {
   403  						req := cli.NewRequest(pb.CmdMethod_GetTxnInfo)
   404  						req.GetTxnInfoRequest = &pb.GetTxnInfoRequest{}
   405  						return req
   406  					},
   407  					handleValidResponse: func(nodeAddr string, rsp *pb.Response) {
   408  						if rsp != nil && rsp.GetTxnInfoResponse != nil {
   409  							fmt.Printf("%v\n", rsp.GetTxnInfoResponse.TxnInfoList[0].UserTxn)
   410  							assert.Equal(t, rsp.GetTxnInfoResponse.GetCnId(), "uuid")
   411  							assert.True(t, rsp.GetTxnInfoResponse.TxnInfoList[0].UserTxn)
   412  							assert.GreaterOrEqual(t, len(rsp.GetTxnInfoResponse.TxnInfoList), 1)
   413  						}
   414  					},
   415  					handleInvalidResponse: nil,
   416  				},
   417  				wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
   418  					assert.Nil(t, err)
   419  					return true
   420  				},
   421  			},
   422  			{
   423  				name: "get lock info",
   424  				args: args{
   425  					ctx:   context.Background(),
   426  					nodes: []string{},
   427  					qs:    nil,
   428  					genRequest: func() *pb.Request {
   429  						req := cli.NewRequest(pb.CmdMethod_GetLockInfo)
   430  						req.GetLockInfoRequest = &pb.GetLockInfoRequest{}
   431  						return req
   432  					},
   433  					handleValidResponse: func(nodeAddr string, rsp *pb.Response) {
   434  						if rsp != nil && rsp.GetLockInfoResponse != nil {
   435  							li := rsp.GetLockInfoResponse.LockInfoList[0]
   436  							fmt.Printf("%v %v %v %v\n", rsp.GetLockInfoResponse.GetCnId(), li.TableId, li.LockMode, li.IsRangeLock)
   437  							assert.Equal(t, rsp.GetLockInfoResponse.GetCnId(), "uuid1")
   438  							assert.Equal(t, li.TableId, uint64(100))
   439  							assert.Equal(t, li.LockMode, lock.LockMode_Shared)
   440  							assert.True(t, li.IsRangeLock)
   441  							assert.GreaterOrEqual(t, len(rsp.GetLockInfoResponse.LockInfoList), 1)
   442  						}
   443  					},
   444  					handleInvalidResponse: nil,
   445  				},
   446  				wantErr: func(t assert.TestingT, err error, i ...interface{}) bool {
   447  					assert.Nil(t, err)
   448  					return true
   449  				},
   450  			},
   451  		}
   452  
   453  		//////
   454  
   455  		for _, tt := range tests {
   456  			t.Run(tt.name, func(t *testing.T) {
   457  				tt.wantErr(t,
   458  					RequestMultipleCn(ctx,
   459  						[]string{addr},
   460  						cli,
   461  						tt.args.genRequest,
   462  						tt.args.handleValidResponse,
   463  						tt.args.handleInvalidResponse),
   464  					fmt.Sprintf("RequestMultipleCn(%v, %v, %v, %v, %v, %v)", tt.args.ctx, tt.args.nodes, tt.args.qs, tt.args.genRequest != nil, tt.args.handleValidResponse != nil, tt.args.handleInvalidResponse != nil))
   465  			})
   466  		}
   467  	})
   468  
   469  }
   470  
   471  func TestQueryService_RemoteCache(t *testing.T) {
   472  	defer leaktest.AfterTest(t)()
   473  	cn := metadata.CNService{
   474  		ServiceID: "s1",
   475  	}
   476  
   477  	qt, err := client.NewQueryClient(cn.ServiceID, morpc.Config{})
   478  	assert.NoError(t, err)
   479  	defer qt.Close()
   480  
   481  	ctx := context.Background()
   482  	dir := t.TempDir()
   483  	memCap := toml.ByteSize(102400)
   484  	fs, err := fileservice.NewLocalFS(ctx, "local", dir,
   485  		fileservice.CacheConfig{
   486  			MemoryCapacity:     &memCap,
   487  			RemoteCacheEnabled: true,
   488  			QueryClient:        qt,
   489  		}, nil)
   490  	assert.Nil(t, err)
   491  	defer func() { fs.Close() }()
   492  
   493  	t.Run("main", func(t *testing.T) {
   494  		runTestWithQueryService(t, cn, fs, func(cli client.QueryClient, addr string) {
   495  			readEntry0 := fileservice.IOEntry{
   496  				Offset:      10,
   497  				Size:        2,
   498  				ToCacheData: fileservice.CacheOriginalData,
   499  			}
   500  			readEntry1 := fileservice.IOEntry{
   501  				Offset:      20,
   502  				Size:        3,
   503  				ToCacheData: fileservice.CacheOriginalData,
   504  			}
   505  			writeEntry0 := readEntry0
   506  			writeEntry0.Data = []byte{10, 20}
   507  			writeEntry0.ToCacheData = nil
   508  			writeEntry1 := readEntry1
   509  			writeEntry1.Data = []byte{30, 40, 50}
   510  			writeEntry1.ToCacheData = nil
   511  
   512  			err = fs.Write(ctx, fileservice.IOVector{
   513  				FilePath: "foo",
   514  				Entries:  []fileservice.IOEntry{writeEntry0, writeEntry1},
   515  			})
   516  			assert.NoError(t, err)
   517  			iov := &fileservice.IOVector{
   518  				FilePath: "foo",
   519  				Entries:  []fileservice.IOEntry{readEntry0, readEntry1},
   520  			}
   521  			defer iov.Release()
   522  			err = fs.Read(ctx, iov)
   523  			assert.NoError(t, err)
   524  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   525  			defer cancel()
   526  			req := cli.NewRequest(pb.CmdMethod_GetCacheData)
   527  			req.GetCacheDataRequest = &pb.GetCacheDataRequest{
   528  				RequestCacheKey: []*pb.RequestCacheKey{
   529  					{
   530  						Index: 0,
   531  						CacheKey: &pb.CacheKey{
   532  							Path:   "foo",
   533  							Offset: 10,
   534  							Sz:     2,
   535  						},
   536  					},
   537  					{
   538  						Index: 1,
   539  						CacheKey: &pb.CacheKey{
   540  							Path:   "foo",
   541  							Offset: 20,
   542  							Sz:     3,
   543  						},
   544  					},
   545  				},
   546  			}
   547  			resp1, err := cli.SendMessage(ctx, addr, req)
   548  			assert.NoError(t, err)
   549  			defer cli.Release(resp1)
   550  			assert.NotNil(t, resp1.GetCacheDataResponse)
   551  			assert.Equal(t, 2, len(resp1.GetCacheDataResponse.ResponseCacheData))
   552  			assert.Equal(t, pb.ResponseCacheData{Index: 0, Hit: true, Data: []byte{10, 20}},
   553  				*resp1.GetCacheDataResponse.GetResponseCacheData()[0])
   554  			assert.Equal(t, pb.ResponseCacheData{Index: 1, Hit: true, Data: []byte{30, 40, 50}},
   555  				*resp1.GetCacheDataResponse.GetResponseCacheData()[1])
   556  
   557  			req.GetCacheDataRequest = &pb.GetCacheDataRequest{
   558  				RequestCacheKey: []*pb.RequestCacheKey{
   559  					{
   560  						Index: 0,
   561  						CacheKey: &pb.CacheKey{
   562  							Path:   "foo1",
   563  							Offset: 40,
   564  							Sz:     2,
   565  						},
   566  					},
   567  				},
   568  			}
   569  			resp2, err := cli.SendMessage(ctx, addr, req)
   570  			assert.NoError(t, err)
   571  			defer cli.Release(resp2)
   572  			assert.NotNil(t, resp2.GetCacheDataResponse)
   573  			assert.Equal(t, 1, len(resp2.GetCacheDataResponse.ResponseCacheData))
   574  			assert.Equal(t, pb.ResponseCacheData{Index: 0, Hit: false},
   575  				*resp2.GetCacheDataResponse.GetResponseCacheData()[0])
   576  		})
   577  	})
   578  
   579  	t.Run("bad request", func(t *testing.T) {
   580  		runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   581  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   582  			defer cancel()
   583  			req := cli.NewRequest(pb.CmdMethod_GetCacheData)
   584  			_, err := cli.SendMessage(ctx, addr, req)
   585  			assert.Error(t, err)
   586  			assert.Equal(t, "internal error: bad request", err.Error())
   587  		})
   588  	})
   589  
   590  	t.Run("unsupported cmd", func(t *testing.T) {
   591  		runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   592  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   593  			defer cancel()
   594  			req := cli.NewRequest(pb.CmdMethod(90))
   595  			_, err := cli.SendMessage(ctx, addr, req)
   596  			assert.Error(t, err)
   597  			assert.Equal(t, "not supported: 90 not support in current version", err.Error())
   598  		})
   599  	})
   600  }
   601  
   602  func TestQueryService_RemoteStatsInfo(t *testing.T) {
   603  	defer leaktest.AfterTest(t)()
   604  	cn := metadata.CNService{
   605  		ServiceID: "s1",
   606  	}
   607  
   608  	t.Run("main", func(t *testing.T) {
   609  		runTestWithQueryService(t, cn, nil, func(cli client.QueryClient, addr string) {
   610  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   611  			defer cancel()
   612  			req := cli.NewRequest(pb.CmdMethod_GetStatsInfo)
   613  			req.GetStatsInfoRequest = &pb.GetStatsInfoRequest{
   614  				StatsInfoKey: &statsinfo.StatsInfoKey{
   615  					DatabaseID: 1,
   616  					TableID:    2,
   617  				},
   618  			}
   619  			resp, err := cli.SendMessage(ctx, addr, req)
   620  			assert.NoError(t, err)
   621  			defer cli.Release(resp)
   622  			assert.NotNil(t, resp.GetStatsInfoResponse)
   623  			assert.NotNil(t, resp.GetStatsInfoResponse.StatsInfo)
   624  			assert.NotEqual(t, 0, resp.GetStatsInfoResponse.StatsInfo.TableCnt)
   625  		})
   626  	})
   627  }