istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/labels/instance_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package labels_test 16 17 import ( 18 "testing" 19 20 "istio.io/istio/pkg/config/labels" 21 "istio.io/istio/pkg/test/util/assert" 22 ) 23 24 func TestInstance(t *testing.T) { 25 type result struct { 26 subsetOf bool 27 selected bool 28 } 29 30 cases := []struct { 31 left labels.Instance 32 right labels.Instance 33 expected result 34 }{ 35 { 36 left: nil, 37 right: labels.Instance{"app": "a"}, 38 expected: result{true, false}, 39 }, 40 { 41 left: labels.Instance{}, 42 right: labels.Instance{"app": "a"}, 43 expected: result{true, false}, 44 }, 45 { 46 left: labels.Instance{"app": "a"}, 47 right: nil, 48 expected: result{false, false}, 49 }, 50 { 51 left: labels.Instance{"app": "a"}, 52 right: labels.Instance{"app": "a", "prod": "env"}, 53 expected: result{true, true}, 54 }, 55 { 56 left: labels.Instance{"app": "a", "prod": "env"}, 57 right: labels.Instance{"app": "a"}, 58 expected: result{false, false}, 59 }, 60 { 61 left: labels.Instance{"app": "a"}, 62 right: labels.Instance{"app": "b", "prod": "env"}, 63 expected: result{false, false}, 64 }, 65 { 66 left: labels.Instance{"foo": ""}, 67 right: labels.Instance{"app": "a"}, 68 expected: result{false, false}, 69 }, 70 { 71 left: labels.Instance{"foo": ""}, 72 right: labels.Instance{"app": "a", "foo": ""}, 73 expected: result{true, true}, 74 }, 75 { 76 left: labels.Instance{"app": "a", "foo": ""}, 77 right: labels.Instance{"foo": ""}, 78 expected: result{false, false}, 79 }, 80 } 81 for _, c := range cases { 82 var got result 83 got.subsetOf = c.left.SubsetOf(c.right) 84 got.selected = c.left.Match(c.right) 85 if got != c.expected { 86 t.Errorf("%v.SubsetOf(%v) got %v, expected %v", c.left, c.right, got, c.expected) 87 } 88 } 89 } 90 91 func TestString(t *testing.T) { 92 cases := []struct { 93 input labels.Instance 94 expected string 95 }{ 96 { 97 input: nil, 98 expected: "", 99 }, 100 { 101 input: labels.Instance{}, 102 expected: "", 103 }, 104 { 105 input: labels.Instance{"app": "a"}, 106 expected: "app=a", 107 }, 108 { 109 input: labels.Instance{"app": "a", "prod": "env"}, 110 expected: "app=a,prod=env", 111 }, 112 { 113 input: labels.Instance{"foo": ""}, 114 expected: "foo", 115 }, 116 { 117 input: labels.Instance{"app": "a", "foo": ""}, 118 expected: "app=a,foo", 119 }, 120 } 121 for _, tt := range cases { 122 t.Run(tt.expected, func(t *testing.T) { 123 assert.Equal(t, tt.input.String(), tt.expected) 124 }) 125 } 126 } 127 128 func TestInstanceValidate(t *testing.T) { 129 cases := []struct { 130 name string 131 tags labels.Instance 132 valid bool 133 }{ 134 { 135 name: "empty tags", 136 valid: true, 137 }, 138 { 139 name: "bad tag", 140 tags: labels.Instance{"^": "^"}, 141 }, 142 { 143 name: "good tag", 144 tags: labels.Instance{"key": "value"}, 145 valid: true, 146 }, 147 { 148 name: "good tag - empty value", 149 tags: labels.Instance{"key": ""}, 150 valid: true, 151 }, 152 { 153 name: "good tag - DNS prefix", 154 tags: labels.Instance{"k8s.io/key": "value"}, 155 valid: true, 156 }, 157 { 158 name: "good tag - subdomain DNS prefix", 159 tags: labels.Instance{"app.kubernetes.io/name": "value"}, 160 valid: true, 161 }, 162 { 163 name: "bad tag - empty key", 164 tags: labels.Instance{"": "value"}, 165 }, 166 { 167 name: "bad tag key 1", 168 tags: labels.Instance{".key": "value"}, 169 }, 170 { 171 name: "bad tag key 2", 172 tags: labels.Instance{"key_": "value"}, 173 }, 174 { 175 name: "bad tag key 3", 176 tags: labels.Instance{"key$": "value"}, 177 }, 178 { 179 name: "bad tag key - invalid DNS prefix", 180 tags: labels.Instance{"istio./key": "value"}, 181 }, 182 { 183 name: "bad tag value 1", 184 tags: labels.Instance{"key": ".value"}, 185 }, 186 { 187 name: "bad tag value 2", 188 tags: labels.Instance{"key": "value_"}, 189 }, 190 { 191 name: "bad tag value 3", 192 tags: labels.Instance{"key": "value$"}, 193 }, 194 } 195 for _, c := range cases { 196 if got := c.tags.Validate(); (got == nil) != c.valid { 197 t.Errorf("%s failed: got valid=%v but wanted valid=%v: %v", c.name, got == nil, c.valid, got) 198 } 199 } 200 } 201 202 func BenchmarkLabelString(b *testing.B) { 203 big := labels.Instance{} 204 for i := 0; i < 50; i++ { 205 big["topology.kubernetes.io/region"] = "some value" 206 } 207 small := labels.Instance{ 208 "app": "foo", 209 "baz": "bar", 210 } 211 cases := []struct { 212 name string 213 label labels.Instance 214 }{ 215 {"small", small}, 216 {"big", big}, 217 } 218 for _, tt := range cases { 219 b.Run(tt.name, func(b *testing.B) { 220 for n := 0; n < b.N; n++ { 221 _ = tt.label.String() 222 } 223 }) 224 } 225 }