github.com/tsuna/gohbase@v0.0.0-20250731002811-4ffcadfba63e/hrpc/hrpc_test.go (about) 1 // Copyright (C) 2015 The GoHBase Authors. All rights reserved. 2 // This file is part of GoHBase. 3 // Use of this source code is governed by the Apache License 2.0 4 // that can be found in the COPYING file. 5 6 package hrpc 7 8 import ( 9 "bytes" 10 "context" 11 "errors" 12 "math" 13 "reflect" 14 "sort" 15 "strconv" 16 "testing" 17 "time" 18 19 "github.com/tsuna/gohbase/filter" 20 "github.com/tsuna/gohbase/pb" 21 "github.com/tsuna/gohbase/test" 22 "google.golang.org/protobuf/proto" 23 ) 24 25 func TestNewGet(t *testing.T) { 26 ctx := context.Background() 27 table := "test" 28 tableb := []byte(table) 29 key := "45" 30 keyb := []byte(key) 31 fam := make(map[string][]string) 32 fam["info"] = []string{"c1"} 33 filter1 := filter.NewFirstKeyOnlyFilter() 34 get, err := NewGet(ctx, tableb, keyb) 35 if err != nil || !confirmGetAttributes(ctx, get, tableb, keyb, nil, nil) { 36 t.Errorf("Get1 didn't set attributes correctly.") 37 } 38 get, err = NewGetStr(ctx, table, key) 39 if err != nil || !confirmGetAttributes(ctx, get, tableb, keyb, nil, nil) { 40 t.Errorf("Get2 didn't set attributes correctly.") 41 } 42 get, err = NewGet(ctx, tableb, keyb, Families(fam)) 43 if err != nil || !confirmGetAttributes(ctx, get, tableb, keyb, fam, nil) { 44 t.Errorf("Get3 didn't set attributes correctly.") 45 } 46 get, err = NewGet(ctx, tableb, keyb, Filters(filter1)) 47 if err != nil || !confirmGetAttributes(ctx, get, tableb, keyb, nil, filter1) { 48 t.Errorf("Get4 didn't set attributes correctly.") 49 } 50 get, err = NewGet(ctx, tableb, keyb, Filters(filter1), Families(fam)) 51 if err != nil || !confirmGetAttributes(ctx, get, tableb, keyb, fam, filter1) { 52 t.Errorf("Get5 didn't set attributes correctly.") 53 } 54 get, err = NewGet(ctx, tableb, keyb, Filters(filter1)) 55 if err != nil { 56 t.Errorf("Get6 didn't set attributes correctly.") 57 } 58 err = Families(fam)(get) 59 if err != nil || !confirmGetAttributes(ctx, get, tableb, keyb, fam, filter1) { 60 t.Errorf("Get6 didn't set attributes correctly.") 61 } 62 _, err = NewGet(ctx, tableb, keyb, MaxVersions(math.MaxInt32)) 63 if err != nil { 64 t.Errorf("Get7 didn't set attributes correctly.") 65 } 66 _, err = NewGet(ctx, tableb, keyb, MaxVersions(math.MaxInt32+1)) 67 errStr := "'MaxVersions' exceeds supported number of versions" 68 if err != nil && errStr != err.Error() || err == nil { 69 t.Errorf("Get8 Expected: %#v\nReceived: %#v", errStr, err) 70 } 71 } 72 73 func confirmGetAttributes(ctx context.Context, g *Get, table, key []byte, 74 fam map[string][]string, filter1 filter.Filter) bool { 75 if g.Context() != ctx || 76 !bytes.Equal(g.Table(), table) || 77 !bytes.Equal(g.Key(), key) || 78 !reflect.DeepEqual(g.families, fam) || 79 (filter1 != nil && g.filter == nil) { 80 return false 81 } 82 return true 83 } 84 85 func TestGetToProto(t *testing.T) { 86 var ( 87 ctx = context.Background() 88 keyStr = "key" 89 key = []byte("key") 90 rs = &pb.RegionSpecifier{ 91 Type: pb.RegionSpecifier_REGION_NAME.Enum(), 92 Value: []byte("region"), 93 } 94 fil = filter.NewList(filter.MustPassAll, filter.NewKeyOnlyFilter(false)) 95 fam = map[string][]string{"cookie": []string{"got", "it"}} 96 ) 97 98 tests := []struct { 99 g *Get 100 expProto *pb.GetRequest 101 }{ 102 { 103 g: func() *Get { 104 get, _ := NewGetStr(ctx, "", keyStr) 105 return get 106 }(), 107 expProto: &pb.GetRequest{ 108 Region: rs, 109 Get: &pb.Get{ 110 Row: key, 111 Column: []*pb.Column{}, 112 TimeRange: &pb.TimeRange{}, 113 }, 114 }, 115 }, 116 { // explicitly set configurable attributes to default values 117 g: func() *Get { 118 get, _ := NewGetStr(ctx, "", keyStr, 119 MaxResultsPerColumnFamily(DefaultMaxResultsPerColumnFamily), 120 ResultOffset(0), 121 MaxVersions(DefaultMaxVersions), 122 CacheBlocks(DefaultCacheBlocks), 123 TimeRangeUint64(MinTimestamp, MaxTimestamp), 124 ) 125 return get 126 }(), 127 expProto: &pb.GetRequest{ 128 Region: rs, 129 Get: &pb.Get{ 130 Row: key, 131 Column: []*pb.Column{}, 132 TimeRange: &pb.TimeRange{}, 133 StoreLimit: nil, 134 StoreOffset: nil, 135 MaxVersions: nil, 136 CacheBlocks: nil, 137 }, 138 }, 139 }, 140 { // set configurable options to non-default values 141 g: func() *Get { 142 get, _ := NewGetStr(ctx, "", keyStr, 143 MaxResultsPerColumnFamily(22), 144 ResultOffset(7), 145 MaxVersions(4), 146 CacheBlocks(!DefaultCacheBlocks), 147 TimeRangeUint64(3456, 6789), 148 ) 149 return get 150 }(), 151 expProto: &pb.GetRequest{ 152 Region: rs, 153 Get: &pb.Get{ 154 Row: key, 155 Column: []*pb.Column{}, 156 TimeRange: &pb.TimeRange{ 157 From: proto.Uint64(3456), 158 To: proto.Uint64(6789), 159 }, 160 StoreLimit: proto.Uint32(22), 161 StoreOffset: proto.Uint32(7), 162 MaxVersions: proto.Uint32(4), 163 CacheBlocks: proto.Bool(!DefaultCacheBlocks), 164 }, 165 }, 166 }, 167 { // set filters, families, and existenceOnly 168 g: func() *Get { 169 get, _ := NewGetStr(ctx, "", keyStr, 170 Filters(fil), 171 Families(fam), 172 ) 173 get.ExistsOnly() 174 return get 175 }(), 176 expProto: func() *pb.GetRequest { 177 pbFilter, _ := fil.ConstructPBFilter() 178 return &pb.GetRequest{ 179 Region: rs, 180 Get: &pb.Get{ 181 Row: key, 182 Column: familiesToColumn(fam), 183 TimeRange: &pb.TimeRange{}, 184 ExistenceOnly: proto.Bool(true), 185 Filter: pbFilter, 186 }, 187 } 188 }(), 189 }, 190 } 191 192 for i, tcase := range tests { 193 t.Run(strconv.Itoa(i), func(t *testing.T) { 194 tcase.g.SetRegion(mockRegionInfo("region")) 195 p := tcase.g.ToProto() 196 out, ok := p.(*pb.GetRequest) 197 if !ok { 198 t.Fatalf("f") 199 } 200 if !proto.Equal(out, tcase.expProto) { 201 t.Fatalf("expected %+v, got %+v", tcase.expProto, out) 202 } 203 }) 204 205 } 206 } 207 208 func TestNewScan(t *testing.T) { 209 ctx := context.Background() 210 table := "test" 211 tableb := []byte(table) 212 fam := make(map[string][]string) 213 fam["info"] = []string{"c1"} 214 filter1 := filter.NewFirstKeyOnlyFilter() 215 start := "0" 216 stop := "100" 217 startb := []byte("0") 218 stopb := []byte("100") 219 scan, err := NewScan(ctx, tableb) 220 if err != nil || !confirmScanAttributes(ctx, scan, tableb, nil, nil, nil, nil, 221 DefaultNumberOfRows, 0, false) { 222 t.Errorf("Scan1 didn't set attributes correctly.") 223 } 224 scan, err = NewScanRange(ctx, tableb, startb, stopb) 225 if err != nil || !confirmScanAttributes(ctx, scan, tableb, startb, stopb, nil, nil, 226 DefaultNumberOfRows, 0, false) { 227 t.Errorf("Scan2 didn't set attributes correctly.") 228 } 229 scan, err = NewScanStr(ctx, table) 230 if err != nil || !confirmScanAttributes(ctx, scan, tableb, nil, nil, nil, nil, 231 DefaultNumberOfRows, 0, false) { 232 t.Errorf("Scan3 didn't set attributes correctly.") 233 } 234 scan, err = NewScanRangeStr(ctx, table, start, stop) 235 if err != nil || !confirmScanAttributes(ctx, scan, tableb, startb, stopb, nil, nil, 236 DefaultNumberOfRows, 0, false) { 237 t.Errorf("Scan4 didn't set attributes correctly.") 238 } 239 scan, err = NewScanRange(ctx, tableb, startb, stopb, Families(fam), Filters(filter1)) 240 if err != nil || !confirmScanAttributes(ctx, scan, tableb, startb, stopb, fam, filter1, 241 DefaultNumberOfRows, 0, false) { 242 t.Errorf("Scan5 didn't set attributes correctly.") 243 } 244 scan, err = NewScan(ctx, tableb, Filters(filter1), Families(fam)) 245 if err != nil || !confirmScanAttributes(ctx, scan, tableb, nil, nil, fam, filter1, 246 DefaultNumberOfRows, 0, false) { 247 t.Errorf("Scan6 didn't set attributes correctly.") 248 } 249 scan, err = NewScan(ctx, tableb, NumberOfRows(1)) 250 if err != nil || !confirmScanAttributes(ctx, scan, tableb, nil, nil, nil, nil, 1, 0, false) { 251 t.Errorf("Scan7 didn't set number of versions correctly") 252 } 253 scan, err = NewScan(ctx, tableb, RenewInterval(10*time.Second)) 254 if err != nil || !confirmScanAttributes(ctx, scan, tableb, nil, nil, nil, nil, 255 DefaultNumberOfRows, 10*time.Second, false) { 256 t.Errorf("Scan8 didn't set renew correctly") 257 } 258 scan, err = NewScan(ctx, tableb, RenewalScan()) 259 if err != nil || !confirmScanAttributes(ctx, scan, tableb, nil, nil, nil, nil, 260 DefaultNumberOfRows, 0, true) { 261 t.Errorf("Scan8 didn't set renew correctly") 262 } 263 } 264 265 func TestScanToProto(t *testing.T) { 266 var ( 267 ctx = context.Background() 268 rs = &pb.RegionSpecifier{ 269 Type: pb.RegionSpecifier_REGION_NAME.Enum(), 270 Value: []byte("region"), 271 } 272 startRow = []byte("start") 273 stopRow = []byte("stop") 274 fil = filter.NewKeyOnlyFilter(false) 275 fam = map[string][]string{"cookie": []string{"got", "it"}} 276 ) 277 278 tests := []struct { 279 s *Scan 280 expProto *pb.ScanRequest 281 }{ 282 { 283 s: func() *Scan { 284 s, _ := NewScanStr(ctx, "") 285 return s 286 }(), 287 expProto: &pb.ScanRequest{ 288 Region: rs, 289 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 290 CloseScanner: proto.Bool(false), 291 ClientHandlesPartials: proto.Bool(true), 292 ClientHandlesHeartbeats: proto.Bool(true), 293 Scan: &pb.Scan{ 294 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 295 Column: []*pb.Column{}, 296 TimeRange: &pb.TimeRange{}, 297 }, 298 TrackScanMetrics: proto.Bool(false), 299 Renew: proto.Bool(false), 300 }, 301 }, 302 { // explicitly set configurable attributes to default values 303 s: func() *Scan { 304 s, _ := NewScanStr(ctx, "", 305 MaxResultSize(DefaultMaxResultSize), 306 ScannerID(math.MaxUint64), 307 NumberOfRows(DefaultNumberOfRows), 308 MaxResultsPerColumnFamily(DefaultMaxResultsPerColumnFamily), 309 ResultOffset(0), 310 MaxVersions(DefaultMaxVersions), 311 CacheBlocks(DefaultCacheBlocks), 312 TimeRangeUint64(MinTimestamp, MaxTimestamp), 313 ) 314 return s 315 }(), 316 expProto: &pb.ScanRequest{ 317 Region: rs, 318 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 319 ScannerId: nil, 320 CloseScanner: proto.Bool(false), 321 ClientHandlesPartials: proto.Bool(true), 322 ClientHandlesHeartbeats: proto.Bool(true), 323 Scan: &pb.Scan{ 324 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 325 Column: []*pb.Column{}, 326 TimeRange: &pb.TimeRange{}, 327 StoreLimit: nil, 328 StoreOffset: nil, 329 MaxVersions: nil, 330 CacheBlocks: nil, 331 }, 332 TrackScanMetrics: proto.Bool(false), 333 Renew: proto.Bool(false), 334 }, 335 }, 336 { // set configurable attributes to non-default values 337 s: func() *Scan { 338 s, _ := NewScanStr(ctx, "", 339 MaxResultSize(52), 340 NumberOfRows(37), 341 MaxResultsPerColumnFamily(13), 342 ResultOffset(7), 343 MaxVersions(89), 344 CacheBlocks(!DefaultCacheBlocks), 345 TimeRangeUint64(1024, 1738), 346 RenewInterval(10*time.Second), 347 RenewalScan(), 348 ) 349 return s 350 }(), 351 expProto: &pb.ScanRequest{ 352 Region: rs, 353 NumberOfRows: proto.Uint32(37), 354 CloseScanner: proto.Bool(false), 355 ClientHandlesPartials: proto.Bool(true), 356 ClientHandlesHeartbeats: proto.Bool(true), 357 Scan: &pb.Scan{ 358 MaxResultSize: proto.Uint64(52), 359 Column: []*pb.Column{}, 360 TimeRange: &pb.TimeRange{ 361 From: proto.Uint64(1024), 362 To: proto.Uint64(1738), 363 }, 364 StoreLimit: proto.Uint32(13), 365 StoreOffset: proto.Uint32(7), 366 MaxVersions: proto.Uint32(89), 367 CacheBlocks: proto.Bool(!DefaultCacheBlocks), 368 }, 369 TrackScanMetrics: proto.Bool(false), 370 Renew: proto.Bool(true), 371 }, 372 }, 373 { // test that pb.ScanRequest.Scan is nil when scanner id is specificed 374 s: func() *Scan { 375 s, _ := NewScanStr(ctx, "", 376 MaxResultSize(52), 377 NumberOfRows(37), 378 ScannerID(4444), 379 MaxResultsPerColumnFamily(13), 380 ResultOffset(7), 381 MaxVersions(89), 382 CacheBlocks(!DefaultCacheBlocks), 383 TimeRangeUint64(1024, 1738), 384 ) 385 return s 386 }(), 387 expProto: &pb.ScanRequest{ 388 Region: rs, 389 NumberOfRows: proto.Uint32(37), 390 ScannerId: proto.Uint64(4444), 391 CloseScanner: proto.Bool(false), 392 ClientHandlesPartials: proto.Bool(true), 393 ClientHandlesHeartbeats: proto.Bool(true), 394 Scan: nil, 395 TrackScanMetrics: proto.Bool(false), 396 Renew: proto.Bool(false), 397 }, 398 }, 399 { // set reversed attribute 400 s: func() *Scan { 401 s, _ := NewScanStr(ctx, "", Reversed()) 402 return s 403 }(), 404 expProto: &pb.ScanRequest{ 405 Region: rs, 406 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 407 CloseScanner: proto.Bool(false), 408 ClientHandlesPartials: proto.Bool(true), 409 ClientHandlesHeartbeats: proto.Bool(true), 410 Scan: &pb.Scan{ 411 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 412 Column: []*pb.Column{}, 413 TimeRange: &pb.TimeRange{}, 414 Reversed: proto.Bool(true), 415 }, 416 TrackScanMetrics: proto.Bool(false), 417 Renew: proto.Bool(false), 418 }, 419 }, 420 { // set scan attribute 421 s: func() *Scan { 422 s, _ := NewScanStr(ctx, "", 423 Attribute("key1", []byte("value1")), 424 Attribute("key2", []byte("value2")), 425 ) 426 return s 427 }(), 428 expProto: &pb.ScanRequest{ 429 Region: rs, 430 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 431 CloseScanner: proto.Bool(false), 432 ClientHandlesPartials: proto.Bool(true), 433 ClientHandlesHeartbeats: proto.Bool(true), 434 Scan: &pb.Scan{ 435 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 436 Column: []*pb.Column{}, 437 TimeRange: &pb.TimeRange{}, 438 Attribute: []*pb.NameBytesPair{ 439 {Name: proto.String("key1"), Value: []byte("value1")}, 440 {Name: proto.String("key2"), Value: []byte("value2")}, 441 }, 442 }, 443 TrackScanMetrics: proto.Bool(false), 444 Renew: proto.Bool(false), 445 }, 446 }, 447 { // scan key range 448 s: func() *Scan { 449 s, _ := NewScanRange(ctx, nil, startRow, stopRow) 450 return s 451 }(), 452 expProto: &pb.ScanRequest{ 453 Region: rs, 454 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 455 CloseScanner: proto.Bool(false), 456 ClientHandlesPartials: proto.Bool(true), 457 ClientHandlesHeartbeats: proto.Bool(true), 458 Scan: &pb.Scan{ 459 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 460 Column: []*pb.Column{}, 461 TimeRange: &pb.TimeRange{}, 462 StartRow: startRow, 463 StopRow: stopRow, 464 }, 465 TrackScanMetrics: proto.Bool(false), 466 Renew: proto.Bool(false), 467 }, 468 }, 469 { // set filters and families 470 s: func() *Scan { 471 s, _ := NewScanStr(ctx, "", Filters(fil), Families(fam)) 472 return s 473 }(), 474 expProto: func() *pb.ScanRequest { 475 pbFilter, _ := fil.ConstructPBFilter() 476 return &pb.ScanRequest{ 477 Region: rs, 478 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 479 CloseScanner: proto.Bool(false), 480 ClientHandlesPartials: proto.Bool(true), 481 ClientHandlesHeartbeats: proto.Bool(true), 482 Scan: &pb.Scan{ 483 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 484 Column: familiesToColumn(fam), 485 TimeRange: &pb.TimeRange{}, 486 Filter: pbFilter, 487 }, 488 TrackScanMetrics: proto.Bool(false), 489 Renew: proto.Bool(false), 490 } 491 }(), 492 }, 493 { // close scanner 494 s: func() *Scan { 495 s, _ := NewScanStr(ctx, "", CloseScanner()) 496 return s 497 }(), 498 expProto: &pb.ScanRequest{ 499 Region: rs, 500 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 501 CloseScanner: proto.Bool(true), 502 ClientHandlesPartials: proto.Bool(true), 503 ClientHandlesHeartbeats: proto.Bool(true), 504 Scan: &pb.Scan{ 505 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 506 Column: []*pb.Column{}, 507 TimeRange: &pb.TimeRange{}, 508 }, 509 TrackScanMetrics: proto.Bool(false), 510 Renew: proto.Bool(false), 511 }, 512 }, 513 // set TrackScanMetrics 514 { 515 s: func() *Scan { 516 s, _ := NewScanStr(ctx, "", TrackScanMetrics()) 517 return s 518 }(), 519 expProto: func() *pb.ScanRequest { 520 return &pb.ScanRequest{ 521 Region: rs, 522 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 523 CloseScanner: proto.Bool(false), 524 ClientHandlesPartials: proto.Bool(true), 525 ClientHandlesHeartbeats: proto.Bool(true), 526 Scan: &pb.Scan{ 527 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 528 TimeRange: &pb.TimeRange{}, 529 }, 530 TrackScanMetrics: proto.Bool(true), 531 Renew: proto.Bool(false), 532 } 533 }(), 534 }, 535 // set RenewInterval, this shouldn't affect the protobuf 536 { 537 s: func() *Scan { 538 s, _ := NewScanStr(ctx, "", RenewInterval(10*time.Second)) 539 return s 540 }(), 541 expProto: func() *pb.ScanRequest { 542 return &pb.ScanRequest{ 543 Region: rs, 544 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 545 CloseScanner: proto.Bool(false), 546 ClientHandlesPartials: proto.Bool(true), 547 ClientHandlesHeartbeats: proto.Bool(true), 548 Scan: &pb.Scan{ 549 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 550 TimeRange: &pb.TimeRange{}, 551 }, 552 TrackScanMetrics: proto.Bool(false), 553 Renew: proto.Bool(false), 554 } 555 }(), 556 }, 557 // set RenewalScan 558 { 559 s: func() *Scan { 560 s, _ := NewScanStr(ctx, "", RenewalScan()) 561 return s 562 }(), 563 expProto: func() *pb.ScanRequest { 564 return &pb.ScanRequest{ 565 Region: rs, 566 NumberOfRows: proto.Uint32(DefaultNumberOfRows), 567 CloseScanner: proto.Bool(false), 568 ClientHandlesPartials: proto.Bool(true), 569 ClientHandlesHeartbeats: proto.Bool(true), 570 Scan: &pb.Scan{ 571 MaxResultSize: proto.Uint64(DefaultMaxResultSize), 572 TimeRange: &pb.TimeRange{}, 573 }, 574 TrackScanMetrics: proto.Bool(false), 575 Renew: proto.Bool(true), 576 } 577 }(), 578 }, 579 } 580 581 for i, tcase := range tests { 582 t.Run(strconv.Itoa(i), func(t *testing.T) { 583 tcase.s.SetRegion(mockRegionInfo("region")) 584 p := tcase.s.ToProto() 585 out, ok := p.(*pb.ScanRequest) 586 if !ok { 587 t.Fatalf("f") 588 } 589 if !proto.Equal(out, tcase.expProto) { 590 t.Fatalf("expected %+v, got %+v", tcase.expProto, out) 591 } 592 }) 593 594 } 595 } 596 597 type mockRegionInfo []byte 598 599 func (ri mockRegionInfo) Name() []byte { 600 return ri 601 } 602 603 func (ri mockRegionInfo) IsUnavailable() bool { return true } 604 func (ri mockRegionInfo) AvailabilityChan() <-chan struct{} { return nil } 605 func (ri mockRegionInfo) MarkUnavailable() bool { return true } 606 func (ri mockRegionInfo) MarkAvailable() {} 607 func (ri mockRegionInfo) MarkDead() {} 608 func (ri mockRegionInfo) Context() context.Context { return nil } 609 func (ri mockRegionInfo) String() string { return "" } 610 func (ri mockRegionInfo) ID() uint64 { return 0 } 611 func (ri mockRegionInfo) StartKey() []byte { return nil } 612 func (ri mockRegionInfo) StopKey() []byte { return nil } 613 func (ri mockRegionInfo) Namespace() []byte { return nil } 614 func (ri mockRegionInfo) Table() []byte { return nil } 615 func (ri mockRegionInfo) SetClient(RegionClient) {} 616 func (ri mockRegionInfo) Client() RegionClient { return nil } 617 618 type byFamily []*pb.MutationProto_ColumnValue 619 620 func (f byFamily) Len() int { return len(f) } 621 func (f byFamily) Swap(i, j int) { f[i], f[j] = f[j], f[i] } 622 func (f byFamily) Less(i, j int) bool { 623 return bytes.Compare(f[i].Family, f[j].Family) < 0 624 } 625 626 type byQualifier []*pb.MutationProto_ColumnValue_QualifierValue 627 628 func (q byQualifier) Len() int { return len(q) } 629 func (q byQualifier) Swap(i, j int) { q[i], q[j] = q[j], q[i] } 630 func (q byQualifier) Less(i, j int) bool { 631 return bytes.Compare(q[i].Qualifier, q[j].Qualifier) < 0 632 } 633 634 type bytesSlice [][]byte 635 636 func (p bytesSlice) Len() int { return len(p) } 637 func (p bytesSlice) Less(i, j int) bool { return bytes.Compare(p[i], p[j]) < 0 } 638 func (p bytesSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } 639 640 func bytesSlicesEqual(a, b [][]byte) bool { 641 if len(a) != len(b) { 642 return false 643 } 644 for i := range a { 645 if !bytes.Equal(a[i], b[i]) { 646 return false 647 } 648 } 649 return true 650 } 651 652 func bytesSlicesLen(a [][]byte) uint32 { 653 var l uint32 654 for _, b := range a { 655 l += uint32(len(b)) 656 } 657 return l 658 } 659 660 func TestMutate(t *testing.T) { 661 var ( 662 ctx = context.Background() 663 tableStr = "table" 664 keyStr = "key" 665 table = []byte("table") 666 key = []byte("key") 667 rs = &pb.RegionSpecifier{ 668 Type: pb.RegionSpecifier_REGION_NAME.Enum(), 669 Value: []byte("region"), 670 } 671 ) 672 673 tests := []struct { 674 in func() (*Mutate, error) 675 inStr func() (*Mutate, error) 676 out *pb.MutateRequest 677 cellblocksProto *pb.MutateRequest 678 679 // testcase contains multiple individual cellblocks. The 680 // actual output cellblocks will have each of these 681 // concatenated into a single slice, but in an 682 // non-deterministic order. 683 cellblocks [][]byte 684 cellblocksLen uint32 685 err error 686 }{ 687 { 688 in: func() (*Mutate, error) { 689 return NewPut(ctx, table, key, nil) 690 }, 691 inStr: func() (*Mutate, error) { 692 return NewPutStr(ctx, tableStr, keyStr, nil) 693 }, 694 out: &pb.MutateRequest{ 695 Region: rs, 696 Mutation: &pb.MutationProto{ 697 Row: key, 698 MutateType: pb.MutationProto_PUT.Enum(), 699 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 700 }, 701 }, 702 cellblocksProto: &pb.MutateRequest{ 703 Region: rs, 704 Mutation: &pb.MutationProto{ 705 Row: key, 706 MutateType: pb.MutationProto_PUT.Enum(), 707 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 708 AssociatedCellCount: proto.Int32(0), 709 }, 710 }, 711 }, 712 { 713 in: func() (*Mutate, error) { 714 return NewPut(ctx, table, key, nil, Durability(SkipWal)) 715 }, 716 inStr: func() (*Mutate, error) { 717 return NewPutStr(ctx, tableStr, keyStr, nil, Durability(SkipWal)) 718 }, 719 out: &pb.MutateRequest{ 720 Region: rs, 721 Mutation: &pb.MutationProto{ 722 Row: key, 723 MutateType: pb.MutationProto_PUT.Enum(), 724 Durability: pb.MutationProto_SKIP_WAL.Enum(), 725 }, 726 }, 727 cellblocksProto: &pb.MutateRequest{ 728 Region: rs, 729 Mutation: &pb.MutationProto{ 730 Row: key, 731 MutateType: pb.MutationProto_PUT.Enum(), 732 Durability: pb.MutationProto_SKIP_WAL.Enum(), 733 AssociatedCellCount: proto.Int32(0), 734 }, 735 }, 736 }, 737 { 738 in: func() (*Mutate, error) { 739 return NewPut(ctx, table, key, nil, Durability(DurabilityType(42))) 740 }, 741 inStr: func() (*Mutate, error) { 742 return NewPutStr(ctx, tableStr, keyStr, nil, Durability(DurabilityType(42))) 743 }, 744 err: errors.New("invalid durability value"), 745 }, 746 { 747 in: func() (*Mutate, error) { 748 return NewPut(ctx, table, key, nil, TTL(time.Second)) 749 }, 750 inStr: func() (*Mutate, error) { 751 return NewPutStr(ctx, tableStr, keyStr, nil, TTL(time.Second)) 752 }, 753 out: &pb.MutateRequest{ 754 Region: rs, 755 Mutation: &pb.MutationProto{ 756 Row: key, 757 MutateType: pb.MutationProto_PUT.Enum(), 758 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 759 Attribute: []*pb.NameBytesPair{ 760 &pb.NameBytesPair{ 761 Name: &attributeNameTTL, 762 Value: []byte("\x00\x00\x00\x00\x00\x00\x03\xe8"), 763 }, 764 }, 765 }, 766 }, 767 cellblocksProto: &pb.MutateRequest{ 768 Region: rs, 769 Mutation: &pb.MutationProto{ 770 Row: key, 771 MutateType: pb.MutationProto_PUT.Enum(), 772 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 773 Attribute: []*pb.NameBytesPair{ 774 &pb.NameBytesPair{ 775 Name: &attributeNameTTL, 776 Value: []byte("\x00\x00\x00\x00\x00\x00\x03\xe8"), 777 }, 778 }, 779 AssociatedCellCount: proto.Int32(0), 780 }, 781 }, 782 }, 783 { 784 in: func() (*Mutate, error) { 785 return NewPut(ctx, table, key, map[string]map[string][]byte{ 786 "cf": map[string][]byte{ 787 "q": []byte("value"), 788 }, 789 }) 790 }, 791 inStr: func() (*Mutate, error) { 792 return NewPutStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 793 "cf": map[string][]byte{ 794 "q": []byte("value"), 795 }, 796 }) 797 }, 798 out: &pb.MutateRequest{ 799 Region: rs, 800 Mutation: &pb.MutationProto{ 801 Row: key, 802 MutateType: pb.MutationProto_PUT.Enum(), 803 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 804 ColumnValue: []*pb.MutationProto_ColumnValue{ 805 &pb.MutationProto_ColumnValue{ 806 Family: []byte("cf"), 807 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 808 &pb.MutationProto_ColumnValue_QualifierValue{ 809 Qualifier: []byte("q"), 810 Value: []byte("value"), 811 }, 812 }, 813 }, 814 }, 815 }, 816 }, 817 cellblocksProto: &pb.MutateRequest{ 818 Region: rs, 819 Mutation: &pb.MutationProto{ 820 Row: key, 821 MutateType: pb.MutationProto_PUT.Enum(), 822 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 823 AssociatedCellCount: proto.Int32(1), 824 }, 825 }, 826 cellblocksLen: 35, 827 cellblocks: [][]byte{ 828 []byte("\x00\x00\x00\x1f\x00\x00\x00\x12\x00\x00\x00\x05\x00\x03" + 829 "key" + "\x02" + "cf" + "q" + 830 "\u007f\xff\xff\xff\xff\xff\xff\xff\x04" + "value")}, 831 }, 832 { 833 in: func() (*Mutate, error) { 834 return NewPut(ctx, table, key, map[string]map[string][]byte{ 835 "cf1": map[string][]byte{ 836 "q1": []byte("value"), 837 "q2": []byte("value"), 838 }, 839 "cf2": map[string][]byte{ 840 "q1": []byte("value"), 841 }, 842 }) 843 }, 844 inStr: func() (*Mutate, error) { 845 return NewPutStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 846 "cf1": map[string][]byte{ 847 "q1": []byte("value"), 848 "q2": []byte("value"), 849 }, 850 "cf2": map[string][]byte{ 851 "q1": []byte("value"), 852 }, 853 }) 854 }, 855 out: &pb.MutateRequest{ 856 Region: rs, 857 Mutation: &pb.MutationProto{ 858 Row: key, 859 MutateType: pb.MutationProto_PUT.Enum(), 860 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 861 ColumnValue: []*pb.MutationProto_ColumnValue{ 862 &pb.MutationProto_ColumnValue{ 863 Family: []byte("cf1"), 864 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 865 &pb.MutationProto_ColumnValue_QualifierValue{ 866 Qualifier: []byte("q1"), 867 Value: []byte("value"), 868 }, 869 &pb.MutationProto_ColumnValue_QualifierValue{ 870 Qualifier: []byte("q2"), 871 Value: []byte("value"), 872 }, 873 }, 874 }, 875 &pb.MutationProto_ColumnValue{ 876 Family: []byte("cf2"), 877 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 878 &pb.MutationProto_ColumnValue_QualifierValue{ 879 Qualifier: []byte("q1"), 880 Value: []byte("value"), 881 }, 882 }, 883 }, 884 }, 885 }, 886 }, 887 cellblocksProto: &pb.MutateRequest{ 888 Region: rs, 889 Mutation: &pb.MutationProto{ 890 Row: key, 891 MutateType: pb.MutationProto_PUT.Enum(), 892 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 893 AssociatedCellCount: proto.Int32(3), 894 }, 895 }, 896 cellblocksLen: 111, 897 cellblocks: [][]byte{ 898 []byte("\x00\x00\x00!\x00\x00\x00\x14\x00\x00\x00\x05\x00\x03" + 899 "key" + "\x03" + "cf1" + "q1" + 900 "\u007f\xff\xff\xff\xff\xff\xff\xff\x04" + "value"), 901 []byte("\x00\x00\x00!\x00\x00\x00\x14\x00\x00\x00\x05\x00\x03" + 902 "key" + "\x03" + "cf1" + "q2" + 903 "\u007f\xff\xff\xff\xff\xff\xff\xff\x04" + "value"), 904 []byte("\x00\x00\x00!\x00\x00\x00\x14\x00\x00\x00\x05\x00\x03" + 905 "key" + "\x03" + "cf2" + "q1" + 906 "\u007f\xff\xff\xff\xff\xff\xff\xff\x04" + "value")}, 907 }, 908 { 909 in: func() (*Mutate, error) { 910 return NewPut(ctx, table, key, map[string]map[string][]byte{ 911 "cf": map[string][]byte{ 912 "q": []byte("value"), 913 }, 914 }, Timestamp(time.Unix(0, 42*1e6))) 915 }, 916 inStr: func() (*Mutate, error) { 917 return NewPutStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 918 "cf": map[string][]byte{ 919 "q": []byte("value"), 920 }, 921 }, Timestamp(time.Unix(0, 42*1e6))) 922 }, 923 out: &pb.MutateRequest{ 924 Region: rs, 925 Mutation: &pb.MutationProto{ 926 Row: key, 927 MutateType: pb.MutationProto_PUT.Enum(), 928 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 929 Timestamp: proto.Uint64(42), 930 ColumnValue: []*pb.MutationProto_ColumnValue{ 931 &pb.MutationProto_ColumnValue{ 932 Family: []byte("cf"), 933 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 934 &pb.MutationProto_ColumnValue_QualifierValue{ 935 Qualifier: []byte("q"), 936 Value: []byte("value"), 937 Timestamp: proto.Uint64(42), 938 }, 939 }, 940 }, 941 }, 942 }, 943 }, 944 cellblocksProto: &pb.MutateRequest{ 945 Region: rs, 946 Mutation: &pb.MutationProto{ 947 Row: key, 948 MutateType: pb.MutationProto_PUT.Enum(), 949 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 950 Timestamp: proto.Uint64(42), 951 AssociatedCellCount: proto.Int32(1), 952 }, 953 }, 954 cellblocksLen: 35, 955 cellblocks: [][]byte{ 956 []byte("\x00\x00\x00\x1f\x00\x00\x00\x12\x00\x00\x00\x05\x00\x03" + 957 "key" + "\x02" + "cf" + "q" + 958 "\x00\x00\x00\x00\x00\x00\x00*\x04" + "value")}, 959 }, 960 { 961 in: func() (*Mutate, error) { 962 return NewPut(ctx, table, key, map[string]map[string][]byte{ 963 "cf": map[string][]byte{ 964 "q": []byte("value"), 965 }, 966 }, TimestampUint64(42)) 967 }, 968 inStr: func() (*Mutate, error) { 969 return NewPutStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 970 "cf": map[string][]byte{ 971 "q": []byte("value"), 972 }, 973 }, TimestampUint64(42)) 974 }, 975 out: &pb.MutateRequest{ 976 Region: rs, 977 Mutation: &pb.MutationProto{ 978 Row: key, 979 MutateType: pb.MutationProto_PUT.Enum(), 980 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 981 Timestamp: proto.Uint64(42), 982 ColumnValue: []*pb.MutationProto_ColumnValue{ 983 &pb.MutationProto_ColumnValue{ 984 Family: []byte("cf"), 985 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 986 &pb.MutationProto_ColumnValue_QualifierValue{ 987 Qualifier: []byte("q"), 988 Value: []byte("value"), 989 Timestamp: proto.Uint64(42), 990 }, 991 }, 992 }, 993 }, 994 }, 995 }, 996 997 cellblocksProto: &pb.MutateRequest{ 998 Region: rs, 999 Mutation: &pb.MutationProto{ 1000 Row: key, 1001 MutateType: pb.MutationProto_PUT.Enum(), 1002 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1003 Timestamp: proto.Uint64(42), 1004 AssociatedCellCount: proto.Int32(1), 1005 }, 1006 }, 1007 cellblocksLen: 35, 1008 cellblocks: [][]byte{ 1009 []byte("\x00\x00\x00\x1f\x00\x00\x00\x12\x00\x00\x00\x05\x00\x03" + 1010 "key" + "\x02" + "cf" + "q" + 1011 "\x00\x00\x00\x00\x00\x00\x00*\x04" + "value")}, 1012 }, 1013 { 1014 in: func() (*Mutate, error) { 1015 return NewDel(ctx, table, key, nil) 1016 }, 1017 inStr: func() (*Mutate, error) { 1018 return NewDelStr(ctx, tableStr, keyStr, nil) 1019 }, 1020 out: &pb.MutateRequest{ 1021 Region: rs, 1022 Mutation: &pb.MutationProto{ 1023 Row: key, 1024 MutateType: pb.MutationProto_DELETE.Enum(), 1025 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1026 }, 1027 }, 1028 cellblocksProto: &pb.MutateRequest{ 1029 Region: rs, 1030 Mutation: &pb.MutationProto{ 1031 Row: key, 1032 MutateType: pb.MutationProto_DELETE.Enum(), 1033 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1034 AssociatedCellCount: proto.Int32(0), 1035 }, 1036 }, 1037 }, 1038 { 1039 in: func() (*Mutate, error) { 1040 return NewDel(ctx, table, key, map[string]map[string][]byte{ 1041 "cf": map[string][]byte{ 1042 "q": []byte("value"), 1043 }, 1044 }, TimestampUint64(42)) 1045 }, 1046 inStr: func() (*Mutate, error) { 1047 return NewDelStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 1048 "cf": map[string][]byte{ 1049 "q": []byte("value"), 1050 }, 1051 }, TimestampUint64(42)) 1052 }, 1053 out: &pb.MutateRequest{ 1054 Region: rs, 1055 Mutation: &pb.MutationProto{ 1056 Row: key, 1057 MutateType: pb.MutationProto_DELETE.Enum(), 1058 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1059 Timestamp: proto.Uint64(42), 1060 ColumnValue: []*pb.MutationProto_ColumnValue{ 1061 &pb.MutationProto_ColumnValue{ 1062 Family: []byte("cf"), 1063 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 1064 &pb.MutationProto_ColumnValue_QualifierValue{ 1065 Qualifier: []byte("q"), 1066 Value: []byte("value"), 1067 Timestamp: proto.Uint64(42), 1068 DeleteType: pb.MutationProto_DELETE_MULTIPLE_VERSIONS.Enum(), 1069 }, 1070 }, 1071 }, 1072 }, 1073 }, 1074 }, 1075 cellblocksProto: &pb.MutateRequest{ 1076 Region: rs, 1077 Mutation: &pb.MutationProto{ 1078 Row: key, 1079 MutateType: pb.MutationProto_DELETE.Enum(), 1080 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1081 Timestamp: proto.Uint64(42), 1082 AssociatedCellCount: proto.Int32(1), 1083 }, 1084 }, 1085 cellblocksLen: 35, 1086 cellblocks: [][]byte{ 1087 []byte("\x00\x00\x00\x1f\x00\x00\x00\x12\x00\x00\x00\x05\x00\x03" + 1088 "key" + "\x02" + "cf" + "q" + 1089 "\x00\x00\x00\x00\x00\x00\x00*\f" + "value")}, 1090 }, 1091 { 1092 in: func() (*Mutate, error) { 1093 return NewApp(ctx, table, key, nil) 1094 }, 1095 inStr: func() (*Mutate, error) { 1096 return NewAppStr(ctx, tableStr, keyStr, nil) 1097 }, 1098 out: &pb.MutateRequest{ 1099 Region: rs, 1100 Mutation: &pb.MutationProto{ 1101 Row: key, 1102 MutateType: pb.MutationProto_APPEND.Enum(), 1103 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1104 }, 1105 }, 1106 cellblocksProto: &pb.MutateRequest{ 1107 Region: rs, 1108 Mutation: &pb.MutationProto{ 1109 Row: key, 1110 MutateType: pb.MutationProto_APPEND.Enum(), 1111 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1112 AssociatedCellCount: proto.Int32(0), 1113 }, 1114 }, 1115 }, 1116 { 1117 in: func() (*Mutate, error) { 1118 return NewInc(ctx, table, key, nil) 1119 }, 1120 inStr: func() (*Mutate, error) { 1121 return NewIncStr(ctx, tableStr, keyStr, nil) 1122 }, 1123 out: &pb.MutateRequest{ 1124 Region: rs, 1125 Mutation: &pb.MutationProto{ 1126 Row: key, 1127 MutateType: pb.MutationProto_INCREMENT.Enum(), 1128 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1129 }, 1130 }, 1131 cellblocksProto: &pb.MutateRequest{ 1132 Region: rs, 1133 Mutation: &pb.MutationProto{ 1134 Row: key, 1135 MutateType: pb.MutationProto_INCREMENT.Enum(), 1136 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1137 AssociatedCellCount: proto.Int32(0), 1138 }, 1139 }, 1140 }, 1141 { 1142 in: func() (*Mutate, error) { 1143 return NewIncSingle(ctx, table, key, "cf", "q", 1) 1144 }, 1145 inStr: func() (*Mutate, error) { 1146 return NewIncStrSingle(ctx, tableStr, keyStr, "cf", "q", 1) 1147 }, 1148 out: &pb.MutateRequest{ 1149 Region: rs, 1150 Mutation: &pb.MutationProto{ 1151 Row: key, 1152 MutateType: pb.MutationProto_INCREMENT.Enum(), 1153 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1154 ColumnValue: []*pb.MutationProto_ColumnValue{ 1155 &pb.MutationProto_ColumnValue{ 1156 Family: []byte("cf"), 1157 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 1158 &pb.MutationProto_ColumnValue_QualifierValue{ 1159 Qualifier: []byte("q"), 1160 Value: []byte("\x00\x00\x00\x00\x00\x00\x00\x01"), 1161 }, 1162 }, 1163 }, 1164 }, 1165 }, 1166 }, 1167 cellblocksProto: &pb.MutateRequest{ 1168 Region: rs, 1169 Mutation: &pb.MutationProto{ 1170 Row: key, 1171 MutateType: pb.MutationProto_INCREMENT.Enum(), 1172 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1173 AssociatedCellCount: proto.Int32(1), 1174 }, 1175 }, 1176 cellblocksLen: 38, 1177 cellblocks: [][]byte{ 1178 []byte("\x00\x00\x00\"\x00\x00\x00\x12\x00\x00\x00\b\x00\x03" + 1179 "key" + "\x02" + "cf" + "q" + 1180 "\u007f\xff\xff\xff\xff\xff\xff\xff\x04" + 1181 "\x00\x00\x00\x00\x00\x00\x00\x01")}, 1182 }, 1183 { 1184 in: func() (*Mutate, error) { 1185 return NewDel(ctx, table, key, map[string]map[string][]byte{ 1186 "cf": nil, 1187 }) 1188 }, 1189 inStr: func() (*Mutate, error) { 1190 return NewDelStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 1191 "cf": nil, 1192 }) 1193 }, 1194 out: &pb.MutateRequest{ 1195 Region: rs, 1196 Mutation: &pb.MutationProto{ 1197 Row: key, 1198 MutateType: pb.MutationProto_DELETE.Enum(), 1199 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1200 ColumnValue: []*pb.MutationProto_ColumnValue{ 1201 &pb.MutationProto_ColumnValue{ 1202 Family: []byte("cf"), 1203 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 1204 &pb.MutationProto_ColumnValue_QualifierValue{ 1205 Qualifier: []byte{}, 1206 DeleteType: pb.MutationProto_DELETE_FAMILY.Enum(), 1207 }, 1208 }, 1209 }, 1210 }, 1211 }, 1212 }, 1213 cellblocksProto: &pb.MutateRequest{ 1214 Region: rs, 1215 Mutation: &pb.MutationProto{ 1216 Row: key, 1217 MutateType: pb.MutationProto_DELETE.Enum(), 1218 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1219 AssociatedCellCount: proto.Int32(1), 1220 }, 1221 }, 1222 cellblocksLen: 29, 1223 cellblocks: [][]byte{ 1224 []byte("\x00\x00\x00\x19\x00\x00\x00\x11\x00\x00\x00\x00\x00\x03" + 1225 "key" + "\x02" + "cf" + "" + 1226 "\u007f\xff\xff\xff\xff\xff\xff\xff\x0e")}, 1227 }, 1228 { 1229 in: func() (*Mutate, error) { 1230 return NewDel(ctx, table, key, map[string]map[string][]byte{ 1231 "cf": nil, 1232 }, TimestampUint64(42)) 1233 }, 1234 inStr: func() (*Mutate, error) { 1235 return NewDelStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 1236 "cf": nil, 1237 }, TimestampUint64(42)) 1238 }, 1239 out: &pb.MutateRequest{ 1240 Region: rs, 1241 Mutation: &pb.MutationProto{ 1242 Row: key, 1243 Timestamp: proto.Uint64(42), 1244 MutateType: pb.MutationProto_DELETE.Enum(), 1245 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1246 ColumnValue: []*pb.MutationProto_ColumnValue{ 1247 &pb.MutationProto_ColumnValue{ 1248 Family: []byte("cf"), 1249 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 1250 &pb.MutationProto_ColumnValue_QualifierValue{ 1251 Qualifier: []byte{}, 1252 Timestamp: proto.Uint64(42), 1253 DeleteType: pb.MutationProto_DELETE_FAMILY.Enum(), 1254 }, 1255 }, 1256 }, 1257 }, 1258 }, 1259 }, 1260 cellblocksProto: &pb.MutateRequest{ 1261 Region: rs, 1262 Mutation: &pb.MutationProto{ 1263 Row: key, 1264 MutateType: pb.MutationProto_DELETE.Enum(), 1265 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1266 Timestamp: proto.Uint64(42), 1267 AssociatedCellCount: proto.Int32(1), 1268 }, 1269 }, 1270 cellblocksLen: 29, 1271 cellblocks: [][]byte{ 1272 []byte("\x00\x00\x00\x19\x00\x00\x00\x11\x00\x00\x00\x00\x00\x03" + 1273 "key" + "\x02" + "cf" + "" + 1274 "\x00\x00\x00\x00\x00\x00\x00*\x0e")}, 1275 }, 1276 { 1277 in: func() (*Mutate, error) { 1278 return NewDel(ctx, table, key, map[string]map[string][]byte{ 1279 "cf": nil, 1280 }, TimestampUint64(42), DeleteOneVersion()) 1281 }, 1282 inStr: func() (*Mutate, error) { 1283 return NewDelStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 1284 "cf": nil, 1285 }, TimestampUint64(42), DeleteOneVersion()) 1286 }, 1287 out: &pb.MutateRequest{ 1288 Region: rs, 1289 Mutation: &pb.MutationProto{ 1290 Row: key, 1291 Timestamp: proto.Uint64(42), 1292 MutateType: pb.MutationProto_DELETE.Enum(), 1293 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1294 ColumnValue: []*pb.MutationProto_ColumnValue{ 1295 &pb.MutationProto_ColumnValue{ 1296 Family: []byte("cf"), 1297 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 1298 &pb.MutationProto_ColumnValue_QualifierValue{ 1299 Qualifier: []byte{}, 1300 Timestamp: proto.Uint64(42), 1301 DeleteType: pb.MutationProto_DELETE_FAMILY_VERSION.Enum(), 1302 }, 1303 }, 1304 }, 1305 }, 1306 }, 1307 }, 1308 cellblocksProto: &pb.MutateRequest{ 1309 Region: rs, 1310 Mutation: &pb.MutationProto{ 1311 Row: key, 1312 MutateType: pb.MutationProto_DELETE.Enum(), 1313 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1314 Timestamp: proto.Uint64(42), 1315 AssociatedCellCount: proto.Int32(1), 1316 }, 1317 }, 1318 cellblocksLen: 29, 1319 cellblocks: [][]byte{ 1320 []byte("\x00\x00\x00\x19\x00\x00\x00\x11\x00\x00\x00\x00\x00\x03" + 1321 "key" + "\x02" + "cf" + "" + 1322 "\x00\x00\x00\x00\x00\x00\x00*\n")}, 1323 }, 1324 { 1325 in: func() (*Mutate, error) { 1326 return NewDel(ctx, table, key, map[string]map[string][]byte{ 1327 "cf": map[string][]byte{ 1328 "a": nil, 1329 }, 1330 }, TimestampUint64(42), DeleteOneVersion()) 1331 }, 1332 inStr: func() (*Mutate, error) { 1333 return NewDelStr(ctx, tableStr, keyStr, map[string]map[string][]byte{ 1334 "cf": map[string][]byte{ 1335 "a": nil, 1336 }, 1337 }, TimestampUint64(42), DeleteOneVersion()) 1338 }, 1339 out: &pb.MutateRequest{ 1340 Region: rs, 1341 Mutation: &pb.MutationProto{ 1342 Row: key, 1343 Timestamp: proto.Uint64(42), 1344 MutateType: pb.MutationProto_DELETE.Enum(), 1345 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1346 ColumnValue: []*pb.MutationProto_ColumnValue{ 1347 &pb.MutationProto_ColumnValue{ 1348 Family: []byte("cf"), 1349 QualifierValue: []*pb.MutationProto_ColumnValue_QualifierValue{ 1350 &pb.MutationProto_ColumnValue_QualifierValue{ 1351 Qualifier: []byte("a"), 1352 Timestamp: proto.Uint64(42), 1353 DeleteType: pb.MutationProto_DELETE_ONE_VERSION.Enum(), 1354 }, 1355 }, 1356 }, 1357 }, 1358 }, 1359 }, 1360 cellblocksProto: &pb.MutateRequest{ 1361 Region: rs, 1362 Mutation: &pb.MutationProto{ 1363 Row: key, 1364 MutateType: pb.MutationProto_DELETE.Enum(), 1365 Durability: pb.MutationProto_USE_DEFAULT.Enum(), 1366 Timestamp: proto.Uint64(42), 1367 AssociatedCellCount: proto.Int32(1), 1368 }, 1369 }, 1370 cellblocksLen: 30, 1371 cellblocks: [][]byte{ 1372 []byte("\x00\x00\x00\x1a\x00\x00\x00\x12\x00\x00\x00\x00\x00\x03" + 1373 "key" + "\x02" + "cf" + "a" + 1374 "\x00\x00\x00\x00\x00\x00\x00*\b")}, 1375 }, 1376 { 1377 in: func() (*Mutate, error) { 1378 return NewDel(ctx, table, key, nil, DeleteOneVersion()) 1379 }, 1380 inStr: func() (*Mutate, error) { 1381 return NewDelStr(ctx, tableStr, keyStr, nil, DeleteOneVersion()) 1382 }, 1383 err: errors.New( 1384 "'DeleteOneVersion' option cannot be specified for delete entire row request"), 1385 }, 1386 } 1387 1388 run := func(t *testing.T, i int, m *Mutate) { 1389 if m.Name() != "Mutate" { 1390 t.Fatalf("Expected name to be 'Mutate', got %s", m.Name()) 1391 } 1392 1393 _, ok := m.NewResponse().(*pb.MutateResponse) 1394 if !ok { 1395 t.Fatalf("Expected response to have type 'pb.MutateResponse', got %T", 1396 m.NewResponse()) 1397 } 1398 1399 m.SetRegion(mockRegionInfo("region")) 1400 1401 // test ToProto 1402 p := m.ToProto() 1403 mr, ok := p.(*pb.MutateRequest) 1404 if !ok { 1405 t.Fatal("expected proto be of type *pb.MutateRequest") 1406 } 1407 1408 sort.Sort(byFamily(mr.Mutation.ColumnValue)) 1409 for _, cv := range mr.Mutation.ColumnValue { 1410 sort.Sort(byQualifier(cv.QualifierValue)) 1411 } 1412 1413 tcase := tests[i] 1414 1415 if !proto.Equal(tcase.out, mr) { 1416 t.Errorf("expected %v, got %v", tcase.out, mr) 1417 } 1418 1419 // test cellblocks 1420 cellblocksProto, cellblocks, cellblocksLen := m.SerializeCellBlocks(nil) 1421 mr, ok = cellblocksProto.(*pb.MutateRequest) 1422 if !ok { 1423 t.Fatal("expected proto be of type *pb.MutateRequest") 1424 } 1425 1426 if !proto.Equal(tcase.cellblocksProto, mr) { 1427 t.Errorf("expected cellblocks proto %v, got %v", 1428 tcase.cellblocksProto, cellblocksProto) 1429 } 1430 1431 if len(tcase.cellblocks) == 0 { 1432 if len(cellblocks) > 0 { 1433 t.Errorf("Expected no cellblocks output, but got: %q", cellblocks) 1434 } 1435 } else if len(cellblocks) != 1 { 1436 t.Errorf("expected one []byte, but got: %v", cellblocks) 1437 } 1438 1439 if cellblocksLen != tcase.cellblocksLen { 1440 t.Errorf("expected cellblocks length %d, got %d", tcase.cellblocksLen, cellblocksLen) 1441 } 1442 1443 // check total length matches the returned 1444 if l := bytesSlicesLen(cellblocks); l != cellblocksLen { 1445 t.Errorf("total length of cellblocks %d doesn't match returned %d", 1446 l, cellblocksLen) 1447 } 1448 1449 // because maps are iterated in random order, the best we can do here 1450 // is check for the presence of each cellblock. This doesn't 1451 // test that byte slices are written out in the correct order. 1452 for _, cb := range tcase.cellblocks { 1453 if !bytes.Contains(cellblocks[0], cb) { 1454 t.Errorf("missing cellblock %q in %q", cb, cellblocks) 1455 } 1456 } 1457 } 1458 for i, tcase := range tests { 1459 t.Run(strconv.Itoa(i), func(t *testing.T) { 1460 m, err := tcase.in() 1461 if !test.ErrEqual(tcase.err, err) { 1462 t.Fatalf("expected %v, got %v", tcase.err, err) 1463 } 1464 if tcase.err != nil { 1465 return 1466 } 1467 run(t, i, m) 1468 }) 1469 t.Run(strconv.Itoa(i)+" str", func(t *testing.T) { 1470 m, err := tcase.inStr() 1471 if !test.ErrEqual(tcase.err, err) { 1472 t.Fatalf("expected %v, got %v", tcase.err, err) 1473 } 1474 if tcase.err != nil { 1475 return 1476 } 1477 run(t, i, m) 1478 }) 1479 } 1480 } 1481 1482 var expectedCells = []*pb.Cell{ 1483 &pb.Cell{ 1484 Row: []byte("row7"), 1485 Family: []byte("cf"), 1486 Qualifier: []byte("b"), 1487 Timestamp: proto.Uint64(1494873081120), 1488 Value: []byte("Hello my name is Dog."), 1489 }, 1490 &pb.Cell{ 1491 Row: []byte("row7"), 1492 Family: []byte("cf"), 1493 Qualifier: []byte("a"), 1494 Timestamp: proto.Uint64(1494873081120), 1495 Value: []byte("Hello my name is Dog."), 1496 CellType: pb.CellType_PUT.Enum(), 1497 }, 1498 } 1499 var cellblock = []byte{0, 0, 0, 48, 0, 0, 0, 19, 0, 0, 0, 21, 0, 4, 114, 111, 119, 55, 2, 99, 1500 102, 97, 0, 0, 1, 92, 13, 97, 5, 32, 4, 72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 1501 97, 109, 101, 32, 105, 115, 32, 68, 111, 103, 46} 1502 1503 func TestDeserializeCellBlocksGet(t *testing.T) { 1504 // the first cell is already in protobuf 1505 getResp := &pb.GetResponse{Result: &pb.Result{ 1506 Cell: []*pb.Cell{expectedCells[0]}, 1507 AssociatedCellCount: proto.Int32(1), 1508 }} 1509 g := &Get{} 1510 n, err := g.DeserializeCellBlocks(getResp, cellblock) 1511 if err != nil { 1512 t.Fatal(err) 1513 } 1514 1515 if !reflect.DeepEqual(expectedCells, getResp.Result.Cell) { 1516 t.Errorf("expected %v, got %v", expectedCells, getResp.Result.Cell) 1517 } 1518 1519 if int(n) != len(cellblock) { 1520 t.Errorf("expected read %d, got read %d", len(cellblock), n) 1521 } 1522 1523 // test error case 1524 getResp = &pb.GetResponse{Result: &pb.Result{ 1525 AssociatedCellCount: proto.Int32(1), 1526 }} 1527 _, err = g.DeserializeCellBlocks(getResp, cellblock[:10]) 1528 if err == nil { 1529 t.Error("expected error, got none") 1530 } 1531 } 1532 1533 func TestDeserializeCellblocksMutate(t *testing.T) { 1534 // the first cell is already in protobuf 1535 mResp := &pb.MutateResponse{Result: &pb.Result{ 1536 Cell: []*pb.Cell{expectedCells[0]}, 1537 AssociatedCellCount: proto.Int32(1), 1538 }} 1539 m := &Mutate{} 1540 n, err := m.DeserializeCellBlocks(mResp, cellblock) 1541 if err != nil { 1542 t.Error(err) 1543 } 1544 1545 if !reflect.DeepEqual(expectedCells, mResp.Result.Cell) { 1546 t.Errorf("expected %v, got %v", expectedCells, mResp.Result.Cell) 1547 } 1548 1549 if int(n) != len(cellblock) { 1550 t.Errorf("expected read %d, got read %d", len(cellblock), n) 1551 } 1552 1553 // test error case 1554 mResp = &pb.MutateResponse{Result: &pb.Result{ 1555 Cell: expectedCells[:1], 1556 AssociatedCellCount: proto.Int32(1), 1557 }} 1558 _, err = m.DeserializeCellBlocks(mResp, cellblock[:10]) 1559 if err == nil { 1560 t.Error("expected error, got none") 1561 } 1562 } 1563 1564 func TestDeserializeCellBlocksScan(t *testing.T) { 1565 expectedResults := []*pb.Result{ 1566 &pb.Result{ 1567 Cell: []*pb.Cell{ 1568 &pb.Cell{ 1569 Row: []byte("row7"), 1570 Family: []byte("cf"), 1571 Qualifier: []byte("c"), 1572 Timestamp: proto.Uint64(1494873081120), 1573 Value: []byte("Hello my name is Dog."), 1574 CellType: pb.CellType_PUT.Enum(), 1575 }, 1576 &pb.Cell{ 1577 Row: []byte("row7"), 1578 Family: []byte("cf"), 1579 Qualifier: []byte("b"), 1580 Timestamp: proto.Uint64(1494873081120), 1581 Value: []byte("Hello my name is Dog."), 1582 CellType: pb.CellType_PUT.Enum(), 1583 }, 1584 }, 1585 Partial: proto.Bool(true), 1586 }, 1587 &pb.Result{ 1588 Cell: []*pb.Cell{ 1589 &pb.Cell{ 1590 Row: []byte("row7"), 1591 Family: []byte("cf"), 1592 Qualifier: []byte("a"), 1593 Timestamp: proto.Uint64(1494873081120), 1594 Value: []byte("Hello my name is Dog."), 1595 CellType: pb.CellType_PUT.Enum(), 1596 }, 1597 }, 1598 Partial: proto.Bool(false), 1599 }, 1600 } 1601 cellblocks := []byte{0, 0, 0, 48, 0, 0, 0, 19, 0, 0, 0, 21, 0, 4, 114, 111, 119, 55, 2, 99, 1602 102, 99, 0, 0, 1, 92, 13, 97, 5, 32, 4, 72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 1603 97, 109, 101, 32, 105, 115, 32, 68, 111, 103, 46, 1604 0, 0, 0, 48, 0, 0, 0, 19, 0, 0, 0, 21, 0, 4, 114, 111, 119, 55, 2, 99, 1605 102, 98, 0, 0, 1, 92, 13, 97, 5, 32, 4, 72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 1606 97, 109, 101, 32, 105, 115, 32, 68, 111, 103, 46, 1607 0, 0, 0, 48, 0, 0, 0, 19, 0, 0, 0, 21, 0, 4, 114, 111, 119, 55, 2, 99, 1608 102, 97, 0, 0, 1, 92, 13, 97, 5, 32, 4, 72, 101, 108, 108, 111, 32, 109, 121, 32, 110, 1609 97, 109, 101, 32, 105, 115, 32, 68, 111, 103, 46} 1610 1611 scanResp := &pb.ScanResponse{ 1612 Results: []*pb.Result{}, 1613 PartialFlagPerResult: []bool{true, false}, 1614 CellsPerResult: []uint32{2, 1}, 1615 } 1616 s := &Scan{} 1617 n, err := s.DeserializeCellBlocks(scanResp, cellblocks) 1618 if err != nil { 1619 t.Fatal(err) 1620 } 1621 1622 if !reflect.DeepEqual(expectedResults, scanResp.Results) { 1623 t.Errorf("expected %v, got %v", expectedResults, scanResp.Results) 1624 } 1625 1626 if int(n) != len(cellblocks) { 1627 t.Errorf("expected read %d, got read %d", len(cellblock), n) 1628 } 1629 1630 // test error case 1631 scanResp = &pb.ScanResponse{ 1632 PartialFlagPerResult: []bool{true, false}, 1633 CellsPerResult: []uint32{2, 1}, 1634 } 1635 _, err = s.DeserializeCellBlocks(scanResp, cellblocks[:10]) 1636 if err == nil { 1637 t.Error("expected error, got none") 1638 } 1639 } 1640 1641 func confirmScanAttributes(ctx context.Context, s *Scan, table, start, stop []byte, 1642 fam map[string][]string, fltr filter.Filter, numberOfRows uint32, 1643 renewInterval time.Duration, renewalScan bool) bool { 1644 if fltr == nil && s.filter != nil { 1645 return false 1646 } 1647 return s.Context() == ctx && 1648 bytes.Equal(s.Table(), table) && 1649 bytes.Equal(s.StartRow(), start) && 1650 bytes.Equal(s.StopRow(), stop) && 1651 reflect.DeepEqual(s.families, fam) && 1652 s.numberOfRows == numberOfRows && 1653 s.renewInterval == renewInterval && 1654 s.renewalScan == renewalScan 1655 } 1656 1657 func BenchmarkMutateToProtoWithNestedMaps(b *testing.B) { 1658 b.ReportAllocs() 1659 1660 regionInfo := mockRegionInfo("region") 1661 1662 b.ResetTimer() 1663 for i := 0; i < b.N; i++ { 1664 data := map[string]map[string][]byte{ 1665 "cf": map[string][]byte{ 1666 "a": []byte{10}, 1667 "b": []byte{20}, 1668 "c": []byte{30, 0}, 1669 "d": []byte{40, 0, 0, 0}, 1670 "e": []byte{50, 0, 0, 0, 0, 0, 0, 0}, 1671 "f": []byte{60}, 1672 "g": []byte{70}, 1673 "h": []byte{80, 0}, 1674 "i": []byte{90, 0, 0, 0}, 1675 "j": []byte{100, 0, 0, 0, 0, 0, 0, 0}, 1676 "k": []byte{0, 0, 220, 66}, 1677 "l": []byte{0, 0, 0, 0, 0, 0, 94, 64}, 1678 "m": []byte{0, 0, 2, 67, 0, 0, 0, 0}, 1679 "n": []byte{0, 0, 0, 0, 0, 128, 97, 64, 0, 0, 0, 0, 0, 0, 0, 0}, 1680 "o": []byte{150}, 1681 "p": []byte{4, 8, 15, 26, 23, 42}, 1682 "q": []byte{1, 1, 3, 5, 8, 13, 21, 34, 55}, 1683 "r": []byte("This is a test string."), 1684 }, 1685 } 1686 mutate, err := NewPutStr(context.Background(), "", "", data) 1687 if err != nil { 1688 b.Errorf("Error creating mutate: %v", err) 1689 } 1690 mutate.SetRegion(regionInfo) 1691 1692 if p := mutate.ToProto(); p == nil { 1693 b.Fatal("got a nil proto") 1694 } 1695 } 1696 }