github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/rkt/api_service_test.go (about) 1 // Copyright 2015 The rkt 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 main 16 17 import ( 18 "io/ioutil" 19 "net" 20 "os" 21 "testing" 22 23 "github.com/rkt/rkt/api/v1alpha" 24 "github.com/rkt/rkt/pkg/log" 25 ) 26 27 func TestFilterPod(t *testing.T) { 28 tests := []struct { 29 pod *v1alpha.Pod 30 filter *v1alpha.PodFilter 31 result bool 32 }{ 33 // Has the status. 34 { 35 &v1alpha.Pod{ 36 State: v1alpha.PodState_POD_STATE_RUNNING, 37 }, 38 &v1alpha.PodFilter{ 39 States: []v1alpha.PodState{v1alpha.PodState_POD_STATE_RUNNING}, 40 }, 41 true, 42 }, 43 // Doesn't have the status. 44 { 45 &v1alpha.Pod{ 46 State: v1alpha.PodState_POD_STATE_EXITED, 47 }, 48 &v1alpha.PodFilter{ 49 States: []v1alpha.PodState{v1alpha.PodState_POD_STATE_RUNNING}, 50 }, 51 false, 52 }, 53 // Has all app names. 54 { 55 &v1alpha.Pod{ 56 Apps: []*v1alpha.App{ 57 {Name: "app-foo"}, 58 {Name: "app-bar"}, 59 }, 60 }, 61 &v1alpha.PodFilter{ 62 AppNames: []string{"app-foo", "app-bar"}, 63 }, 64 true, 65 }, 66 // Doesn't have all app name. 67 { 68 &v1alpha.Pod{ 69 Apps: []*v1alpha.App{ 70 {Name: "app-foo"}, 71 {Name: "app-bar"}, 72 }, 73 }, 74 &v1alpha.PodFilter{ 75 AppNames: []string{"app-foo", "app-bar", "app-baz"}, 76 }, 77 false, 78 }, 79 // Has all network names. 80 { 81 &v1alpha.Pod{ 82 Networks: []*v1alpha.Network{ 83 {Name: "network-foo"}, 84 {Name: "network-bar"}, 85 }, 86 }, 87 &v1alpha.PodFilter{ 88 NetworkNames: []string{"network-foo", "network-bar"}, 89 }, 90 true, 91 }, 92 // Doesn't have all network names. 93 { 94 &v1alpha.Pod{ 95 Networks: []*v1alpha.Network{ 96 {Name: "network-foo"}, 97 {Name: "network-bar"}, 98 }, 99 }, 100 &v1alpha.PodFilter{ 101 NetworkNames: []string{"network-foo", "network-bar", "network-baz"}, 102 }, 103 false, 104 }, 105 // Has all annotations. 106 { 107 &v1alpha.Pod{ 108 Annotations: []*v1alpha.KeyValue{ 109 {"annotation-key-foo", "annotation-value-foo"}, 110 {"annotation-key-bar", "annotation-value-bar"}, 111 }, 112 }, 113 &v1alpha.PodFilter{ 114 Annotations: []*v1alpha.KeyValue{ 115 {"annotation-key-foo", "annotation-value-foo"}, 116 {"annotation-key-bar", "annotation-value-bar"}, 117 }, 118 }, 119 true, 120 }, 121 // Doesn't have all annotation keys. 122 { 123 &v1alpha.Pod{ 124 Annotations: []*v1alpha.KeyValue{ 125 {"annotation-key-foo", "annotation-value-foo"}, 126 {"annotation-key-bar", "annotation-value-bar"}, 127 }, 128 }, 129 &v1alpha.PodFilter{ 130 Annotations: []*v1alpha.KeyValue{ 131 {"annotation-key-foo", "annotation-value-foo"}, 132 {"annotation-key-bar", "annotation-value-bar"}, 133 {"annotation-key-baz", "annotation-value-baz"}, 134 }, 135 }, 136 false, 137 }, 138 // Doesn't have all annotation values. 139 { 140 &v1alpha.Pod{ 141 Annotations: []*v1alpha.KeyValue{ 142 {"annotation-key-foo", "annotation-value-foo"}, 143 {"annotation-key-bar", "annotation-value-bar"}, 144 }, 145 }, 146 &v1alpha.PodFilter{ 147 Annotations: []*v1alpha.KeyValue{ 148 {"annotation-key-foo", "annotation-value-foo"}, 149 {"annotation-key-bar", "annotation-value-baz"}, 150 }, 151 }, 152 false, 153 }, 154 // Doesn't satisfy any filter conditions. 155 { 156 &v1alpha.Pod{ 157 Apps: []*v1alpha.App{{Name: "app-foo"}}, 158 Networks: []*v1alpha.Network{{Name: "network-foo"}}, 159 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 160 }, 161 &v1alpha.PodFilter{ 162 AppNames: []string{"app-bar"}, 163 NetworkNames: []string{"network-bar"}, 164 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-bar"}}, 165 }, 166 false, 167 }, 168 // Satisfies some filter conditions. 169 { 170 &v1alpha.Pod{ 171 Apps: []*v1alpha.App{{Name: "app-foo"}}, 172 Networks: []*v1alpha.Network{{Name: "network-foo"}}, 173 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 174 }, 175 &v1alpha.PodFilter{ 176 AppNames: []string{"app-foo", "app-bar"}, 177 NetworkNames: []string{"network-bar"}, 178 Annotations: []*v1alpha.KeyValue{{"annotation-key-bar", "annotation-value-bar"}}, 179 }, 180 false, 181 }, 182 // Satisfies all filter conditions. 183 { 184 &v1alpha.Pod{ 185 Apps: []*v1alpha.App{{Name: "app-foo"}}, 186 Networks: []*v1alpha.Network{{Name: "network-foo"}}, 187 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 188 }, 189 &v1alpha.PodFilter{ 190 AppNames: []string{"app-foo"}, 191 NetworkNames: []string{"network-foo"}, 192 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 193 }, 194 true, 195 }, 196 } 197 198 for i, tt := range tests { 199 result := satisfiesPodFilter(*tt.pod, *tt.filter) 200 if result != tt.result { 201 t.Errorf("#%d: got %v, want %v", i, result, tt.result) 202 } 203 } 204 } 205 206 func TestFilterPodAny(t *testing.T) { 207 tests := []struct { 208 pod *v1alpha.Pod 209 filters []*v1alpha.PodFilter 210 result bool 211 }{ 212 // No filters. 213 { 214 &v1alpha.Pod{ 215 Apps: []*v1alpha.App{{Name: "app-foo"}}, 216 Networks: []*v1alpha.Network{{Name: "network-foo"}}, 217 }, 218 nil, 219 true, 220 }, 221 // Satisfies all filters. 222 { 223 &v1alpha.Pod{ 224 Apps: []*v1alpha.App{{Name: "app-foo"}}, 225 Networks: []*v1alpha.Network{{Name: "network-foo"}}, 226 }, 227 []*v1alpha.PodFilter{ 228 {AppNames: []string{"app-foo"}}, 229 {NetworkNames: []string{"network-foo"}}, 230 }, 231 true, 232 }, 233 // Satisfies any filters. 234 { 235 &v1alpha.Pod{ 236 Apps: []*v1alpha.App{{Name: "app-foo"}}, 237 Networks: []*v1alpha.Network{{Name: "network-foo"}}, 238 }, 239 []*v1alpha.PodFilter{ 240 {AppNames: []string{"app-foo"}}, 241 {NetworkNames: []string{"network-bar"}}, 242 }, 243 true, 244 }, 245 // Satisfies none filters. 246 { 247 &v1alpha.Pod{ 248 Apps: []*v1alpha.App{{Name: "app-foo"}}, 249 Networks: []*v1alpha.Network{{Name: "network-foo"}}, 250 }, 251 []*v1alpha.PodFilter{ 252 {AppNames: []string{"app-bar"}}, 253 {NetworkNames: []string{"network-bar"}}, 254 }, 255 false, 256 }, 257 } 258 259 for i, tt := range tests { 260 result := satisfiesAnyPodFilters(tt.pod, tt.filters) 261 if result != tt.result { 262 t.Errorf("#%d: got %v, want %v", i, result, tt.result) 263 } 264 } 265 } 266 267 func TestFilterImage(t *testing.T) { 268 tests := []struct { 269 image *v1alpha.Image 270 filter *v1alpha.ImageFilter 271 result bool 272 }{ 273 // Has the id. 274 { 275 &v1alpha.Image{ 276 Id: "id-foo", 277 }, 278 &v1alpha.ImageFilter{ 279 Ids: []string{"id-first", "id-foo", "id-last"}, 280 }, 281 true, 282 }, 283 // Doesn't have the id. 284 { 285 &v1alpha.Image{ 286 Id: "id-foo", 287 }, 288 &v1alpha.ImageFilter{ 289 Ids: []string{"id-first", "id-second", "id-last"}, 290 }, 291 false, 292 }, 293 // Has the prefix in the name. 294 { 295 &v1alpha.Image{ 296 Name: "prefix-foo-foo", 297 }, 298 &v1alpha.ImageFilter{ 299 Prefixes: []string{"prefix-first", "prefix-foo", "prefix-last"}, 300 }, 301 true, 302 }, 303 // Doesn't have the prefix in the name. 304 { 305 &v1alpha.Image{ 306 Name: "prefix-foo-foo", 307 }, 308 &v1alpha.ImageFilter{ 309 Prefixes: []string{"prefix-first", "prefix-second", "prefix-last"}, 310 }, 311 false, 312 }, 313 // Has the base name in the name. 314 { 315 &v1alpha.Image{ 316 Name: "foo/basename-foo", 317 }, 318 &v1alpha.ImageFilter{ 319 BaseNames: []string{"basename-first", "basename-foo", "basename-last"}, 320 }, 321 true, 322 }, 323 // Doesn't have the base name in the name. 324 { 325 &v1alpha.Image{ 326 Name: "foo/basename-foo", 327 }, 328 &v1alpha.ImageFilter{ 329 BaseNames: []string{"basename-first", "basename-second", "basename-last"}, 330 }, 331 false, 332 }, 333 // Has the keyword in the name. 334 { 335 &v1alpha.Image{ 336 Name: "foo-keyword-foo-foo", 337 }, 338 &v1alpha.ImageFilter{ 339 Keywords: []string{"keyword-first", "keyword-foo", "keyword-last"}, 340 }, 341 true, 342 }, 343 // Doesn't have the keyword in the name. 344 { 345 &v1alpha.Image{ 346 Name: "foo-keyword-foo-foo", 347 }, 348 &v1alpha.ImageFilter{ 349 Keywords: []string{"keyword-first", "keyword-second", "keyword-last"}, 350 }, 351 false, 352 }, 353 // Has all the labels in the manifest. 354 { 355 &v1alpha.Image{ 356 Labels: []*v1alpha.KeyValue{ 357 {"label-key-foo", "label-value-foo"}, 358 {"label-key-bar", "label-value-bar"}, 359 }, 360 }, 361 &v1alpha.ImageFilter{ 362 Labels: []*v1alpha.KeyValue{ 363 {"label-key-foo", "label-value-foo"}, 364 {"label-key-bar", "label-value-bar"}, 365 }, 366 }, 367 true, 368 }, 369 // Doesn't have all the label keys in the manifest. 370 { 371 &v1alpha.Image{ 372 Labels: []*v1alpha.KeyValue{ 373 {"label-key-foo", "label-value-foo"}, 374 {"label-key-bar", "label-value-bar"}, 375 }, 376 }, 377 &v1alpha.ImageFilter{ 378 Labels: []*v1alpha.KeyValue{ 379 {"label-key-foo", "label-value-foo"}, 380 {"label-key-bar", "label-value-bar"}, 381 {"label-key-baz", "label-value-baz"}, 382 }, 383 }, 384 false, 385 }, 386 // Doesn't have all the label values in the manifest. 387 { 388 &v1alpha.Image{ 389 Labels: []*v1alpha.KeyValue{ 390 {"label-key-foo", "label-value-foo"}, 391 {"label-key-bar", "label-value-bar"}, 392 }, 393 }, 394 &v1alpha.ImageFilter{ 395 Labels: []*v1alpha.KeyValue{ 396 {"label-key-foo", "label-value-foo"}, 397 {"label-key-bar", "label-value-baz"}, 398 }, 399 }, 400 false, 401 }, 402 // Has all the annotation in the manifest. 403 { 404 &v1alpha.Image{ 405 Annotations: []*v1alpha.KeyValue{ 406 {"annotation-key-foo", "annotation-value-foo"}, 407 {"annotation-key-bar", "annotation-value-bar"}, 408 }, 409 }, 410 &v1alpha.ImageFilter{ 411 Annotations: []*v1alpha.KeyValue{ 412 {"annotation-key-foo", "annotation-value-foo"}, 413 {"annotation-key-bar", "annotation-value-bar"}, 414 }, 415 }, 416 true, 417 }, 418 // Doesn't have all the annotation keys in the manifest. 419 { 420 &v1alpha.Image{ 421 Annotations: []*v1alpha.KeyValue{ 422 {"annotation-key-foo", "annotation-value-foo"}, 423 {"annotation-key-bar", "annotation-value-bar"}, 424 }, 425 }, 426 &v1alpha.ImageFilter{ 427 Annotations: []*v1alpha.KeyValue{ 428 {"annotation-key-foo", "annotation-value-foo"}, 429 {"annotation-key-bar", "annotation-value-bar"}, 430 {"annotation-key-baz", "annotation-value-baz"}, 431 }, 432 }, 433 false, 434 }, 435 // Doesn't have all the annotation values in the manifest. 436 { 437 &v1alpha.Image{ 438 Annotations: []*v1alpha.KeyValue{ 439 {"annotation-key-foo", "annotation-value-foo"}, 440 {"annotation-key-bar", "annotation-value-bar"}, 441 }, 442 }, 443 &v1alpha.ImageFilter{ 444 Annotations: []*v1alpha.KeyValue{ 445 {"annotation-key-foo", "annotation-value-foo"}, 446 {"annotation-key-bar", "annotation-value-baz"}, 447 }, 448 }, 449 false, 450 }, 451 // Satisfies 'imported after'. 452 { 453 &v1alpha.Image{ImportTimestamp: 1024}, 454 &v1alpha.ImageFilter{ 455 ImportedAfter: 1023, 456 }, 457 true, 458 }, 459 // Doesn't satisfy 'imported after'. 460 { 461 &v1alpha.Image{ImportTimestamp: 1024}, 462 &v1alpha.ImageFilter{ 463 ImportedAfter: 1024, 464 }, 465 false, 466 }, 467 // Satisfies 'imported before'. 468 { 469 &v1alpha.Image{ImportTimestamp: 1024}, 470 &v1alpha.ImageFilter{ 471 ImportedBefore: 1025, 472 }, 473 true, 474 }, 475 // Doesn't satisfy 'imported before'. 476 { 477 &v1alpha.Image{ImportTimestamp: 1024}, 478 &v1alpha.ImageFilter{ 479 ImportedBefore: 1024, 480 }, 481 false, 482 }, 483 // Match one of the full names. 484 { 485 &v1alpha.Image{Name: "foo/basename-foo"}, 486 &v1alpha.ImageFilter{ 487 FullNames: []string{"foo/basename-foo", "foo/basename-bar"}, 488 }, 489 true, 490 }, 491 // Doesn't match any full names. 492 { 493 &v1alpha.Image{Name: "foo/basename-foo"}, 494 &v1alpha.ImageFilter{ 495 FullNames: []string{"bar/basename-foo", "foo/basename-bar"}, 496 }, 497 false, 498 }, 499 // Doesn't satisfy any filter conditions. 500 { 501 &v1alpha.Image{ 502 Id: "id-foo", 503 Name: "prefix-foo-keyword-foo/basename-foo", 504 Version: "1.0", 505 ImportTimestamp: 1024, 506 Labels: []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}}, 507 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 508 }, 509 &v1alpha.ImageFilter{ 510 Ids: []string{"id-bar"}, 511 Prefixes: []string{"prefix-bar"}, 512 BaseNames: []string{"basename-bar"}, 513 Keywords: []string{"keyword-bar"}, 514 Labels: []*v1alpha.KeyValue{{"label-key-bar", "label-value-bar"}}, 515 Annotations: []*v1alpha.KeyValue{{"annotation-key-bar", "annotation-value-bar"}}, 516 ImportedBefore: 1024, 517 ImportedAfter: 1024, 518 }, 519 false, 520 }, 521 // Satisfies some filter conditions. 522 { 523 &v1alpha.Image{ 524 Id: "id-foo", 525 Name: "prefix-foo-keyword-foo/basename-foo", 526 Version: "1.0", 527 ImportTimestamp: 1024, 528 Labels: []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}}, 529 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 530 }, 531 &v1alpha.ImageFilter{ 532 Ids: []string{"id-bar", "id-foo"}, 533 Prefixes: []string{"prefix-bar"}, 534 BaseNames: []string{"basename-bar"}, 535 Keywords: []string{"keyword-bar"}, 536 Labels: []*v1alpha.KeyValue{{"label-key-bar", "label-value-bar"}}, 537 Annotations: []*v1alpha.KeyValue{{"annotation-key-bar", "annotation-value-bar"}}, 538 ImportedBefore: 1024, 539 ImportedAfter: 1024, 540 }, 541 false, 542 }, 543 // Satisfies all filter conditions. 544 { 545 &v1alpha.Image{ 546 Id: "id-foo", 547 Name: "prefix-foo-keyword-foo/basename-foo", 548 Version: "1.0", 549 ImportTimestamp: 1024, 550 Labels: []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}}, 551 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 552 }, 553 &v1alpha.ImageFilter{ 554 Ids: []string{"id-bar", "id-foo"}, 555 Prefixes: []string{"prefix-bar", "prefix-foo"}, 556 BaseNames: []string{"basename-bar", "basename-foo"}, 557 Keywords: []string{"keyword-bar", "keyword-foo"}, 558 Labels: []*v1alpha.KeyValue{{"label-key-foo", "label-value-foo"}}, 559 Annotations: []*v1alpha.KeyValue{{"annotation-key-foo", "annotation-value-foo"}}, 560 ImportedBefore: 1025, 561 ImportedAfter: 1023, 562 }, 563 true, 564 }, 565 } 566 567 for i, tt := range tests { 568 result := satisfiesImageFilter(*tt.image, *tt.filter) 569 if result != tt.result { 570 t.Errorf("#%d: got %v, want %v", i, result, tt.result) 571 } 572 } 573 } 574 575 func TestFilterImageAny(t *testing.T) { 576 tests := []struct { 577 image *v1alpha.Image 578 filters []*v1alpha.ImageFilter 579 result bool 580 }{ 581 // No filters. 582 { 583 &v1alpha.Image{ 584 Id: "id-foo", 585 Name: "prefix-foo-keyword-foo/basename-foo", 586 }, 587 nil, 588 true, 589 }, 590 // Satisfies all filters. 591 { 592 &v1alpha.Image{ 593 Id: "id-foo", 594 Name: "prefix-foo-keyword-foo/basename-foo", 595 }, 596 []*v1alpha.ImageFilter{ 597 {Ids: []string{"id-foo"}}, 598 {BaseNames: []string{"basename-foo"}}, 599 }, 600 true, 601 }, 602 // Satisfies any filters. 603 { 604 &v1alpha.Image{ 605 Id: "id-foo", 606 Name: "prefix-foo-keyword-foo/basename-foo", 607 }, 608 []*v1alpha.ImageFilter{ 609 {Ids: []string{"id-foo"}}, 610 {BaseNames: []string{"basename-bar"}}, 611 }, 612 true, 613 }, 614 // Satisfies none filters. 615 { 616 &v1alpha.Image{ 617 Id: "id-foo", 618 Name: "prefix-foo-keyword-foo/basename-foo", 619 }, 620 []*v1alpha.ImageFilter{ 621 {Ids: []string{"id-bar"}}, 622 {BaseNames: []string{"basename-bar"}}, 623 }, 624 false, 625 }, 626 } 627 628 for i, tt := range tests { 629 result := satisfiesAnyImageFilters(tt.image, tt.filters) 630 if result != tt.result { 631 t.Errorf("#%d: got %v, want %v", i, result, tt.result) 632 } 633 } 634 } 635 636 // Test that we open the correct kinds of sockets 637 func TestOpenSocket(t *testing.T) { 638 stderr = log.New(os.Stderr, "TestOpenSocket", globalFlags.Debug) 639 // get a temp unix socket for us to play with 640 tempdir, err := ioutil.TempDir("", "TestOpenSocket") 641 if err != nil { 642 t.Fatal(err) 643 } 644 defer os.RemoveAll(tempdir) 645 646 l, err := net.Listen("unix", tempdir+"/sock") 647 if err != nil { 648 t.Fatal(err) 649 } 650 defer l.Close() 651 lfd, err := l.(*net.UnixListener).File() 652 if err != nil { 653 t.Fatal(err) 654 } 655 defer lfd.Close() 656 657 // Mock out the systemd FD function 658 systemdFDs = func(x bool) []*os.File { 659 return []*os.File{lfd} 660 } 661 662 // Test that we will open a systemd socket when asked for 663 l1, err := openAPISockets() 664 if err != nil { 665 t.Fatal(err) 666 } 667 if len(l1) != 1 { 668 t.Errorf("expected len(l1) = 1, got %d", len(l1)) 669 } 670 671 // Test that we fail when --listen is passed with a systemd socket 672 flagAPIServiceListenAddr = "localhost:0" 673 _, err = openAPISockets() 674 if err == nil { 675 t.Error("openAPISockets() did not fail when passed systemd socket and --listen") 676 } 677 678 // Then, disable socket mode and ask it to open a random tcp server port 679 systemdFDs = func(x bool) []*os.File { 680 return nil 681 } 682 683 l2, err := openAPISockets() 684 if err != nil { 685 t.Fatal("failed to open socket", err) 686 } 687 688 for _, ll := range l2 { 689 defer ll.Close() 690 } 691 692 if len(l2) != 1 { 693 t.Errorf("expected len(l2) == 1, but got %d", len(l2)) 694 } 695 696 switch l2[0].(type) { 697 case *net.TCPListener: 698 // ok 699 default: 700 t.Errorf("expected type=*net.TCPListener, got %T", l2[0]) 701 } 702 }