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

     1  // Copyright 2018 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 sql
    12  
    13  import (
    14  	"context"
    15  	"testing"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/config/zonepb"
    18  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    19  	"github.com/cockroachdb/cockroach/pkg/server/serverpb"
    20  	"github.com/cockroachdb/cockroach/pkg/server/status/statuspb"
    21  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    22  	yaml "gopkg.in/yaml.v2"
    23  )
    24  
    25  func TestValidateNoRepeatKeysInZone(t *testing.T) {
    26  	defer leaktest.AfterTest(t)()
    27  	testCases := []struct {
    28  		constraint    string
    29  		expectSuccess bool
    30  	}{
    31  		{`constraints: ["+region=us-east-1"]`, true},
    32  		{`constraints: ["+region=us-east-1", "+zone=pa"]`, true},
    33  		{`constraints: ["+region=us-east-1", "-region=us-west-1"]`, true},
    34  		{`constraints: ["+region=us-east-1", "+region=us-east-2"]`, false},
    35  		{`constraints: ["+region=us-east-1", "+zone=pa", "+region=us-west-1"]`, false},
    36  		{`constraints: ["+region=us-east-1", "-region=us-east-1"]`, false},
    37  		{`constraints: ["-region=us-east-1", "+region=us-east-1"]`, false},
    38  		{`constraints: {"+region=us-east-1":2, "+region=us-east-2":2}`, true},
    39  		{`constraints: {"+region=us-east-1,+region=us-west-1":2, "+region=us-east-2":2}`, false},
    40  		{`constraints: ["+x1", "+x2", "+x3"]`, true},
    41  		{`constraints: ["+x1", "+x1"]`, false},
    42  		{`constraints: ["+x1", "-x1"]`, false},
    43  		{`constraints: ["-x1", "+x1"]`, false},
    44  	}
    45  
    46  	for _, tc := range testCases {
    47  		var zone zonepb.ZoneConfig
    48  		err := yaml.UnmarshalStrict([]byte(tc.constraint), &zone)
    49  		if err != nil {
    50  			t.Fatal(err)
    51  		}
    52  		err = validateNoRepeatKeysInZone(&zone)
    53  		if err != nil && tc.expectSuccess {
    54  			t.Errorf("expected success for %q; got %v", tc.constraint, err)
    55  		} else if err == nil && !tc.expectSuccess {
    56  			t.Errorf("expected err for %q; got success", tc.constraint)
    57  		}
    58  	}
    59  }
    60  
    61  func TestValidateZoneAttrsAndLocalities(t *testing.T) {
    62  	defer leaktest.AfterTest(t)()
    63  
    64  	stores := []struct {
    65  		nodeAttrs     []string
    66  		storeAttrs    []string
    67  		storeLocality []roachpb.Tier
    68  	}{
    69  		{
    70  			nodeAttrs:  []string{"highcpu", "highmem"},
    71  			storeAttrs: []string{"ssd"},
    72  			storeLocality: []roachpb.Tier{
    73  				{Key: "geo", Value: "us"},
    74  				{Key: "region", Value: "us-east1"},
    75  				{Key: "zone", Value: "us-east1-b"},
    76  			},
    77  		},
    78  		{
    79  			nodeAttrs:  []string{"lowcpu", "lowmem"},
    80  			storeAttrs: []string{"hdd"},
    81  			storeLocality: []roachpb.Tier{
    82  				{Key: "geo", Value: "eu"},
    83  				{Key: "region", Value: "eu-west1"},
    84  				{Key: "zone", Value: "eu-west1-b"},
    85  				{Key: "rack", Value: "17"},
    86  			},
    87  		},
    88  	}
    89  
    90  	genStatusFromStore := func(nodeAttrs []string, storeAttrs []string, storeLocality []roachpb.Tier) statuspb.NodeStatus {
    91  		return statuspb.NodeStatus{
    92  			StoreStatuses: []statuspb.StoreStatus{
    93  				{
    94  					Desc: roachpb.StoreDescriptor{
    95  						Attrs: roachpb.Attributes{
    96  							Attrs: storeAttrs,
    97  						},
    98  						Node: roachpb.NodeDescriptor{
    99  							Attrs: roachpb.Attributes{
   100  								Attrs: nodeAttrs,
   101  							},
   102  							Locality: roachpb.Locality{
   103  								Tiers: storeLocality,
   104  							},
   105  						},
   106  					},
   107  				},
   108  			},
   109  		}
   110  	}
   111  
   112  	nodes := &serverpb.NodesResponse{}
   113  	for _, store := range stores {
   114  		nodes.Nodes = append(nodes.Nodes, genStatusFromStore(store.nodeAttrs, store.storeAttrs, store.storeLocality))
   115  	}
   116  
   117  	// Different cluster settings to test validation behavior.
   118  	getNodes := func(_ context.Context, _ *serverpb.NodesRequest) (*serverpb.NodesResponse, error) {
   119  		return nodes, nil
   120  	}
   121  
   122  	// Regressions for negative constraint validation
   123  	singleAttrNode := func(_ context.Context, _ *serverpb.NodesRequest) (*serverpb.NodesResponse, error) {
   124  		nodes := &serverpb.NodesResponse{}
   125  		nodes.Nodes = append(nodes.Nodes, genStatusFromStore([]string{}, []string{"ssd"}, []roachpb.Tier{}))
   126  		return nodes, nil
   127  	}
   128  	singleLocalityNode := func(_ context.Context, _ *serverpb.NodesRequest) (*serverpb.NodesResponse, error) {
   129  		nodes := &serverpb.NodesResponse{}
   130  		nodes.Nodes = append(nodes.Nodes, genStatusFromStore([]string{}, []string{}, []roachpb.Tier{{Key: "region", Value: "us-east1"}}))
   131  		return nodes, nil
   132  	}
   133  
   134  	const expectSuccess = 0
   135  	const expectParseErr = 1
   136  	const expectValidateErr = 2
   137  	for i, tc := range []struct {
   138  		cfg       string
   139  		expectErr int
   140  		nodes     nodeGetter
   141  	}{
   142  		{`nonsense`, expectParseErr, getNodes},
   143  		{`range_max_bytes: 100`, expectSuccess, getNodes},
   144  		{`range_max_byte: 100`, expectParseErr, getNodes},
   145  		{`constraints: ["+region=us-east1"]`, expectSuccess, getNodes},
   146  		{`constraints: {"+region=us-east1": 2, "+region=eu-west1": 1}`, expectSuccess, getNodes},
   147  		{`constraints: ["+region=us-eas1"]`, expectValidateErr, getNodes},
   148  		{`constraints: {"+region=us-eas1": 2, "+region=eu-west1": 1}`, expectValidateErr, getNodes},
   149  		{`constraints: {"+region=us-east1": 2, "+region=eu-wes1": 1}`, expectValidateErr, getNodes},
   150  		{`constraints: ["+regio=us-east1"]`, expectValidateErr, getNodes},
   151  		{`constraints: ["+rack=17"]`, expectSuccess, getNodes},
   152  		{`constraints: ["+rack=18"]`, expectValidateErr, getNodes},
   153  		{`constraints: ["+rach=17"]`, expectValidateErr, getNodes},
   154  		{`constraints: ["+highcpu"]`, expectSuccess, getNodes},
   155  		{`constraints: ["+lowmem"]`, expectSuccess, getNodes},
   156  		{`constraints: ["+ssd"]`, expectSuccess, getNodes},
   157  		{`constraints: ["+highcp"]`, expectValidateErr, getNodes},
   158  		{`constraints: ["+owmem"]`, expectValidateErr, getNodes},
   159  		{`constraints: ["+sssd"]`, expectValidateErr, getNodes},
   160  		{`lease_preferences: [["+region=us-east1", "+ssd"], ["+geo=us", "+highcpu"]]`, expectSuccess, getNodes},
   161  		{`lease_preferences: [["+region=us-eat1", "+ssd"], ["+geo=us", "+highcpu"]]`, expectValidateErr, getNodes},
   162  		{`lease_preferences: [["+region=us-east1", "+foo"], ["+geo=us", "+highcpu"]]`, expectValidateErr, getNodes},
   163  		{`lease_preferences: [["+region=us-east1", "+ssd"], ["+geo=us", "+bar"]]`, expectValidateErr, getNodes},
   164  		{`constraints: ["-region=us-east1"]`, expectSuccess, singleLocalityNode},
   165  		{`constraints: ["-ssd"]`, expectSuccess, singleAttrNode},
   166  		{`constraints: ["-regio=us-eas1"]`, expectSuccess, getNodes},
   167  		{`constraints: {"-region=us-eas1": 2, "-region=eu-wes1": 1}`, expectSuccess, getNodes},
   168  		{`constraints: ["-foo=bar"]`, expectSuccess, getNodes},
   169  		{`constraints: ["-highcpu"]`, expectSuccess, getNodes},
   170  		{`constraints: ["-ssd"]`, expectSuccess, getNodes},
   171  		{`constraints: ["-fake"]`, expectSuccess, getNodes},
   172  	} {
   173  		var zone zonepb.ZoneConfig
   174  		err := yaml.UnmarshalStrict([]byte(tc.cfg), &zone)
   175  		if err != nil && tc.expectErr == expectSuccess {
   176  			t.Fatalf("#%d: expected success for %q; got %v", i, tc.cfg, err)
   177  		} else if err == nil && tc.expectErr == expectParseErr {
   178  			t.Fatalf("#%d: expected parse err for %q; got success", i, tc.cfg)
   179  		}
   180  
   181  		err = validateZoneAttrsAndLocalities(context.Background(), tc.nodes, &zone)
   182  		if err != nil && tc.expectErr == expectSuccess {
   183  			t.Errorf("#%d: expected success for %q; got %v", i, tc.cfg, err)
   184  		} else if err == nil && tc.expectErr == expectValidateErr {
   185  			t.Errorf("#%d: expected err for %q; got success", i, tc.cfg)
   186  		}
   187  	}
   188  }