vitess.io/vitess@v0.16.2/go/vt/key/destination_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package key
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    24  )
    25  
    26  // initShardArray returns the ShardReference array for the provided
    27  // sharding spec.
    28  func initShardArray(t *testing.T, shardingSpec string) []*topodatapb.ShardReference {
    29  	// unsharded keyspace, we use ""
    30  	if shardingSpec == "" {
    31  		return []*topodatapb.ShardReference{
    32  			{
    33  				Name:     "0",
    34  				KeyRange: &topodatapb.KeyRange{},
    35  			},
    36  		}
    37  	}
    38  
    39  	// custom sharded keyspace, we use "custom"
    40  	if shardingSpec == "custom" {
    41  		return []*topodatapb.ShardReference{
    42  			{
    43  				Name:     "0",
    44  				KeyRange: &topodatapb.KeyRange{},
    45  			},
    46  			{
    47  				Name:     "1",
    48  				KeyRange: &topodatapb.KeyRange{},
    49  			},
    50  		}
    51  	}
    52  
    53  	shardKrArray, err := ParseShardingSpec(shardingSpec)
    54  	if err != nil {
    55  		t.Fatalf("ParseShardingSpec failed: %v", err)
    56  	}
    57  
    58  	result := make([]*topodatapb.ShardReference, len(shardKrArray))
    59  	for i, kr := range shardKrArray {
    60  		shard := KeyRangeString(kr)
    61  		result[i] = &topodatapb.ShardReference{
    62  			Name:     shard,
    63  			KeyRange: kr,
    64  		}
    65  	}
    66  	return result
    67  }
    68  
    69  func TestDestinationExactKeyRange(t *testing.T) {
    70  	var testCases = []struct {
    71  		keyspace string
    72  		keyRange string
    73  		shards   []string
    74  		err      string
    75  	}{
    76  		{
    77  			// success case, spanning one shard.
    78  			keyspace: "-20-40-60-80-a0-c0-e0-",
    79  			keyRange: "20-40",
    80  			shards:   []string{"20-40"},
    81  		},
    82  		{
    83  			// check for partial keyrange, spanning one shard
    84  			keyspace: "-20-40-60-80-a0-c0-e0-",
    85  			keyRange: "10-18",
    86  			shards:   nil,
    87  			err:      "keyrange 10-18 does not exactly match shards",
    88  		},
    89  		{
    90  			// check for keyrange intersecting with multiple shards
    91  			keyspace: "-20-40-60-80-a0-c0-e0-",
    92  			keyRange: "10-40",
    93  			shards:   nil,
    94  			err:      "keyrange 10-40 does not exactly match shards",
    95  		},
    96  		{
    97  			// check for keyrange intersecting with multiple shards
    98  			keyspace: "-20-40-60-80-a0-c0-e0-",
    99  			keyRange: "1c-2a",
   100  			shards:   nil,
   101  			err:      "keyrange 1c-2a does not exactly match shards",
   102  		},
   103  		{
   104  			// check for keyrange where kr.End is Max Key ""
   105  			keyspace: "-20-40-60-80-a0-c0-e0-",
   106  			keyRange: "80-",
   107  			shards:   []string{"80-a0", "a0-c0", "c0-e0", "e0-"},
   108  		},
   109  		{
   110  			// test for sharded, non-partial keyrange spanning the entire space.
   111  			keyspace: "-20-40-60-80-a0-c0-e0-",
   112  			keyRange: "",
   113  			shards:   []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"},
   114  		},
   115  		{
   116  			// test for unsharded keyspace
   117  			keyspace: "",
   118  			keyRange: "",
   119  			shards:   []string{"0"},
   120  		},
   121  		{
   122  			// test for custom sharded keyspace
   123  			// FIXME(alainjobart) this is wrong, it should return "0", "1"
   124  			// Note this was wrong before the refactor that moved the code here.
   125  			keyspace: "custom",
   126  			keyRange: "",
   127  			shards:   []string{"0"},
   128  		},
   129  	}
   130  
   131  	for _, testCase := range testCases {
   132  		allShards := initShardArray(t, testCase.keyspace)
   133  
   134  		var keyRange *topodatapb.KeyRange
   135  		var err error
   136  		if testCase.keyRange == "" {
   137  			keyRange = &topodatapb.KeyRange{}
   138  		} else {
   139  			krArray, err := ParseShardingSpec(testCase.keyRange)
   140  			if err != nil {
   141  				t.Errorf("Got error while parsing sharding spec %v", err)
   142  			}
   143  			keyRange = krArray[0]
   144  		}
   145  		dkr := DestinationExactKeyRange{KeyRange: keyRange}
   146  		var gotShards []string
   147  		err = dkr.Resolve(allShards, func(shard string) error {
   148  			gotShards = append(gotShards, shard)
   149  			return nil
   150  		})
   151  		if err != nil && err.Error() != testCase.err {
   152  			t.Errorf("gotShards: %v, want %s", err, testCase.err)
   153  		}
   154  		if !reflect.DeepEqual(testCase.shards, gotShards) {
   155  			t.Errorf("want \n%#v, got \n%#v", testCase.shards, gotShards)
   156  		}
   157  	}
   158  }
   159  
   160  func TestDestinationKeyRange(t *testing.T) {
   161  	var testCases = []struct {
   162  		keyspace string
   163  		keyRange string
   164  		shards   []string
   165  	}{
   166  		{
   167  			keyspace: "-20-40-60-80-a0-c0-e0-",
   168  			keyRange: "20-40",
   169  			shards:   []string{"20-40"},
   170  		},
   171  		{
   172  			// check for partial keyrange, spanning one shard
   173  			keyspace: "-20-40-60-80-a0-c0-e0-",
   174  			keyRange: "10-18",
   175  			shards:   []string{"-20"},
   176  		},
   177  		{
   178  			// check for keyrange intersecting with multiple shards
   179  			keyspace: "-20-40-60-80-a0-c0-e0-",
   180  			keyRange: "10-40",
   181  			shards:   []string{"-20", "20-40"},
   182  		},
   183  		{
   184  			// check for keyrange intersecting with multiple shards
   185  			keyspace: "-20-40-60-80-a0-c0-e0-",
   186  			keyRange: "1c-2a",
   187  			shards:   []string{"-20", "20-40"},
   188  		},
   189  		{
   190  			// check for keyrange where kr.End is Max Key ""
   191  			keyspace: "-20-40-60-80-a0-c0-e0-",
   192  			keyRange: "80-",
   193  			shards:   []string{"80-a0", "a0-c0", "c0-e0", "e0-"},
   194  		},
   195  		{
   196  			// test for sharded, non-partial keyrange spanning the entire space.
   197  			keyspace: "-20-40-60-80-a0-c0-e0-",
   198  			keyRange: "",
   199  			shards:   []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"},
   200  		},
   201  		{
   202  			// test for sharded, non-partial keyrange spanning the entire space,
   203  			// with nil keyrange.
   204  			keyspace: "-20-40-60-80-a0-c0-e0-",
   205  			keyRange: "nil",
   206  			shards:   []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"},
   207  		},
   208  		{
   209  			// test for unsharded, non-partial keyrange spanning the entire space.
   210  			keyspace: "",
   211  			keyRange: "",
   212  			shards:   []string{"0"},
   213  		},
   214  		{
   215  			// test for unsharded, non-partial keyrange spanning the entire space,
   216  			// with nil keyrange.
   217  			keyspace: "",
   218  			keyRange: "nil",
   219  			shards:   []string{"0"},
   220  		},
   221  		{
   222  			// custom sharding
   223  			keyspace: "custom",
   224  			keyRange: "",
   225  			shards:   []string{"0", "1"},
   226  		},
   227  		{
   228  			// custom sharding, with nil keyrange.
   229  			keyspace: "custom",
   230  			keyRange: "nil",
   231  			shards:   []string{"0", "1"},
   232  		},
   233  	}
   234  
   235  	for _, testCase := range testCases {
   236  		allShards := initShardArray(t, testCase.keyspace)
   237  
   238  		var keyRange *topodatapb.KeyRange
   239  		if testCase.keyRange == "nil" {
   240  		} else if testCase.keyRange == "" {
   241  			keyRange = &topodatapb.KeyRange{}
   242  		} else {
   243  			krArray, err := ParseShardingSpec(testCase.keyRange)
   244  			if err != nil {
   245  				t.Errorf("Got error while parsing sharding spec %v", err)
   246  			}
   247  			keyRange = krArray[0]
   248  		}
   249  		dkr := DestinationKeyRange{KeyRange: keyRange}
   250  		var gotShards []string
   251  		if err := dkr.Resolve(allShards, func(shard string) error {
   252  			gotShards = append(gotShards, shard)
   253  			return nil
   254  		}); err != nil {
   255  			t.Errorf("want nil, got %v", err)
   256  		}
   257  		if !reflect.DeepEqual(testCase.shards, gotShards) {
   258  			t.Errorf("want \n%#v, got \n%#v", testCase.shards, gotShards)
   259  		}
   260  	}
   261  }