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 }