1
2
3
4
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
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 }
753
View as plain text