...

Source file src/k8s.io/kubernetes/pkg/volume/util/fsquota/quota_linux_test.go

Documentation: k8s.io/kubernetes/pkg/volume/util/fsquota

     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  }
   753  

View as plain text