github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/labels/selector_test.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package labels 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 "testing" 24 25 "github.com/google/go-cmp/cmp" 26 "github.com/google/go-cmp/cmp/cmpopts" 27 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/selection" 28 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/sets" 29 "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/validation/field" 30 ) 31 32 var ( 33 ignoreDetail = cmpopts.IgnoreFields(field.Error{}, "Detail") 34 ) 35 36 func TestSelectorParse(t *testing.T) { 37 testGoodStrings := []string{ 38 "x=a,y=b,z=c", 39 "", 40 "x!=a,y=b", 41 "x=", 42 "x= ", 43 "x=,z= ", 44 "x= ,z= ", 45 "!x", 46 "x>1", 47 "x>1,z<5", 48 } 49 testBadStrings := []string{ 50 "x=a||y=b", 51 "x==a==b", 52 "!x=a", 53 "x<a", 54 } 55 for _, test := range testGoodStrings { 56 lq, err := Parse(test) 57 if err != nil { 58 t.Errorf("%v: error %v (%#v)\n", test, err, err) 59 } 60 if strings.Replace(test, " ", "", -1) != lq.String() { 61 t.Errorf("%v restring gave: %v\n", test, lq.String()) 62 } 63 } 64 for _, test := range testBadStrings { 65 _, err := Parse(test) 66 if err == nil { 67 t.Errorf("%v: did not get expected error\n", test) 68 } 69 } 70 } 71 72 func TestDeterministicParse(t *testing.T) { 73 s1, err := Parse("x=a,a=x") 74 s2, err2 := Parse("a=x,x=a") 75 if err != nil || err2 != nil { 76 t.Errorf("Unexpected parse error") 77 } 78 if s1.String() != s2.String() { 79 t.Errorf("Non-deterministic parse") 80 } 81 } 82 83 func expectMatch(t *testing.T, selector string, ls Set) { 84 lq, err := Parse(selector) 85 if err != nil { 86 t.Errorf("Unable to parse %v as a selector\n", selector) 87 return 88 } 89 if !lq.Matches(ls) { 90 t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) 91 } 92 } 93 94 func expectNoMatch(t *testing.T, selector string, ls Set) { 95 lq, err := Parse(selector) 96 if err != nil { 97 t.Errorf("Unable to parse %v as a selector\n", selector) 98 return 99 } 100 if lq.Matches(ls) { 101 t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) 102 } 103 } 104 105 func TestEverything(t *testing.T) { 106 if !Everything().Matches(Set{"x": "y"}) { 107 t.Errorf("Nil selector didn't match") 108 } 109 if !Everything().Empty() { 110 t.Errorf("Everything was not empty") 111 } 112 } 113 114 func TestSelectorMatches(t *testing.T) { 115 expectMatch(t, "", Set{"x": "y"}) 116 expectMatch(t, "x=y", Set{"x": "y"}) 117 expectMatch(t, "x=y,z=w", Set{"x": "y", "z": "w"}) 118 expectMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "a"}) 119 expectMatch(t, "notin=in", Set{"notin": "in"}) // in and notin in exactMatch 120 expectMatch(t, "x", Set{"x": "z"}) 121 expectMatch(t, "!x", Set{"y": "z"}) 122 expectMatch(t, "x>1", Set{"x": "2"}) 123 expectMatch(t, "x<1", Set{"x": "0"}) 124 expectNoMatch(t, "x=z", Set{}) 125 expectNoMatch(t, "x=y", Set{"x": "z"}) 126 expectNoMatch(t, "x=y,z=w", Set{"x": "w", "z": "w"}) 127 expectNoMatch(t, "x!=y,z!=w", Set{"x": "z", "z": "w"}) 128 expectNoMatch(t, "x", Set{"y": "z"}) 129 expectNoMatch(t, "!x", Set{"x": "z"}) 130 expectNoMatch(t, "x>1", Set{"x": "0"}) 131 expectNoMatch(t, "x<1", Set{"x": "2"}) 132 133 labelset := Set{ 134 "foo": "bar", 135 "baz": "blah", 136 } 137 expectMatch(t, "foo=bar", labelset) 138 expectMatch(t, "baz=blah", labelset) 139 expectMatch(t, "foo=bar,baz=blah", labelset) 140 expectNoMatch(t, "foo=blah", labelset) 141 expectNoMatch(t, "baz=bar", labelset) 142 expectNoMatch(t, "foo=bar,foobar=bar,baz=blah", labelset) 143 } 144 145 func expectMatchDirect(t *testing.T, selector, ls Set) { 146 if !SelectorFromSet(selector).Matches(ls) { 147 t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls) 148 } 149 } 150 151 //nolint:staticcheck,unused //iccheck // U1000 currently commented out in TODO of TestSetMatches 152 func expectNoMatchDirect(t *testing.T, selector, ls Set) { 153 if SelectorFromSet(selector).Matches(ls) { 154 t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls) 155 } 156 } 157 158 func TestSetMatches(t *testing.T) { 159 labelset := Set{ 160 "foo": "bar", 161 "baz": "blah", 162 } 163 expectMatchDirect(t, Set{}, labelset) 164 expectMatchDirect(t, Set{"foo": "bar"}, labelset) 165 expectMatchDirect(t, Set{"baz": "blah"}, labelset) 166 expectMatchDirect(t, Set{"foo": "bar", "baz": "blah"}, labelset) 167 168 //TODO: bad values not handled for the moment in SelectorFromSet 169 //expectNoMatchDirect(t, Set{"foo": "=blah"}, labelset) 170 //expectNoMatchDirect(t, Set{"baz": "=bar"}, labelset) 171 //expectNoMatchDirect(t, Set{"foo": "=bar", "foobar": "bar", "baz": "blah"}, labelset) 172 } 173 174 func TestNilMapIsValid(t *testing.T) { 175 selector := Set(nil).AsSelector() 176 if selector == nil { 177 t.Errorf("Selector for nil set should be Everything") 178 } 179 if !selector.Empty() { 180 t.Errorf("Selector for nil set should be Empty") 181 } 182 } 183 184 func TestSetIsEmpty(t *testing.T) { 185 if !(Set{}).AsSelector().Empty() { 186 t.Errorf("Empty set should be empty") 187 } 188 if !(NewSelector()).Empty() { 189 t.Errorf("Nil Selector should be empty") 190 } 191 } 192 193 func TestLexer(t *testing.T) { 194 testcases := []struct { 195 s string 196 t Token 197 }{ 198 {"", EndOfStringToken}, 199 {",", CommaToken}, 200 {"notin", NotInToken}, 201 {"in", InToken}, 202 {"=", EqualsToken}, 203 {"==", DoubleEqualsToken}, 204 {">", GreaterThanToken}, 205 {"<", LessThanToken}, 206 //Note that Lex returns the longest valid token found 207 {"!", DoesNotExistToken}, 208 {"!=", NotEqualsToken}, 209 {"(", OpenParToken}, 210 {")", ClosedParToken}, 211 //Non-"special" characters are considered part of an identifier 212 {"~", IdentifierToken}, 213 {"||", IdentifierToken}, 214 } 215 for _, v := range testcases { 216 l := &Lexer{s: v.s, pos: 0} 217 token, lit := l.Lex() 218 if token != v.t { 219 t.Errorf("Got %d it should be %d for '%s'", token, v.t, v.s) 220 } 221 if v.t != ErrorToken && lit != v.s { 222 t.Errorf("Got '%s' it should be '%s'", lit, v.s) 223 } 224 } 225 } 226 227 func min(l, r int) (m int) { 228 m = r 229 if l < r { 230 m = l 231 } 232 return m 233 } 234 235 func TestLexerSequence(t *testing.T) { 236 testcases := []struct { 237 s string 238 t []Token 239 }{ 240 {"key in ( value )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, ClosedParToken}}, 241 {"key notin ( value )", []Token{IdentifierToken, NotInToken, OpenParToken, IdentifierToken, ClosedParToken}}, 242 {"key in ( value1, value2 )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, CommaToken, IdentifierToken, ClosedParToken}}, 243 {"key", []Token{IdentifierToken}}, 244 {"!key", []Token{DoesNotExistToken, IdentifierToken}}, 245 {"()", []Token{OpenParToken, ClosedParToken}}, 246 {"x in (),y", []Token{IdentifierToken, InToken, OpenParToken, ClosedParToken, CommaToken, IdentifierToken}}, 247 {"== != (), = notin", []Token{DoubleEqualsToken, NotEqualsToken, OpenParToken, ClosedParToken, CommaToken, EqualsToken, NotInToken}}, 248 {"key>2", []Token{IdentifierToken, GreaterThanToken, IdentifierToken}}, 249 {"key<1", []Token{IdentifierToken, LessThanToken, IdentifierToken}}, 250 } 251 for _, v := range testcases { 252 var tokens []Token 253 l := &Lexer{s: v.s, pos: 0} 254 for { 255 token, _ := l.Lex() 256 if token == EndOfStringToken { 257 break 258 } 259 tokens = append(tokens, token) 260 } 261 if len(tokens) != len(v.t) { 262 t.Errorf("Bad number of tokens for '%s %d, %d", v.s, len(tokens), len(v.t)) 263 } 264 for i := 0; i < min(len(tokens), len(v.t)); i++ { 265 if tokens[i] != v.t[i] { 266 t.Errorf("Test '%s': Mismatching in token type found '%v' it should be '%v'", v.s, tokens[i], v.t[i]) 267 } 268 } 269 } 270 } 271 func TestParserLookahead(t *testing.T) { 272 testcases := []struct { 273 s string 274 t []Token 275 }{ 276 {"key in ( value )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, ClosedParToken, EndOfStringToken}}, 277 {"key notin ( value )", []Token{IdentifierToken, NotInToken, OpenParToken, IdentifierToken, ClosedParToken, EndOfStringToken}}, 278 {"key in ( value1, value2 )", []Token{IdentifierToken, InToken, OpenParToken, IdentifierToken, CommaToken, IdentifierToken, ClosedParToken, EndOfStringToken}}, 279 {"key", []Token{IdentifierToken, EndOfStringToken}}, 280 {"!key", []Token{DoesNotExistToken, IdentifierToken, EndOfStringToken}}, 281 {"()", []Token{OpenParToken, ClosedParToken, EndOfStringToken}}, 282 {"", []Token{EndOfStringToken}}, 283 {"x in (),y", []Token{IdentifierToken, InToken, OpenParToken, ClosedParToken, CommaToken, IdentifierToken, EndOfStringToken}}, 284 {"== != (), = notin", []Token{DoubleEqualsToken, NotEqualsToken, OpenParToken, ClosedParToken, CommaToken, EqualsToken, NotInToken, EndOfStringToken}}, 285 {"key>2", []Token{IdentifierToken, GreaterThanToken, IdentifierToken, EndOfStringToken}}, 286 {"key<1", []Token{IdentifierToken, LessThanToken, IdentifierToken, EndOfStringToken}}, 287 } 288 for _, v := range testcases { 289 p := &Parser{l: &Lexer{s: v.s, pos: 0}, position: 0} 290 p.scan() 291 if len(p.scannedItems) != len(v.t) { 292 t.Errorf("Expected %d items found %d", len(v.t), len(p.scannedItems)) 293 } 294 for { 295 token, lit := p.lookahead(KeyAndOperator) 296 297 token2, lit2 := p.consume(KeyAndOperator) 298 if token == EndOfStringToken { 299 break 300 } 301 if token != token2 || lit != lit2 { 302 t.Errorf("Bad values") 303 } 304 } 305 } 306 } 307 308 func TestParseOperator(t *testing.T) { 309 testcases := []struct { 310 token string 311 expectedError error 312 }{ 313 {"in", nil}, 314 {"=", nil}, 315 {"==", nil}, 316 {">", nil}, 317 {"<", nil}, 318 {"notin", nil}, 319 {"!=", nil}, 320 {"!", fmt.Errorf("found '%s', expected: %v", selection.DoesNotExist, strings.Join(binaryOperators, ", "))}, 321 {"exists", fmt.Errorf("found '%s', expected: %v", selection.Exists, strings.Join(binaryOperators, ", "))}, 322 {"(", fmt.Errorf("found '%s', expected: %v", "(", strings.Join(binaryOperators, ", "))}, 323 } 324 for _, testcase := range testcases { 325 p := &Parser{l: &Lexer{s: testcase.token, pos: 0}, position: 0} 326 p.scan() 327 328 _, err := p.parseOperator() 329 if ok := reflect.DeepEqual(testcase.expectedError, err); !ok { 330 t.Errorf("\nexpect err [%v], \nactual err [%v]", testcase.expectedError, err) 331 } 332 } 333 } 334 335 func TestRequirementConstructor(t *testing.T) { 336 requirementConstructorTests := []struct { 337 Key string 338 Op selection.Operator 339 Vals sets.String 340 WantErr field.ErrorList 341 }{ 342 { 343 Key: "x1", 344 Op: selection.In, 345 WantErr: field.ErrorList{ 346 &field.Error{ 347 Type: field.ErrorTypeInvalid, 348 Field: "values", 349 BadValue: []string{}, 350 }, 351 }, 352 }, 353 { 354 Key: "x2", 355 Op: selection.NotIn, 356 Vals: sets.NewString(), 357 WantErr: field.ErrorList{ 358 &field.Error{ 359 Type: field.ErrorTypeInvalid, 360 Field: "values", 361 BadValue: []string{}, 362 }, 363 }, 364 }, 365 { 366 Key: "x3", 367 Op: selection.In, 368 Vals: sets.NewString("foo"), 369 }, 370 { 371 Key: "x4", 372 Op: selection.NotIn, 373 Vals: sets.NewString("foo"), 374 }, 375 { 376 Key: "x5", 377 Op: selection.Equals, 378 Vals: sets.NewString("foo", "bar"), 379 WantErr: field.ErrorList{ 380 &field.Error{ 381 Type: field.ErrorTypeInvalid, 382 Field: "values", 383 BadValue: []string{"bar", "foo"}, 384 }, 385 }, 386 }, 387 { 388 Key: "x6", 389 Op: selection.Exists, 390 }, 391 { 392 Key: "x7", 393 Op: selection.DoesNotExist, 394 }, 395 { 396 Key: "x8", 397 Op: selection.Exists, 398 Vals: sets.NewString("foo"), 399 WantErr: field.ErrorList{ 400 &field.Error{ 401 Type: field.ErrorTypeInvalid, 402 Field: "values", 403 BadValue: []string{"foo"}, 404 }, 405 }, 406 }, 407 { 408 Key: "x9", 409 Op: selection.In, 410 Vals: sets.NewString("bar"), 411 }, 412 { 413 Key: "x10", 414 Op: selection.In, 415 Vals: sets.NewString("bar"), 416 }, 417 { 418 Key: "x11", 419 Op: selection.GreaterThan, 420 Vals: sets.NewString("1"), 421 }, 422 { 423 Key: "x12", 424 Op: selection.LessThan, 425 Vals: sets.NewString("6"), 426 }, 427 { 428 Key: "x13", 429 Op: selection.GreaterThan, 430 WantErr: field.ErrorList{ 431 &field.Error{ 432 Type: field.ErrorTypeInvalid, 433 Field: "values", 434 BadValue: []string{}, 435 }, 436 }, 437 }, 438 { 439 Key: "x14", 440 Op: selection.GreaterThan, 441 Vals: sets.NewString("bar"), 442 WantErr: field.ErrorList{ 443 &field.Error{ 444 Type: field.ErrorTypeInvalid, 445 Field: "values[0]", 446 BadValue: "bar", 447 }, 448 }, 449 }, 450 { 451 Key: "x15", 452 Op: selection.LessThan, 453 Vals: sets.NewString("bar"), 454 WantErr: field.ErrorList{ 455 &field.Error{ 456 Type: field.ErrorTypeInvalid, 457 Field: "values[0]", 458 BadValue: "bar", 459 }, 460 }, 461 }, 462 { 463 Key: strings.Repeat("a", 254), //breaks DNS rule that len(key) <= 253 464 Op: selection.Exists, 465 WantErr: field.ErrorList{ 466 &field.Error{ 467 Type: field.ErrorTypeInvalid, 468 Field: "key", 469 BadValue: strings.Repeat("a", 254), 470 }, 471 }, 472 }, 473 { 474 Key: "x16", 475 Op: selection.Equals, 476 Vals: sets.NewString(strings.Repeat("a", 254)), 477 WantErr: field.ErrorList{ 478 &field.Error{ 479 Type: field.ErrorTypeInvalid, 480 Field: "values[0][x16]", 481 BadValue: strings.Repeat("a", 254), 482 }, 483 }, 484 }, 485 { 486 Key: "x17", 487 Op: selection.Equals, 488 Vals: sets.NewString("a b"), 489 WantErr: field.ErrorList{ 490 &field.Error{ 491 Type: field.ErrorTypeInvalid, 492 Field: "values[0][x17]", 493 BadValue: "a b", 494 }, 495 }, 496 }, 497 { 498 Key: "x18", 499 Op: "unsupportedOp", 500 WantErr: field.ErrorList{ 501 &field.Error{ 502 Type: field.ErrorTypeNotSupported, 503 Field: "operator", 504 BadValue: selection.Operator("unsupportedOp"), 505 }, 506 }, 507 }, 508 } 509 for _, rc := range requirementConstructorTests { 510 _, err := NewRequirement(rc.Key, rc.Op, rc.Vals.List()) 511 if diff := cmp.Diff(rc.WantErr.ToAggregate(), err, ignoreDetail); diff != "" { 512 t.Errorf("NewRequirement test %v returned unexpected error (-want,+got):\n%s", rc.Key, diff) 513 } 514 } 515 } 516 517 func TestToString(t *testing.T) { 518 var req Requirement 519 toStringTests := []struct { 520 In *internalSelector 521 Out string 522 Valid bool 523 }{ 524 525 {&internalSelector{ 526 getRequirement("x", selection.In, sets.NewString("abc", "def"), t), 527 getRequirement("y", selection.NotIn, sets.NewString("jkl"), t), 528 getRequirement("z", selection.Exists, nil, t)}, 529 "x in (abc,def),y notin (jkl),z", true}, 530 {&internalSelector{ 531 getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t), 532 getRequirement("y", selection.NotEquals, sets.NewString("jkl"), t), 533 getRequirement("z", selection.DoesNotExist, nil, t)}, 534 "x notin (abc,def),y!=jkl,!z", true}, 535 {&internalSelector{ 536 getRequirement("x", selection.In, sets.NewString("abc", "def"), t), 537 req}, // adding empty req for the trailing ',' 538 "x in (abc,def),", false}, 539 {&internalSelector{ 540 getRequirement("x", selection.NotIn, sets.NewString("abc"), t), 541 getRequirement("y", selection.In, sets.NewString("jkl", "mno"), t), 542 getRequirement("z", selection.NotIn, sets.NewString(""), t)}, 543 "x notin (abc),y in (jkl,mno),z notin ()", true}, 544 {&internalSelector{ 545 getRequirement("x", selection.Equals, sets.NewString("abc"), t), 546 getRequirement("y", selection.DoubleEquals, sets.NewString("jkl"), t), 547 getRequirement("z", selection.NotEquals, sets.NewString("a"), t), 548 getRequirement("z", selection.Exists, nil, t)}, 549 "x=abc,y==jkl,z!=a,z", true}, 550 {&internalSelector{ 551 getRequirement("x", selection.GreaterThan, sets.NewString("2"), t), 552 getRequirement("y", selection.LessThan, sets.NewString("8"), t), 553 getRequirement("z", selection.Exists, nil, t)}, 554 "x>2,y<8,z", true}, 555 } 556 for _, ts := range toStringTests { 557 if out := ts.In.String(); out == "" && ts.Valid { 558 t.Errorf("%#v.String() => '%v' expected no error", ts.In, out) 559 } else if out != ts.Out { 560 t.Errorf("%#v.String() => '%v' want '%v'", ts.In, out, ts.Out) 561 } 562 } 563 } 564 565 func TestRequirementSelectorMatching(t *testing.T) { 566 var req Requirement 567 labelSelectorMatchingTests := []struct { 568 Set Set 569 Sel Selector 570 Match bool 571 }{ 572 {Set{"x": "foo", "y": "baz"}, &internalSelector{ 573 req, 574 }, false}, 575 {Set{"x": "foo", "y": "baz"}, &internalSelector{ 576 getRequirement("x", selection.In, sets.NewString("foo"), t), 577 getRequirement("y", selection.NotIn, sets.NewString("alpha"), t), 578 }, true}, 579 {Set{"x": "foo", "y": "baz"}, &internalSelector{ 580 getRequirement("x", selection.In, sets.NewString("foo"), t), 581 getRequirement("y", selection.In, sets.NewString("alpha"), t), 582 }, false}, 583 {Set{"y": ""}, &internalSelector{ 584 getRequirement("x", selection.NotIn, sets.NewString(""), t), 585 getRequirement("y", selection.Exists, nil, t), 586 }, true}, 587 {Set{"y": ""}, &internalSelector{ 588 getRequirement("x", selection.DoesNotExist, nil, t), 589 getRequirement("y", selection.Exists, nil, t), 590 }, true}, 591 {Set{"y": ""}, &internalSelector{ 592 getRequirement("x", selection.NotIn, sets.NewString(""), t), 593 getRequirement("y", selection.DoesNotExist, nil, t), 594 }, false}, 595 {Set{"y": "baz"}, &internalSelector{ 596 getRequirement("x", selection.In, sets.NewString(""), t), 597 }, false}, 598 {Set{"z": "2"}, &internalSelector{ 599 getRequirement("z", selection.GreaterThan, sets.NewString("1"), t), 600 }, true}, 601 {Set{"z": "v2"}, &internalSelector{ 602 getRequirement("z", selection.GreaterThan, sets.NewString("1"), t), 603 }, false}, 604 } 605 for _, lsm := range labelSelectorMatchingTests { 606 if match := lsm.Sel.Matches(lsm.Set); match != lsm.Match { 607 t.Errorf("%+v.Matches(%#v) => %v, want %v", lsm.Sel, lsm.Set, match, lsm.Match) 608 } 609 } 610 } 611 612 func TestSetSelectorParser(t *testing.T) { 613 setSelectorParserTests := []struct { 614 In string 615 Out Selector 616 Match bool 617 Valid bool 618 }{ 619 {"", NewSelector(), true, true}, 620 {"\rx", internalSelector{ 621 getRequirement("x", selection.Exists, nil, t), 622 }, true, true}, 623 {"this-is-a-dns.domain.com/key-with-dash", internalSelector{ 624 getRequirement("this-is-a-dns.domain.com/key-with-dash", selection.Exists, nil, t), 625 }, true, true}, 626 {"this-is-another-dns.domain.com/key-with-dash in (so,what)", internalSelector{ 627 getRequirement("this-is-another-dns.domain.com/key-with-dash", selection.In, sets.NewString("so", "what"), t), 628 }, true, true}, 629 {"0.1.2.domain/99 notin (10.10.100.1, tick.tack.clock)", internalSelector{ 630 getRequirement("0.1.2.domain/99", selection.NotIn, sets.NewString("10.10.100.1", "tick.tack.clock"), t), 631 }, true, true}, 632 {"foo in (abc)", internalSelector{ 633 getRequirement("foo", selection.In, sets.NewString("abc"), t), 634 }, true, true}, 635 {"x notin\n (abc)", internalSelector{ 636 getRequirement("x", selection.NotIn, sets.NewString("abc"), t), 637 }, true, true}, 638 {"x notin \t (abc,def)", internalSelector{ 639 getRequirement("x", selection.NotIn, sets.NewString("abc", "def"), t), 640 }, true, true}, 641 {"x in (abc,def)", internalSelector{ 642 getRequirement("x", selection.In, sets.NewString("abc", "def"), t), 643 }, true, true}, 644 {"x in (abc,)", internalSelector{ 645 getRequirement("x", selection.In, sets.NewString("abc", ""), t), 646 }, true, true}, 647 {"x in ()", internalSelector{ 648 getRequirement("x", selection.In, sets.NewString(""), t), 649 }, true, true}, 650 {"x notin (abc,,def),bar,z in (),w", internalSelector{ 651 getRequirement("bar", selection.Exists, nil, t), 652 getRequirement("w", selection.Exists, nil, t), 653 getRequirement("x", selection.NotIn, sets.NewString("abc", "", "def"), t), 654 getRequirement("z", selection.In, sets.NewString(""), t), 655 }, true, true}, 656 {"x,y in (a)", internalSelector{ 657 getRequirement("y", selection.In, sets.NewString("a"), t), 658 getRequirement("x", selection.Exists, nil, t), 659 }, false, true}, 660 {"x=a", internalSelector{ 661 getRequirement("x", selection.Equals, sets.NewString("a"), t), 662 }, true, true}, 663 {"x>1", internalSelector{ 664 getRequirement("x", selection.GreaterThan, sets.NewString("1"), t), 665 }, true, true}, 666 {"x<7", internalSelector{ 667 getRequirement("x", selection.LessThan, sets.NewString("7"), t), 668 }, true, true}, 669 {"x=a,y!=b", internalSelector{ 670 getRequirement("x", selection.Equals, sets.NewString("a"), t), 671 getRequirement("y", selection.NotEquals, sets.NewString("b"), t), 672 }, true, true}, 673 {"x=a,y!=b,z in (h,i,j)", internalSelector{ 674 getRequirement("x", selection.Equals, sets.NewString("a"), t), 675 getRequirement("y", selection.NotEquals, sets.NewString("b"), t), 676 getRequirement("z", selection.In, sets.NewString("h", "i", "j"), t), 677 }, true, true}, 678 {"x=a||y=b", internalSelector{}, false, false}, 679 {"x,,y", nil, true, false}, 680 {",x,y", nil, true, false}, 681 {"x nott in (y)", nil, true, false}, 682 {"x notin ( )", internalSelector{ 683 getRequirement("x", selection.NotIn, sets.NewString(""), t), 684 }, true, true}, 685 {"x notin (, a)", internalSelector{ 686 getRequirement("x", selection.NotIn, sets.NewString("", "a"), t), 687 }, true, true}, 688 {"a in (xyz),", nil, true, false}, 689 {"a in (xyz)b notin ()", nil, true, false}, 690 {"a ", internalSelector{ 691 getRequirement("a", selection.Exists, nil, t), 692 }, true, true}, 693 {"a in (x,y,notin, z,in)", internalSelector{ 694 getRequirement("a", selection.In, sets.NewString("in", "notin", "x", "y", "z"), t), 695 }, true, true}, // operator 'in' inside list of identifiers 696 {"a in (xyz abc)", nil, false, false}, // no comma 697 {"a notin(", nil, true, false}, // bad formed 698 {"a (", nil, false, false}, // cpar 699 {"(", nil, false, false}, // opar 700 } 701 702 for _, ssp := range setSelectorParserTests { 703 if sel, err := Parse(ssp.In); err != nil && ssp.Valid { 704 t.Errorf("Parse(%s) => %v expected no error", ssp.In, err) 705 } else if err == nil && !ssp.Valid { 706 t.Errorf("Parse(%s) => %+v expected error", ssp.In, sel) 707 } else if ssp.Match && !reflect.DeepEqual(sel, ssp.Out) { 708 t.Errorf("Parse(%s) => parse output '%#v' doesn't match '%#v' expected match", ssp.In, sel, ssp.Out) 709 } 710 } 711 } 712 713 func getRequirement(key string, op selection.Operator, vals sets.String, t *testing.T) Requirement { 714 req, err := NewRequirement(key, op, vals.List()) 715 if err != nil { 716 t.Errorf("NewRequirement(%v, %v, %v) resulted in error:%v", key, op, vals, err) 717 return Requirement{} 718 } 719 return *req 720 } 721 722 func TestAdd(t *testing.T) { 723 testCases := []struct { 724 name string 725 sel Selector 726 key string 727 operator selection.Operator 728 values []string 729 refSelector Selector 730 }{ 731 { 732 "keyInOperator", 733 internalSelector{}, 734 "key", 735 selection.In, 736 []string{"value"}, 737 internalSelector{Requirement{"key", selection.In, []string{"value"}}}, 738 }, 739 { 740 "keyEqualsOperator", 741 internalSelector{Requirement{"key", selection.In, []string{"value"}}}, 742 "key2", 743 selection.Equals, 744 []string{"value2"}, 745 internalSelector{ 746 Requirement{"key", selection.In, []string{"value"}}, 747 Requirement{"key2", selection.Equals, []string{"value2"}}, 748 }, 749 }, 750 } 751 for _, ts := range testCases { 752 req, err := NewRequirement(ts.key, ts.operator, ts.values) 753 if err != nil { 754 t.Errorf("%s - Unable to create labels.Requirement", ts.name) 755 } 756 ts.sel = ts.sel.Add(*req) 757 if !reflect.DeepEqual(ts.sel, ts.refSelector) { 758 t.Errorf("%s - Expected %v found %v", ts.name, ts.refSelector, ts.sel) 759 } 760 } 761 } 762 763 func TestSafeSort(t *testing.T) { 764 tests := []struct { 765 name string 766 in []string 767 inCopy []string 768 want []string 769 }{ 770 { 771 name: "nil strings", 772 in: nil, 773 inCopy: nil, 774 want: nil, 775 }, 776 { 777 name: "ordered strings", 778 in: []string{"bar", "foo"}, 779 inCopy: []string{"bar", "foo"}, 780 want: []string{"bar", "foo"}, 781 }, 782 { 783 name: "unordered strings", 784 in: []string{"foo", "bar"}, 785 inCopy: []string{"foo", "bar"}, 786 want: []string{"bar", "foo"}, 787 }, 788 { 789 name: "duplicated strings", 790 in: []string{"foo", "bar", "foo", "bar"}, 791 inCopy: []string{"foo", "bar", "foo", "bar"}, 792 want: []string{"bar", "bar", "foo", "foo"}, 793 }, 794 } 795 for _, tt := range tests { 796 t.Run(tt.name, func(t *testing.T) { 797 if got := safeSort(tt.in); !reflect.DeepEqual(got, tt.want) { 798 t.Errorf("safeSort() = %v, want %v", got, tt.want) 799 } 800 if !reflect.DeepEqual(tt.in, tt.inCopy) { 801 t.Errorf("after safeSort(), input = %v, want %v", tt.in, tt.inCopy) 802 } 803 }) 804 } 805 } 806 807 func BenchmarkSelectorFromValidatedSet(b *testing.B) { 808 set := map[string]string{ 809 "foo": "foo", 810 "bar": "bar", 811 } 812 813 for i := 0; i < b.N; i++ { 814 if SelectorFromValidatedSet(set).Empty() { 815 b.Errorf("Unexpected selector") 816 } 817 } 818 } 819 820 func TestRequiresExactMatch(t *testing.T) { 821 testCases := []struct { 822 name string 823 sel Selector 824 label string 825 expectedFound bool 826 expectedValue string 827 }{ 828 { 829 name: "keyInOperatorExactMatch", 830 sel: internalSelector{Requirement{"key", selection.In, []string{"value"}}}, 831 label: "key", 832 expectedFound: true, 833 expectedValue: "value", 834 }, 835 { 836 name: "keyInOperatorNotExactMatch", 837 sel: internalSelector{Requirement{"key", selection.In, []string{"value", "value2"}}}, 838 label: "key", 839 expectedFound: false, 840 expectedValue: "", 841 }, 842 { 843 name: "keyInOperatorNotExactMatch", 844 sel: internalSelector{ 845 Requirement{"key", selection.In, []string{"value", "value1"}}, 846 Requirement{"key2", selection.In, []string{"value2"}}, 847 }, 848 label: "key2", 849 expectedFound: true, 850 expectedValue: "value2", 851 }, 852 { 853 name: "keyEqualOperatorExactMatch", 854 sel: internalSelector{Requirement{"key", selection.Equals, []string{"value"}}}, 855 label: "key", 856 expectedFound: true, 857 expectedValue: "value", 858 }, 859 { 860 name: "keyDoubleEqualOperatorExactMatch", 861 sel: internalSelector{Requirement{"key", selection.DoubleEquals, []string{"value"}}}, 862 label: "key", 863 expectedFound: true, 864 expectedValue: "value", 865 }, 866 { 867 name: "keyNotEqualOperatorExactMatch", 868 sel: internalSelector{Requirement{"key", selection.NotEquals, []string{"value"}}}, 869 label: "key", 870 expectedFound: false, 871 expectedValue: "", 872 }, 873 { 874 name: "keyEqualOperatorExactMatchFirst", 875 sel: internalSelector{ 876 Requirement{"key", selection.In, []string{"value"}}, 877 Requirement{"key2", selection.In, []string{"value2"}}, 878 }, 879 label: "key", 880 expectedFound: true, 881 expectedValue: "value", 882 }, 883 } 884 for _, ts := range testCases { 885 t.Run(ts.name, func(t *testing.T) { 886 value, found := ts.sel.RequiresExactMatch(ts.label) 887 if found != ts.expectedFound { 888 t.Errorf("Expected match %v, found %v", ts.expectedFound, found) 889 } 890 if found && value != ts.expectedValue { 891 t.Errorf("Expected value %v, found %v", ts.expectedValue, value) 892 } 893 894 }) 895 } 896 } 897 898 func TestValidatedSelectorFromSet(t *testing.T) { 899 tests := []struct { 900 name string 901 input Set 902 expectedSelector internalSelector 903 expectedError field.ErrorList 904 }{ 905 { 906 name: "Simple Set, no error", 907 input: Set{"key": "val"}, 908 expectedSelector: internalSelector{ 909 Requirement{ 910 key: "key", 911 operator: selection.Equals, 912 strValues: []string{"val"}, 913 }, 914 }, 915 }, 916 { 917 name: "Invalid Set, value too long", 918 input: Set{"Key": "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui"}, 919 expectedError: field.ErrorList{ 920 &field.Error{ 921 Type: field.ErrorTypeInvalid, 922 Field: "values[0][Key]", 923 BadValue: "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui", 924 }, 925 }, 926 }, 927 } 928 929 for _, tc := range tests { 930 selector, err := ValidatedSelectorFromSet(tc.input) 931 if diff := cmp.Diff(tc.expectedError.ToAggregate(), err, ignoreDetail); diff != "" { 932 t.Errorf("ValidatedSelectorFromSet %#v returned unexpected error (-want,+got):\n%s", tc.name, diff) 933 } 934 if err == nil { 935 if diff := cmp.Diff(tc.expectedSelector, selector); diff != "" { 936 t.Errorf("ValidatedSelectorFromSet %#v returned unexpected selector (-want,+got):\n%s", tc.name, diff) 937 } 938 } 939 } 940 } 941 942 func BenchmarkRequirementString(b *testing.B) { 943 r := Requirement{ 944 key: "environment", 945 operator: selection.NotIn, 946 strValues: []string{ 947 "dev", 948 }, 949 } 950 951 b.ReportAllocs() 952 b.ResetTimer() 953 for i := 0; i < b.N; i++ { 954 if r.String() != "environment notin (dev)" { 955 b.Errorf("Unexpected Requirement string") 956 } 957 } 958 } 959 960 func TestRequirementEqual(t *testing.T) { 961 tests := []struct { 962 name string 963 x, y *Requirement 964 want bool 965 }{ 966 { 967 name: "same requirements should be equal", 968 x: &Requirement{ 969 key: "key", 970 operator: selection.Equals, 971 strValues: []string{"foo", "bar"}, 972 }, 973 y: &Requirement{ 974 key: "key", 975 operator: selection.Equals, 976 strValues: []string{"foo", "bar"}, 977 }, 978 want: true, 979 }, 980 { 981 name: "requirements with different keys should not be equal", 982 x: &Requirement{ 983 key: "key1", 984 operator: selection.Equals, 985 strValues: []string{"foo", "bar"}, 986 }, 987 y: &Requirement{ 988 key: "key2", 989 operator: selection.Equals, 990 strValues: []string{"foo", "bar"}, 991 }, 992 want: false, 993 }, 994 { 995 name: "requirements with different operators should not be equal", 996 x: &Requirement{ 997 key: "key", 998 operator: selection.Equals, 999 strValues: []string{"foo", "bar"}, 1000 }, 1001 y: &Requirement{ 1002 key: "key", 1003 operator: selection.In, 1004 strValues: []string{"foo", "bar"}, 1005 }, 1006 want: false, 1007 }, 1008 { 1009 name: "requirements with different values should not be equal", 1010 x: &Requirement{ 1011 key: "key", 1012 operator: selection.Equals, 1013 strValues: []string{"foo", "bar"}, 1014 }, 1015 y: &Requirement{ 1016 key: "key", 1017 operator: selection.Equals, 1018 strValues: []string{"foobar"}, 1019 }, 1020 want: false, 1021 }, 1022 } 1023 for _, tt := range tests { 1024 t.Run(tt.name, func(t *testing.T) { 1025 if got := cmp.Equal(tt.x, tt.y); got != tt.want { 1026 t.Errorf("cmp.Equal() = %v, want %v", got, tt.want) 1027 } 1028 }) 1029 } 1030 }