github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/table/session_test.go (about) 1 package table 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "reflect" 8 "testing" 9 "time" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 "github.com/ydb-platform/ydb-go-genproto/Ydb_Table_V1" 14 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" 15 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations" 16 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Scheme" 17 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table" 18 "google.golang.org/grpc" 19 "google.golang.org/protobuf/proto" 20 "google.golang.org/protobuf/types/known/durationpb" 21 22 "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator" 23 "github.com/ydb-platform/ydb-go-sdk/v3/internal/operation" 24 "github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config" 25 "github.com/ydb-platform/ydb-go-sdk/v3/internal/types" 26 "github.com/ydb-platform/ydb-go-sdk/v3/internal/value" 27 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext" 28 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" 29 "github.com/ydb-platform/ydb-go-sdk/v3/table" 30 "github.com/ydb-platform/ydb-go-sdk/v3/table/options" 31 "github.com/ydb-platform/ydb-go-sdk/v3/testutil" 32 ) 33 34 func TestSessionKeepAlive(t *testing.T) { 35 ctx, cancel := xcontext.WithCancel(context.Background()) 36 defer cancel() 37 38 var ( 39 status Ydb_Table.KeepAliveResult_SessionStatus 40 e error 41 ) 42 b := StubBuilder{ 43 T: t, 44 cc: testutil.NewBalancer( 45 testutil.WithInvokeHandlers( 46 testutil.InvokeHandlers{ 47 testutil.TableKeepAlive: func(interface{}) (proto.Message, error) { 48 return &Ydb_Table.KeepAliveResult{SessionStatus: status}, e 49 }, 50 testutil.TableCreateSession: func(interface{}) (proto.Message, error) { 51 return &Ydb_Table.CreateSessionResult{ 52 SessionId: testutil.SessionID(), 53 }, nil 54 }, 55 }, 56 ), 57 ), 58 } 59 s, err := b.createSession(ctx) 60 if err != nil { 61 t.Fatal(err) 62 } 63 e = fmt.Errorf("any error") 64 err = s.KeepAlive(ctx) 65 if err == nil { 66 t.Fatal(err) 67 } 68 69 status, e = Ydb_Table.KeepAliveResult_SESSION_STATUS_READY, nil 70 err = s.KeepAlive(ctx) 71 if err != nil { 72 t.Fatal(err) 73 } 74 if s.Status() != table.SessionReady { 75 t.Fatalf("Result %v differ from, expectd %v", s.Status(), table.SessionReady) 76 } 77 78 status, e = Ydb_Table.KeepAliveResult_SESSION_STATUS_BUSY, nil 79 err = s.KeepAlive(ctx) 80 if err != nil { 81 t.Fatal(err) 82 } 83 if s.Status() != table.SessionBusy { 84 t.Fatalf("Result %v differ from, expectd %v", s.Status(), table.SessionBusy) 85 } 86 } 87 88 func TestSessionDescribeTable(t *testing.T) { 89 ctx, cancel := xcontext.WithCancel(context.Background()) 90 defer cancel() 91 92 var ( 93 result *Ydb_Table.DescribeTableResult 94 e error 95 ) 96 b := StubBuilder{ 97 T: t, 98 cc: testutil.NewBalancer( 99 testutil.WithInvokeHandlers( 100 testutil.InvokeHandlers{ 101 testutil.TableCreateSession: func(interface{}) (proto.Message, error) { 102 return &Ydb_Table.CreateSessionResult{ 103 SessionId: testutil.SessionID(), 104 }, nil 105 }, 106 testutil.TableDescribeTable: func(interface{}) (proto.Message, error) { 107 r := &Ydb_Table.DescribeTableResult{} 108 proto.Merge(r, result) 109 110 return r, e 111 }, 112 }, 113 ), 114 ), 115 } 116 s, err := b.createSession(ctx) 117 if err != nil { 118 t.Fatal(err) 119 } 120 121 { 122 e = fmt.Errorf("any error") 123 _, err = s.DescribeTable(ctx, "") 124 if err == nil { 125 t.Fatal(err) 126 } 127 } 128 { 129 e = nil 130 expect := options.Description{ 131 Name: "testName", 132 PrimaryKey: []string{"testKey"}, 133 Columns: []options.Column{ 134 { 135 Name: "testColumn", 136 Type: types.NewVoid(), 137 Family: "testFamily", 138 }, 139 }, 140 KeyRanges: []options.KeyRange{ 141 { 142 From: nil, 143 To: value.Int64Value(100500), 144 }, 145 { 146 From: value.Int64Value(100500), 147 To: nil, 148 }, 149 }, 150 ColumnFamilies: []options.ColumnFamily{ 151 { 152 Name: "testFamily", 153 Data: options.StoragePool{}, 154 Compression: options.ColumnFamilyCompressionLZ4, 155 KeepInMemory: options.FeatureEnabled, 156 }, 157 }, 158 Attributes: map[string]string{}, 159 ReadReplicaSettings: options.ReadReplicasSettings{ 160 Type: options.ReadReplicasAnyAzReadReplicas, 161 Count: 42, 162 }, 163 StorageSettings: options.StorageSettings{ 164 TableCommitLog0: options.StoragePool{Media: "m1"}, 165 TableCommitLog1: options.StoragePool{Media: "m2"}, 166 External: options.StoragePool{Media: "m3"}, 167 StoreExternalBlobs: options.FeatureEnabled, 168 }, 169 Indexes: []options.IndexDescription{}, 170 Changefeeds: make([]options.ChangefeedDescription, 0), 171 } 172 a := allocator.New() 173 defer a.Free() 174 result = &Ydb_Table.DescribeTableResult{ 175 Self: &Ydb_Scheme.Entry{ 176 Name: expect.Name, 177 Owner: "", 178 Type: 0, 179 EffectivePermissions: nil, 180 Permissions: nil, 181 }, 182 Columns: []*Ydb_Table.ColumnMeta{ 183 { 184 Name: expect.Columns[0].Name, 185 Type: types.TypeToYDB(expect.Columns[0].Type, a), 186 Family: "testFamily", 187 }, 188 }, 189 PrimaryKey: expect.PrimaryKey, 190 ShardKeyBounds: []*Ydb.TypedValue{ 191 value.ToYDB(expect.KeyRanges[0].To, a), 192 }, 193 Indexes: nil, 194 TableStats: nil, 195 ColumnFamilies: []*Ydb_Table.ColumnFamily{ 196 { 197 Name: "testFamily", 198 Data: nil, 199 Compression: Ydb_Table.ColumnFamily_COMPRESSION_LZ4, 200 KeepInMemory: Ydb.FeatureFlag_ENABLED, 201 }, 202 }, 203 ReadReplicasSettings: expect.ReadReplicaSettings.ToYDB(), 204 StorageSettings: expect.StorageSettings.ToYDB(), 205 } 206 207 d, err := s.DescribeTable(ctx, "") 208 if err != nil { 209 t.Fatal(err) 210 } 211 if !reflect.DeepEqual(d, expect) { 212 t.Fatalf("Result %+v differ from, expectd %+v", d, expect) 213 } 214 } 215 } 216 217 func TestSessionOperationModeOnExecuteDataQuery(t *testing.T) { 218 fromTo := [...]struct { 219 srcMode operation.Mode 220 dstMode operation.Mode 221 }{ 222 { 223 srcMode: operation.ModeUnknown, 224 dstMode: operation.ModeSync, 225 }, 226 { 227 srcMode: operation.ModeSync, 228 dstMode: operation.ModeSync, 229 }, 230 { 231 srcMode: operation.ModeAsync, 232 dstMode: operation.ModeAsync, 233 }, 234 } 235 for _, test := range []struct { 236 method testutil.MethodCode 237 do func(t *testing.T, ctx context.Context, c *Client) 238 }{ 239 { 240 method: testutil.TableExecuteDataQuery, 241 do: func(t *testing.T, ctx context.Context, c *Client) { 242 s := &session{ 243 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 244 config: config.New(), 245 } 246 _, _, err := s.Execute(ctx, table.TxControl(), "", table.NewQueryParameters()) 247 require.NoError(t, err) 248 }, 249 }, 250 { 251 method: testutil.TableExplainDataQuery, 252 do: func(t *testing.T, ctx context.Context, c *Client) { 253 s := &session{ 254 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 255 config: config.New(), 256 } 257 _, err := s.Explain(ctx, "") 258 require.NoError(t, err) 259 }, 260 }, 261 { 262 method: testutil.TablePrepareDataQuery, 263 do: func(t *testing.T, ctx context.Context, c *Client) { 264 s := &session{ 265 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 266 config: config.New(), 267 } 268 _, err := s.Prepare(ctx, "") 269 require.NoError(t, err) 270 }, 271 }, 272 { 273 method: testutil.TableCreateSession, 274 do: func(t *testing.T, ctx context.Context, c *Client) { 275 _, err := c.internalPoolCreateSession(ctx) 276 require.NoError(t, err) 277 }, 278 }, 279 { 280 method: testutil.TableDeleteSession, 281 do: func(t *testing.T, ctx context.Context, c *Client) { 282 s := &session{ 283 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 284 config: config.New(), 285 } 286 require.NoError(t, s.Close(ctx)) 287 }, 288 }, 289 { 290 method: testutil.TableBeginTransaction, 291 do: func(t *testing.T, ctx context.Context, c *Client) { 292 s := &session{ 293 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 294 config: config.New(), 295 } 296 _, err := s.BeginTransaction(ctx, table.TxSettings()) 297 require.NoError(t, err) 298 }, 299 }, 300 { 301 method: testutil.TableCommitTransaction, 302 do: func(t *testing.T, ctx context.Context, c *Client) { 303 tx := &transaction{ 304 s: &session{ 305 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 306 config: config.New(), 307 }, 308 } 309 _, err := tx.CommitTx(ctx) 310 require.NoError(t, err) 311 }, 312 }, 313 { 314 method: testutil.TableRollbackTransaction, 315 do: func(t *testing.T, ctx context.Context, c *Client) { 316 tx := &transaction{ 317 s: &session{ 318 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 319 config: config.New(), 320 }, 321 } 322 err := tx.Rollback(ctx) 323 require.NoError(t, err) 324 }, 325 }, 326 { 327 method: testutil.TableKeepAlive, 328 do: func(t *testing.T, ctx context.Context, c *Client) { 329 s := &session{ 330 tableService: Ydb_Table_V1.NewTableServiceClient(c.cc), 331 config: config.New(), 332 } 333 require.NoError(t, s.KeepAlive(ctx)) 334 }, 335 }, 336 } { 337 t.Run( 338 test.method.String(), 339 func(t *testing.T) { 340 for _, srcDst := range fromTo { 341 t.Run(srcDst.srcMode.String()+"->"+srcDst.dstMode.String(), func(t *testing.T) { 342 client, err := New(context.Background(), testutil.NewBalancer( 343 testutil.WithInvokeHandlers( 344 testutil.InvokeHandlers{ 345 testutil.TableExecuteDataQuery: func(interface{}) (proto.Message, error) { 346 return &Ydb_Table.ExecuteQueryResult{ 347 TxMeta: &Ydb_Table.TransactionMeta{ 348 Id: "", 349 }, 350 }, nil 351 }, 352 testutil.TableBeginTransaction: func(interface{}) (proto.Message, error) { 353 return &Ydb_Table.BeginTransactionResult{ 354 TxMeta: &Ydb_Table.TransactionMeta{ 355 Id: "", 356 }, 357 }, nil 358 }, 359 testutil.TableExplainDataQuery: func(request interface{}) (result proto.Message, err error) { 360 return &Ydb_Table.ExplainQueryResult{}, nil 361 }, 362 testutil.TablePrepareDataQuery: func(request interface{}) (result proto.Message, err error) { 363 return &Ydb_Table.PrepareQueryResult{}, nil 364 }, 365 testutil.TableCreateSession: func(interface{}) (proto.Message, error) { 366 return &Ydb_Table.CreateSessionResult{ 367 SessionId: testutil.SessionID(), 368 }, nil 369 }, 370 testutil.TableDeleteSession: func(request interface{}) (result proto.Message, err error) { 371 return &Ydb_Table.DeleteSessionResponse{}, nil 372 }, 373 testutil.TableCommitTransaction: func(request interface{}) (result proto.Message, err error) { 374 return &Ydb_Table.CommitTransactionResult{}, nil 375 }, 376 testutil.TableRollbackTransaction: func(request interface{}) (result proto.Message, err error) { 377 return &Ydb_Table.RollbackTransactionResponse{}, nil 378 }, 379 testutil.TableKeepAlive: func(request interface{}) (result proto.Message, err error) { 380 return &Ydb_Table.KeepAliveResult{}, nil 381 }, 382 }, 383 ), 384 ), config.New()) 385 require.NoError(t, err) 386 ctx, cancel := xcontext.WithTimeout( 387 context.Background(), 388 time.Second, 389 ) 390 defer cancel() 391 test.do(t, ctx, client) 392 }) 393 } 394 }, 395 ) 396 } 397 } 398 399 func TestCreateTableRegression(t *testing.T) { 400 client, err := New(context.Background(), testutil.NewBalancer( 401 testutil.WithInvokeHandlers( 402 testutil.InvokeHandlers{ 403 testutil.TableCreateSession: func(request interface{}) (proto.Message, error) { 404 return &Ydb_Table.CreateSessionResult{ 405 SessionId: "", 406 }, nil 407 }, 408 testutil.TableCreateTable: func(act interface{}) (proto.Message, error) { 409 exp := &Ydb_Table.CreateTableRequest{ 410 SessionId: "", 411 Path: "episodes", 412 Columns: []*Ydb_Table.ColumnMeta{ 413 { 414 Name: "series_id", 415 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 416 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 417 TypeId: Ydb.Type_UINT64, 418 }}}, 419 }}, 420 }, 421 { 422 Name: "season_id", 423 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 424 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 425 TypeId: Ydb.Type_UINT64, 426 }}}, 427 }}, 428 }, 429 { 430 Name: "episode_id", 431 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 432 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 433 TypeId: Ydb.Type_UINT64, 434 }}}, 435 }}, 436 }, 437 { 438 Name: "title", 439 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 440 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 441 TypeId: Ydb.Type_UTF8, 442 }}}, 443 }}, 444 }, 445 { 446 Name: "air_date", 447 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 448 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 449 TypeId: Ydb.Type_UINT64, 450 }}}, 451 }}, 452 }, 453 }, 454 PrimaryKey: []string{ 455 "series_id", 456 "season_id", 457 "episode_id", 458 }, 459 OperationParams: &Ydb_Operations.OperationParams{ 460 OperationMode: Ydb_Operations.OperationParams_SYNC, 461 }, 462 Attributes: map[string]string{ 463 "attr": "attr_value", 464 }, 465 } 466 if !proto.Equal(exp, act.(proto.Message)) { 467 //nolint:revive 468 return nil, fmt.Errorf("proto's not equal: \n\nact: %v\n\nexp: %s\n\n", act, exp) 469 } 470 471 return &Ydb_Table.CreateTableResponse{}, nil 472 }, 473 }, 474 ), 475 ), config.New()) 476 477 require.NoError(t, err) 478 479 ctx, cancel := xcontext.WithTimeout( 480 context.Background(), 481 time.Second, 482 ) 483 defer cancel() 484 485 err = client.Do(ctx, func(ctx context.Context, s table.Session) error { 486 return s.CreateTable(ctx, "episodes", 487 options.WithColumn("series_id", types.NewOptional(types.Uint64)), 488 options.WithColumn("season_id", types.NewOptional(types.Uint64)), 489 options.WithColumn("episode_id", types.NewOptional(types.Uint64)), 490 options.WithColumn("title", types.NewOptional(types.Text)), 491 options.WithColumn("air_date", types.NewOptional(types.Uint64)), 492 options.WithPrimaryKeyColumn("series_id", "season_id", "episode_id"), 493 options.WithAttribute("attr", "attr_value"), 494 ) 495 }) 496 497 require.NoError(t, err, "") 498 } 499 500 func TestDescribeTableRegression(t *testing.T) { 501 client, err := New(context.Background(), testutil.NewBalancer( 502 testutil.WithInvokeHandlers( 503 testutil.InvokeHandlers{ 504 testutil.TableCreateSession: func(request interface{}) (proto.Message, error) { 505 return &Ydb_Table.CreateSessionResult{ 506 SessionId: "", 507 }, nil 508 }, 509 testutil.TableDescribeTable: func(act interface{}) (proto.Message, error) { 510 return &Ydb_Table.DescribeTableResult{ 511 Self: &Ydb_Scheme.Entry{ 512 Name: "episodes", 513 }, 514 Columns: []*Ydb_Table.ColumnMeta{ 515 { 516 Name: "series_id", 517 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 518 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 519 TypeId: Ydb.Type_UINT64, 520 }}}, 521 }}, 522 }, 523 { 524 Name: "season_id", 525 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 526 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 527 TypeId: Ydb.Type_UINT64, 528 }}}, 529 }}, 530 }, 531 { 532 Name: "episode_id", 533 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 534 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 535 TypeId: Ydb.Type_UINT64, 536 }}}, 537 }}, 538 }, 539 { 540 Name: "title", 541 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 542 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 543 TypeId: Ydb.Type_UTF8, 544 }}}, 545 }}, 546 }, 547 { 548 Name: "air_date", 549 Type: &Ydb.Type{Type: &Ydb.Type_OptionalType{ 550 OptionalType: &Ydb.OptionalType{Item: &Ydb.Type{Type: &Ydb.Type_TypeId{ 551 TypeId: Ydb.Type_UINT64, 552 }}}, 553 }}, 554 }, 555 }, 556 PrimaryKey: []string{ 557 "series_id", 558 "season_id", 559 "episode_id", 560 }, 561 Attributes: map[string]string{ 562 "attr": "attr_value", 563 }, 564 }, nil 565 }, 566 }, 567 ), 568 ), config.New()) 569 570 require.NoError(t, err) 571 572 ctx, cancel := xcontext.WithTimeout( 573 context.Background(), 574 time.Second, 575 ) 576 defer cancel() 577 578 var act options.Description 579 580 err = client.Do(ctx, func(ctx context.Context, s table.Session) (err error) { 581 act, err = s.DescribeTable(ctx, "episodes") 582 583 return err 584 }) 585 586 require.NoError(t, err, "") 587 588 exp := options.Description{ 589 Name: "episodes", 590 Columns: []options.Column{ 591 { 592 Name: "series_id", 593 Type: types.NewOptional(types.Uint64), 594 }, 595 { 596 Name: "season_id", 597 Type: types.NewOptional(types.Uint64), 598 }, 599 { 600 Name: "episode_id", 601 Type: types.NewOptional(types.Uint64), 602 }, 603 { 604 Name: "title", 605 Type: types.NewOptional(types.Text), 606 }, 607 { 608 Name: "air_date", 609 Type: types.NewOptional(types.Uint64), 610 }, 611 }, 612 KeyRanges: []options.KeyRange{ 613 {}, 614 }, 615 PrimaryKey: []string{ 616 "series_id", 617 "season_id", 618 "episode_id", 619 }, 620 ColumnFamilies: []options.ColumnFamily{}, 621 Attributes: map[string]string{ 622 "attr": "attr_value", 623 }, 624 Indexes: []options.IndexDescription{}, 625 Changefeeds: []options.ChangefeedDescription{}, 626 } 627 628 assert.Equal(t, exp, act) 629 } 630 631 var errUnexpectedRequest = errors.New("unexpected request") 632 633 type copyTablesMock struct { 634 *Ydb_Table.CopyTablesRequest 635 } 636 637 func (mock *copyTablesMock) CopyTables( 638 _ context.Context, in *Ydb_Table.CopyTablesRequest, opts ...grpc.CallOption, 639 ) (*Ydb_Table.CopyTablesResponse, error) { 640 if in.String() == mock.String() { 641 return &Ydb_Table.CopyTablesResponse{}, nil 642 } 643 644 return nil, fmt.Errorf("%w: %s, exp: %s", errUnexpectedRequest, in, mock.String()) 645 } 646 647 func Test_copyTables(t *testing.T) { 648 ctx := xtest.Context(t) 649 for _, tt := range []struct { 650 sessionID string 651 operationTimeout time.Duration 652 operationCancelAfter time.Duration 653 service *copyTablesMock 654 opts []options.CopyTablesOption 655 err error 656 }{ 657 { 658 sessionID: "1", 659 operationTimeout: time.Second, 660 operationCancelAfter: time.Second, 661 service: ©TablesMock{ 662 CopyTablesRequest: &Ydb_Table.CopyTablesRequest{ 663 SessionId: "1", 664 Tables: []*Ydb_Table.CopyTableItem{ 665 { 666 SourcePath: "from", 667 DestinationPath: "to", 668 OmitIndexes: true, 669 }, 670 }, 671 OperationParams: &Ydb_Operations.OperationParams{ 672 OperationMode: Ydb_Operations.OperationParams_SYNC, 673 OperationTimeout: durationpb.New(time.Second), 674 CancelAfter: durationpb.New(time.Second), 675 }, 676 }, 677 }, 678 opts: []options.CopyTablesOption{ 679 options.CopyTablesItem("from", "to", true), 680 }, 681 err: nil, 682 }, 683 { 684 sessionID: "2", 685 operationTimeout: 2 * time.Second, 686 operationCancelAfter: 2 * time.Second, 687 service: ©TablesMock{ 688 CopyTablesRequest: &Ydb_Table.CopyTablesRequest{ 689 SessionId: "2", 690 Tables: []*Ydb_Table.CopyTableItem{ 691 { 692 SourcePath: "from1", 693 DestinationPath: "to1", 694 OmitIndexes: true, 695 }, 696 { 697 SourcePath: "from2", 698 DestinationPath: "to2", 699 OmitIndexes: false, 700 }, 701 { 702 SourcePath: "from3", 703 DestinationPath: "to3", 704 OmitIndexes: true, 705 }, 706 }, 707 OperationParams: &Ydb_Operations.OperationParams{ 708 OperationMode: Ydb_Operations.OperationParams_SYNC, 709 OperationTimeout: durationpb.New(2 * time.Second), 710 CancelAfter: durationpb.New(2 * time.Second), 711 }, 712 }, 713 }, 714 opts: []options.CopyTablesOption{ 715 options.CopyTablesItem("from1", "to1", true), 716 options.CopyTablesItem("from2", "to2", false), 717 options.CopyTablesItem("from3", "to3", true), 718 }, 719 err: nil, 720 }, 721 { 722 sessionID: "3", 723 operationTimeout: time.Second, 724 operationCancelAfter: time.Second, 725 service: ©TablesMock{ 726 CopyTablesRequest: &Ydb_Table.CopyTablesRequest{ 727 SessionId: "1", 728 Tables: []*Ydb_Table.CopyTableItem{ 729 { 730 SourcePath: "from", 731 DestinationPath: "to", 732 OmitIndexes: true, 733 }, 734 }, 735 OperationParams: &Ydb_Operations.OperationParams{ 736 OperationMode: Ydb_Operations.OperationParams_SYNC, 737 OperationTimeout: durationpb.New(time.Second), 738 CancelAfter: durationpb.New(time.Second), 739 }, 740 }, 741 }, 742 opts: []options.CopyTablesOption{ 743 options.CopyTablesItem("from1", "to1", true), 744 }, 745 err: errUnexpectedRequest, 746 }, 747 { 748 sessionID: "4", 749 operationTimeout: time.Second, 750 operationCancelAfter: time.Second, 751 service: ©TablesMock{}, 752 opts: nil, 753 err: errParamsRequired, 754 }, 755 } { 756 t.Run("", func(t *testing.T) { 757 err := copyTables(ctx, tt.sessionID, tt.operationTimeout, tt.operationCancelAfter, tt.service, tt.opts...) 758 if tt.err != nil { 759 require.ErrorIs(t, err, tt.err) 760 } else { 761 require.NoError(t, err) 762 } 763 }) 764 } 765 }