github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/configs/validate/validator_test.go (about) 1 package validate 2 3 import ( 4 "os" 5 "path/filepath" 6 "testing" 7 8 "github.com/opencontainers/runc/libcontainer/configs" 9 "github.com/opencontainers/runtime-spec/specs-go" 10 "golang.org/x/sys/unix" 11 ) 12 13 func TestValidate(t *testing.T) { 14 config := &configs.Config{ 15 Rootfs: "/var", 16 } 17 18 err := Validate(config) 19 if err != nil { 20 t.Errorf("Expected error to not occur: %+v", err) 21 } 22 } 23 24 func TestValidateWithInvalidRootfs(t *testing.T) { 25 dir := "rootfs" 26 if err := os.Symlink("/var", dir); err != nil { 27 t.Fatal(err) 28 } 29 defer os.Remove(dir) 30 31 config := &configs.Config{ 32 Rootfs: dir, 33 } 34 35 err := Validate(config) 36 if err == nil { 37 t.Error("Expected error to occur but it was nil") 38 } 39 } 40 41 func TestValidateNetworkWithoutNETNamespace(t *testing.T) { 42 network := &configs.Network{Type: "loopback"} 43 config := &configs.Config{ 44 Rootfs: "/var", 45 Namespaces: []configs.Namespace{}, 46 Networks: []*configs.Network{network}, 47 } 48 49 err := Validate(config) 50 if err == nil { 51 t.Error("Expected error to occur but it was nil") 52 } 53 } 54 55 func TestValidateNetworkRoutesWithoutNETNamespace(t *testing.T) { 56 route := &configs.Route{Gateway: "255.255.255.0"} 57 config := &configs.Config{ 58 Rootfs: "/var", 59 Namespaces: []configs.Namespace{}, 60 Routes: []*configs.Route{route}, 61 } 62 63 err := Validate(config) 64 if err == nil { 65 t.Error("Expected error to occur but it was nil") 66 } 67 } 68 69 func TestValidateHostname(t *testing.T) { 70 config := &configs.Config{ 71 Rootfs: "/var", 72 Hostname: "runc", 73 Namespaces: configs.Namespaces( 74 []configs.Namespace{ 75 {Type: configs.NEWUTS}, 76 }, 77 ), 78 } 79 80 err := Validate(config) 81 if err != nil { 82 t.Errorf("Expected error to not occur: %+v", err) 83 } 84 } 85 86 func TestValidateUTS(t *testing.T) { 87 config := &configs.Config{ 88 Rootfs: "/var", 89 Domainname: "runc", 90 Hostname: "runc", 91 Namespaces: configs.Namespaces( 92 []configs.Namespace{ 93 {Type: configs.NEWUTS}, 94 }, 95 ), 96 } 97 98 err := Validate(config) 99 if err != nil { 100 t.Errorf("Expected error to not occur: %+v", err) 101 } 102 } 103 104 func TestValidateUTSWithoutUTSNamespace(t *testing.T) { 105 config := &configs.Config{ 106 Rootfs: "/var", 107 Hostname: "runc", 108 } 109 110 err := Validate(config) 111 if err == nil { 112 t.Error("Expected error to occur but it was nil") 113 } 114 115 config = &configs.Config{ 116 Rootfs: "/var", 117 Domainname: "runc", 118 } 119 120 err = Validate(config) 121 if err == nil { 122 t.Error("Expected error to occur but it was nil") 123 } 124 } 125 126 func TestValidateSecurityWithMaskPaths(t *testing.T) { 127 config := &configs.Config{ 128 Rootfs: "/var", 129 MaskPaths: []string{"/proc/kcore"}, 130 Namespaces: configs.Namespaces( 131 []configs.Namespace{ 132 {Type: configs.NEWNS}, 133 }, 134 ), 135 } 136 137 err := Validate(config) 138 if err != nil { 139 t.Errorf("Expected error to not occur: %+v", err) 140 } 141 } 142 143 func TestValidateSecurityWithROPaths(t *testing.T) { 144 config := &configs.Config{ 145 Rootfs: "/var", 146 ReadonlyPaths: []string{"/proc/sys"}, 147 Namespaces: configs.Namespaces( 148 []configs.Namespace{ 149 {Type: configs.NEWNS}, 150 }, 151 ), 152 } 153 154 err := Validate(config) 155 if err != nil { 156 t.Errorf("Expected error to not occur: %+v", err) 157 } 158 } 159 160 func TestValidateSecurityWithoutNEWNS(t *testing.T) { 161 config := &configs.Config{ 162 Rootfs: "/var", 163 MaskPaths: []string{"/proc/kcore"}, 164 ReadonlyPaths: []string{"/proc/sys"}, 165 } 166 167 err := Validate(config) 168 if err == nil { 169 t.Error("Expected error to occur but it was nil") 170 } 171 } 172 173 func TestValidateUserNamespace(t *testing.T) { 174 if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { 175 t.Skip("Test requires userns.") 176 } 177 config := &configs.Config{ 178 Rootfs: "/var", 179 Namespaces: configs.Namespaces( 180 []configs.Namespace{ 181 {Type: configs.NEWUSER}, 182 }, 183 ), 184 UIDMappings: []configs.IDMap{{HostID: 0, ContainerID: 123, Size: 100}}, 185 GIDMappings: []configs.IDMap{{HostID: 0, ContainerID: 123, Size: 100}}, 186 } 187 188 err := Validate(config) 189 if err != nil { 190 t.Errorf("expected error to not occur %+v", err) 191 } 192 } 193 194 func TestValidateUsernsMappingWithoutNamespace(t *testing.T) { 195 config := &configs.Config{ 196 Rootfs: "/var", 197 UIDMappings: []configs.IDMap{{HostID: 0, ContainerID: 123, Size: 100}}, 198 GIDMappings: []configs.IDMap{{HostID: 0, ContainerID: 123, Size: 100}}, 199 } 200 201 err := Validate(config) 202 if err == nil { 203 t.Error("Expected error to occur but it was nil") 204 } 205 } 206 207 func TestValidateTimeNamespace(t *testing.T) { 208 if _, err := os.Stat("/proc/self/ns/time"); os.IsNotExist(err) { 209 t.Skip("Test requires timens.") 210 } 211 config := &configs.Config{ 212 Rootfs: "/var", 213 Namespaces: configs.Namespaces( 214 []configs.Namespace{ 215 {Type: configs.NEWTIME}, 216 }, 217 ), 218 } 219 220 err := Validate(config) 221 if err != nil { 222 t.Errorf("expected error to not occur %+v", err) 223 } 224 } 225 226 func TestValidateTimeNamespaceWithBothPathAndTimeOffset(t *testing.T) { 227 if _, err := os.Stat("/proc/self/ns/time"); os.IsNotExist(err) { 228 t.Skip("Test requires timens.") 229 } 230 config := &configs.Config{ 231 Rootfs: "/var", 232 Namespaces: configs.Namespaces( 233 []configs.Namespace{ 234 {Type: configs.NEWTIME, Path: "/proc/1/ns/time"}, 235 }, 236 ), 237 TimeOffsets: map[string]specs.LinuxTimeOffset{ 238 "boottime": {Secs: 150, Nanosecs: 314159}, 239 "monotonic": {Secs: 512, Nanosecs: 271818}, 240 }, 241 } 242 243 err := Validate(config) 244 if err == nil { 245 t.Error("Expected error to occur but it was nil") 246 } 247 } 248 249 func TestValidateTimeOffsetsWithoutTimeNamespace(t *testing.T) { 250 config := &configs.Config{ 251 Rootfs: "/var", 252 TimeOffsets: map[string]specs.LinuxTimeOffset{ 253 "boottime": {Secs: 150, Nanosecs: 314159}, 254 "monotonic": {Secs: 512, Nanosecs: 271818}, 255 }, 256 } 257 258 err := Validate(config) 259 if err == nil { 260 t.Error("Expected error to occur but it was nil") 261 } 262 } 263 264 // TestConvertSysctlVariableToDotsSeparator tests whether the sysctl variable 265 // can be correctly converted to a dot as a separator. 266 func TestConvertSysctlVariableToDotsSeparator(t *testing.T) { 267 type testCase struct { 268 in string 269 out string 270 } 271 valid := []testCase{ 272 {in: "kernel.shm_rmid_forced", out: "kernel.shm_rmid_forced"}, 273 {in: "kernel/shm_rmid_forced", out: "kernel.shm_rmid_forced"}, 274 {in: "net.ipv4.conf.eno2/100.rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"}, 275 {in: "net/ipv4/conf/eno2.100/rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"}, 276 {in: "net/ipv4/ip_local_port_range", out: "net.ipv4.ip_local_port_range"}, 277 {in: "kernel/msgmax", out: "kernel.msgmax"}, 278 {in: "kernel/sem", out: "kernel.sem"}, 279 } 280 281 for _, test := range valid { 282 convertSysctlVal := convertSysctlVariableToDotsSeparator(test.in) 283 if convertSysctlVal != test.out { 284 t.Errorf("The sysctl variable was not converted correctly. got: %s, want: %s", convertSysctlVal, test.out) 285 } 286 } 287 } 288 289 func TestValidateSysctl(t *testing.T) { 290 sysctl := map[string]string{ 291 "fs.mqueue.ctl": "ctl", 292 "fs/mqueue/ctl": "ctl", 293 "net.ctl": "ctl", 294 "net/ctl": "ctl", 295 "net.ipv4.conf.eno2/100.rp_filter": "ctl", 296 "kernel.ctl": "ctl", 297 "kernel/ctl": "ctl", 298 } 299 300 for k, v := range sysctl { 301 config := &configs.Config{ 302 Rootfs: "/var", 303 Sysctl: map[string]string{k: v}, 304 } 305 306 err := Validate(config) 307 if err == nil { 308 t.Error("Expected error to occur but it was nil") 309 } 310 } 311 } 312 313 func TestValidateValidSysctl(t *testing.T) { 314 sysctl := map[string]string{ 315 "fs.mqueue.ctl": "ctl", 316 "fs/mqueue/ctl": "ctl", 317 "net.ctl": "ctl", 318 "net/ctl": "ctl", 319 "net.ipv4.conf.eno2/100.rp_filter": "ctl", 320 "kernel.msgmax": "ctl", 321 "kernel/msgmax": "ctl", 322 } 323 324 for k, v := range sysctl { 325 config := &configs.Config{ 326 Rootfs: "/var", 327 Sysctl: map[string]string{k: v}, 328 Namespaces: []configs.Namespace{ 329 { 330 Type: configs.NEWNET, 331 }, 332 { 333 Type: configs.NEWIPC, 334 }, 335 }, 336 } 337 338 err := Validate(config) 339 if err != nil { 340 t.Errorf("Expected error to not occur with {%s=%s} but got: %q", k, v, err) 341 } 342 } 343 } 344 345 func TestValidateSysctlWithSameNs(t *testing.T) { 346 config := &configs.Config{ 347 Rootfs: "/var", 348 Sysctl: map[string]string{"net.ctl": "ctl"}, 349 Namespaces: configs.Namespaces( 350 []configs.Namespace{ 351 { 352 Type: configs.NEWNET, 353 Path: "/proc/self/ns/net", 354 }, 355 }, 356 ), 357 } 358 359 err := Validate(config) 360 if err == nil { 361 t.Error("Expected error to occur but it was nil") 362 } 363 } 364 365 func TestValidateSysctlWithBindHostNetNS(t *testing.T) { 366 if os.Getuid() != 0 { 367 t.Skip("requires root") 368 } 369 370 const selfnet = "/proc/self/ns/net" 371 372 file := filepath.Join(t.TempDir(), "default") 373 fd, err := os.Create(file) 374 if err != nil { 375 t.Fatal(err) 376 } 377 defer os.Remove(file) 378 fd.Close() 379 380 if err := unix.Mount(selfnet, file, "bind", unix.MS_BIND, ""); err != nil { 381 t.Fatalf("can't bind-mount %s to %s: %s", selfnet, file, err) 382 } 383 defer func() { 384 _ = unix.Unmount(file, unix.MNT_DETACH) 385 }() 386 387 config := &configs.Config{ 388 Rootfs: "/var", 389 Sysctl: map[string]string{"net.ctl": "ctl", "net.foo": "bar"}, 390 Namespaces: configs.Namespaces( 391 []configs.Namespace{ 392 { 393 Type: configs.NEWNET, 394 Path: file, 395 }, 396 }, 397 ), 398 } 399 400 if err := Validate(config); err == nil { 401 t.Error("Expected error to occur but it was nil") 402 } 403 } 404 405 func TestValidateSysctlWithoutNETNamespace(t *testing.T) { 406 config := &configs.Config{ 407 Rootfs: "/var", 408 Sysctl: map[string]string{"net.ctl": "ctl"}, 409 Namespaces: []configs.Namespace{}, 410 } 411 412 err := Validate(config) 413 if err == nil { 414 t.Error("Expected error to occur but it was nil") 415 } 416 } 417 418 func TestValidateMounts(t *testing.T) { 419 testCases := []struct { 420 isErr bool 421 dest string 422 }{ 423 {isErr: false, dest: "not/an/abs/path"}, 424 {isErr: false, dest: "./rel/path"}, 425 {isErr: false, dest: "./rel/path"}, 426 {isErr: false, dest: "../../path"}, 427 {isErr: false, dest: "/abs/path"}, 428 {isErr: false, dest: "/abs/but/../unclean"}, 429 } 430 431 for _, tc := range testCases { 432 config := &configs.Config{ 433 Rootfs: "/var", 434 Mounts: []*configs.Mount{ 435 {Destination: tc.dest}, 436 }, 437 } 438 439 err := Validate(config) 440 if tc.isErr && err == nil { 441 t.Errorf("mount dest: %s, expected error, got nil", tc.dest) 442 } 443 if !tc.isErr && err != nil { 444 t.Errorf("mount dest: %s, expected nil, got error %v", tc.dest, err) 445 } 446 } 447 } 448 449 func TestValidateBindMounts(t *testing.T) { 450 testCases := []struct { 451 isErr bool 452 flags int 453 data string 454 }{ 455 {isErr: false, flags: 0, data: ""}, 456 {isErr: false, flags: unix.MS_RDONLY | unix.MS_NOSYMFOLLOW, data: ""}, 457 458 {isErr: true, flags: 0, data: "idmap"}, 459 {isErr: true, flags: unix.MS_RDONLY, data: "custom_ext4_flag"}, 460 {isErr: true, flags: unix.MS_NOATIME, data: "rw=foobar"}, 461 } 462 463 for _, tc := range testCases { 464 for _, bind := range []string{"bind", "rbind"} { 465 bindFlag := map[string]int{ 466 "bind": unix.MS_BIND, 467 "rbind": unix.MS_BIND | unix.MS_REC, 468 }[bind] 469 470 config := &configs.Config{ 471 Rootfs: "/var", 472 Mounts: []*configs.Mount{ 473 { 474 Destination: "/", 475 Flags: tc.flags | bindFlag, 476 Data: tc.data, 477 }, 478 }, 479 } 480 481 err := Validate(config) 482 if tc.isErr && err == nil { 483 t.Errorf("%s mount flags:0x%x data:%v, expected error, got nil", bind, tc.flags, tc.data) 484 } 485 if !tc.isErr && err != nil { 486 t.Errorf("%s mount flags:0x%x data:%v, expected nil, got error %v", bind, tc.flags, tc.data, err) 487 } 488 } 489 } 490 } 491 492 func TestValidateIDMapMounts(t *testing.T) { 493 mapping := []configs.IDMap{ 494 { 495 ContainerID: 0, 496 HostID: 10000, 497 Size: 1, 498 }, 499 } 500 501 testCases := []struct { 502 name string 503 isErr bool 504 config *configs.Config 505 }{ 506 { 507 name: "idmap non-bind mount", 508 isErr: true, 509 config: &configs.Config{ 510 UIDMappings: mapping, 511 GIDMappings: mapping, 512 Mounts: []*configs.Mount{ 513 { 514 Source: "/dev/sda1", 515 Destination: "/abs/path/", 516 Device: "ext4", 517 IDMapping: &configs.MountIDMapping{ 518 UIDMappings: mapping, 519 GIDMappings: mapping, 520 }, 521 }, 522 }, 523 }, 524 }, 525 { 526 name: "idmap option non-bind mount", 527 isErr: true, 528 config: &configs.Config{ 529 Mounts: []*configs.Mount{ 530 { 531 Source: "/dev/sda1", 532 Destination: "/abs/path/", 533 Device: "ext4", 534 IDMapping: &configs.MountIDMapping{}, 535 }, 536 }, 537 }, 538 }, 539 { 540 name: "ridmap option non-bind mount", 541 isErr: true, 542 config: &configs.Config{ 543 Mounts: []*configs.Mount{ 544 { 545 Source: "/dev/sda1", 546 Destination: "/abs/path/", 547 Device: "ext4", 548 IDMapping: &configs.MountIDMapping{ 549 Recursive: true, 550 }, 551 }, 552 }, 553 }, 554 }, 555 { 556 name: "idmap mount no uid mapping", 557 isErr: true, 558 config: &configs.Config{ 559 Mounts: []*configs.Mount{ 560 { 561 Source: "/abs/path/", 562 Destination: "/abs/path/", 563 Flags: unix.MS_BIND, 564 IDMapping: &configs.MountIDMapping{ 565 GIDMappings: mapping, 566 }, 567 }, 568 }, 569 }, 570 }, 571 { 572 name: "idmap mount no gid mapping", 573 isErr: true, 574 config: &configs.Config{ 575 Mounts: []*configs.Mount{ 576 { 577 Source: "/abs/path/", 578 Destination: "/abs/path/", 579 Flags: unix.MS_BIND, 580 IDMapping: &configs.MountIDMapping{ 581 UIDMappings: mapping, 582 }, 583 }, 584 }, 585 }, 586 }, 587 { 588 name: "rootless idmap mount", 589 isErr: true, 590 config: &configs.Config{ 591 RootlessEUID: true, 592 UIDMappings: mapping, 593 GIDMappings: mapping, 594 Mounts: []*configs.Mount{ 595 { 596 Source: "/abs/path/", 597 Destination: "/abs/path/", 598 Flags: unix.MS_BIND, 599 IDMapping: &configs.MountIDMapping{ 600 UIDMappings: mapping, 601 GIDMappings: mapping, 602 }, 603 }, 604 }, 605 }, 606 }, 607 { 608 name: "idmap mounts without abs source path", 609 config: &configs.Config{ 610 UIDMappings: mapping, 611 GIDMappings: mapping, 612 Mounts: []*configs.Mount{ 613 { 614 Source: "./rel/path/", 615 Destination: "/abs/path/", 616 Flags: unix.MS_BIND, 617 IDMapping: &configs.MountIDMapping{ 618 UIDMappings: mapping, 619 GIDMappings: mapping, 620 }, 621 }, 622 }, 623 }, 624 }, 625 { 626 name: "idmap mounts without abs dest path", 627 config: &configs.Config{ 628 UIDMappings: mapping, 629 GIDMappings: mapping, 630 Mounts: []*configs.Mount{ 631 { 632 Source: "/abs/path/", 633 Destination: "./rel/path/", 634 Flags: unix.MS_BIND, 635 IDMapping: &configs.MountIDMapping{ 636 UIDMappings: mapping, 637 GIDMappings: mapping, 638 }, 639 }, 640 }, 641 }, 642 }, 643 { 644 name: "simple idmap mount", 645 config: &configs.Config{ 646 UIDMappings: mapping, 647 GIDMappings: mapping, 648 Mounts: []*configs.Mount{ 649 { 650 Source: "/another-abs/path/", 651 Destination: "/abs/path/", 652 Flags: unix.MS_BIND, 653 IDMapping: &configs.MountIDMapping{ 654 UIDMappings: mapping, 655 GIDMappings: mapping, 656 }, 657 }, 658 }, 659 }, 660 }, 661 { 662 name: "idmap mount with more flags", 663 config: &configs.Config{ 664 UIDMappings: mapping, 665 GIDMappings: mapping, 666 Mounts: []*configs.Mount{ 667 { 668 Source: "/another-abs/path/", 669 Destination: "/abs/path/", 670 Flags: unix.MS_BIND | unix.MS_RDONLY, 671 IDMapping: &configs.MountIDMapping{ 672 UIDMappings: mapping, 673 GIDMappings: mapping, 674 }, 675 }, 676 }, 677 }, 678 }, 679 { 680 name: "idmap mount without userns mappings", 681 config: &configs.Config{ 682 Mounts: []*configs.Mount{ 683 { 684 Source: "/abs/path/", 685 Destination: "/abs/path/", 686 Flags: unix.MS_BIND, 687 IDMapping: &configs.MountIDMapping{ 688 UIDMappings: mapping, 689 GIDMappings: mapping, 690 }, 691 }, 692 }, 693 }, 694 }, 695 { 696 name: "idmap mounts with different userns and mount mappings", 697 config: &configs.Config{ 698 UIDMappings: mapping, 699 GIDMappings: mapping, 700 Mounts: []*configs.Mount{ 701 { 702 Source: "/abs/path/", 703 Destination: "/abs/path/", 704 Flags: unix.MS_BIND, 705 IDMapping: &configs.MountIDMapping{ 706 UIDMappings: []configs.IDMap{ 707 { 708 ContainerID: 10, 709 HostID: 10, 710 Size: 1, 711 }, 712 }, 713 GIDMappings: mapping, 714 }, 715 }, 716 }, 717 }, 718 }, 719 { 720 name: "idmap mounts with different userns and mount mappings", 721 config: &configs.Config{ 722 UIDMappings: mapping, 723 GIDMappings: mapping, 724 Mounts: []*configs.Mount{ 725 { 726 Source: "/abs/path/", 727 Destination: "/abs/path/", 728 Flags: unix.MS_BIND, 729 IDMapping: &configs.MountIDMapping{ 730 UIDMappings: mapping, 731 GIDMappings: []configs.IDMap{ 732 { 733 ContainerID: 10, 734 HostID: 10, 735 Size: 1, 736 }, 737 }, 738 }, 739 }, 740 }, 741 }, 742 }, 743 { 744 name: "mount with 'idmap' option but no mappings", 745 isErr: true, 746 config: &configs.Config{ 747 Mounts: []*configs.Mount{ 748 { 749 Source: "/abs/path/", 750 Destination: "/abs/path/", 751 Flags: unix.MS_BIND, 752 IDMapping: &configs.MountIDMapping{}, 753 }, 754 }, 755 }, 756 }, 757 { 758 name: "mount with 'ridmap' option but no mappings", 759 isErr: true, 760 config: &configs.Config{ 761 Mounts: []*configs.Mount{ 762 { 763 Source: "/abs/path/", 764 Destination: "/abs/path/", 765 Flags: unix.MS_BIND, 766 IDMapping: &configs.MountIDMapping{ 767 Recursive: true, 768 }, 769 }, 770 }, 771 }, 772 }, 773 } 774 775 for _, tc := range testCases { 776 tc := tc 777 t.Run(tc.name, func(t *testing.T) { 778 config := tc.config 779 config.Rootfs = "/var" 780 781 err := mountsStrict(config) 782 if tc.isErr && err == nil { 783 t.Error("expected error, got nil") 784 } 785 786 if !tc.isErr && err != nil { 787 t.Error(err) 788 } 789 }) 790 } 791 } 792 793 func TestValidateScheduler(t *testing.T) { 794 testCases := []struct { 795 isErr bool 796 policy string 797 niceValue int32 798 priority int32 799 runtime uint64 800 deadline uint64 801 period uint64 802 }{ 803 {isErr: true, niceValue: 0}, 804 {isErr: false, policy: "SCHED_OTHER", niceValue: 19}, 805 {isErr: false, policy: "SCHED_OTHER", niceValue: -20}, 806 {isErr: true, policy: "SCHED_OTHER", niceValue: 20}, 807 {isErr: true, policy: "SCHED_OTHER", niceValue: -21}, 808 {isErr: true, policy: "SCHED_OTHER", priority: 100}, 809 {isErr: false, policy: "SCHED_FIFO", priority: 100}, 810 {isErr: true, policy: "SCHED_FIFO", runtime: 20}, 811 {isErr: true, policy: "SCHED_BATCH", deadline: 30}, 812 {isErr: true, policy: "SCHED_IDLE", period: 40}, 813 {isErr: true, policy: "SCHED_DEADLINE", priority: 100}, 814 {isErr: false, policy: "SCHED_DEADLINE", runtime: 200}, 815 {isErr: false, policy: "SCHED_DEADLINE", deadline: 300}, 816 {isErr: false, policy: "SCHED_DEADLINE", period: 400}, 817 {isErr: true, policy: "SCHED_OTHER", niceValue: 20}, 818 {isErr: true, policy: "SCHED_OTHER", niceValue: -21}, 819 {isErr: false, policy: "SCHED_FIFO", priority: 100, niceValue: 100}, 820 } 821 822 for _, tc := range testCases { 823 scheduler := configs.Scheduler{ 824 Policy: specs.LinuxSchedulerPolicy(tc.policy), 825 Nice: tc.niceValue, 826 Priority: tc.priority, 827 Runtime: tc.runtime, 828 Deadline: tc.deadline, 829 Period: tc.period, 830 } 831 config := &configs.Config{ 832 Rootfs: "/var", 833 Scheduler: &scheduler, 834 } 835 836 err := Validate(config) 837 if tc.isErr && err == nil { 838 t.Errorf("scheduler: %d, expected error, got nil", tc.niceValue) 839 } 840 if !tc.isErr && err != nil { 841 t.Errorf("scheduler: %d, expected nil, got error %v", tc.niceValue, err) 842 } 843 } 844 } 845 846 func TestValidateIOPriority(t *testing.T) { 847 testCases := []struct { 848 isErr bool 849 priority int 850 }{ 851 {isErr: false, priority: 0}, 852 {isErr: false, priority: 7}, 853 {isErr: true, priority: -1}, 854 } 855 856 for _, tc := range testCases { 857 ioPriroty := configs.IOPriority{ 858 Priority: tc.priority, 859 } 860 config := &configs.Config{ 861 Rootfs: "/var", 862 IOPriority: &ioPriroty, 863 } 864 865 err := Validate(config) 866 if tc.isErr && err == nil { 867 t.Errorf("iopriority: %d, expected error, got nil", tc.priority) 868 } 869 if !tc.isErr && err != nil { 870 t.Errorf("iopriority: %d, expected nil, got error %v", tc.priority, err) 871 } 872 } 873 }