github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/label/selector_test.go (about) 1 // Copyright 2022 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package label 15 16 import ( 17 "strconv" 18 "sync" 19 "testing" 20 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestSelectorMatches(t *testing.T) { 25 t.Parallel() 26 27 cases := []struct { 28 selector *Selector 29 labels Set 30 shouldMatch bool 31 }{ 32 { 33 selector: &Selector{ 34 Key: "tenant", 35 Target: "1", 36 Op: OpEq, 37 }, 38 labels: map[Key]Value{"tenant": "1", "node_type": "2"}, 39 shouldMatch: true, 40 }, 41 { 42 selector: &Selector{ 43 Key: "tenant", 44 Target: "1", 45 Op: OpEq, 46 }, 47 labels: map[Key]Value{"tenant": "2", "node_type": "2"}, 48 shouldMatch: false, 49 }, 50 { 51 selector: &Selector{ 52 Key: "tenant", 53 Target: "1", 54 Op: OpEq, 55 }, 56 labels: map[Key]Value{"node_type": "2"}, 57 shouldMatch: false, 58 }, 59 { 60 selector: &Selector{ 61 Key: "tenant", 62 Target: "1", 63 Op: OpNeq, 64 }, 65 labels: map[Key]Value{"tenant": "2", "node_type": "2"}, 66 shouldMatch: true, 67 }, 68 { 69 selector: &Selector{ 70 Key: "tenant", 71 Target: "1", 72 Op: OpNeq, 73 }, 74 labels: map[Key]Value{"tenant": "1", "node_type": "2"}, 75 shouldMatch: false, 76 }, 77 { 78 selector: &Selector{ 79 Key: "tenant", 80 Target: "1", 81 Op: OpNeq, 82 }, 83 labels: map[Key]Value{"node_type": "2"}, 84 shouldMatch: true, 85 }, 86 { 87 selector: &Selector{ 88 Key: "tenant", 89 Target: ".*abc.*", 90 Op: OpRegex, 91 }, 92 labels: map[Key]Value{"tenant": "1abc2", "node_type": "2"}, 93 shouldMatch: true, 94 }, 95 { 96 selector: &Selector{ 97 Key: "tenant", 98 Target: ".*abc.*", 99 Op: OpRegex, 100 }, 101 labels: map[Key]Value{"tenant": "asdf", "node_type": "2"}, 102 shouldMatch: false, 103 }, 104 { 105 selector: &Selector{ 106 Key: "tenant", 107 Target: "^(abc|def)$", 108 Op: OpRegex, 109 }, 110 labels: map[Key]Value{"tenant": "def", "node_type": "2"}, 111 shouldMatch: true, 112 }, 113 { 114 selector: &Selector{ 115 Key: "tenant", 116 Target: "^(abc|def)$", 117 Op: OpRegex, 118 }, 119 labels: map[Key]Value{"tenant": "abc", "node_type": "2"}, 120 shouldMatch: true, 121 }, 122 { 123 selector: &Selector{ 124 Key: "tenant", 125 Target: "^(abc|def)$", 126 Op: OpRegex, 127 }, 128 labels: map[Key]Value{"tenant": "abcdef", "node_type": "2"}, 129 shouldMatch: false, 130 }, 131 { 132 selector: &Selector{ 133 Key: "tenant", 134 Target: "^(abc|def)$", 135 Op: OpRegex, 136 }, 137 labels: map[Key]Value{"node_type": "2"}, 138 shouldMatch: false, 139 }, 140 } 141 142 for idx, tc := range cases { 143 tc := tc 144 t.Run(strconv.Itoa(idx), func(t *testing.T) { 145 t.Parallel() 146 require.Equal(t, tc.shouldMatch, tc.selector.Matches(tc.labels)) 147 }) 148 } 149 } 150 151 func TestSelectorRegexLazyCompile(t *testing.T) { 152 t.Parallel() 153 154 selector := Selector{ 155 Key: "tenant", 156 Target: "^(abc|def)$", 157 Op: OpRegex, 158 } 159 160 labelSetMatch := map[Key]Value{"tenant": "abc", "node_type": "2"} 161 labelSetNotMatch := map[Key]Value{"tenant": "abcdef", "node_type": "2"} 162 163 var wg sync.WaitGroup 164 for i := 0; i < 10; i++ { 165 wg.Add(1) 166 go func() { 167 defer wg.Done() 168 require.True(t, selector.Matches(labelSetMatch)) 169 require.False(t, selector.Matches(labelSetNotMatch)) 170 }() 171 } 172 173 wg.Wait() 174 } 175 176 func TestSelectorRegexIllegal(t *testing.T) { 177 t.Parallel() 178 179 selector := Selector{ 180 Key: "tenant", 181 Target: "(((", // illegal regular expression 182 Op: OpRegex, 183 } 184 require.False(t, selector.Matches(map[Key]Value{"tenant": "abc", "node_type": "2"})) 185 } 186 187 func TestSelectorValidate(t *testing.T) { 188 t.Parallel() 189 190 cases := []struct { 191 selector *Selector 192 checkErr func(err error) 193 }{ 194 { 195 selector: &Selector{ 196 Key: "#@$!@#", // Illegal Key 197 Target: "1234", 198 Op: OpEq, 199 }, 200 checkErr: func(err error) { 201 require.EqualError(t, err, 202 "validate selector key: label string has wrong format: #@$!@#") 203 }, 204 }, 205 { 206 selector: &Selector{ 207 Key: "tenant", 208 Target: "1234", 209 Op: Op("invalid"), // invalid op code 210 }, 211 checkErr: func(err error) { 212 require.EqualError(t, err, "invalid selector op: key: tenant, op: invalid") 213 }, 214 }, 215 { 216 selector: &Selector{ 217 Key: "tenant", 218 Target: ")))", // invalid regex 219 Op: OpRegex, 220 }, 221 checkErr: func(err error) { 222 require.ErrorContains(t, err, ")))") 223 }, 224 }, 225 { 226 selector: &Selector{ 227 Key: "tenant", 228 Target: ".*abc.*", 229 Op: OpRegex, 230 }, 231 checkErr: func(err error) { 232 require.NoError(t, err) 233 }, 234 }, 235 } 236 237 for idx, tc := range cases { 238 tc := tc 239 t.Run(strconv.Itoa(idx), func(t *testing.T) { 240 t.Parallel() 241 tc.checkErr(tc.selector.Validate()) 242 }) 243 } 244 }