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  }