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 }