vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletconntest/fakequeryservice.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package tabletconntest 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "testing" 24 25 "vitess.io/vitess/go/vt/vttablet/queryservice" 26 27 "google.golang.org/protobuf/proto" 28 29 "vitess.io/vitess/go/sqltypes" 30 "vitess.io/vitess/go/vt/callerid" 31 32 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 33 querypb "vitess.io/vitess/go/vt/proto/query" 34 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 35 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 36 ) 37 38 // FakeQueryService implements a programmable fake for the query service 39 // server side. 40 type FakeQueryService struct { 41 t testing.TB 42 TestingGateway bool 43 44 // these fields are used to simulate and synchronize on errors 45 HasError bool 46 HasBeginError bool 47 HasReserveError bool 48 TabletError error 49 ErrorWait chan struct{} 50 51 // these fields are used to simulate and synchronize on panics 52 Panics bool 53 StreamExecutePanicsEarly bool 54 PanicWait chan struct{} 55 56 // ExpectedTransactionID is what transactionID to expect for Execute 57 ExpectedTransactionID int64 58 59 // StreamHealthResponse is what we return for StreamHealth. 60 // If not set, return TestStreamHealthStreamHealthResponse 61 StreamHealthResponse *querypb.StreamHealthResponse 62 } 63 64 var _ queryservice.QueryService = (*FakeQueryService)(nil) 65 66 // Close is a no-op. 67 func (f *FakeQueryService) Close(ctx context.Context) error { 68 return nil 69 } 70 71 // HandlePanic is part of the queryservice.QueryService interface 72 func (f *FakeQueryService) HandlePanic(err *error) { 73 if x := recover(); x != nil { 74 *err = fmt.Errorf("caught test panic: %v", x) 75 } 76 } 77 78 // TestTarget is the target we use for this test 79 var TestTarget = &querypb.Target{ 80 Keyspace: "test_keyspace", 81 Shard: "test_shard", 82 TabletType: topodatapb.TabletType_REPLICA, 83 } 84 85 // TestCell is the cell we use for this test (and TestGRPCDiscovery) 86 var TestCell = "aa" 87 88 // TestAlias is the tablet alias we use for this test (and TestGRPCDiscovery) 89 var TestAlias = &topodatapb.TabletAlias{ 90 Cell: TestCell, 91 Uid: 1, 92 } 93 94 // TestCallerID is a test caller id. 95 var TestCallerID = &vtrpcpb.CallerID{ 96 Principal: "test_principal", 97 Component: "test_component", 98 Subcomponent: "test_subcomponent", 99 } 100 101 // TestVTGateCallerID is a test vtgate caller id. 102 var TestVTGateCallerID = &querypb.VTGateCallerID{ 103 Username: "test_username", 104 } 105 106 // TestExecuteOptions is a test execute options. 107 var TestExecuteOptions = &querypb.ExecuteOptions{ 108 IncludedFields: querypb.ExecuteOptions_TYPE_ONLY, 109 ClientFoundRows: true, 110 } 111 112 // TestAsTransaction is a test 'asTransaction' flag. 113 const TestAsTransaction bool = true 114 115 func (f *FakeQueryService) checkTargetCallerID(ctx context.Context, name string, target *querypb.Target) { 116 if !proto.Equal(target, TestTarget) { 117 f.t.Errorf("invalid Target for %v: got %#v expected %#v", name, target, TestTarget) 118 } 119 120 ef := callerid.EffectiveCallerIDFromContext(ctx) 121 if ef == nil { 122 f.t.Errorf("no effective caller id for %v", name) 123 } else { 124 if !proto.Equal(ef, TestCallerID) { 125 f.t.Errorf("invalid effective caller id for %v: got %v expected %v", name, ef, TestCallerID) 126 } 127 } 128 129 im := callerid.ImmediateCallerIDFromContext(ctx) 130 if im == nil { 131 f.t.Errorf("no immediate caller id for %v", name) 132 } else { 133 if !proto.Equal(im, TestVTGateCallerID) { 134 f.t.Errorf("invalid immediate caller id for %v: got %v expected %v", name, im, TestVTGateCallerID) 135 } 136 } 137 } 138 139 // beginTransactionID is a test transaction id for Begin. 140 const beginTransactionID int64 = 9990 141 142 // Begin is part of the queryservice.QueryService interface 143 func (f *FakeQueryService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (queryservice.TransactionState, error) { 144 if f.HasBeginError { 145 return queryservice.TransactionState{}, f.TabletError 146 } 147 if f.Panics { 148 panic(fmt.Errorf("test-triggered panic")) 149 } 150 f.checkTargetCallerID(ctx, "Begin", target) 151 if !proto.Equal(options, TestExecuteOptions) { 152 f.t.Errorf("invalid Execute.ExecuteOptions: got %v expected %v", options, TestExecuteOptions) 153 } 154 return queryservice.TransactionState{TransactionID: beginTransactionID, TabletAlias: TestAlias}, nil 155 } 156 157 // commitTransactionID is a test transaction id for Commit. 158 const commitTransactionID int64 = 999044 159 160 // Commit is part of the queryservice.QueryService interface 161 func (f *FakeQueryService) Commit(ctx context.Context, target *querypb.Target, transactionID int64) (int64, error) { 162 if f.HasError { 163 return 0, f.TabletError 164 } 165 if f.Panics { 166 panic(fmt.Errorf("test-triggered panic")) 167 } 168 f.checkTargetCallerID(ctx, "Commit", target) 169 if transactionID != commitTransactionID { 170 f.t.Errorf("Commit: invalid TransactionId: got %v expected %v", transactionID, commitTransactionID) 171 } 172 return 0, nil 173 } 174 175 // rollbackTransactionID is a test transactin id for Rollback. 176 const rollbackTransactionID int64 = 999044 177 178 // Rollback is part of the queryservice.QueryService interface 179 func (f *FakeQueryService) Rollback(ctx context.Context, target *querypb.Target, transactionID int64) (int64, error) { 180 if f.HasError { 181 return 0, f.TabletError 182 } 183 if f.Panics { 184 panic(fmt.Errorf("test-triggered panic")) 185 } 186 f.checkTargetCallerID(ctx, "Rollback", target) 187 if transactionID != rollbackTransactionID { 188 f.t.Errorf("Rollback: invalid TransactionId: got %v expected %v", transactionID, rollbackTransactionID) 189 } 190 return 0, nil 191 } 192 193 // Dtid is a test dtid 194 const Dtid string = "aa" 195 196 // Prepare is part of the queryservice.QueryService interface 197 func (f *FakeQueryService) Prepare(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) (err error) { 198 if f.HasError { 199 return f.TabletError 200 } 201 if f.Panics { 202 panic(fmt.Errorf("test-triggered panic")) 203 } 204 f.checkTargetCallerID(ctx, "Prepare", target) 205 if transactionID != commitTransactionID { 206 f.t.Errorf("Prepare: invalid TransactionID: got %v expected %v", transactionID, commitTransactionID) 207 } 208 if dtid != Dtid { 209 f.t.Errorf("Prepare: invalid dtid: got %s expected %s", dtid, Dtid) 210 } 211 return nil 212 } 213 214 // CommitPrepared is part of the queryservice.QueryService interface 215 func (f *FakeQueryService) CommitPrepared(ctx context.Context, target *querypb.Target, dtid string) (err error) { 216 if f.HasError { 217 return f.TabletError 218 } 219 if f.Panics { 220 panic(fmt.Errorf("test-triggered panic")) 221 } 222 f.checkTargetCallerID(ctx, "CommitPrepared", target) 223 if dtid != Dtid { 224 f.t.Errorf("CommitPrepared: invalid dtid: got %s expected %s", dtid, Dtid) 225 } 226 return nil 227 } 228 229 // RollbackPrepared is part of the queryservice.QueryService interface 230 func (f *FakeQueryService) RollbackPrepared(ctx context.Context, target *querypb.Target, dtid string, originalID int64) (err error) { 231 if f.HasError { 232 return f.TabletError 233 } 234 if f.Panics { 235 panic(fmt.Errorf("test-triggered panic")) 236 } 237 f.checkTargetCallerID(ctx, "RollbackPrepared", target) 238 if originalID != rollbackTransactionID { 239 f.t.Errorf("RollbackPrepared: invalid TransactionID: got %v expected %v", originalID, rollbackTransactionID) 240 } 241 if dtid != Dtid { 242 f.t.Errorf("RollbackPrepared: invalid dtid: got %s expected %s", dtid, Dtid) 243 } 244 return nil 245 } 246 247 // Participants is a test list of 2pc participants. 248 var Participants = []*querypb.Target{{ 249 Keyspace: "ks0", 250 Shard: "0", 251 }, { 252 Keyspace: "ks1", 253 Shard: "1", 254 }} 255 256 // TargetsEqual returns true if the targets are equal. 257 func TargetsEqual(t1, t2 []*querypb.Target) bool { 258 if len(t1) != len(t2) { 259 return false 260 } 261 for i, t := range t1 { 262 if !proto.Equal(t, t2[i]) { 263 return false 264 } 265 } 266 return true 267 } 268 269 // CreateTransaction is part of the queryservice.QueryService interface 270 func (f *FakeQueryService) CreateTransaction(ctx context.Context, target *querypb.Target, dtid string, participants []*querypb.Target) (err error) { 271 if f.HasError { 272 return f.TabletError 273 } 274 if f.Panics { 275 panic(fmt.Errorf("test-triggered panic")) 276 } 277 f.checkTargetCallerID(ctx, "CreateTransaction", target) 278 if dtid != Dtid { 279 f.t.Errorf("CreateTransaction: invalid dtid: got %s expected %s", dtid, Dtid) 280 } 281 if !TargetsEqual(participants, Participants) { 282 f.t.Errorf("invalid CreateTransaction participants: got %v, expected %v", participants, Participants) 283 } 284 return nil 285 } 286 287 // StartCommit is part of the queryservice.QueryService interface 288 func (f *FakeQueryService) StartCommit(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) (err error) { 289 if f.HasError { 290 return f.TabletError 291 } 292 if f.Panics { 293 panic(fmt.Errorf("test-triggered panic")) 294 } 295 f.checkTargetCallerID(ctx, "StartCommit", target) 296 if transactionID != commitTransactionID { 297 f.t.Errorf("StartCommit: invalid TransactionID: got %v expected %v", transactionID, commitTransactionID) 298 } 299 if dtid != Dtid { 300 f.t.Errorf("StartCommit: invalid dtid: got %s expected %s", dtid, Dtid) 301 } 302 return nil 303 } 304 305 // SetRollback is part of the queryservice.QueryService interface 306 func (f *FakeQueryService) SetRollback(ctx context.Context, target *querypb.Target, dtid string, transactionID int64) (err error) { 307 if f.HasError { 308 return f.TabletError 309 } 310 if f.Panics { 311 panic(fmt.Errorf("test-triggered panic")) 312 } 313 f.checkTargetCallerID(ctx, "SetRollback", target) 314 if transactionID != commitTransactionID { 315 f.t.Errorf("SetRollback: invalid TransactionID: got %v expected %v", transactionID, commitTransactionID) 316 } 317 if dtid != Dtid { 318 f.t.Errorf("SetRollback: invalid dtid: got %s expected %s", dtid, Dtid) 319 } 320 return nil 321 } 322 323 // ConcludeTransaction is part of the queryservice.QueryService interface 324 func (f *FakeQueryService) ConcludeTransaction(ctx context.Context, target *querypb.Target, dtid string) (err error) { 325 if f.HasError { 326 return f.TabletError 327 } 328 if f.Panics { 329 panic(fmt.Errorf("test-triggered panic")) 330 } 331 f.checkTargetCallerID(ctx, "ConcludeTransaction", target) 332 if dtid != Dtid { 333 f.t.Errorf("ConcludeTransaction: invalid dtid: got %s expected %s", dtid, Dtid) 334 } 335 return nil 336 } 337 338 // Metadata is a test metadata for 2pc transactions. 339 var Metadata = &querypb.TransactionMetadata{ 340 Dtid: "aa", 341 State: querypb.TransactionState_PREPARE, 342 TimeCreated: 1, 343 Participants: Participants, 344 } 345 346 // ReadTransaction is part of the queryservice.QueryService interface 347 func (f *FakeQueryService) ReadTransaction(ctx context.Context, target *querypb.Target, dtid string) (metadata *querypb.TransactionMetadata, err error) { 348 if f.HasError { 349 return nil, f.TabletError 350 } 351 if f.Panics { 352 panic(fmt.Errorf("test-triggered panic")) 353 } 354 f.checkTargetCallerID(ctx, "ReadTransaction", target) 355 if dtid != Dtid { 356 f.t.Errorf("ReadTransaction: invalid dtid: got %s expected %s", dtid, Dtid) 357 } 358 return Metadata, nil 359 } 360 361 // ExecuteQuery is a fake test query. 362 const ExecuteQuery = "executeQuery" 363 364 // ExecuteBindVars is a test bind var. 365 var ExecuteBindVars = map[string]*querypb.BindVariable{ 366 "bind1": sqltypes.Int64BindVariable(1114444), 367 } 368 369 // ExecuteTransactionID is a test transaction id. 370 const ExecuteTransactionID int64 = 678 371 372 // ReserveConnectionID is a test reserved connection id. 373 const ReserveConnectionID int64 = 933 374 375 // ExecuteQueryResult is a test query result. 376 var ExecuteQueryResult = sqltypes.Result{ 377 Fields: []*querypb.Field{ 378 { 379 Name: "field1", 380 Type: sqltypes.Int8, 381 }, 382 { 383 Name: "field2", 384 Type: sqltypes.Char, 385 }, 386 }, 387 RowsAffected: 123, 388 InsertID: 72, 389 Rows: [][]sqltypes.Value{ 390 { 391 sqltypes.TestValue(sqltypes.Int8, "1"), 392 sqltypes.NULL, 393 }, 394 { 395 sqltypes.TestValue(sqltypes.Int8, "2"), 396 sqltypes.TestValue(sqltypes.Char, "row2 value2"), 397 }, 398 }, 399 } 400 401 // Execute is part of the queryservice.QueryService interface 402 func (f *FakeQueryService) Execute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, transactionID, reservedID int64, options *querypb.ExecuteOptions) (*sqltypes.Result, error) { 403 if f.HasError { 404 return nil, f.TabletError 405 } 406 if f.Panics { 407 panic(fmt.Errorf("test-triggered panic")) 408 } 409 if sql != ExecuteQuery { 410 f.t.Errorf("invalid Execute.Query.Sql: got %v expected %v", sql, ExecuteQuery) 411 } 412 if !sqltypes.BindVariablesEqual(bindVariables, ExecuteBindVars) { 413 f.t.Errorf("invalid Execute.BindVariables: got %v expected %v", bindVariables, ExecuteBindVars) 414 } 415 if !proto.Equal(options, TestExecuteOptions) { 416 f.t.Errorf("invalid Execute.ExecuteOptions: got %v expected %v", options, TestExecuteOptions) 417 } 418 f.checkTargetCallerID(ctx, "Execute", target) 419 if transactionID != f.ExpectedTransactionID { 420 f.t.Errorf("invalid Execute.TransactionId: got %v expected %v", transactionID, f.ExpectedTransactionID) 421 } 422 return &ExecuteQueryResult, nil 423 } 424 425 // StreamExecuteQuery is a fake test query for streaming. 426 const StreamExecuteQuery = "streamExecuteQuery" 427 428 // StreamExecuteBindVars is a test bind var for streaming. 429 var StreamExecuteBindVars = map[string]*querypb.BindVariable{ 430 "bind1": sqltypes.Int64BindVariable(93848000), 431 } 432 433 // StreamExecuteQueryResult1 is the first packet of a streaming result. 434 var StreamExecuteQueryResult1 = sqltypes.Result{ 435 Fields: []*querypb.Field{ 436 { 437 Name: "field1", 438 Type: sqltypes.Int8, 439 }, 440 { 441 Name: "field2", 442 Type: sqltypes.Char, 443 }, 444 }, 445 } 446 447 // StreamExecuteQueryResult2 is the second packet of a streaming result. 448 var StreamExecuteQueryResult2 = sqltypes.Result{ 449 Rows: [][]sqltypes.Value{ 450 { 451 sqltypes.TestValue(sqltypes.Int8, "1"), 452 sqltypes.TestValue(sqltypes.Char, "row1 value2"), 453 }, 454 { 455 sqltypes.TestValue(sqltypes.Int8, "2"), 456 sqltypes.TestValue(sqltypes.Char, "row2 value2"), 457 }, 458 }, 459 } 460 461 // StreamExecute is part of the queryservice.QueryService interface 462 func (f *FakeQueryService) StreamExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, reservedID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) error { 463 if f.Panics && f.StreamExecutePanicsEarly { 464 panic(fmt.Errorf("test-triggered panic early")) 465 } 466 if sql != StreamExecuteQuery { 467 f.t.Errorf("invalid StreamExecute.Sql: got %v expected %v", sql, StreamExecuteQuery) 468 } 469 if !sqltypes.BindVariablesEqual(bindVariables, StreamExecuteBindVars) { 470 f.t.Errorf("invalid StreamExecute.BindVariables: got %v expected %v", bindVariables, StreamExecuteBindVars) 471 } 472 if !proto.Equal(options, TestExecuteOptions) { 473 f.t.Errorf("invalid StreamExecute.ExecuteOptions: got %v expected %v", options, TestExecuteOptions) 474 } 475 f.checkTargetCallerID(ctx, "StreamExecute", target) 476 if err := callback(&StreamExecuteQueryResult1); err != nil { 477 f.t.Errorf("callback1 failed: %v", err) 478 } 479 if f.Panics && !f.StreamExecutePanicsEarly { 480 // wait until the client gets the response, then panics 481 <-f.PanicWait 482 panic(fmt.Errorf("test-triggered panic late")) 483 } 484 if f.HasError { 485 // wait until the client has the response, since all 486 // streaming implementation may not send previous 487 // messages if an error has been triggered. 488 <-f.ErrorWait 489 return f.TabletError 490 } 491 if err := callback(&StreamExecuteQueryResult2); err != nil { 492 f.t.Errorf("callback2 failed: %v", err) 493 } 494 return nil 495 } 496 497 // ExecuteBatchQueries are test queries for batch. 498 var ExecuteBatchQueries = []*querypb.BoundQuery{ 499 { 500 Sql: "executeBatchQueries1", 501 BindVariables: map[string]*querypb.BindVariable{ 502 "bind1": sqltypes.Int64BindVariable(43), 503 }, 504 }, 505 { 506 Sql: "executeBatchQueries2", 507 BindVariables: map[string]*querypb.BindVariable{ 508 "bind2": sqltypes.Int64BindVariable(72), 509 }, 510 }, 511 } 512 513 // ExecuteBatchTransactionID is a test transaction id for batch. 514 const ExecuteBatchTransactionID int64 = 678 515 516 // ExecuteBatchQueryResultList is a list of test query results. 517 var ExecuteBatchQueryResultList = []sqltypes.Result{ 518 { 519 Fields: []*querypb.Field{ 520 { 521 Name: "field1", 522 Type: sqltypes.Int8, 523 }, 524 }, 525 RowsAffected: 1232, 526 InsertID: 712, 527 Rows: [][]sqltypes.Value{ 528 { 529 sqltypes.TestValue(sqltypes.Int8, "1"), 530 }, 531 { 532 sqltypes.TestValue(sqltypes.Int8, "2"), 533 }, 534 }, 535 }, 536 { 537 Fields: []*querypb.Field{ 538 { 539 Name: "field1", 540 Type: sqltypes.VarBinary, 541 }, 542 }, 543 RowsAffected: 12333, 544 InsertID: 74442, 545 Rows: [][]sqltypes.Value{ 546 { 547 sqltypes.NewVarBinary("row1 value1"), 548 }, 549 { 550 sqltypes.NewVarBinary("row1 value2"), 551 }, 552 }, 553 }, 554 } 555 556 // BeginExecute combines Begin and Execute. 557 func (f *FakeQueryService) BeginExecute(ctx context.Context, target *querypb.Target, _ []string, sql string, bindVariables map[string]*querypb.BindVariable, reservedID int64, options *querypb.ExecuteOptions) (queryservice.TransactionState, *sqltypes.Result, error) { 558 state, err := f.Begin(ctx, target, options) 559 if err != nil { 560 return state, nil, err 561 } 562 563 // TODO(deepthi): what alias should we actually return here? 564 result, err := f.Execute(ctx, target, sql, bindVariables, state.TransactionID, reservedID, options) 565 return state, result, err 566 } 567 568 // BeginStreamExecute combines Begin and StreamExecute. 569 func (f *FakeQueryService) BeginStreamExecute(ctx context.Context, target *querypb.Target, preQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, reservedID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) (queryservice.TransactionState, error) { 570 state, err := f.Begin(ctx, target, options) 571 if err != nil { 572 return state, err 573 } 574 575 for _, preQuery := range preQueries { 576 _, err := f.Execute(ctx, target, preQuery, nil, state.TransactionID, reservedID, options) 577 if err != nil { 578 return state, err 579 } 580 } 581 582 err = f.StreamExecute(ctx, target, sql, bindVariables, state.TransactionID, reservedID, options, callback) 583 return state, err 584 } 585 586 var ( 587 // MessageName is a test message name. 588 MessageName = "vitess_message" 589 590 // MessageStreamResult is a test stream result. 591 MessageStreamResult = &sqltypes.Result{ 592 Fields: []*querypb.Field{{ 593 Name: "id", 594 Type: sqltypes.VarBinary, 595 }, { 596 Name: "message", 597 Type: sqltypes.VarBinary, 598 }}, 599 Rows: [][]sqltypes.Value{{ 600 sqltypes.NewVarBinary("1"), 601 sqltypes.NewVarBinary("row1 value2"), 602 }, { 603 sqltypes.NewVarBinary("2"), 604 sqltypes.NewVarBinary("row2 value2"), 605 }}, 606 } 607 608 // MessageIDs is a test list of message ids. 609 MessageIDs = []*querypb.Value{{ 610 Type: sqltypes.VarChar, 611 Value: []byte("1"), 612 }} 613 ) 614 615 // MessageStream is part of the queryservice.QueryService interface 616 func (f *FakeQueryService) MessageStream(ctx context.Context, target *querypb.Target, name string, callback func(*sqltypes.Result) error) (err error) { 617 if f.HasError { 618 return f.TabletError 619 } 620 if f.Panics { 621 panic(fmt.Errorf("test-triggered panic")) 622 } 623 if name != MessageName { 624 f.t.Errorf("name: %s, want %s", name, MessageName) 625 } 626 if err := callback(MessageStreamResult); err != nil { 627 f.t.Logf("MessageStream callback failed: %v", err) 628 } 629 return nil 630 } 631 632 // MessageAck is part of the queryservice.QueryService interface 633 func (f *FakeQueryService) MessageAck(ctx context.Context, target *querypb.Target, name string, ids []*querypb.Value) (count int64, err error) { 634 if f.HasError { 635 return 0, f.TabletError 636 } 637 if f.Panics { 638 panic(fmt.Errorf("test-triggered panic")) 639 } 640 if name != MessageName { 641 f.t.Errorf("name: %s, want %s", name, MessageName) 642 } 643 if !sqltypes.Proto3ValuesEqual(ids, MessageIDs) { 644 f.t.Errorf("ids: %v, want %v", ids, MessageIDs) 645 } 646 return 1, nil 647 } 648 649 // TestStreamHealthStreamHealthResponse is a test stream health response. 650 var TestStreamHealthStreamHealthResponse = &querypb.StreamHealthResponse{ 651 Target: &querypb.Target{ 652 Keyspace: "test_keyspace", 653 Shard: "test_shard", 654 TabletType: topodatapb.TabletType_RDONLY, 655 }, 656 Serving: true, 657 658 TabletExternallyReparentedTimestamp: 1234589, 659 660 RealtimeStats: &querypb.RealtimeStats{ 661 CpuUsage: 1.0, 662 HealthError: "random error", 663 ReplicationLagSeconds: 234, 664 BinlogPlayersCount: 1, 665 FilteredReplicationLagSeconds: 2, 666 }, 667 } 668 669 // TestStreamHealthErrorMsg is a test error message for health streaming. 670 var TestStreamHealthErrorMsg = "to trigger a server error" 671 672 // StreamHealth is part of the queryservice.QueryService interface 673 func (f *FakeQueryService) StreamHealth(ctx context.Context, callback func(*querypb.StreamHealthResponse) error) error { 674 if f.HasError { 675 return errors.New(TestStreamHealthErrorMsg) 676 } 677 if f.Panics { 678 panic(fmt.Errorf("test-triggered panic")) 679 } 680 shr := f.StreamHealthResponse 681 if shr == nil { 682 shr = TestStreamHealthStreamHealthResponse 683 } 684 if err := callback(shr); err != nil { 685 f.t.Logf("StreamHealth callback failed: %v", err) 686 } 687 return nil 688 } 689 690 // VStream is part of the queryservice.QueryService interface 691 func (f *FakeQueryService) VStream(ctx context.Context, request *binlogdatapb.VStreamRequest, send func([]*binlogdatapb.VEvent) error) error { 692 panic("not implemented") 693 } 694 695 // VStreamRows is part of the QueryService interface. 696 func (f *FakeQueryService) VStreamRows(ctx context.Context, request *binlogdatapb.VStreamRowsRequest, send func(*binlogdatapb.VStreamRowsResponse) error) error { 697 panic("not implemented") 698 } 699 700 // VStreamResults is part of the QueryService interface. 701 func (f *FakeQueryService) VStreamResults(ctx context.Context, target *querypb.Target, query string, send func(*binlogdatapb.VStreamResultsResponse) error) error { 702 panic("not implemented") 703 } 704 705 // QueryServiceByAlias satisfies the Gateway interface 706 func (f *FakeQueryService) QueryServiceByAlias(_ *topodatapb.TabletAlias, _ *querypb.Target) (queryservice.QueryService, error) { 707 panic("not implemented") 708 } 709 710 // ReserveBeginExecute satisfies the Gateway interface 711 func (f *FakeQueryService) ReserveBeginExecute(ctx context.Context, target *querypb.Target, preQueries []string, postBeginQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (queryservice.ReservedTransactionState, *sqltypes.Result, error) { 712 panic("implement me") 713 } 714 715 // ReserveBeginStreamExecute satisfies the Gateway interface 716 func (f *FakeQueryService) ReserveBeginStreamExecute(ctx context.Context, target *querypb.Target, preQueries []string, postBeginQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) (queryservice.ReservedTransactionState, error) { 717 panic("implement me") 718 } 719 720 // ReserveExecute implements the QueryService interface 721 func (f *FakeQueryService) ReserveExecute(ctx context.Context, target *querypb.Target, preQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions) (queryservice.ReservedState, *sqltypes.Result, error) { 722 panic("implement me") 723 } 724 725 // ReserveStreamExecute satisfies the Gateway interface 726 func (f *FakeQueryService) ReserveStreamExecute(ctx context.Context, target *querypb.Target, preQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) (queryservice.ReservedState, error) { 727 state, err := f.reserve(transactionID) 728 if err != nil { 729 return state, err 730 } 731 err = f.StreamExecute(ctx, target, sql, bindVariables, transactionID, state.ReservedID, options, callback) 732 return state, err 733 } 734 735 func (f *FakeQueryService) reserve(transactionID int64) (queryservice.ReservedState, error) { 736 reserveID := transactionID 737 if reserveID == 0 { 738 reserveID = beginTransactionID 739 } 740 if f.HasReserveError { 741 return queryservice.ReservedState{}, f.TabletError 742 } 743 state := queryservice.ReservedState{ReservedID: reserveID, TabletAlias: TestAlias} 744 return state, nil 745 } 746 747 // Release implements the QueryService interface 748 func (f *FakeQueryService) Release(ctx context.Context, target *querypb.Target, transactionID, reservedID int64) error { 749 panic("implement me") 750 } 751 752 // GetSchema implements the QueryService interface 753 func (f *FakeQueryService) GetSchema(ctx context.Context, target *querypb.Target, tableType querypb.SchemaTableType, tableNames []string, callback func(schemaRes *querypb.GetSchemaResponse) error) error { 754 panic("implement me") 755 } 756 757 // CreateFakeServer returns the fake server for the tests 758 func CreateFakeServer(t testing.TB) *FakeQueryService { 759 return &FakeQueryService{ 760 t: t, 761 } 762 }