github.com/tsuna/gohbase@v0.0.0-20250731002811-4ffcadfba63e/metacache_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 gohbase
     7  
     8  import (
     9  	"bytes"
    10  	"fmt"
    11  	"reflect"
    12  	"sort"
    13  	"strconv"
    14  	"testing"
    15  
    16  	"github.com/tsuna/gohbase/hrpc"
    17  	"github.com/tsuna/gohbase/region"
    18  	mockRegion "github.com/tsuna/gohbase/test/mock/region"
    19  	"go.uber.org/mock/gomock"
    20  )
    21  
    22  func TestMetaCache(t *testing.T) {
    23  	client := newClient("~invalid.quorum~") // We shouldn't connect to ZK.
    24  
    25  	reg := client.getRegionFromCache([]byte("test"), []byte("theKey"))
    26  	if reg != nil {
    27  		t.Errorf("Found region %v even though the cache was empty?!", reg)
    28  	}
    29  
    30  	// Inject an entry in the cache.  This entry covers the entire key range.
    31  	wholeTable := region.NewInfo(
    32  		0,
    33  		nil,
    34  		[]byte("test"),
    35  		[]byte("test,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
    36  		nil,
    37  		nil,
    38  	)
    39  	ctrl := gomock.NewController(t)
    40  	defer ctrl.Finish()
    41  
    42  	regClient := mockRegion.NewMockRegionClient(ctrl)
    43  	regClient.EXPECT().Addr().Return("regionserver:1").AnyTimes()
    44  	regClient.EXPECT().String().Return("mock region client").AnyTimes()
    45  	newClientFn := func() hrpc.RegionClient {
    46  		return regClient
    47  	}
    48  
    49  	client.regions.put(wholeTable)
    50  	client.clients.put("regionserver:1", wholeTable, newClientFn)
    51  
    52  	reg = client.getRegionFromCache([]byte("test"), []byte("theKey"))
    53  	if !reflect.DeepEqual(reg, wholeTable) {
    54  		t.Errorf("Found region %v but expected %v", reg, wholeTable)
    55  	}
    56  	reg = client.getRegionFromCache([]byte("test"), []byte("")) // edge case.
    57  	if !reflect.DeepEqual(reg, wholeTable) {
    58  		t.Errorf("Found region %v but expected %v", reg, wholeTable)
    59  	}
    60  
    61  	// Clear our client.
    62  	client = newClient("~invalid.quorum~")
    63  
    64  	// Inject 3 entries in the cache.
    65  	region1 := region.NewInfo(
    66  		0,
    67  		nil,
    68  		[]byte("test"),
    69  		[]byte("test,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
    70  		[]byte(""),
    71  		[]byte("foo"),
    72  	)
    73  	if os, replaced := client.regions.put(region1); !replaced {
    74  		t.Errorf("Expected to put new region into cache, got: %v", os)
    75  	} else if len(os) != 0 {
    76  		t.Errorf("Didn't expect any overlaps, got: %v", os)
    77  	}
    78  	client.clients.put("regionserver:1", region1, newClientFn)
    79  
    80  	region2 := region.NewInfo(
    81  		0,
    82  		nil,
    83  		[]byte("test"),
    84  		[]byte("test,foo,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
    85  		[]byte("foo"),
    86  		[]byte("gohbase"),
    87  	)
    88  	if os, replaced := client.regions.put(region2); !replaced {
    89  		t.Errorf("Expected to put new region into cache, got: %v", os)
    90  	} else if len(os) != 0 {
    91  		t.Errorf("Didn't expect any overlaps, got: %v", os)
    92  	}
    93  	client.clients.put("regionserver:1", region2, newClientFn)
    94  
    95  	region3 := region.NewInfo(
    96  		0,
    97  		nil,
    98  		[]byte("test"),
    99  		[]byte("test,gohbase,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   100  		[]byte("gohbase"),
   101  		[]byte(""),
   102  	)
   103  	if os, replaced := client.regions.put(region3); !replaced {
   104  		t.Errorf("Expected to put new region into cache, got: %v", os)
   105  	} else if len(os) != 0 {
   106  		t.Errorf("Didn't expect any overlaps, got: %v", os)
   107  	}
   108  	client.clients.put("regionserver:1", region3, newClientFn)
   109  
   110  	testcases := []struct {
   111  		key string
   112  		reg hrpc.RegionInfo
   113  	}{
   114  		{key: "theKey", reg: region3},
   115  		{key: "", reg: region1},
   116  		{key: "bar", reg: region1},
   117  		{key: "fon\xFF", reg: region1},
   118  		{key: "foo", reg: region2},
   119  		{key: "foo\x00", reg: region2},
   120  		{key: "gohbase", reg: region3},
   121  	}
   122  	for i, testcase := range testcases {
   123  		reg = client.getRegionFromCache([]byte("test"), []byte(testcase.key))
   124  		if !reflect.DeepEqual(reg, testcase.reg) {
   125  			t.Errorf("[#%d] Found region %v but expected %v", i, reg, testcase.reg)
   126  		}
   127  	}
   128  
   129  	// Change the last region (maybe it got split).
   130  	region4 := region.NewInfo(
   131  		0,
   132  		nil,
   133  		[]byte("test"),
   134  		[]byte("test,gohbase,1234567890042.swagswagswagswagswagswagswagswag."),
   135  		[]byte("gohbase"),
   136  		[]byte("zab"),
   137  	)
   138  	if os, replaced := client.regions.put(region4); !replaced {
   139  		t.Errorf("Expected to put new region into cache, got: %v", os)
   140  	} else if len(os) != 1 || os[0] != region3 {
   141  		t.Errorf("Expected one overlap, got: %v", os)
   142  	}
   143  	client.clients.put("regionserver:1", region4, newClientFn)
   144  
   145  	reg = client.getRegionFromCache([]byte("test"), []byte("theKey"))
   146  	if !reflect.DeepEqual(reg, region4) {
   147  		t.Errorf("Found region %v but expected %v", reg, region4)
   148  	}
   149  	reg = client.getRegionFromCache([]byte("test"), []byte("zoo"))
   150  	if reg != nil {
   151  		t.Errorf("Shouldn't have found any region yet found %v", reg)
   152  	}
   153  
   154  	// attempt putting a region with same name
   155  	region5 := region.NewInfo(
   156  		0,
   157  		nil,
   158  		[]byte("test"),
   159  		[]byte("test,gohbase,1234567890042.swagswagswagswagswagswagswagswag."),
   160  		nil,
   161  		[]byte("zab"),
   162  	)
   163  	if os, replaced := client.regions.put(region5); replaced {
   164  		t.Errorf("Expected to not replace a region in cache, got: %v", os)
   165  	} else if len(os) != 1 || os[0] != region4 {
   166  		t.Errorf("Expected overlaps, got: %v", os)
   167  	}
   168  }
   169  
   170  func TestMetaCacheGet(t *testing.T) {
   171  	tcases := []struct {
   172  		in             []hrpc.RegionInfo
   173  		table          []byte
   174  		key            []byte
   175  		outIndexFromIn int
   176  	}{
   177  		{
   178  			table:          []byte("yolo"),
   179  			key:            []byte("swag"),
   180  			outIndexFromIn: -1,
   181  		},
   182  		{ // the whole table
   183  			in: []hrpc.RegionInfo{
   184  				region.NewInfo(0, nil, []byte("test"),
   185  					[]byte("test,,1234567890042.swagswagswagswagswagswagswagswag."),
   186  					nil, nil),
   187  			},
   188  			table:          []byte("test"),
   189  			key:            []byte("swag"),
   190  			outIndexFromIn: 0,
   191  		},
   192  		{ // one region in cache, different table
   193  			in: []hrpc.RegionInfo{
   194  				region.NewInfo(0, nil, []byte("test"),
   195  					[]byte("test,,1234567890042.swagswagswagswagswagswagswagswag."),
   196  					nil, nil),
   197  			},
   198  			table:          []byte("yolo"),
   199  			key:            []byte("swag"),
   200  			outIndexFromIn: -1,
   201  		},
   202  		{ // key is before the first region in cache
   203  			in: []hrpc.RegionInfo{
   204  				region.NewInfo(0, nil, []byte("test"),
   205  					[]byte("test,foo,1234567890042.swagswagswagswagswagswagswagswag."),
   206  					[]byte("foo"), nil),
   207  			},
   208  			table:          []byte("test"),
   209  			key:            []byte("bar"),
   210  			outIndexFromIn: -1,
   211  		},
   212  		{ // key is between two regions in cache
   213  			in: []hrpc.RegionInfo{
   214  				region.NewInfo(0, nil, []byte("meow"),
   215  					[]byte("meow,bar,1234567890042.swagswagswagswagswagswagswagswag."),
   216  					[]byte("bar"), []byte("foo")),
   217  				region.NewInfo(0, nil, []byte("test"),
   218  					[]byte("test,foo,1234567890042.swagswagswagswagswagswagswagswag."),
   219  					[]byte("foo"), nil),
   220  			},
   221  			table:          []byte("meow"),
   222  			key:            []byte("swag"),
   223  			outIndexFromIn: -1,
   224  		},
   225  		{ // test with namespace region in cache
   226  			in: []hrpc.RegionInfo{
   227  				region.NewInfo(0, []byte("n1"), []byte("test"),
   228  					[]byte("n1:test,,1234567890042.swagswagswagswagswagswagswagswag."),
   229  					nil, nil),
   230  			},
   231  			table:          []byte("test"),
   232  			key:            []byte("swag"),
   233  			outIndexFromIn: -1,
   234  		},
   235  		{ // test with namespace region in cache
   236  			in: []hrpc.RegionInfo{
   237  				region.NewInfo(0, []byte("n1"), []byte("test"),
   238  					[]byte("n1:test,,1234567890042.swagswagswagswagswagswagswagswag."),
   239  					nil, nil),
   240  			},
   241  			table:          []byte("n1:test"),
   242  			key:            []byte("swag"),
   243  			outIndexFromIn: 0,
   244  		},
   245  		{ // test with default namespace in cache, but non-default key
   246  			in: []hrpc.RegionInfo{
   247  				region.NewInfo(0, nil, []byte("test"),
   248  					[]byte("test,,1234567890042.swagswagswagswagswagswagswagswag."),
   249  					nil, nil),
   250  			},
   251  			table:          []byte("n1:test"),
   252  			key:            []byte("swag"),
   253  			outIndexFromIn: -1,
   254  		},
   255  		{ // test with non-default namespace region in cache, but default key
   256  			in: []hrpc.RegionInfo{
   257  				region.NewInfo(0, []byte("n1"), []byte("test"),
   258  					[]byte("n1:test,,1234567890042.swagswagswagswagswagswagswagswag."),
   259  					nil, nil),
   260  			},
   261  			table:          []byte("test"),
   262  			key:            []byte("swag"),
   263  			outIndexFromIn: -1,
   264  		},
   265  		{ // test 3 regions
   266  			in: []hrpc.RegionInfo{
   267  				region.NewInfo(0, nil, []byte("test"),
   268  					[]byte("test,,1234567890042.swagswagswagswagswagswagswagswag."),
   269  					nil, []byte("bar")),
   270  				region.NewInfo(0, nil, []byte("test"),
   271  					[]byte("test,bar,1234567890042.swagswagswagswagswagswagswagswag."),
   272  					[]byte("bar"), []byte("foo")),
   273  				region.NewInfo(0, nil, []byte("test"),
   274  					[]byte("test,foo,1234567890042.swagswagswagswagswagswagswagswag."),
   275  					[]byte("foo"), []byte("yolo")),
   276  			},
   277  			table:          []byte("test"),
   278  			key:            []byte("baz"),
   279  			outIndexFromIn: 1,
   280  		},
   281  	}
   282  
   283  	for i, tcase := range tcases {
   284  		t.Run(fmt.Sprintf("Test %d", i), func(t *testing.T) {
   285  			client := newClient("~invalid.quorum~") // We shouldn't connect to ZK.
   286  
   287  			for _, r := range tcase.in {
   288  				overlaps, replaced := client.regions.put(r)
   289  				if len(overlaps) != 0 {
   290  					t.Fatalf("Didn't expect any overlaps, got %q", overlaps)
   291  				}
   292  				if !replaced {
   293  					t.Fatal("Didn't expect to replace anything in cache")
   294  				}
   295  			}
   296  
   297  			// lookup region in cache
   298  			region := client.getRegionFromCache(tcase.table, tcase.key)
   299  
   300  			if tcase.outIndexFromIn == -1 && region != nil {
   301  				t.Fatalf("expected to get nil region, got %v", region)
   302  			} else {
   303  				return
   304  			}
   305  
   306  			if len(tcase.in) == 0 && region != nil {
   307  				t.Fatalf("didn't expect to get anything from empty cache, got %v", region)
   308  			}
   309  
   310  			if tcase.in[tcase.outIndexFromIn].String() != region.String() {
   311  				t.Errorf("Expected %v, Got %v",
   312  					tcase.in[tcase.outIndexFromIn].String(), region.String())
   313  			}
   314  		})
   315  	}
   316  }
   317  
   318  func TestRegionCacheAge(t *testing.T) {
   319  	tcases := []struct {
   320  		cachedRegions []hrpc.RegionInfo
   321  		newRegion     hrpc.RegionInfo
   322  		replaced      bool
   323  	}{
   324  		{ // all older
   325  			cachedRegions: []hrpc.RegionInfo{
   326  				region.NewInfo(
   327  					1, nil, []byte("hello"),
   328  					[]byte("hello,,1.yoloyoloyoloyoloyoloyoloyoloyolo."),
   329  					[]byte(""), []byte("foo"),
   330  				),
   331  				region.NewInfo(
   332  					1, nil, []byte("hello"),
   333  					[]byte("hello,foo,1.swagswagswagswagswagswagswagswag."),
   334  					[]byte("foo"), []byte(""),
   335  				)},
   336  			newRegion: region.NewInfo(
   337  				2, nil, []byte("hello"),
   338  				[]byte("hello,,2.meowmemowmeowmemowmeowmemowmeow."),
   339  				[]byte(""), []byte(""),
   340  			),
   341  			replaced: true,
   342  		},
   343  		{ // all younger
   344  			cachedRegions: []hrpc.RegionInfo{
   345  				region.NewInfo(
   346  					2, nil, []byte("hello"),
   347  					[]byte("hello,,2.yoloyoloyoloyoloyoloyoloyoloyolo."),
   348  					[]byte(""), []byte("foo"),
   349  				),
   350  				region.NewInfo(
   351  					2, nil, []byte("hello"),
   352  					[]byte("hello,foo,2.swagswagswagswagswagswagswagswag."),
   353  					[]byte("foo"), []byte(""),
   354  				)},
   355  			newRegion: region.NewInfo(
   356  				1, nil, []byte("hello"),
   357  				[]byte("hello,,1.meowmemowmeowmemowmeowmemowmeow."),
   358  				[]byte(""), []byte(""),
   359  			),
   360  			replaced: false,
   361  		},
   362  		{ // one younger, one older
   363  			cachedRegions: []hrpc.RegionInfo{
   364  				region.NewInfo(
   365  					1, nil, []byte("hello"),
   366  					[]byte("hello,,1.yoloyoloyoloyoloyoloyoloyoloyolo."),
   367  					[]byte(""), []byte("foo"),
   368  				),
   369  				region.NewInfo(
   370  					3, nil, []byte("hello"),
   371  					[]byte("hello,foo,3.swagswagswagswagswagswagswagswag."),
   372  					[]byte("foo"), []byte(""),
   373  				)},
   374  			newRegion: region.NewInfo(
   375  				2, nil, []byte("hello"),
   376  				[]byte("hello,,1.meowmemowmeowmemowmeowmemowmeow."),
   377  				[]byte(""), []byte(""),
   378  			),
   379  			replaced: false,
   380  		},
   381  	}
   382  
   383  	client := newClient("~invalid.quorum~")
   384  	for i, tcase := range tcases {
   385  		t.Run(strconv.Itoa(i), func(t *testing.T) {
   386  			client.regions.regions.Clear()
   387  			// set up initial cache
   388  			for _, region := range tcase.cachedRegions {
   389  				client.regions.put(region)
   390  			}
   391  
   392  			overlaps, replaced := client.regions.put(tcase.newRegion)
   393  			if replaced != tcase.replaced {
   394  				t.Errorf("expected %v, got %v", tcase.replaced, replaced)
   395  			}
   396  
   397  			expectedNames := make(regionNames, len(tcase.cachedRegions))
   398  			for i, r := range tcase.cachedRegions {
   399  				expectedNames[i] = r.Name()
   400  			}
   401  			osNames := make(regionNames, len(overlaps))
   402  			for i, o := range overlaps {
   403  				osNames[i] = o.Name()
   404  			}
   405  
   406  			// check overlaps are correct
   407  			if !reflect.DeepEqual(expectedNames, osNames) {
   408  				t.Errorf("expected %v, got %v", expectedNames, osNames)
   409  			}
   410  		})
   411  	}
   412  }
   413  
   414  type regionNames [][]byte
   415  
   416  func (a regionNames) Len() int           { return len(a) }
   417  func (a regionNames) Less(i, j int) bool { return bytes.Compare(a[i], a[j]) < 0 }
   418  func (a regionNames) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   419  
   420  func TestMetaCacheGetOverlaps(t *testing.T) {
   421  	region1 := region.NewInfo(
   422  		0,
   423  		nil,
   424  		[]byte("test"),
   425  		[]byte("test,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   426  		[]byte(""),
   427  		[]byte("foo"),
   428  	)
   429  
   430  	regionA := region.NewInfo(
   431  		0,
   432  		nil,
   433  		[]byte("hello"),
   434  		[]byte("hello,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   435  		[]byte(""),
   436  		[]byte("foo"),
   437  	)
   438  
   439  	regionB := region.NewInfo(
   440  		0,
   441  		nil,
   442  		[]byte("hello"),
   443  		[]byte("hello,foo,987654321042.56f833d5569a27c7a43fbf547b4924a4."),
   444  		[]byte("foo"),
   445  		[]byte("fox"),
   446  	)
   447  
   448  	regionC := region.NewInfo(
   449  		0,
   450  		nil,
   451  		[]byte("hello"),
   452  		[]byte("hello,fox,987654321042.56f833d5569a27c7a43fbf547b4924a4."),
   453  		[]byte("fox"),
   454  		[]byte("yolo"),
   455  	)
   456  
   457  	regionWhole := region.NewInfo(
   458  		0,
   459  		nil,
   460  		[]byte("hello"),
   461  		[]byte("hello,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   462  		nil,
   463  		nil,
   464  	)
   465  
   466  	regionTests := []struct {
   467  		cachedRegions []hrpc.RegionInfo
   468  		newRegion     hrpc.RegionInfo
   469  		expected      []hrpc.RegionInfo
   470  	}{
   471  		{[]hrpc.RegionInfo{}, region1, []hrpc.RegionInfo{}},               // empty cache
   472  		{[]hrpc.RegionInfo{region1}, region1, []hrpc.RegionInfo{region1}}, // with itself
   473  		{ // different table
   474  			[]hrpc.RegionInfo{region1},
   475  			region.NewInfo(
   476  				0,
   477  				nil,
   478  				[]byte("hello"),
   479  				[]byte("hello,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   480  				[]byte(""),
   481  				[]byte("fake"),
   482  			),
   483  			[]hrpc.RegionInfo{},
   484  		},
   485  		{ // different namespace
   486  			[]hrpc.RegionInfo{
   487  				region.NewInfo(
   488  					0,
   489  					[]byte("ns1"),
   490  					[]byte("test"),
   491  					[]byte("ns1:test,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   492  					[]byte(""),
   493  					[]byte("foo"),
   494  				),
   495  			},
   496  			region.NewInfo(
   497  				0,
   498  				nil,
   499  				[]byte("test"),
   500  				[]byte("test,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   501  				[]byte(""),
   502  				[]byte("foo"),
   503  			),
   504  			[]hrpc.RegionInfo{},
   505  		},
   506  		{ // overlaps with both
   507  			[]hrpc.RegionInfo{regionA, regionB},
   508  			region.NewInfo(
   509  				0,
   510  				nil,
   511  				[]byte("hello"),
   512  				[]byte("hello,bar,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   513  				[]byte("bar"),
   514  				[]byte("fop"),
   515  			),
   516  			[]hrpc.RegionInfo{regionA, regionB},
   517  		},
   518  		{ // overlaps with both, key start == old one
   519  			[]hrpc.RegionInfo{regionA, regionB},
   520  			region.NewInfo(
   521  				0,
   522  				nil,
   523  				[]byte("hello"),
   524  				[]byte("hello,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   525  				[]byte(""),
   526  				[]byte("yolo"),
   527  			),
   528  			[]hrpc.RegionInfo{regionA, regionB},
   529  		},
   530  		{ // overlaps with second
   531  			[]hrpc.RegionInfo{regionA, regionB},
   532  			region.NewInfo(
   533  				0,
   534  				nil,
   535  				[]byte("hello"),
   536  				[]byte("hello,fop,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   537  				[]byte("fop"),
   538  				[]byte("yolo"),
   539  			),
   540  			[]hrpc.RegionInfo{regionB},
   541  		},
   542  		{ // overlaps with first, new key start == old one
   543  			[]hrpc.RegionInfo{regionA, regionB},
   544  			region.NewInfo(
   545  				0,
   546  				nil,
   547  				[]byte("hello"),
   548  				[]byte("hello,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   549  				[]byte(""),
   550  				[]byte("abc"),
   551  			),
   552  			[]hrpc.RegionInfo{regionA},
   553  		},
   554  		{ // doesn't overlap, is between existing
   555  			[]hrpc.RegionInfo{regionA, regionC},
   556  			regionB,
   557  			[]hrpc.RegionInfo{},
   558  		},
   559  		{ // without bounds in cache, replaced by region with both bounds
   560  			[]hrpc.RegionInfo{regionWhole},
   561  			regionB,
   562  			[]hrpc.RegionInfo{regionWhole},
   563  		},
   564  		{ // without bounds in cache, replaced by the empty stop key only
   565  			[]hrpc.RegionInfo{regionWhole},
   566  			region.NewInfo(
   567  				0,
   568  				nil,
   569  				[]byte("hello"),
   570  				[]byte("hello,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   571  				[]byte("yolo"),
   572  				nil,
   573  			),
   574  			[]hrpc.RegionInfo{regionWhole},
   575  		},
   576  		{ // without bounds in cache, replaced by the empty start key only
   577  			[]hrpc.RegionInfo{regionWhole},
   578  			region.NewInfo(
   579  				0,
   580  				nil,
   581  				[]byte("hello"),
   582  				[]byte("hello,,1234567890042.56f833d5569a27c7a43fbf547b4924a4."),
   583  				nil,
   584  				[]byte("yolo"),
   585  			),
   586  			[]hrpc.RegionInfo{regionWhole},
   587  		},
   588  		{ // regions with bounds in cache, replaced by without bounds
   589  			[]hrpc.RegionInfo{regionB, regionC},
   590  			regionWhole,
   591  			[]hrpc.RegionInfo{regionB, regionC},
   592  		},
   593  		{ // without bounds in cache, replaced by without bounds
   594  			[]hrpc.RegionInfo{regionWhole},
   595  			region.NewInfo(
   596  				0,
   597  				nil,
   598  				[]byte("hello"),
   599  				[]byte("hello,,1234567890042.yoloyoloyoloyoloyoloyoloyoloyolo."),
   600  				nil,
   601  				nil,
   602  			),
   603  			[]hrpc.RegionInfo{regionWhole},
   604  		},
   605  	}
   606  
   607  	for i, tt := range regionTests {
   608  		t.Run(fmt.Sprintf("Test %d", i), func(t *testing.T) {
   609  			client := newClient("~invalid.quorum~") // fake client
   610  			// set up initial cache
   611  			for _, region := range tt.cachedRegions {
   612  				client.regions.regions.Set(region.Name(), region)
   613  			}
   614  
   615  			expectedNames := make(regionNames, len(tt.expected))
   616  			for i, r := range tt.expected {
   617  				expectedNames[i] = r.Name()
   618  			}
   619  			os := client.regions.getOverlaps(tt.newRegion)
   620  			osNames := make(regionNames, len(os))
   621  			for i, o := range os {
   622  				osNames[i] = o.Name()
   623  			}
   624  			sort.Sort(expectedNames)
   625  			sort.Sort(osNames)
   626  			if !reflect.DeepEqual(expectedNames, osNames) {
   627  				t.Errorf("Expected overlaps %q, found %q", expectedNames, osNames)
   628  			}
   629  		})
   630  	}
   631  }
   632  
   633  func TestClientCachePut(t *testing.T) {
   634  	client := newClient("~invalid.quorum~")
   635  
   636  	ctrl := gomock.NewController(t)
   637  	defer ctrl.Finish()
   638  
   639  	var newClientCalled bool
   640  
   641  	regClient := client.clients.put("regionserver:1", region.NewInfo(0, nil, []byte("test"),
   642  		[]byte("test,,1234567890042.yoloyoloyoloyoloyoloyoloyoloyolo."), nil, nil),
   643  		func() hrpc.RegionClient {
   644  			newClientCalled = true
   645  			regClient := mockRegion.NewMockRegionClient(ctrl)
   646  			regClient.EXPECT().Addr().Return("regionserver:1").AnyTimes()
   647  			regClient.EXPECT().String().Return("mock region client").AnyTimes()
   648  			return regClient
   649  		})
   650  
   651  	if !newClientCalled {
   652  		t.Fatal("expected newClient to be called")
   653  	}
   654  
   655  	if len(client.clients.regions) != 1 {
   656  		t.Errorf("Expected 1 client in cache, got %d", len(client.clients.regions))
   657  	}
   658  
   659  	if len(client.clients.regions[regClient]) != 1 {
   660  		t.Errorf("Expected 1 region for client in cache, got %d",
   661  			len(client.clients.regions[regClient]))
   662  	}
   663  
   664  	// but put a different region for the same address
   665  	regClient2 := client.clients.put("regionserver:1", region.NewInfo(0, nil, []byte("yolo"),
   666  		[]byte("yolo,,1234567890042.yoloyoloyoloyoloyoloyoloyoloyolo."), nil, nil),
   667  		func() hrpc.RegionClient {
   668  			t.Fatal("newClient should not be called")
   669  			return nil
   670  		})
   671  
   672  	if regClient2 != regClient {
   673  		t.Fatalf("expected to get the same exact region client: %s vs %s", regClient2, regClient)
   674  	}
   675  
   676  	// nothing should have changed in clients cache
   677  	if len(client.clients.regions) != 1 {
   678  		t.Errorf("Expected 1 client in cache, got %d", len(client.clients.regions))
   679  	}
   680  
   681  	if len(client.clients.regions[regClient]) != 2 {
   682  		t.Errorf("Expected 2 regions for client in cache, got %d",
   683  			len(client.clients.regions[regClient]))
   684  	}
   685  }