github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/roachpb/metadata_test.go (about)

     1  // Copyright 2014 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package roachpb
    12  
    13  import (
    14  	"fmt"
    15  	"reflect"
    16  	"strings"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/errors"
    20  )
    21  
    22  func TestPercentilesFromData(t *testing.T) {
    23  	testCases := []struct {
    24  		data      []float64
    25  		percents  []float64
    26  		expecteds []float64
    27  	}{
    28  		{
    29  			[]float64{},
    30  			[]float64{-10, 0, 10, 25, 50, 75, 90, 100, 110},
    31  			[]float64{0, 0, 0, 0, 0, 0, 0, 0, 0},
    32  		},
    33  		{
    34  			[]float64{5},
    35  			[]float64{-10, 0, 10, 25, 50, 75, 90, 100, 110},
    36  			[]float64{5, 5, 5, 5, 5, 5, 5, 5, 5},
    37  		},
    38  		{
    39  			[]float64{1, 2},
    40  			[]float64{-10, 0, 10, 25, 50, 75, 90, 100, 110},
    41  			[]float64{1, 1, 1, 1, 2, 2, 2, 2, 2},
    42  		},
    43  		{
    44  			[]float64{1, 2, 3},
    45  			[]float64{-10, 0, 10, 25, 50, 75, 90, 100, 110},
    46  			[]float64{1, 1, 1, 1, 2, 3, 3, 3, 3},
    47  		},
    48  		{
    49  			[]float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
    50  			[]float64{-10, 0, 10, 25, 50, 75, 90, 100, 110},
    51  			[]float64{0, 0, 1, 2, 5, 8, 9, 10, 10},
    52  		},
    53  	}
    54  	for _, tc := range testCases {
    55  		for i := range tc.percents {
    56  			if actual := percentileFromSortedData(tc.data, tc.percents[i]); actual != tc.expecteds[i] {
    57  				t.Errorf("percentile(%v, %f) got %f, want %f", tc.data, tc.percents[i], actual, tc.expecteds[i])
    58  			}
    59  		}
    60  	}
    61  }
    62  
    63  func TestRangeDescriptorFindReplica(t *testing.T) {
    64  	desc := RangeDescriptor{
    65  		InternalReplicas: []ReplicaDescriptor{
    66  			{NodeID: 1, StoreID: 1},
    67  			{NodeID: 2, StoreID: 2},
    68  			{NodeID: 3, StoreID: 3},
    69  		},
    70  	}
    71  	for i, e := range desc.InternalReplicas {
    72  		if a, ok := desc.GetReplicaDescriptor(e.StoreID); !ok {
    73  			t.Errorf("%d: expected to find %+v in %+v for store %d", i, e, desc, e.StoreID)
    74  		} else if a != e {
    75  			t.Errorf("%d: expected to find %+v in %+v for store %d; got %+v", i, e, desc, e.StoreID, a)
    76  		}
    77  	}
    78  }
    79  
    80  func TestRangeDescriptorSafeMessage(t *testing.T) {
    81  	desc := RangeDescriptor{
    82  		RangeID:  1,
    83  		StartKey: RKey("c"),
    84  		EndKey:   RKey("g"),
    85  		InternalReplicas: []ReplicaDescriptor{
    86  			{NodeID: 1, StoreID: 1},
    87  			{NodeID: 2, StoreID: 2},
    88  			{NodeID: 3, StoreID: 3},
    89  		},
    90  	}
    91  
    92  	const expStr = `r1: [(n1,s1):?, (n2,s2):?, (n3,s3):?, next=0, gen=0]`
    93  
    94  	if str := desc.SafeMessage(); str != expStr {
    95  		t.Errorf(
    96  			"expected meta: %s\n"+
    97  				"got:          %s",
    98  			expStr, str)
    99  	}
   100  }
   101  
   102  func TestRangeDescriptorMissingReplica(t *testing.T) {
   103  	desc := RangeDescriptor{}
   104  	r, ok := desc.GetReplicaDescriptor(0)
   105  	if ok {
   106  		t.Fatalf("unexpectedly found missing replica: %s", r)
   107  	}
   108  	if (r != ReplicaDescriptor{}) {
   109  		t.Fatalf("unexpectedly got nontrivial return: %s", r)
   110  	}
   111  }
   112  
   113  // TestLocalityConversions verifies that setting the value from the CLI short
   114  // hand format works correctly.
   115  func TestLocalityConversions(t *testing.T) {
   116  	testCases := []struct {
   117  		in       string
   118  		expected Locality
   119  		err      string
   120  	}{
   121  		{
   122  			in: "a=b,c=d,e=f",
   123  			expected: Locality{
   124  				Tiers: []Tier{
   125  					{Key: "a", Value: "b"},
   126  					{Key: "c", Value: "d"},
   127  					{Key: "e", Value: "f"},
   128  				},
   129  			},
   130  		},
   131  		{
   132  			in:       "",
   133  			expected: Locality{},
   134  			err:      "empty locality",
   135  		},
   136  		{
   137  			in:       "c=d=e",
   138  			expected: Locality{},
   139  			err:      "tier must be in the form",
   140  		},
   141  		{
   142  			in:       "a",
   143  			expected: Locality{},
   144  			err:      "tier must be in the form",
   145  		},
   146  	}
   147  
   148  	for i, tc := range testCases {
   149  		var l Locality
   150  		if err := l.Set(tc.in); tc.err == "" && err != nil {
   151  			t.Error(err)
   152  		} else if tc.err != "" && !strings.Contains(err.Error(), tc.err) {
   153  			t.Error(errors.Wrapf(err, "%d: expected %q", i, tc.err))
   154  		}
   155  
   156  		if !reflect.DeepEqual(l, tc.expected) {
   157  			t.Errorf("%d: Locality.Set(%q) = %+v; not %+v", i, tc.in, l, tc.expected)
   158  		}
   159  	}
   160  }
   161  
   162  func TestDiversityScore(t *testing.T) {
   163  	// Keys are not considered for score, just the order, so we don't need to
   164  	// specify them.
   165  	generateLocality := func(values string) Locality {
   166  		var locality Locality
   167  		if len(values) > 0 {
   168  			for i, value := range strings.Split(values, ",") {
   169  				locality.Tiers = append(locality.Tiers, Tier{
   170  					Key:   fmt.Sprintf("%d", i),
   171  					Value: value,
   172  				})
   173  			}
   174  		}
   175  		return locality
   176  	}
   177  
   178  	testCases := []struct {
   179  		left     string
   180  		right    string
   181  		expected float64
   182  	}{
   183  		{"", "", 0},
   184  		{"a", "", 1},
   185  		{"a,b", "", 1},
   186  		{"a,b,c", "", 1},
   187  		{"a", "b", 1},
   188  		{"a,aa", "b,bb", 1},
   189  		{"a,aa,aaa", "b,bb,bbb", 1},
   190  		{"a,aa,aaa", "b,aa,aaa", 1},
   191  		{"a", "a", 0},
   192  		{"a,aa", "a,aa", 0},
   193  		{"a,aa,aaa", "a,aa,aaa", 0},
   194  		{"a,aa,aaa", "a,aa", 1.0 / 3.0},
   195  		{"a,aa", "a,bb", 1.0 / 2.0},
   196  		{"a,aa,aaa", "a,bb,bbb", 2.0 / 3.0},
   197  		{"a,aa,aaa", "a,bb,aaa", 2.0 / 3.0},
   198  		{"a,aa,aaa", "a,aa,bbb", 1.0 / 3.0},
   199  		{"a,aa,aaa,aaaa", "b,aa,aaa,aaaa", 1},
   200  		{"a,aa,aaa,aaaa", "a,bb,aaa,aaaa", 3.0 / 4.0},
   201  		{"a,aa,aaa,aaaa", "a,aa,bbb,aaaa", 2.0 / 4.0},
   202  		{"a,aa,aaa,aaaa", "a,aa,aaa,bbbb", 1.0 / 4.0},
   203  		{"a,aa,aaa,aaaa", "a,aa,aaa", 1.0 / 4.0},
   204  		{"a,aa,aaa,aaaa", "b,aa", 1},
   205  		{"a,aa,aaa,aaaa", "a,bb", 1.0 / 2.0},
   206  	}
   207  
   208  	for _, testCase := range testCases {
   209  		t.Run(fmt.Sprintf("%s:%s", testCase.left, testCase.right), func(t *testing.T) {
   210  			left := generateLocality(testCase.left)
   211  			right := generateLocality(testCase.right)
   212  			if a := left.DiversityScore(right); a != testCase.expected {
   213  				t.Fatalf("expected %f, got %f", testCase.expected, a)
   214  			}
   215  			if a := right.DiversityScore(left); a != testCase.expected {
   216  				t.Fatalf("expected %f, got %f", testCase.expected, a)
   217  			}
   218  		})
   219  	}
   220  }