github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/boskos/ranch/ranch_test.go (about) 1 /* 2 Copyright 2017 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 ranch 18 19 import ( 20 "reflect" 21 "testing" 22 "time" 23 24 "k8s.io/test-infra/boskos/common" 25 ) 26 27 func MakeTestRanch(resources []common.Resource) *Ranch { 28 newRanch := &Ranch{ 29 Resources: resources, 30 } 31 32 return newRanch 33 } 34 35 func AreErrorsEqual(got error, expect error) bool { 36 if got == nil && expect == nil { 37 return true 38 } 39 40 if got == nil || expect == nil { 41 return false 42 } 43 44 switch got.(type) { 45 default: 46 return false 47 case *OwnerNotMatch: 48 if o, ok := expect.(*OwnerNotMatch); ok { 49 if o.request == got.(*OwnerNotMatch).request && o.owner == got.(*OwnerNotMatch).owner { 50 return true 51 } 52 } 53 return false 54 case *ResourceNotFound: 55 if o, ok := expect.(*ResourceNotFound); ok { 56 if o.name == got.(*ResourceNotFound).name { 57 return true 58 } 59 } 60 return false 61 case *StateNotMatch: 62 if o, ok := expect.(*StateNotMatch); ok { 63 if o.expect == got.(*StateNotMatch).expect && o.current == got.(*StateNotMatch).current { 64 return true 65 } 66 } 67 return false 68 } 69 } 70 71 func TestAcquire(t *testing.T) { 72 FakeNow := time.Now() 73 var testcases = []struct { 74 name string 75 resources []common.Resource 76 owner string 77 rtype string 78 state string 79 dest string 80 expectErr error 81 }{ 82 { 83 name: "ranch has no resource", 84 resources: []common.Resource{}, 85 owner: "user", 86 rtype: "t", 87 state: "s", 88 dest: "d", 89 expectErr: &ResourceNotFound{"t"}, 90 }, 91 { 92 name: "no match type", 93 resources: []common.Resource{ 94 { 95 Name: "res", 96 Type: "wrong", 97 State: "s", 98 Owner: "", 99 LastUpdate: FakeNow, 100 }, 101 }, 102 owner: "user", 103 rtype: "t", 104 state: "s", 105 dest: "d", 106 expectErr: &ResourceNotFound{"t"}, 107 }, 108 { 109 name: "no match state", 110 resources: []common.Resource{ 111 { 112 Name: "res", 113 Type: "t", 114 State: "wrong", 115 Owner: "", 116 LastUpdate: FakeNow, 117 }, 118 }, 119 owner: "user", 120 rtype: "t", 121 state: "s", 122 dest: "d", 123 expectErr: &ResourceNotFound{"t"}, 124 }, 125 { 126 name: "busy", 127 resources: []common.Resource{ 128 { 129 Name: "res", 130 Type: "t", 131 State: "s", 132 Owner: "foo", 133 LastUpdate: FakeNow, 134 }, 135 }, 136 owner: "user", 137 rtype: "t", 138 state: "s", 139 dest: "d", 140 expectErr: &ResourceNotFound{"t"}, 141 }, 142 { 143 name: "ok", 144 resources: []common.Resource{ 145 { 146 Name: "res", 147 Type: "t", 148 State: "s", 149 Owner: "", 150 LastUpdate: FakeNow, 151 }, 152 }, 153 owner: "user", 154 rtype: "t", 155 state: "s", 156 dest: "d", 157 expectErr: nil, 158 }, 159 } 160 161 for _, tc := range testcases { 162 c := MakeTestRanch(tc.resources) 163 res, err := c.Acquire(tc.rtype, tc.state, tc.dest, tc.owner) 164 if !AreErrorsEqual(err, tc.expectErr) { 165 t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr) 166 continue 167 } 168 169 if err == nil { 170 if res.State != tc.dest { 171 t.Errorf("%s - Wrong final state. Got %v, expect %v", tc.name, res.State, tc.dest) 172 } 173 if *res != c.Resources[0] { 174 t.Errorf("%s - Wrong resource. Got %v, expect %v", tc.name, res, c.Resources[0]) 175 } else if !res.LastUpdate.After(FakeNow) { 176 t.Errorf("%s - LastUpdate did not update.", tc.name) 177 } 178 } else { 179 for _, res := range c.Resources { 180 if res.LastUpdate != FakeNow { 181 t.Errorf("%s - LastUpdate should not update. Got %v, expect %v", tc.name, c.Resources[0].LastUpdate, FakeNow) 182 } 183 } 184 } 185 } 186 } 187 188 func TestAcquireRoundRobin(t *testing.T) { 189 FakeNow := time.Now() 190 resources := []common.Resource{ 191 { 192 Name: "res-1", 193 Type: "t", 194 State: "s", 195 Owner: "", 196 LastUpdate: FakeNow, 197 }, 198 { 199 Name: "res-2", 200 Type: "t", 201 State: "s", 202 Owner: "", 203 LastUpdate: FakeNow, 204 }, 205 { 206 Name: "res-3", 207 Type: "t", 208 State: "s", 209 Owner: "", 210 LastUpdate: FakeNow, 211 }, 212 { 213 Name: "res-4", 214 Type: "t", 215 State: "s", 216 Owner: "", 217 LastUpdate: FakeNow, 218 }, 219 } 220 221 expected := []string{"res-3", "res-4", "res-1", "res-2"} 222 223 c := MakeTestRanch(resources) 224 for i := 0; i < 2; i++ { 225 _, err := c.Acquire("t", "s", "d", "foo") 226 if err != nil { 227 t.Fatalf("Unexpected error: %v", err) 228 } 229 } 230 231 for idx := range c.Resources { 232 if c.Resources[idx].Name != expected[idx] { 233 t.Errorf("Resource %d, expected %v, got %v", idx, expected[idx], c.Resources[idx].Name) 234 } 235 } 236 237 } 238 239 func TestRelease(t *testing.T) { 240 FakeNow := time.Now() 241 var testcases = []struct { 242 name string 243 resources []common.Resource 244 resName string 245 owner string 246 dest string 247 expectErr error 248 }{ 249 { 250 name: "ranch has no resource", 251 resources: []common.Resource{}, 252 resName: "res", 253 owner: "user", 254 dest: "d", 255 expectErr: &ResourceNotFound{"res"}, 256 }, 257 { 258 name: "wrong owner", 259 resources: []common.Resource{ 260 { 261 Name: "res", 262 Type: "t", 263 State: "s", 264 Owner: "merlin", 265 LastUpdate: FakeNow, 266 }, 267 }, 268 resName: "res", 269 owner: "user", 270 dest: "d", 271 expectErr: &OwnerNotMatch{"merlin", "user"}, 272 }, 273 { 274 name: "no match name", 275 resources: []common.Resource{ 276 { 277 Name: "foo", 278 Type: "t", 279 State: "s", 280 Owner: "merlin", 281 LastUpdate: FakeNow, 282 }, 283 }, 284 resName: "res", 285 owner: "user", 286 dest: "d", 287 expectErr: &ResourceNotFound{"res"}, 288 }, 289 { 290 name: "ok", 291 resources: []common.Resource{ 292 { 293 Name: "res", 294 Type: "t", 295 State: "s", 296 Owner: "merlin", 297 LastUpdate: FakeNow, 298 }, 299 }, 300 resName: "res", 301 owner: "merlin", 302 dest: "d", 303 expectErr: nil, 304 }, 305 } 306 307 for _, tc := range testcases { 308 c := MakeTestRanch(tc.resources) 309 err := c.Release(tc.resName, tc.dest, tc.owner) 310 if !AreErrorsEqual(err, tc.expectErr) { 311 t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr) 312 continue 313 } 314 315 if err == nil { 316 if c.Resources[0].Owner != "" { 317 t.Errorf("%s - Wrong owner after release. Got %v, expect empty", tc.name, c.Resources[0].Owner) 318 } else if c.Resources[0].State != tc.dest { 319 t.Errorf("%s - Wrong state after release. Got %v, expect %v", tc.name, c.Resources[0].State, tc.dest) 320 } else if !c.Resources[0].LastUpdate.After(FakeNow) { 321 t.Errorf("%s - LastUpdate did not update.", tc.name) 322 } 323 } else { 324 for _, res := range c.Resources { 325 if res.LastUpdate != FakeNow { 326 t.Errorf("%s - LastUpdate should not update. Got %v, expect %v", tc.name, c.Resources[0].LastUpdate, FakeNow) 327 } 328 } 329 } 330 } 331 } 332 333 func TestReset(t *testing.T) { 334 FakeNow := time.Now() 335 336 var testcases = []struct { 337 name string 338 resources []common.Resource 339 rtype string 340 state string 341 dest string 342 expire time.Duration 343 hasContent bool 344 }{ 345 346 { 347 name: "empty - has no owner", 348 resources: []common.Resource{ 349 { 350 Name: "res", 351 Type: "t", 352 State: "s", 353 Owner: "", 354 LastUpdate: FakeNow.Add(-time.Minute * 20), 355 }, 356 }, 357 rtype: "t", 358 state: "s", 359 expire: time.Minute * 10, 360 dest: "d", 361 }, 362 { 363 name: "empty - not expire", 364 resources: []common.Resource{ 365 { 366 Name: "res", 367 Type: "t", 368 State: "s", 369 Owner: "", 370 LastUpdate: FakeNow, 371 }, 372 }, 373 rtype: "t", 374 state: "s", 375 expire: time.Minute * 10, 376 dest: "d", 377 }, 378 { 379 name: "empty - no match type", 380 resources: []common.Resource{ 381 { 382 Name: "res", 383 Type: "wrong", 384 State: "s", 385 Owner: "", 386 LastUpdate: FakeNow.Add(-time.Minute * 20), 387 }, 388 }, 389 rtype: "t", 390 state: "s", 391 expire: time.Minute * 10, 392 dest: "d", 393 }, 394 { 395 name: "empty - no match state", 396 resources: []common.Resource{ 397 { 398 Name: "res", 399 Type: "t", 400 State: "wrong", 401 Owner: "", 402 LastUpdate: FakeNow.Add(-time.Minute * 20), 403 }, 404 }, 405 rtype: "t", 406 state: "s", 407 expire: time.Minute * 10, 408 dest: "d", 409 }, 410 { 411 name: "ok", 412 resources: []common.Resource{ 413 { 414 Name: "res", 415 Type: "t", 416 State: "s", 417 Owner: "user", 418 LastUpdate: FakeNow.Add(-time.Minute * 20), 419 }, 420 }, 421 rtype: "t", 422 state: "s", 423 expire: time.Minute * 10, 424 dest: "d", 425 hasContent: true, 426 }, 427 } 428 429 for _, tc := range testcases { 430 c := MakeTestRanch(tc.resources) 431 rmap := c.Reset(tc.rtype, tc.state, tc.expire, tc.dest) 432 433 if !tc.hasContent { 434 if len(rmap) != 0 { 435 t.Errorf("%s - Expect empty map. Got %v", tc.name, rmap) 436 } 437 } else { 438 if owner, ok := rmap["res"]; !ok || owner != "user" { 439 t.Errorf("%s - Expect res - user. Got %v", tc.name, rmap) 440 } 441 if !c.Resources[0].LastUpdate.After(FakeNow) { 442 t.Errorf("%s - LastUpdate did not update.", tc.name) 443 } 444 } 445 } 446 } 447 448 func TestUpdate(t *testing.T) { 449 FakeNow := time.Now() 450 451 var testcases = []struct { 452 name string 453 resources []common.Resource 454 resName string 455 owner string 456 state string 457 expectErr error 458 }{ 459 { 460 name: "ranch has no resource", 461 resources: []common.Resource{}, 462 resName: "res", 463 owner: "user", 464 state: "s", 465 expectErr: &ResourceNotFound{"res"}, 466 }, 467 { 468 name: "wrong owner", 469 resources: []common.Resource{ 470 { 471 Name: "res", 472 Type: "t", 473 State: "s", 474 Owner: "merlin", 475 LastUpdate: FakeNow, 476 }, 477 }, 478 resName: "res", 479 owner: "user", 480 state: "s", 481 expectErr: &OwnerNotMatch{"merlin", "user"}, 482 }, 483 { 484 name: "wrong state", 485 resources: []common.Resource{ 486 { 487 Name: "res", 488 Type: "t", 489 State: "s", 490 Owner: "merlin", 491 LastUpdate: FakeNow, 492 }, 493 }, 494 resName: "res", 495 owner: "merlin", 496 state: "foo", 497 expectErr: &StateNotMatch{"s", "foo"}, 498 }, 499 { 500 name: "no matched resource", 501 resources: []common.Resource{ 502 { 503 Name: "foo", 504 Type: "t", 505 State: "s", 506 Owner: "merlin", 507 LastUpdate: FakeNow, 508 }, 509 }, 510 resName: "res", 511 owner: "merlin", 512 state: "s", 513 expectErr: &ResourceNotFound{"res"}, 514 }, 515 { 516 name: "ok", 517 resources: []common.Resource{ 518 { 519 Name: "res", 520 Type: "t", 521 State: "s", 522 Owner: "merlin", 523 LastUpdate: FakeNow, 524 }, 525 }, 526 resName: "res", 527 owner: "merlin", 528 state: "s", 529 }, 530 } 531 532 for _, tc := range testcases { 533 c := MakeTestRanch(tc.resources) 534 err := c.Update(tc.resName, tc.owner, tc.state) 535 if !AreErrorsEqual(err, tc.expectErr) { 536 t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr) 537 continue 538 } 539 540 if err == nil { 541 if c.Resources[0].Owner != tc.owner { 542 t.Errorf("%s - Wrong owner after release. Got %v, expect %v", tc.name, c.Resources[0].Owner, tc.owner) 543 } else if c.Resources[0].State != tc.state { 544 t.Errorf("%s - Wrong state after release. Got %v, expect %v", tc.name, c.Resources[0].State, tc.state) 545 } else if !c.Resources[0].LastUpdate.After(FakeNow) { 546 t.Errorf("%s - LastUpdate did not update.", tc.name) 547 } 548 } else { 549 for _, res := range c.Resources { 550 if res.LastUpdate != FakeNow { 551 t.Errorf("%s - LastUpdate should not update. Got %v, expect %v", tc.name, c.Resources[0].LastUpdate, FakeNow) 552 } 553 } 554 } 555 } 556 } 557 558 func TestMetric(t *testing.T) { 559 var testcases = []struct { 560 name string 561 resources []common.Resource 562 metricType string 563 expectErr error 564 expectMetric common.Metric 565 }{ 566 { 567 name: "ranch has no resource", 568 resources: []common.Resource{}, 569 metricType: "t", 570 expectErr: &ResourceNotFound{"t"}, 571 }, 572 { 573 name: "no matching resource", 574 resources: []common.Resource{ 575 { 576 Name: "res", 577 Type: "t", 578 State: "s", 579 Owner: "merlin", 580 }, 581 }, 582 metricType: "foo", 583 expectErr: &ResourceNotFound{"foo"}, 584 }, 585 { 586 name: "one resource", 587 resources: []common.Resource{ 588 { 589 Name: "res", 590 Type: "t", 591 State: "s", 592 Owner: "merlin", 593 }, 594 }, 595 metricType: "t", 596 expectMetric: common.Metric{ 597 Type: "t", 598 Current: map[string]int{ 599 "s": 1, 600 }, 601 Owners: map[string]int{ 602 "merlin": 1, 603 }, 604 }, 605 }, 606 { 607 name: "multiple resources", 608 resources: []common.Resource{ 609 { 610 Name: "res-1", 611 Type: "t", 612 State: "s", 613 Owner: "merlin", 614 }, 615 { 616 Name: "res-2", 617 Type: "t", 618 State: "p", 619 Owner: "pony", 620 }, 621 { 622 Name: "res-2", 623 Type: "t", 624 State: "s", 625 Owner: "pony", 626 }, 627 { 628 Name: "res-3", 629 Type: "foo", 630 State: "s", 631 Owner: "pony", 632 }, 633 { 634 Name: "res-4", 635 Type: "t", 636 State: "d", 637 Owner: "merlin", 638 }, 639 }, 640 metricType: "t", 641 expectMetric: common.Metric{ 642 Type: "t", 643 Current: map[string]int{ 644 "s": 2, 645 "d": 1, 646 "p": 1, 647 }, 648 Owners: map[string]int{ 649 "merlin": 2, 650 "pony": 2, 651 }, 652 }, 653 }, 654 } 655 656 for _, tc := range testcases { 657 c := MakeTestRanch(tc.resources) 658 metric, err := c.Metric(tc.metricType) 659 if !AreErrorsEqual(err, tc.expectErr) { 660 t.Errorf("%s - Got error %v, expect error %v", tc.name, err, tc.expectErr) 661 continue 662 } 663 664 if err == nil { 665 if !reflect.DeepEqual(metric, tc.expectMetric) { 666 t.Errorf("%s - wrong metric, got %v, want %v", tc.name, metric, tc.expectMetric) 667 } 668 } 669 } 670 } 671 672 func TestSyncConfig(t *testing.T) { 673 var testcases = []struct { 674 name string 675 oldRes []common.Resource 676 newRes []common.Resource 677 expect []common.Resource 678 }{ 679 { 680 name: "empty", 681 oldRes: []common.Resource{}, 682 newRes: []common.Resource{}, 683 expect: []common.Resource{}, 684 }, 685 { 686 name: "append", 687 oldRes: []common.Resource{}, 688 newRes: []common.Resource{ 689 { 690 Name: "res", 691 Type: "t", 692 }, 693 }, 694 expect: []common.Resource{ 695 { 696 Name: "res", 697 Type: "t", 698 State: "free", 699 }, 700 }, 701 }, 702 { 703 name: "should not have a type change", 704 oldRes: []common.Resource{ 705 { 706 Name: "res", 707 Type: "t", 708 }, 709 }, 710 newRes: []common.Resource{ 711 { 712 Name: "res", 713 Type: "d", 714 }, 715 }, 716 expect: []common.Resource{ 717 { 718 Name: "res", 719 Type: "t", 720 }, 721 }, 722 }, 723 { 724 name: "delete", 725 oldRes: []common.Resource{ 726 { 727 Name: "res", 728 Type: "t", 729 }, 730 }, 731 newRes: []common.Resource{}, 732 expect: []common.Resource{}, 733 }, 734 { 735 name: "delete busy", 736 oldRes: []common.Resource{ 737 { 738 Name: "res", 739 Type: "t", 740 State: "busy", 741 Owner: "o", 742 }, 743 }, 744 newRes: []common.Resource{}, 745 expect: []common.Resource{ 746 { 747 Name: "res", 748 Type: "t", 749 State: "busy", 750 Owner: "o", 751 }, 752 }, 753 }, 754 { 755 name: "append and delete", 756 oldRes: []common.Resource{ 757 { 758 Name: "res-1", 759 Type: "t", 760 }, 761 }, 762 newRes: []common.Resource{ 763 { 764 Name: "res-2", 765 Type: "t", 766 }, 767 }, 768 expect: []common.Resource{ 769 { 770 Name: "res-2", 771 Type: "t", 772 State: "free", 773 }, 774 }, 775 }, 776 { 777 name: "append and delete busy", 778 oldRes: []common.Resource{ 779 { 780 Name: "res-1", 781 Type: "t", 782 State: "busy", 783 Owner: "o", 784 }, 785 }, 786 newRes: []common.Resource{ 787 { 788 Name: "res-2", 789 Type: "t", 790 }, 791 }, 792 expect: []common.Resource{ 793 { 794 Name: "res-1", 795 Type: "t", 796 State: "busy", 797 Owner: "o", 798 }, 799 { 800 Name: "res-2", 801 Type: "t", 802 State: "free", 803 }, 804 }, 805 }, 806 { 807 name: "append/delete mixed type", 808 oldRes: []common.Resource{ 809 { 810 Name: "res-1", 811 Type: "t", 812 }, 813 }, 814 newRes: []common.Resource{ 815 { 816 Name: "res-2", 817 Type: "t", 818 }, 819 { 820 Name: "res-3", 821 Type: "t2", 822 }, 823 }, 824 expect: []common.Resource{ 825 { 826 Name: "res-2", 827 Type: "t", 828 State: "free", 829 }, 830 { 831 Name: "res-3", 832 Type: "t2", 833 State: "free", 834 }, 835 }, 836 }, 837 } 838 839 for _, tc := range testcases { 840 c := MakeTestRanch(tc.oldRes) 841 c.syncConfigHelper(tc.newRes) 842 if !reflect.DeepEqual(c.Resources, tc.expect) { 843 t.Errorf("Test %v: got %v, expect %v", tc.name, c.Resources, tc.expect) 844 } 845 } 846 }