quota_linux_test.go 21 KB

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