quota_linux_test.go 20 KB

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