k8s.io/kubernetes@v1.29.3/pkg/volume/util/fsquota/quota_linux_test.go (about) 1 //go:build linux 2 // +build linux 3 4 /* 5 Copyright 2018 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package fsquota 21 22 import ( 23 "fmt" 24 "os" 25 "strings" 26 "testing" 27 28 "k8s.io/mount-utils" 29 30 "k8s.io/apimachinery/pkg/api/resource" 31 "k8s.io/apimachinery/pkg/types" 32 utilfeature "k8s.io/apiserver/pkg/util/feature" 33 featuregatetesting "k8s.io/component-base/featuregate/testing" 34 "k8s.io/kubernetes/pkg/features" 35 "k8s.io/kubernetes/pkg/volume/util/fsquota/common" 36 ) 37 38 const dummyMountData = `sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 39 proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 40 devtmpfs /dev devtmpfs rw,nosuid,size=6133536k,nr_inodes=1533384,mode=755 0 0 41 tmpfs /tmp tmpfs rw,nosuid,nodev 0 0 42 /dev/sda1 /boot ext4 rw,relatime 0 0 43 /dev/mapper/fedora-root / ext4 rw,noatime 0 0 44 /dev/mapper/fedora-home /home ext4 rw,noatime 0 0 45 /dev/sdb1 /virt xfs rw,noatime,attr2,inode64,usrquota,prjquota 0 0 46 ` 47 48 func dummyFakeMount1() mount.Interface { 49 return mount.NewFakeMounter( 50 []mount.MountPoint{ 51 { 52 Device: "tmpfs", 53 Path: "/tmp", 54 Type: "tmpfs", 55 Opts: []string{"rw", "nosuid", "nodev"}, 56 }, 57 { 58 Device: "/dev/sda1", 59 Path: "/boot", 60 Type: "ext4", 61 Opts: []string{"rw", "relatime"}, 62 }, 63 { 64 Device: "/dev/mapper/fedora-root", 65 Path: "/", 66 Type: "ext4", 67 Opts: []string{"rw", "relatime"}, 68 }, 69 { 70 Device: "/dev/mapper/fedora-home", 71 Path: "/home", 72 Type: "ext4", 73 Opts: []string{"rw", "relatime"}, 74 }, 75 { 76 Device: "/dev/sdb1", 77 Path: "/mnt/virt", 78 Type: "xfs", 79 Opts: []string{"rw", "relatime", "attr2", "inode64", "usrquota", "prjquota"}, 80 }, 81 }) 82 } 83 84 type backingDevTest struct { 85 path string 86 mountdata string 87 expectedResult string 88 expectFailure bool 89 } 90 91 type mountpointTest struct { 92 path string 93 mounter mount.Interface 94 expectedResult string 95 expectFailure bool 96 } 97 98 func testBackingDev1(testcase backingDevTest) error { 99 tmpfile, err := os.CreateTemp("", "backingdev") 100 if err != nil { 101 return err 102 } 103 defer os.Remove(tmpfile.Name()) 104 if _, err = tmpfile.WriteString(testcase.mountdata); err != nil { 105 return err 106 } 107 108 backingDev, err := detectBackingDevInternal(testcase.path, tmpfile.Name()) 109 if err != nil { 110 if testcase.expectFailure { 111 return nil 112 } 113 return err 114 } 115 if testcase.expectFailure { 116 return fmt.Errorf("path %s expected to fail; succeeded and got %s", testcase.path, backingDev) 117 } 118 if backingDev == testcase.expectedResult { 119 return nil 120 } 121 return fmt.Errorf("mismatch: path %s expects mountpoint %s got %s", testcase.path, testcase.expectedResult, backingDev) 122 } 123 124 func TestBackingDev(t *testing.T) { 125 testcasesBackingDev := map[string]backingDevTest{ 126 "Root": { 127 "/", 128 dummyMountData, 129 "/dev/mapper/fedora-root", 130 false, 131 }, 132 "tmpfs": { 133 "/tmp", 134 dummyMountData, 135 "tmpfs", 136 false, 137 }, 138 "user filesystem": { 139 "/virt", 140 dummyMountData, 141 "/dev/sdb1", 142 false, 143 }, 144 "empty mountpoint": { 145 "", 146 dummyMountData, 147 "", 148 true, 149 }, 150 "bad mountpoint": { 151 "/kiusf", 152 dummyMountData, 153 "", 154 true, 155 }, 156 } 157 for name, testcase := range testcasesBackingDev { 158 err := testBackingDev1(testcase) 159 if err != nil { 160 t.Errorf("%s failed: %s", name, err.Error()) 161 } 162 } 163 } 164 165 func TestDetectMountPoint(t *testing.T) { 166 testcasesMount := map[string]mountpointTest{ 167 "Root": { 168 "/", 169 dummyFakeMount1(), 170 "/", 171 false, 172 }, 173 "(empty)": { 174 "", 175 dummyFakeMount1(), 176 "/", 177 false, 178 }, 179 "(invalid)": { 180 "", 181 dummyFakeMount1(), 182 "/", 183 false, 184 }, 185 "/usr": { 186 "/usr", 187 dummyFakeMount1(), 188 "/", 189 false, 190 }, 191 "/var/tmp": { 192 "/var/tmp", 193 dummyFakeMount1(), 194 "/", 195 false, 196 }, 197 } 198 for name, testcase := range testcasesMount { 199 mountpoint, err := detectMountpointInternal(testcase.mounter, testcase.path) 200 if err == nil && testcase.expectFailure { 201 t.Errorf("Case %s expected failure, but succeeded, returning mountpoint %s", name, mountpoint) 202 } else if err != nil { 203 t.Errorf("Case %s failed: %s", name, err.Error()) 204 } else if mountpoint != testcase.expectedResult { 205 t.Errorf("Case %s got mountpoint %s, expected %s", name, mountpoint, testcase.expectedResult) 206 } 207 } 208 } 209 210 var dummyMountPoints = []mount.MountPoint{ 211 { 212 Device: "/dev/sda2", 213 Path: "/quota1", 214 Type: "ext4", 215 Opts: []string{"rw", "relatime", "prjquota"}, 216 }, 217 { 218 Device: "/dev/sda3", 219 Path: "/quota2", 220 Type: "ext4", 221 Opts: []string{"rw", "relatime", "prjquota"}, 222 }, 223 { 224 Device: "/dev/sda3", 225 Path: "/noquota", 226 Type: "ext4", 227 Opts: []string{"rw", "relatime"}, 228 }, 229 { 230 Device: "/dev/sda1", 231 Path: "/", 232 Type: "ext4", 233 Opts: []string{"rw", "relatime"}, 234 }, 235 } 236 237 func dummyQuotaTest() mount.Interface { 238 return mount.NewFakeMounter(dummyMountPoints) 239 } 240 241 func dummySetFSInfo(path string) { 242 if enabledQuotasForMonitoring() { 243 for _, mount := range dummyMountPoints { 244 if strings.HasPrefix(path, mount.Path) { 245 mountpointMap[path] = mount.Path 246 backingDevMap[path] = mount.Device 247 return 248 } 249 } 250 } 251 } 252 253 type VolumeProvider1 struct { 254 } 255 256 type VolumeProvider2 struct { 257 } 258 259 type testVolumeQuota struct { 260 } 261 262 func logAllMaps(where string) { 263 fmt.Printf("Maps at %s\n", where) 264 fmt.Printf(" Map podQuotaMap contents:\n") 265 for key, val := range podQuotaMap { 266 fmt.Printf(" %v -> %v\n", key, val) 267 } 268 fmt.Printf(" Map dirQuotaMap contents:\n") 269 for key, val := range dirQuotaMap { 270 fmt.Printf(" %v -> %v\n", key, val) 271 } 272 fmt.Printf(" Map quotaPodMap contents:\n") 273 for key, val := range quotaPodMap { 274 fmt.Printf(" %v -> %v\n", key, val) 275 } 276 fmt.Printf(" Map dirPodMap contents:\n") 277 for key, val := range dirPodMap { 278 fmt.Printf(" %v -> %v\n", key, val) 279 } 280 fmt.Printf(" Map devApplierMap contents:\n") 281 for key, val := range devApplierMap { 282 fmt.Printf(" %v -> %v\n", key, val) 283 } 284 fmt.Printf(" Map dirApplierMap contents:\n") 285 for key, val := range dirApplierMap { 286 fmt.Printf(" %v -> %v\n", key, val) 287 } 288 fmt.Printf(" Map podDirCountMap contents:\n") 289 for key, val := range podDirCountMap { 290 fmt.Printf(" %v -> %v\n", key, val) 291 } 292 fmt.Printf(" Map quotaSizeMap contents:\n") 293 for key, val := range quotaSizeMap { 294 fmt.Printf(" %v -> %v\n", key, val) 295 } 296 fmt.Printf(" Map supportsQuotasMap contents:\n") 297 for key, val := range supportsQuotasMap { 298 fmt.Printf(" %v -> %v\n", key, val) 299 } 300 fmt.Printf(" Map backingDevMap contents:\n") 301 for key, val := range backingDevMap { 302 fmt.Printf(" %v -> %v\n", key, val) 303 } 304 fmt.Printf(" Map mountpointMap contents:\n") 305 for key, val := range mountpointMap { 306 fmt.Printf(" %v -> %v\n", key, val) 307 } 308 fmt.Printf("End maps %s\n", where) 309 } 310 311 var testIDQuotaMap = make(map[common.QuotaID]string) 312 var testQuotaIDMap = make(map[string]common.QuotaID) 313 314 func (*VolumeProvider1) GetQuotaApplier(mountpoint string, backingDev string) common.LinuxVolumeQuotaApplier { 315 if strings.HasPrefix(mountpoint, "/quota1") { 316 return testVolumeQuota{} 317 } 318 return nil 319 } 320 321 func (*VolumeProvider2) GetQuotaApplier(mountpoint string, backingDev string) common.LinuxVolumeQuotaApplier { 322 if strings.HasPrefix(mountpoint, "/quota2") { 323 return testVolumeQuota{} 324 } 325 return nil 326 } 327 328 func (v testVolumeQuota) SetQuotaOnDir(dir string, id common.QuotaID, _ int64) error { 329 odir, ok := testIDQuotaMap[id] 330 if ok && dir != odir { 331 return fmt.Errorf("ID %v is already in use", id) 332 } 333 oid, ok := testQuotaIDMap[dir] 334 if ok && id != oid { 335 return fmt.Errorf("directory %s already has a quota applied", dir) 336 } 337 testQuotaIDMap[dir] = id 338 testIDQuotaMap[id] = dir 339 return nil 340 } 341 342 func (v testVolumeQuota) GetQuotaOnDir(path string) (common.QuotaID, error) { 343 id, ok := testQuotaIDMap[path] 344 if ok { 345 return id, nil 346 } 347 return common.BadQuotaID, fmt.Errorf("no quota available for %s", path) 348 } 349 350 func (v testVolumeQuota) QuotaIDIsInUse(id common.QuotaID) (bool, error) { 351 if _, ok := testIDQuotaMap[id]; ok { 352 return true, nil 353 } 354 // So that we reject some 355 if id%3 == 0 { 356 return false, nil 357 } 358 return false, nil 359 } 360 361 func (v testVolumeQuota) GetConsumption(_ string, _ common.QuotaID) (int64, error) { 362 return 4096, nil 363 } 364 365 func (v testVolumeQuota) GetInodes(_ string, _ common.QuotaID) (int64, error) { 366 return 1, nil 367 } 368 369 func fakeSupportsQuotas(path string) (bool, error) { 370 dummySetFSInfo(path) 371 return SupportsQuotas(dummyQuotaTest(), path) 372 } 373 374 func fakeAssignQuota(path string, poduid types.UID, bytes int64) error { 375 dummySetFSInfo(path) 376 return AssignQuota(dummyQuotaTest(), path, poduid, resource.NewQuantity(bytes, resource.DecimalSI)) 377 } 378 379 func fakeClearQuota(path string) error { 380 dummySetFSInfo(path) 381 return ClearQuota(dummyQuotaTest(), path) 382 } 383 384 type quotaTestCase struct { 385 name string 386 path string 387 poduid types.UID 388 bytes int64 389 op string 390 expectedProjects string 391 expectedProjid string 392 supportsQuota bool 393 expectsSetQuota bool 394 deltaExpectedPodQuotaCount int 395 deltaExpectedDirQuotaCount int 396 deltaExpectedQuotaPodCount int 397 deltaExpectedDirPodCount int 398 deltaExpectedDevApplierCount int 399 deltaExpectedDirApplierCount int 400 deltaExpectedPodDirCountCount int 401 deltaExpectedQuotaSizeCount int 402 deltaExpectedSupportsQuotasCount int 403 deltaExpectedBackingDevCount int 404 deltaExpectedMountpointCount int 405 } 406 407 const ( 408 projectsHeader = `# This is a /etc/projects header 409 1048578:/quota/d 410 ` 411 projects1 = `1048577:/quota1/a 412 ` 413 projects2 = `1048577:/quota1/a 414 1048580:/quota1/b 415 ` 416 projects3 = `1048577:/quota1/a 417 1048580:/quota1/b 418 1048581:/quota2/b 419 ` 420 projects4 = `1048577:/quota1/a 421 1048581:/quota2/b 422 ` 423 projects5 = `1048581:/quota2/b 424 ` 425 426 projidHeader = `# This is a /etc/projid header 427 xxxxxx:1048579 428 ` 429 projid1 = `volume1048577:1048577 430 ` 431 projid2 = `volume1048577:1048577 432 volume1048580:1048580 433 ` 434 projid3 = `volume1048577:1048577 435 volume1048580:1048580 436 volume1048581:1048581 437 ` 438 projid4 = `volume1048577:1048577 439 volume1048581:1048581 440 ` 441 projid5 = `volume1048581:1048581 442 ` 443 ) 444 445 var quotaTestCases = []quotaTestCase{ 446 { 447 "SupportsQuotaOnQuotaVolume", 448 "/quota1/a", "", 1024, "Supports", "", "", 449 true, true, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 450 }, 451 { 452 "AssignQuotaFirstTime", 453 "/quota1/a", "", 1024, "Set", projects1, projid1, 454 true, true, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 455 }, 456 { 457 "AssignQuotaFirstTime", 458 "/quota1/b", "x", 1024, "Set", projects2, projid2, 459 true, true, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 460 }, 461 { 462 "AssignQuotaFirstTime", 463 "/quota2/b", "x", 1024, "Set", projects3, projid3, 464 true, true, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 465 }, 466 { 467 "AssignQuotaSecondTimeWithSameSize", 468 "/quota1/b", "x", 1024, "Set", projects3, projid3, 469 true, true, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 470 }, 471 { 472 "AssignQuotaSecondTimeWithDifferentSize", 473 "/quota2/b", "x", 2048, "Set", projects3, projid3, 474 true, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 475 }, 476 { 477 "ClearQuotaFirstTime", 478 "/quota1/b", "", 1024, "Clear", projects4, projid4, 479 true, true, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, 480 }, 481 { 482 "SupportsQuotaOnNonQuotaVolume", 483 "/noquota/a", "", 1024, "Supports", projects4, projid4, 484 false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 485 }, 486 { 487 "ClearQuotaFirstTime", 488 "/quota1/a", "", 1024, "Clear", projects5, projid5, 489 true, true, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, 490 }, 491 { 492 "ClearQuotaSecondTime", 493 "/quota1/a", "", 1024, "Clear", projects5, projid5, 494 true, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 495 }, 496 { 497 "ClearQuotaFirstTime", 498 "/quota2/b", "", 1024, "Clear", "", "", 499 true, true, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, 500 }, 501 } 502 503 func compareProjectsFiles(t *testing.T, testcase quotaTestCase, projectsFile string, projidFile string, enabled bool) { 504 bytes, err := os.ReadFile(projectsFile) 505 if err != nil { 506 t.Error(err.Error()) 507 } else { 508 s := string(bytes) 509 p := projectsHeader 510 if enabled { 511 p += testcase.expectedProjects 512 } 513 if s != p { 514 t.Errorf("Case %v /etc/projects miscompare: expected\n`%s`\ngot\n`%s`\n", testcase.path, p, s) 515 } 516 } 517 bytes, err = os.ReadFile(projidFile) 518 if err != nil { 519 t.Error(err.Error()) 520 } else { 521 s := string(bytes) 522 p := projidHeader 523 if enabled { 524 p += testcase.expectedProjid 525 } 526 if s != p { 527 t.Errorf("Case %v /etc/projid miscompare: expected\n`%s`\ngot\n`%s`\n", testcase.path, p, s) 528 } 529 } 530 } 531 532 func runCaseEnabled(t *testing.T, testcase quotaTestCase, seq int) bool { 533 fail := false 534 var err error 535 switch testcase.op { 536 case "Supports": 537 supports, err := fakeSupportsQuotas(testcase.path) 538 if err != nil { 539 fail = true 540 t.Errorf("Case %v (%s, %s, %v) Got error in fakeSupportsQuotas: %v", seq, testcase.name, testcase.path, true, err) 541 } 542 if supports != testcase.supportsQuota { 543 fail = true 544 t.Errorf("Case %v (%s, %s, %v) fakeSupportsQuotas got %v, expect %v", seq, testcase.name, testcase.path, true, supports, testcase.supportsQuota) 545 } 546 return fail 547 case "Set": 548 err = fakeAssignQuota(testcase.path, testcase.poduid, testcase.bytes) 549 case "Clear": 550 err = fakeClearQuota(testcase.path) 551 case "GetConsumption": 552 _, err = GetConsumption(testcase.path) 553 case "GetInodes": 554 _, err = GetInodes(testcase.path) 555 default: 556 t.Errorf("Case %v (%s, %s, %v) unknown operation %s", seq, testcase.name, testcase.path, true, testcase.op) 557 return true 558 } 559 if err != nil && testcase.expectsSetQuota { 560 fail = true 561 t.Errorf("Case %v (%s, %s, %v) %s expected to clear quota but failed %v", seq, testcase.name, testcase.path, true, testcase.op, err) 562 } else if err == nil && !testcase.expectsSetQuota { 563 fail = true 564 t.Errorf("Case %v (%s, %s, %v) %s expected not to clear quota but succeeded", seq, testcase.name, testcase.path, true, testcase.op) 565 } 566 return fail 567 } 568 569 func runCaseDisabled(t *testing.T, testcase quotaTestCase, seq int) bool { 570 var err error 571 var supports bool 572 switch testcase.op { 573 case "Supports": 574 if supports, _ = fakeSupportsQuotas(testcase.path); supports { 575 t.Errorf("Case %v (%s, %s, %v) supports quotas but shouldn't", seq, testcase.name, testcase.path, false) 576 return true 577 } 578 return false 579 case "Set": 580 err = fakeAssignQuota(testcase.path, testcase.poduid, testcase.bytes) 581 case "Clear": 582 err = fakeClearQuota(testcase.path) 583 case "GetConsumption": 584 _, err = GetConsumption(testcase.path) 585 case "GetInodes": 586 _, err = GetInodes(testcase.path) 587 default: 588 t.Errorf("Case %v (%s, %s, %v) unknown operation %s", seq, testcase.name, testcase.path, false, testcase.op) 589 return true 590 } 591 if err == nil { 592 t.Errorf("Case %v (%s, %s, %v) %s: supports quotas but shouldn't", seq, testcase.name, testcase.path, false, testcase.op) 593 return true 594 } 595 return false 596 } 597 598 func testAddRemoveQuotas(t *testing.T, enabled bool) { 599 defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LocalStorageCapacityIsolationFSQuotaMonitoring, enabled)() 600 tmpProjectsFile, err := os.CreateTemp("", "projects") 601 if err == nil { 602 _, err = tmpProjectsFile.WriteString(projectsHeader) 603 } 604 if err != nil { 605 t.Errorf("Unable to create fake projects file") 606 } 607 projectsFile = tmpProjectsFile.Name() 608 tmpProjectsFile.Close() 609 tmpProjidFile, err := os.CreateTemp("", "projid") 610 if err == nil { 611 _, err = tmpProjidFile.WriteString(projidHeader) 612 } 613 if err != nil { 614 t.Errorf("Unable to create fake projid file") 615 } 616 projidFile = tmpProjidFile.Name() 617 tmpProjidFile.Close() 618 providers = []common.LinuxVolumeQuotaProvider{ 619 &VolumeProvider1{}, 620 &VolumeProvider2{}, 621 } 622 for k := range podQuotaMap { 623 delete(podQuotaMap, k) 624 } 625 for k := range dirQuotaMap { 626 delete(dirQuotaMap, k) 627 } 628 for k := range quotaPodMap { 629 delete(quotaPodMap, k) 630 } 631 for k := range dirPodMap { 632 delete(dirPodMap, k) 633 } 634 for k := range devApplierMap { 635 delete(devApplierMap, k) 636 } 637 for k := range dirApplierMap { 638 delete(dirApplierMap, k) 639 } 640 for k := range podDirCountMap { 641 delete(podDirCountMap, k) 642 } 643 for k := range quotaSizeMap { 644 delete(quotaSizeMap, k) 645 } 646 for k := range supportsQuotasMap { 647 delete(supportsQuotasMap, k) 648 } 649 for k := range backingDevMap { 650 delete(backingDevMap, k) 651 } 652 for k := range mountpointMap { 653 delete(mountpointMap, k) 654 } 655 for k := range testIDQuotaMap { 656 delete(testIDQuotaMap, k) 657 } 658 for k := range testQuotaIDMap { 659 delete(testQuotaIDMap, k) 660 } 661 expectedPodQuotaCount := 0 662 expectedDirQuotaCount := 0 663 expectedQuotaPodCount := 0 664 expectedDirPodCount := 0 665 expectedDevApplierCount := 0 666 expectedDirApplierCount := 0 667 expectedPodDirCountCount := 0 668 expectedQuotaSizeCount := 0 669 expectedSupportsQuotasCount := 0 670 expectedBackingDevCount := 0 671 expectedMountpointCount := 0 672 for seq, testcase := range quotaTestCases { 673 if enabled { 674 expectedPodQuotaCount += testcase.deltaExpectedPodQuotaCount 675 expectedDirQuotaCount += testcase.deltaExpectedDirQuotaCount 676 expectedQuotaPodCount += testcase.deltaExpectedQuotaPodCount 677 expectedDirPodCount += testcase.deltaExpectedDirPodCount 678 expectedDevApplierCount += testcase.deltaExpectedDevApplierCount 679 expectedDirApplierCount += testcase.deltaExpectedDirApplierCount 680 expectedPodDirCountCount += testcase.deltaExpectedPodDirCountCount 681 expectedQuotaSizeCount += testcase.deltaExpectedQuotaSizeCount 682 expectedSupportsQuotasCount += testcase.deltaExpectedSupportsQuotasCount 683 expectedBackingDevCount += testcase.deltaExpectedBackingDevCount 684 expectedMountpointCount += testcase.deltaExpectedMountpointCount 685 } 686 fail := false 687 if enabled { 688 fail = runCaseEnabled(t, testcase, seq) 689 } else { 690 fail = runCaseDisabled(t, testcase, seq) 691 } 692 693 compareProjectsFiles(t, testcase, projectsFile, projidFile, enabled) 694 if len(podQuotaMap) != expectedPodQuotaCount { 695 fail = true 696 t.Errorf("Case %v (%s, %s, %v) podQuotaCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(podQuotaMap), expectedPodQuotaCount) 697 } 698 if len(dirQuotaMap) != expectedDirQuotaCount { 699 fail = true 700 t.Errorf("Case %v (%s, %s, %v) dirQuotaCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(dirQuotaMap), expectedDirQuotaCount) 701 } 702 if len(quotaPodMap) != expectedQuotaPodCount { 703 fail = true 704 t.Errorf("Case %v (%s, %s, %v) quotaPodCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(quotaPodMap), expectedQuotaPodCount) 705 } 706 if len(dirPodMap) != expectedDirPodCount { 707 fail = true 708 t.Errorf("Case %v (%s, %s, %v) dirPodCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(dirPodMap), expectedDirPodCount) 709 } 710 if len(devApplierMap) != expectedDevApplierCount { 711 fail = true 712 t.Errorf("Case %v (%s, %s, %v) devApplierCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(devApplierMap), expectedDevApplierCount) 713 } 714 if len(dirApplierMap) != expectedDirApplierCount { 715 fail = true 716 t.Errorf("Case %v (%s, %s, %v) dirApplierCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(dirApplierMap), expectedDirApplierCount) 717 } 718 if len(podDirCountMap) != expectedPodDirCountCount { 719 fail = true 720 t.Errorf("Case %v (%s, %s, %v) podDirCountCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(podDirCountMap), expectedPodDirCountCount) 721 } 722 if len(quotaSizeMap) != expectedQuotaSizeCount { 723 fail = true 724 t.Errorf("Case %v (%s, %s, %v) quotaSizeCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(quotaSizeMap), expectedQuotaSizeCount) 725 } 726 if len(supportsQuotasMap) != expectedSupportsQuotasCount { 727 fail = true 728 t.Errorf("Case %v (%s, %s, %v) supportsQuotasCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(supportsQuotasMap), expectedSupportsQuotasCount) 729 } 730 if len(backingDevMap) != expectedBackingDevCount { 731 fail = true 732 t.Errorf("Case %v (%s, %s, %v) BackingDevCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(backingDevMap), expectedBackingDevCount) 733 } 734 if len(mountpointMap) != expectedMountpointCount { 735 fail = true 736 t.Errorf("Case %v (%s, %s, %v) MountpointCount mismatch: got %v, expect %v", seq, testcase.name, testcase.path, enabled, len(mountpointMap), expectedMountpointCount) 737 } 738 if fail { 739 logAllMaps(fmt.Sprintf("%v %s %s", seq, testcase.name, testcase.path)) 740 } 741 } 742 os.Remove(projectsFile) 743 os.Remove(projidFile) 744 } 745 746 func TestAddRemoveQuotasEnabled(t *testing.T) { 747 testAddRemoveQuotas(t, true) 748 } 749 750 func TestAddRemoveQuotasDisabled(t *testing.T) { 751 testAddRemoveQuotas(t, false) 752 }